Векторное представление слов в PyTorch

Векторное представление слов — одна из самых фундаментальных и важных техник в обработке естественного языка.

Векторное представление слов отображает дискретные символы слов в непрерывные плотные векторы, позволяя машинам понимать и обрабатывать текстовые данные.

PyTorch предоставляетnn.Embeddingмодуль для реализации этой функциональности, служащий основой для построения различных моделей NLP.


1. Основные понятия встраивания слов

В компьютере текст по сути представляет собой последовательность целых чисел. Каждому слову присваивается уникальный индексный ID, но у этого дискретного представления есть проблема: семантически похожие слова могут иметь близкое значение, однако их ID совершенно не связаны.

Встраивание слов решает эту проблему путём обученияматрицы встраивания:

\[ E \in \mathbb{R}^{V \times D} \]

Где \(V\) — размер словаря, а \(D\) — размерность встраивания. Каждый ID слова соответствует строке в матрице встраивания, а его векторное представление получается с помощью операции поиска:

\[ \text{embedding} = E[\text{word\_id}] \]

Преимущества встраивания слов включают:

  • Преобразование высокоразмерных разреженных one-hot векторов в низкоразмерные плотные векторы, что значительно снижает вычислительные затраты
  • Семантически похожие слова находятся ближе в векторном пространстве, и сходство слов можно вычислить с помощью косинусного сходства
  • Векторы встраивания являются обучаемыми параметрами и могут автоматически настраиваться с помощью обратного распространения ошибки

2. Подробное объяснение nn.Embedding

nn.Embedding— это слой встраивания слов, предоставляемый PyTorch, инкапсулирующий создание матрицы встраивания и операцию поиска.

2.1 Базовое использование

Пример

import torch
import torch.nn as nn

# Создание слоя встраивания
# num_embeddings: размер словаря (vocab_size)
# embedding_dim: размерность встраивания (embedding_dim)
vocab_size = 10000
embedding_dim = 256

embedding = nn.Embedding(num_embeddings=vocab_size, embedding_dim=embedding_dim)

# Просмотр формы матрицы встраивания
print(embedding.weight.shape)   # torch.Size([10000, 256])

# Входные индексы слов (LongTensor) для получения векторов встраивания
word_ids = torch.tensor([0, 1, 2, 9999])  # Произвольные индексы слов
embedded = embedding(word_ids)

print(embedded.shape)           # torch.Size([4, 256])
# Каждый ID слова соответствует 256-мерному вектору

2.2 Подробности параметров nn.Embedding

Пример

import torch.nn as nn

embedding = nn.Embedding(
    num_embeddings=10000,    # Размер словаря, должен быть больше или равен максимальному значению индекса во входных данных
    embedding_dim=256,       # Размерность вектора эмбеддинга, обычно 50, 100, 200, 300 и т. д.
    padding_idx=None,        # Индекс слова-заполнителя; вектор эмбеддинга для слова-заполнителя состоит из нулей
    max_norm=None,          # Максимальная норма вектора эмбеддинга, используется для нормализации
    norm_type=2.0,          # Тип нормализации, обычно норма L2
    scale_grad_by_freq=False,# Масштабировать градиенты по частоте слов
    sparse=False,           # Использовать ли разреженные градиенты (экономит память GPU, но обучение медленнее)
    _weight=None,           # Предопределённые веса, используются для загрузки предобученных эмбеддингов
)

# Просмотр количества параметров
total_params = embedding.num_embeddings * embedding.embedding_dim
print(f"Количество параметров слоя эмбеддингов: {total_params:,}")
# 10000 * 256 = 2,560,000

Число параметров в слое эмбеддингов = размер словаря × размерность эмбеддинга. Это очень большая матрица. Обычно слой эмбеддингов NLP-модели составляет большую долю от общего числа параметров модели.

2.3 Индекс паддинга padding_idx

При обработке последовательностей переменной длины короткие последовательности нужно дополнять. Используяpadding_idx, можно зафиксировать вектор эмбеддинга слова паддинга как нулевой вектор, чтобы содержимое паддинга не влияло на модель:

Пример

import torch
import torch.nn as nn

# Установить padding_idx=0, то есть индекс 0 — это слово паддинга
embedding = nn.Embedding(num_embeddings=10000, embedding_dim=128, padding_idx=0)

# Инициализация весов
nn.init.uniform_(embedding.weight, -0.1, 0.1)

