Эмбеддинги токенов: вектор на токен (запускаемая близость)

Токены — это номера, но модели нужны числа со смыслом. Этот урок про эмбеддинги: как каждому токену сопоставляют вектор, в котором близость означает похожесть смысла.

Эмбеддинг (embedding) — это обучаемый вектор чисел, сопоставленный токену; близкие по смыслу токены получают близкие векторы.

Сначала наивно: one-hot

Самый прямой способ превратить токен в числа — one-hot вектор: длина = размер словаря, на месте нужного токена единица, везде нули.

vocab = ["кот", "пёс", "молоко", "лает", "мяукает"]

def one_hot(word):
    return [1 if w == word else 0 for w in vocab]

print("One-hot векторы (по одному на токен словаря):")
for w in vocab:
    print(f"  {w:9} -> {one_hot(w)}")

print()
print("Проблема: размер вектора = размер словаря.")
print("Для словаря в 50000 токенов это вектор из 50000 нулей и одной единицы.")
print("И любые два слова одинаково 'далеки' — близости смыслов нет.")

Вывод:

One-hot векторы (по одному на токен словаря):
  кот       -> [1, 0, 0, 0, 0]
  пёс       -> [0, 1, 0, 0, 0]
  молоко    -> [0, 0, 1, 0, 0]
  лает      -> [0, 0, 0, 1, 0]
  мяукает   -> [0, 0, 0, 0, 1]

Проблема: размер вектора = размер словаря.
Для словаря в 50000 токенов это вектор из 50000 нулей и одной единицы.
И любые два слова одинаково 'далеки' — близости смыслов нет.

Проблем две. Во-первых, для словаря в 50 000 токенов это вектор из 50 000 чисел — расточительно. Во-вторых, и это важнее, любые два разных токена в one-hot одинаково «далеки» друг от друга: «кот» и «кошка» так же не похожи, как «кот» и «молоко». Никакой информации о смысле здесь нет.

Эмбеддинги: плотные векторы со смыслом

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

Технически это просто таблица: матрица размером «словарь × размерность». Номер токена — это номер строки, а строка — его эмбеддинг. Превращение токена в вектор — это поиск строки в таблице.

Как измерить «близость»

Похожесть двух векторов чаще всего меряют косинусной близостью — косинусом угла между ними. Значение от −1 до 1: ближе к 1 — векторы смотрят в одну сторону (похожи), около 0 — не связаны. Зададим игрушечные эмбеддинги вручную и посчитаем близость.

import math

# Игрушечные эмбеддинги: каждому слову вручную задан вектор из 3 чисел.
# Близкие по смыслу слова мы намеренно поместили рядом в пространстве.
embeddings = {
    "кот":    [0.9, 0.1, 0.2],
    "кошка":  [0.8, 0.2, 0.1],
    "собака": [0.7, 0.3, 0.2],
    "банан":  [0.1, 0.9, 0.8],
    "яблоко": [0.2, 0.8, 0.9],
}

def dot(a, b):
    return sum(x * y for x, y in zip(a, b))

def cosine(a, b):
    return dot(a, b) / (math.sqrt(dot(a, a)) * math.sqrt(dot(b, b)))

target = "кот"
print(f"Близость к слову '{target}':")
scores = []
for word, vec in embeddings.items():
    if word == target:
        continue
    scores.append((word, cosine(embeddings[target], vec)))

for word, score in sorted(scores, key=lambda p: p[1], reverse=True):
    print(f"  {word:7} {score:.3f}")

Вывод:

Близость к слову 'кот':
  кошка   0.987
  собака  0.959
  яблоко  0.389
  банан   0.303

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

Важная оговорка

Эмбеддинг токена из таблицы — статичный: один и тот же токен «банк» получает одинаковый стартовый вектор в «банк реки» и «денежный банк». Различать смыслы по контексту — задача следующих слоёв (внимания), которые «дорабатывают» эти векторы. Об этом — раздел про attention.

Итог

  • One-hot — расточителен и не несёт смысла: все токены одинаково «далеки».
  • Эмбеддинг — плотный обучаемый вектор; похожие по смыслу токены оказываются рядом.
  • Близость векторов измеряют косинусной близостью (косинусом угла).
  • Эмбеддинг из таблицы статичен; уточняют смысл по контексту уже слои внимания.
Проверьте себя
1. В чём главная смысловая проблема one-hot векторов?
AОни слишком короткие
BЛюбые два разных токена одинаково далеки — близости смыслов нет
CИх нельзя обучить
DОни содержат дробные числа
2. Откуда берутся значения в эмбеддингах токенов?
AИх задаёт программист вручную для каждого слова
BОни обучаются вместе с моделью, выстраиваясь по контекстам употребления
CОни берутся из словаря Ожегова
DОни всегда равны индексу токена
3. Чем меряют близость двух эмбеддингов?
AРазностью длин строк
BКосинусной близостью — косинусом угла между векторами
CКоличеством общих букв
DСуммой их индексов
Поддержать проект