В чем разница между слоем встраивания со смещением сразу после этого и линейным слоем в PyTorch

Я читаю книгу «Глубокое обучение кодеров с помощью 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)
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
12
0
5 381
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Встраивание

[...] то, что 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 может быть одним горячим кодированием, а также может быть разреженным, но в зависимости от алгоритмов (и от того, поддерживают ли они разреженность) может быть повышение производительности или нет.

TL;DR

  • nn.Embedding для категорического ввода.
  • nn.Linear для порядкового ввода.

Объяснение

Вы используете nn.Embedding при работе с категориальными данными, например, метками классов (0, 1, 2, ...). Потому что в таблице поиска значение не будет пропорционально ключу. Такое поведение подходит для категориальных данных, значение которых не имеет ничего общего с семантикой.

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

Другие вопросы по теме