# Вектор эмбеддинга для индекса 0 состоит из нулей
word_0 = embedding(torch.tensor([0]))
print(f"Эмбеддинг слова-заполнителя: {word_0}")   # Все нули

# Остальные индексы остаются обычными
word_5 = embedding(torch.tensor([5]))
print(f"Эмбеддинг слова 5: {word_5}")     # Ненулевые значения

2.4 Нормализация максимальной нормы

Использованиеmax_normможно ограничить норму векторов эмбеддингов, не позволяя им становиться слишком большими во время обучения:

Пример

import torch
import torch.nn as nn

# Установите максимальную норму равной 1.0
embedding = nn.Embedding(num_embeddings=1000, embedding_dim=64, max_norm=1.0)

# Введите произвольные индексы слов
ids = torch.tensor([1, 2, 3])
embedded = embedding(ids)

# Проверьте L2-норму каждого вектора
norms = torch.norm(embedded, p=2, dim=1)
print(f"Нормы каждого вектора: {norms}")   # Все значения близки к 1.0

3. Загрузка предобученных эмбеддингов слов

Использование предобученных эмбеддингов слов может значительно улучшить производительность модели, особенно когда обучающих данных мало. Распространенные предобученные эмбеддинги слов включают Word2Vec, GloVe, FastText и т. д.

3.1 Разница между обучением с нуля и загрузкой предобученных эмбеддингов

Метод Преимущества Недостатки Применимые сценарии
Случайная инициализация и обучение Полностью настраиваемый, адаптируется к конкретным задачам Требует большого объема обучающих данных Много предметно-специфичных слов и достаточный объем обучающих данных
Загрузка предобученных эмбеддингов Использует знания из крупномасштабных корпусов, быстрое обучение и хорошие результаты Ограниченный охват словаря, не может обрабатывать слова вне словаря Общие задачи, ограниченные обучающие данные
Замораживание предобученных эмбеддингов Быстрое обучение, низкое потребление памяти GPU Эмбеддинги нельзя дообучить Ограниченные ресурсы для обучения, фокус только на верхних слоях модели
Дообучение предобученных эмбеддингов Можно адаптировать под конкретные задачи Более медленное обучение, высокое потребление памяти GPU Умеренный объём данных, определённые доменные различия

3.2 Загрузка предобученных векторов слов GloVe

GloVe — это предобученный вектор слов, выпущенный Стэнфордским университетом. Ниже показано, как его загрузить:

Пример

import torch
import torch.nn as nn
import numpy as np

# Имитация загрузки векторов слов GloVe (на самом деле нужно скачать файлы GloVe)
# Предположим, что уже есть файл векторов слов со следующим форматом: каждая строка содержит слово, за которым следуют его векторы

def load_glove_embeddings(path, word2idx, embedding_dim=300):
    """
Загрузить предобученные векторы слов GloVe
path: путь к файлу векторов слов
word2idx: словарь, отображающий слова в индексы
embedding_dim: размерность векторов слов
    """

    embeddings = np.random.randn(len(word2idx), embedding_dim).astype(np.float32)
    word_count = 0

    with open(path, 'r', encoding='utf-8') as f:
        for line in f:
            values = line.strip().split()
            word = values[0]
            if word in word2idx:
                word_idx = word2idx[word]
                embeddings[word_idx] = np.asarray(values[1:], dtype=np.float32)
                word_count += 1

    print(f"Загружено {word_count}/{len(word2idx)} векторов слов")
    return torch.from_numpy(embeddings)


# Предположим, что словарь уже существует
word2idx = {'hello': 0, 'world': 1, 'example': 2, 'python': 3}
EMBED_DIM = 300

# Загрузить предобученные эмбеддинги и создать слой эмбеддингов
# pretrained_embeddings = load_glove_embeddings('glove.6B.300d.txt', word2idx, EMBED_DIM)
# embedding = nn.Embedding.from_pretrained(pretrained_embeddings, padding_idx=0)

# Упрощённый пример: используем случайно инициализированную предобученную матрицу
pretrained_embeddings = torch.randn(len(word2idx), EMBED_DIM)
embedding = nn.Embedding.from_pretrained(pretrained_embeddings, padding_idx=0)

print(f"Форма слоя эмбеддингов: {embedding.weight.shape}")

3.3 Замораживание и дообучение слоя эмбеддингов

В зависимости от требований задачи вы можете заморозить или дообучить слой эмбеддингов:

Пример

import torch
import torch.nn as nn

