Арифметика слов и похожесть на векторах

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

Векторная арифметика слов — свойство эмбеддингов, при котором сложение и вычитание векторов слов отражает смысловые отношения: король − мужчина + женщина ≈ королева.

Почему это вообще возможно

Когда эмбеддинги обучены, разные смысловые «оси» (пол, число, время, столица-страна) оказываются закодированы как устойчивые направления в пространстве. Вектор от «мужчина» к «женщина» — это направление «смены пола». Прибавив его к «король», мы сдвигаемся в ту же сторону и попадаем рядом с «королева». Модель не понимает пол как человек — она лишь выучила, что такие пары слов систематически смещены в одном направлении.

Считаем близость и арифметику руками

Зададим маленькие игрушечные эмбеддинги «руками» так, чтобы они кодировали два признака: «королевственность» и «женскость». Затем посчитаем косинусную близость и проверим знаменитое уравнение.

import math

# игрушечные эмбеддинги: [королевственность, женскость, обычный-человек]
emb = {
    "король":   [0.9, 0.1, 0.2],
    "королева": [0.9, 0.9, 0.2],
    "мужчина":  [0.1, 0.1, 0.9],
    "женщина":  [0.1, 0.9, 0.9],
}

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)

def add(a, b):  return [x + y for x, y in zip(a, b)]
def sub(a, b):  return [x - y for x, y in zip(a, b)]

# король - мужчина + женщина = ?
result = add(sub(emb["король"], emb["мужчина"]), emb["женщина"])
print("Результат вектора:", [round(x, 2) for x in result])

# к какому слову он ближе всего?
for word, vec in emb.items():
    print("cos(результат, %-8s) = %.3f" % (word, cosine(result, vec)))

Вывод:

Результат вектора: [0.9, 0.9, 0.2]
cos(результат, король  ) = 0.787
cos(результат, королева) = 1.000
cos(результат, мужчина ) = 0.307
cos(результат, женщина ) = 0.657

Вычисление король − мужчина + женщина дало вектор [0.9, 0.9, 0.2] — ровно эмбеддинг «королева», косинус 1.000. Мы убрали «мужскую часть» и добавили «женскую», оставив «королевственность». Арифметика над смыслом сработала. На настоящих 300-мерных эмбеддингах это происходит само, без ручной разметки осей.

Поиск похожих слов

Та же косинусная близость даёт поиск синонимов и ассоциаций: для слова находим ближайшие по косинусу векторы. Так находят «похожие на кот» (кошка, котёнок, питомец) или ближайшие к запросу документы в семантическом поиске.

import math

emb = {
    "кот":     [0.9, 0.8, 0.1],
    "кошка":   [0.85, 0.82, 0.12],
    "котёнок": [0.8, 0.75, 0.2],
    "молоток": [0.1, 0.05, 0.9],
}

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)

query = "кот"
sims = [(w, cosine(emb[query], v)) for w, v in emb.items() if w != query]
sims.sort(key=lambda x: x[1], reverse=True)
for w, s in sims:
    print("%-8s %.3f" % (w, s))

Вывод:

кошка    0.999
котёнок  0.995
молоток  0.201

Ближайшие к «кот» — «кошка» и «котёнок», а «молоток» далеко. То самое, чего классика дать не могла: осмысленная близость слов.

Где это используют на практике

  • Семантический поиск: искать по смыслу, а не по совпадению слов.
  • Рекомендации и кластеризация: группировать близкие понятия.
  • Расширение запросов: добавить синонимы к поисковому запросу.
  • Вход для моделей: подавать эмбеддинги вместо one-hot.

Итог

  • Смысловые отношения кодируются как направления в пространстве эмбеддингов.
  • Поэтому работает арифметика: король − мужчина + женщина ≈ королева.
  • Похожие слова находят по косинусной близости их векторов.
  • Это основа семантического поиска и рекомендаций.
Проверьте себя
1. Почему над эмбеддингами работает арифметика вроде «король − мужчина + женщина ≈ королева»?
AПотому что модель понимает значение слов как человек
BПотому что смысловые отношения закодированы как устойчивые направления в пространстве
CПотому что все векторы случайны
DПотому что слова отсортированы по алфавиту
2. Как найти слова, похожие на заданное, имея эмбеддинги?
AСравнить длины слов
BНайти векторы с наибольшей косинусной близостью к вектору слова
CОтсортировать слова по частоте
DСложить все векторы корпуса
3. Чего из этого классические one-hot векторы дать НЕ могут, а эмбеддинги могут?
AХранить слова в памяти
BОсмысленную близость слов и арифметику над их смыслом
CПриводить текст к нижнему регистру
DСчитать длину документа
Поддержать проект