Пределы статичных эмбеддингов: проблема омонимов

Word2vec — огромный шаг вперёд, но у него есть встроенный изъян: одно слово получает ровно один вектор, даже если у слова несколько значений.

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

В чём проблема

Вернёмся к омонимам из второго урока. «Ключ» — это и от двери, и родник, и нотный знак. Но word2vec выдаёт ему один вектор на все значения. При обучении контексты всех смыслов смешались, и итоговый вектор — компромисс, «среднее» между значениями. Он не точен ни для одного из них.

Покажем размывание на цифрах

Представим, что у «ключа» два чистых смысла-вектора: «дверной» и «водный». Статичный эмбеддинг — их усреднение. Посмотрим, как он соотносится с каждым настоящим смыслом.

import math

dveri = [1.0, 0.0]   # смысл «ключ от двери»
voda  = [0.0, 1.0]   # смысл «родник»

# статичный эмбеддинг = усреднение контекстов обоих смыслов
static = [(dveri[i] + voda[i]) / 2 for i in range(2)]

def cosine(a, b):
    dot = sum(x * y for x, y in zip(a, b))
    na = math.sqrt(sum(x * x for x in a))
    nb = math.sqrt(sum(y * y for y in b))
    return dot / (na * nb)

print("Статичный вектор 'ключ':", static)
print("cos(статичный, 'дверной смысл') =", round(cosine(static, dveri), 3))
print("cos(статичный, 'водный смысл')  =", round(cosine(static, voda), 3))
print("Ни к одному смыслу не близок идеально — это компромисс.")

Вывод:

Статичный вектор 'ключ': [0.5, 0.5]
cos(статичный, 'дверной смысл') = 0.707
cos(статичный, 'водный смысл')  = 0.707
Ни к одному смыслу не близок идеально — это компромисс.

Косинус 0.707 (а не 1.0) с каждым смыслом показывает: усреднённый вектор «застрял» между значениями и плохо представляет любое из них. В предложении «я повернул ключ в замке» нам нужен «дверной» смысл, но статичный эмбеддинг даёт смешанный.

Другие ограничения статичных эмбеддингов

  • Нет учёта контекста предложения: «банк реки» и «банк выдал кредит» — слово «банк» получит один вектор.
  • Слабый учёт порядка: сами по себе эмбеддинги — это про слова, а не про то, как они сложены в предложение.
  • Out-of-vocabulary: у слова, которого не было на обучении, вектора нет вовсе (fastText частично решает это подсловами).

Что напрашивается: контекстные эмбеддинги

Хочется, чтобы вектор слова зависел от предложения: «ключ» в «повернул ключ в замке» и «ключ бьёт из земли» получали бы разные векторы. Для этого нужно читать всё предложение и подстраивать представление слова под контекст. Именно это делают контекстные эмбеддинги из моделей вроде BERT — но чтобы их построить, нужны нейросети для последовательностей и механизм внимания. Ровно к ним мы и переходим в следующем разделе.

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

Итог

  • Статичный эмбеддинг — один вектор на слово, независимо от предложения.
  • Омонимы получают усреднённый компромиссный вектор, плохой для каждого смысла.
  • Контекст предложения не учитывается: «банк реки» и «банк-кредит» неразличимы.
  • Решение — контекстные эмбеддинги (BERT), для которых нужны внимание и трансформеры.
Проверьте себя
1. В чём главное ограничение статичных эмбеддингов вроде word2vec?
AОни слишком быстро обучаются
BСлово получает один вектор независимо от контекста, что плохо для омонимов
CОни не умеют считать косинусную близость
DОни требуют размеченных данных
2. Почему усреднённый вектор омонима «ключ» имеет косинус 0.707 с каждым отдельным смыслом, а не 1.0?
AПотому что смыслы идентичны
BПотому что вектор — компромисс между смыслами и не совпадает идеально ни с одним
CПотому что косинус всегда равен 0.707
DПотому что слово редкое
3. Что предлагают контекстные эмбеддинги (например, из BERT) в отличие от статичных?
AПолностью отказаться от векторов
BДавать слову разный вектор в зависимости от предложения, в котором оно стоит
CДелать векторы короче
DИгнорировать редкие слова
Поддержать проект