embedding = nn.Embedding(num_embeddings=10000, embedding_dim=256)

# Метод 1: заморозить слой эмбеддингов (не участвует в обучении)
embedding.weight.requires_grad = False
# Во время обучения не будут обновляться только параметры с embedding.weight.requires_grad = False

# Метод 2: дообучить слой эмбеддингов (участвует в обучении)
embedding.weight.requires_grad = True

# Метод 3: заморозить часть векторов слов (заморозить высокочастотные слова, такие как "the", "is")
# Предположим, что индексы высокочастотных слов находятся в диапазоне 0-99
embedding.weight.requires_grad = True
with torch.no_grad():
    embedding.weight[0:100] *= 0  # Или присвоить фиксированные значения

# Исключить замороженные параметры из оптимизатора
optimizer = torch.optim.Adam(
    filter(lambda p: p.requires_grad, embedding.parameters()),
    lr=1e-3
)

4. Объединение слоя Embedding с RNN/LSTM

Векторное представление слов — это первый слой NLP-модели. Оно преобразует текстовые ID в плотные векторы, которые затем передаются в последовательностные модели, такие как RNN и LSTM, для обработки.

4.1 Классификация текста с помощью слоя Embedding + LSTM

Пример

import torch
import torch.nn as nn

class TextClassifier(nn.Module):
    """
Модель классификации текста на основе Embedding Layer + LSTM
    """

    def __init__(self, vocab_size, embed_dim, hidden_size, num_classes, padding_idx=0):
        super().__init__()

        # Слой встраивания слов
        self.embedding = nn.Embedding(
            num_embeddings=vocab_size,
            embedding_dim=embed_dim,
            padding_idx=padding_idx
        )

        # Слой LSTM
        self.lstm = nn.LSTM(
            input_size=embed_dim,
            hidden_size=hidden_size,
            num_layers=2,
            batch_first=True,
            bidirectional=True,
            dropout=0.3
        )

        # Классификатор
        self.fc = nn.Linear(hidden_size * 2, num_classes)

    def forward(self, x):
        # x: (batch_size, seq_len) - индексы слов
        embedded = self.embedding(x)  # (batch_size, seq_len, embed_dim)

        # Выход LSTM
        output, (h_n, c_n) = self.lstm(embedded)

        # Взять скрытое состояние последнего временного шага (двунаправленная конкатенация)
        # Последнее скрытое состояние прямого направления: h_n[-2]
        # Последнее скрытое состояние обратного направления: h_n[-1]
        h_combined = torch.cat([h_n[-2], h_n[-1]], dim=-1)

        # Классификация
        logits = self.fc(h_combined)
        return logits


# Создать экземпляр модели
VOCAB_SIZE = 10000
EMBED_DIM = 128
HIDDEN_SIZE = 128
NUM_CLASSES = 2

model = TextClassifier(VOCAB_SIZE, EMBED_DIM, HIDDEN_SIZE, NUM_CLASSES)

# Имитация входа: batch_size=4, длина последовательности=10
batch_input = torch.randint(1, VOCAB_SIZE, (4, 10))
output = model(batch_input)

print(f"Форма входа: {batch_input.shape}")      # torch.Size([4, 10])
print(f"Форма выхода: {output.shape}")           # torch.Size([4, 2])

4.2 Использование предварительно обученных векторов слов

Пример

import torch
import torch.nn as nn

# Предположим, что предварительно обученные векторы слов загружены
pretrained_vectors = torch.randn(10000, 300)  # Имитация предварительно обученных векторов

# Создать слой встраивания и загрузить предварительно обученные веса
embedding = nn.Embedding.from_pretrained(
    pretrained_vectors,
    padding_idx=0,
    freeze=False  # True: заморозить и не обучать, False: дообучать
)

# При использовании GloVe или других предобученных векторов слов обычно сначала замораживают на несколько эпох, затем размораживают для дообучения
# В течение первых нескольких эпох обучайте только верхние слои модели
embedding.weight.requires_grad = False

# После обучения в течение нескольких эпох разморозьте слой эмбеддингов для дообучения
# embedding.weight.requires_grad = True

5. Позиционное кодирование

В отличие от RNN/LSTM, модель Transformer не включает информацию о позиции. Чтобы модель воспринимала порядок слов в последовательности, необходимо дополнительно добавить позиционное кодирование.

5.1 Принцип позиционного кодирования

Позиционное кодирование использует функции синуса и косинуса для генерации векторов позиций:

