Функция Pytorch Loss для создания подобных вложений

Я работаю над моделью встраивания, где есть модель BERT, которая принимает текстовые входы и выводит многомерный вектор. Цель модели - найти похожие вложения (высокое косинусное сходство) для похожих текстов и разные вложения (низкое косинусное сходство) для разных текстов.

При обучении в мини-пакетном режиме модель BERT дает N*D размерный результат, где N - размер пакета, а D - выходной размер модели BERT.

Кроме того, у меня есть целевая матрица размерности N*N, которая содержит 1 в [i, j] позиции, если sentence[i] и sentence[j] похожи по смыслу, и -1 в противном случае.

Что я хочу сделать, так это найти потерю / ошибку для всего пакета, найдя косинусное сходство всех вложений в выводе BERT и сравнив его с целевой матрицей.

Я просто умножил тензор на его транспонирование, а затем взял поэлементный сигмоид.

scores = torch.matmul(document_embedding, torch.transpose(document_embedding, 0, 1))
scores = torch.sigmoid(scores)

loss = self.bceloss(scores, targets)

Но это, похоже, не работает.

Есть ли другой способ сделать это?

P.S. Я хочу сделать аналогично методу, описанному в этой статье.


person krishanudb    schedule 31.12.2020    source источник


Ответы (1)


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

Позвольте нам называть x ваш документ_ вложением формы (n, d), где d - размер вложения. Возьмем n=3 и d=5. Итак, x состоит из [x1, x2, x3].T.

>>> x = torch.rand(n, d)
tensor([[0.8620, 0.9322, 0.4220, 0.0280, 0.3789],
        [0.2747, 0.4047, 0.6418, 0.7147, 0.3409],
        [0.6573, 0.3432, 0.5663, 0.2512, 0.0582]])

Сходство косинуса - это нормализованное скалярное произведение. [email protected] умножение матриц даст вам попарный точечный продукт: который содержит : ||x1||², <x1/x2>, <x1/x3>, <x2/x1>, ||x2||² и т. Д.

>>> sim = [email protected]
tensor([[1.9343, 1.0340, 1.1545],
        [1.0340, 1.2782, 0.8822],
        [1.1545, 0.8822, 0.9370]])

Для нормализации возьмите вектор всех норм: ||x1||, ||x2|| и ||x3||:

>>> norm = x.norm(dim=1)
tensor([1.3908, 1.1306, 0.9680])

Постройте матрицу, содержащую коэффициенты нормализации: ||x1||², ||x1||.||x2||, ||x1||.||x3||, ||x2||.||x1||, ||x2||² и т. Д.

>>> factor = norm*norm.unsqueeze(1)
tensor([[1.9343, 1.5724, 1.3462],
        [1.5724, 1.2782, 1.0944],
        [1.3462, 1.0944, 0.9370]])

Затем нормализуйте:

>>> sim /= factor
tensor([[1.0000, 0.6576, 0.8576],
        [0.6576, 1.0000, 0.8062],
        [0.8576, 0.8062, 1.0000]])

В качестве альтернативы более быстрый способ, который позволяет избежать создания матрицы норм, - это нормализовать перед умножением:

>>> x /= x.norm(dim=1, keepdim=True)
>>> sim = [email protected]
tensor([[1.0000, 0.6576, 0.8576],
        [0.6576, 1.0000, 0.8062],
        [0.8576, 0.8062, 1.0000]])

Для функции потерь я бы применил nn.CrossEntropyLoss прямо между предсказанная матрица сходства и целевая матрица вместо применения сигмоида + BCE. Примечание. nn.CrossEntropyLoss включает nn.LogSoftmax < / а>.

person Ivan    schedule 31.12.2020