Я читаю книгу «Глубокое обучение кодеров с помощью fastai и PyTorch». Я все еще немного смущен тем, что делает модуль Embedding. Это похоже на короткую и простую сеть, за исключением того, что я не могу понять, что Embedding делает иначе, чем Linear без предвзятости. Я знаю, что это более быстрая вычислительная версия скалярного произведения, где одна из матриц является матрицей с горячим кодированием, а другая — матрицей вложения. Это делает это, чтобы фактически выбрать часть данных? Пожалуйста, укажите, где я ошибаюсь. Вот одна из простых сетей, показанных в книге.
class DotProduct(Module):
def __init__(self, n_users, n_movies, n_factors):
self.user_factors = Embedding(n_users, n_factors)
self.movie_factors = Embedding(n_movies, n_factors)
def forward(self, x):
users = self.user_factors(x[:,0])
movies = self.movie_factors(x[:,1])
return (users * movies).sum(dim=1)
[...] то, что Embedding делает иначе, чем Linear без предвзятости.
По сути все. torch.nn.Embedding — таблица поиска; он работает так же, как torch.Tensor
, но с некоторыми особенностями (например, возможность использовать разреженное встраивание или значение по умолчанию для указанного индекса).
Например:
import torch
embedding = torch.nn.Embedding(3, 4)
print(embedding.weight)
print(embedding(torch.tensor([1])))
Будет вывод:
Parameter containing:
tensor([[ 0.1420, -0.1886, 0.6524, 0.3079],
[ 0.2620, 0.4661, 0.7936, -1.6946],
[ 0.0931, 0.3512, 0.3210, -0.5828]], requires_grad=True)
tensor([[ 0.2620, 0.4661, 0.7936, -1.6946]], grad_fn=<EmbeddingBackward>)
Итак, мы взяли первый ряд встраивания. Это не делает ничего больше, чем это.
Обычно, когда мы хотим закодировать некоторое значение (например, word2vec) для каждой строки (например, слова, близкие семантически, близки в евклидовом пространстве) и, возможно, обучить их.
torch.nn.Linear (без смещения) также является torch.Tensor
(весом), но выполняет операцию над ним (и вводом), которая по сути:
output = input.matmul(weight.t())
каждый раз, когда вы вызываете слой (см. исходный код и функциональное определение этого слоя).
Слой в вашем фрагменте кода делает это:
__init__
(batch_size, 2)
:
(batch_size,)
(так что это отличается от nn.Linear
, которое возвращает (batch_size, out_features)
и выполняет скалярное произведение вместо поэлементного умножения с последующим суммированием, как здесь)Это, вероятно, используется для обучения обоих представлений (пользователей и фильмов) для какой-то рекомендательной системы.
Я знаю, что это более быстрая вычислительная версия скалярного произведения. где одна из матриц является матрицей горячего кодирования, а другая матрица вложения.
Нет, это не так. torch.nn.Embedding
может быть одним горячим кодированием, а также может быть разреженным, но в зависимости от алгоритмов (и от того, поддерживают ли они разреженность) может быть повышение производительности или нет.
nn.Embedding
для категорического ввода.nn.Linear
для порядкового ввода.Вы используете nn.Embedding
при работе с категориальными данными, например, метками классов (0, 1, 2, ...). Потому что в таблице поиска значение не будет пропорционально ключу. Такое поведение подходит для категориальных данных, значение которых не имеет ничего общего с семантикой.
С другой стороны, nn.Linear
, будучи матричным умножением, не обеспечивает вышеупомянутого поведения. Вход и выход пропорциональны натуральному умножению. Поэтому вы используете nn.Linear
для порядковых данных.