\[ \begin{aligned} PE_{(pos, 2i)} &= \sin\left(\frac{pos}{10000^{2i/d_{model}}}\right) \\ PE_{(pos, 2i+1)} &= \cos\left(\frac{pos}{10000^{2i/d_{model}}}\right) \end{aligned} \]

Особенность этого метода кодирования заключается в том, что кодировки на разных позициях могут быть преобразованы друг в друга с помощью линейных преобразований, что позволяет модели легко изучать позиционные взаимосвязи.

5.2 Реализация позиционного кодирования

Пример

import torch
import torch.nn as nn
import math

class PositionalEncoding(nn.Module):
    """
Слой позиционного кодирования
    """

    def __init__(self, d_model, max_len=5000):
        super().__init__()

        # Создать матрицу позиционного кодирования
        pe = torch.zeros(max_len, d_model)
        position = torch.arange(0, max_len, dtype=torch.float).unsqueeze(1)

        # Вычислить член делителя
        div_term = torch.exp(torch.arange(0, d_model, 2).float() * (-math.log(10000.0) / d_model))

        # Использовать sin для чётных индексов и cos для нечётных индексов
        pe[:, 0::2] = torch.sin(position * div_term)
        pe[:, 1::2] = torch.cos(position * div_term)

        # Добавить размерность пакета и зарегистрировать её как буфер, не участвующий в вычислении градиента
        pe = pe.unsqueeze(0)  # (1, max_len, d_model)
        self.register_buffer('pe', pe)

    def forward(self, x):
        """
        x: (batch_size, seq_len, d_model)
        """

        seq_len = x.size(1)
        # Взять срез позиционного кодирования соответствующей длины и добавить его
        x = x + self.pe[:, :seq_len, :]
        return x


# Пример использования
d_model = 256
max_len = 100

pos_encoding = PositionalEncoding(d_model, max_len)

# Смоделированный вход: batch_size=4, seq_len=20, d_model=256
x = torch.randn(4, 20, d_model)
x = pos_encoding(x)

print(f"Форма входа: {x.shape}")   # torch.Size([4, 20, 256])

Позиционное кодирование — ключевой компонент архитектуры Transformer. Оно позволяет модели различать слова на разных позициях, даже если их векторы эмбеддингов одинаковы.

5.3 Обучаемое позиционное кодирование

В дополнение к фиксированному позиционному кодированию также можно использовать обучаемое позиционное кодирование:

Пример

import torch
import torch.nn as nn

class LearnablePositionalEncoding(nn.Module):
    """
Обучаемое позиционное кодирование
    """

    def __init__(self, d_model, max_len=5000):
        super().__init__()
        self.pos_embedding = nn.Embedding(max_len, d_model)

    def forward(self, x):
        batch_size, seq_len, d_model = x.size(1), x.size(1), x.size(2)
        # Создать индексы позиций [0, 1, 2, ..., seq_len-1]
        positions = torch.arange(seq_len, device=x.device).unsqueeze(0).expand(batch_size, -1)
        pos_encoded = self.pos_embedding(positions)
        return x + pos_encoded


# Пример использования
pos_encoding = LearnablePositionalEncoding(d_model=256, max_len=100)
x = torch.randn(4, 20, 256)
x = pos_encoding(x)
print(f"Форма выхода: {x.shape}")   # torch.Size([4, 20, 256])

6. Продвинутые методы для слоёв эмбеддингов

6.1. Снижение использования памяти GPU

Когда словарь очень большой, слой эмбеддингов потребляет много памяти GPU. Для оптимизации можно использовать следующие методы:

Пример

import torch
import torch.nn as nn

# Метод 1: Использовать разреженные градиенты (sparse=True)
embedding = nn.Embedding(
    num_embeddings=100000,
    embedding_dim=256,
    sparse=True  # Градиенты хранятся в разреженном формате, что экономит память GPU
)

# Техника 2: Использовать квантование
# Преобразование float32 в int8 или float16
embedding_int8 = embedding.to(torch.int8)

# Техника 3: Заморозить редко используемые векторы слов
# В крупномасштабном словаре обучайте только высокочастотные слова; низкочастотные слова оставляйте замороженными
embedding = nn.Embedding(num_embeddings=100000, embedding_dim=256)
embedding.weight.requires_grad = True

# Заморозить векторы слов с индексом больше 50000
with torch.no_grad():
    embedding.weight[50000:] *= 0
embedding.weight.requires_grad = False

# Обучать только высокочастотные слова
embedding.weight[1:50000].requires_grad = True

6.2 Обработка слов вне словаря (OOV)

Слова, отсутствующие в словаре (слова вне словаря / OOV), могут появляться в тестовом наборе и требуют специальной обработки:

Пример

import torch
import torch.nn as nn

class EmbeddingWithOOV(nn.Module):
    """
Слой эмбеддингов, поддерживающий слова вне словаря
    """

    def __init__(self, vocab_size, embed_dim, oov_idx=Отсутствует):
        super().__init__()
        self.embedding = nn.Embedding(vocab_size + 1, embed_dim, padding_idx=0)
        self.oov_idx = oov_idx if oov_idx is not None else vocab_size  # Использовать последний индекс как OOV

    def forward(self, x):
        # Заменить индексы OOV-слов на oov_idx
        oov_mask = x >= self.vocab_size
        x = x.clone()
        x[oov_mask] = self.oov_idx
        return self.embedding(x)


# Использовать методы хеширования для обработки больших словарей
class HashEmbedding(nn.Module):
    """
Слой эмбеддингов с использованием хеширования для обработки словарей произвольного размера
    """

    def __init__(self, num_buckets, embed_dim):
        super().__init__()
        self.num_buckets = num_buckets
        self.embedding = nn.Embedding(num_buckets, embed_dim)

    def forward(self, x):
        # Хеширование индексов слов в бакеты
        # Использовать метод хеширования словаря Python
        hashed = torch.remainder(x, self.num_buckets)
        return self.embedding(hashed)

6.3 Субсловные эмбеддинги

Для языков с богатой морфологией (таких как немецкий и русский) субсловные эмбеддинги могут эффективно справляться с проблемой слов вне словаря:

Пример

import torch
import torch.nn as nn

class SubwordEmbedding(nn.Module):
    """
Упрощённый пример субсловных эмбеддингов
На практике для токенизации следует использовать такие алгоритмы, как BPE и WordPiece
    """

    def __init__(self, vocab_size, embed_dim, char_dim=50):
        super().__init__()
        # Эмбеддинг на уровне символов
        self.char_embedding = nn.Embedding(vocab_size, char_dim)
        # Эмбеддинг на уровне слов
        self.word_embedding = nn.Embedding(vocab_size, embed_dim - char_dim)
        # LSTM на уровне символов для объединения векторов символов
        self.char_lstm = nn.LSTM(
            char_dim, char_dim,
            batch_first=True, bidirectional=True
        )

    def forward(self, word_ids, char_ids):
        """
word_ids: индексы слов (batch_size, seq_len)
char_ids: индексы символов (batch_size, seq_len, max_word_len)
        """

        # Векторное представление слов
        word_emb = self.word_embedding(word_ids)

        # Символьный эмбеддинг + LSTM
        batch_size, seq_len, max_word_len = char_ids.shape
        char_ids_flat = char_ids.view(-1, max_word_len)  # (batch_size * seq_len, max_word_len)
        char_emb = self.char_embedding(char_ids_flat)    # (batch_size * seq_len, max_word_len, char_dim)

        char_output, (h_n, _) = self.char_lstm(char_emb)
        # Взять финальные скрытые состояния двунаправленного слоя и конкатенировать
        char_rep = torch.cat([h_n[-2], h_n[-1]], dim=-1)  # (batch_size * seq_len, char_dim * 2)

        char_rep = char_rep.view(batch_size, seq_len, -1)  # (batch_size, seq_len, char_dim * 2)

        # Объединить эмбеддинг слова и символьное представление
        combined = torch.cat([word_emb, char_rep], dim=-1)
        return combined

7. Полный практический пример: модель классификации текста

Ниже приведён полный пример модели классификации текста, включая слой эмбеддингов, LSTM и классификатор:

Пример

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import Dataset, DataLoader

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# ── Параметры конфигурации ──────────────────────────────────────
VOCAB_SIZE = 10000
EMBED_DIM = 128
HIDDEN_SIZE = 128
NUM_LAYERS = 2
NUM_CLASSES = 5
DROPOUT = 0.3
MAX_LEN = 200

# ── Определение модели ──────────────────────────────────────
class TextClassificationModel(nn.Module):
    def __init__(self, vocab_size, embed_dim, hidden_size,
                 num_layers, num_classes, dropout=0.3, padding_idx=0):
        super().__init__()

        # Слой эмбеддингов
        self.embedding = nn.Embedding(
            vocab_size,
            embed_dim,
            padding_idx=padding_idx
        )

        # BiLSTM
        self.lstm = nn.LSTM(
            embed_dim,
            hidden_size,
            num_layers=num_layers,
            batch_first=True,
            bidirectional=True,
            dropout=dropout if num_layers > 1 else 0
        )

        # Классификатор
        self.dropout = nn.Dropout(dropout)
        self.fc = nn.Linear(hidden_size * 2, num_classes)

    def forward(self, x):
        # x: (batch_size, seq_len)
        embedded = self.embedding(x)  # (batch_size, seq_len, embed_dim)

        # LSTM
        output, (h_n, c_n) = self.lstm(embedded)

        # Объединить финальные скрытые состояния двунаправленной сети
        h_forward = h_n[-2]   # (batch_size, hidden_size)
        h_backward = h_n[-1]  # (batch_size, hidden_size)
        h_combined = torch.cat([h_forward, h_backward], dim=-1)

        # Классификация
        dropped = self.dropout(h_combined)
        logits = self.fc(droped)
        return logits


# ── Набор данных ──────────────────────────────────────
class TextDataset(Dataset):
    def __init__(self, texts, labels, vocab, max_len=200):
        self.texts = texts
        self.labels = labels
        self.vocab = vocab
        self.max_len = max_len

    def __len__(self):
        return len(self.texts)

    def __getitem__(self, idx):
        text = self.texts[idx][:self.max_len]
        # Преобразовать слова в индексы, неизвестные слова обозначены 1 (<UNK>)
        ids = [self.vocab.get(word, 1) for word in text]
        # Дополнить нулями до фиксированной длины
        if len(ids) < self.max_len:
            ids += [0] * (self.max_len - len(ids))
        return torch.tensor(ids), torch.tensor(self.labels[idx])


# ── Функция обучения ──────────────────────────────────────
def train_epoch(model, loader, optimizer, criterion, device):
    model.train()
    total_loss = 0
    correct = 0
    total = 0

    for inputs, labels in loader:
        inputs, labels = inputs.to(device), labels.to(device)

        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        total_loss += loss.item() * inputs.size(0)
        _, predicted = outputs.max(1)
        correct += predicted.eq(labels).sum().item()
        total += labels.size(0)

    return total_loss / total, correct / total


# ── Инициализация и обучение ──────────────────────────────────
# Предполагается, что словарь уже существует
word2idx = {'<PAD>': 0, '<UNK>': 1}  # Словарь нужно построить на основе реального корпуса

model = TextClassificationModel(
    VOCAB_SIZE, EMBED_DIM, HIDDEN_SIZE,
    NUM_LAYERS, NUM_CLASSES, DROPOUT
).to(device)

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=1e-3)

# Имитация обучения
print("Начало обучения...")
for epoch in range(10):
    train_loss, train_acc = train_epoch(model, None, optimizer, criterion, device)
    print(f"Epoch {epoch+1}: Loss={train_loss:.4f}, Acc={train_acc:.4f}")

8. Краткий справочник по API

8.1 Общие операции с nn.Embedding

Действие Code
Создать слой эмбеддингов nn.Embedding(num_embeddings, embedding_dim)
Загрузить предобученные эмбеддинги nn.Embedding.from_pretrained(weights)
Поиск по таблице для получения эмбеддингов embedding(word_ids)
Заморозить эмбеддинги embedding.weight.requires_grad = False
Получить векторы эмбеддингов embedding.weight[idx]

8.2 Ресурсы предобученных векторов слов

Ресурс Измерение Особенности
GloVe 50, 100, 200, 300 Статистика совместной встречаемости слов, быстрое обучение
Word2Vec 50-500 Обучен Google, широкий охват
FastText 300 Поддерживает субслова, хорошо справляется с OOV
BERT 768+ Зависит от контекста, наилучшая производительность

8.3 Рекомендации по выбору слоя эмбеддингов

数据量小(< 10K)
    -> 使用预训练词向量(GloVe/FastText)+ 冻结或微调

数据量中等(10K ~ 100K)
    -> 使用预训练词向量 + 微调

数据量大(> 100K)
    -> 可考虑从头训练,或使用大规模预训练模型

领域差异大
    -> 使用领域相关预训练模型或增量训练

资源受限
    -> 冻结嵌入层,使用较小的嵌入维度
Другие расширения