Векторы и эмбеддинги
После токенизации текст превращается в список целых чисел: The cat sat («кот сидел») становится [976, 9059, 10139]. Нейросеть умеет только складывать и умножать числа, так что напрашивается идея подать ей эти ID напрямую. Это не работает: ID — всего лишь номер в списке словаря, и зависит он от того, в каком порядке токенизатор выучил свои кусочки. Вот настоящие ID из токенизатора GPT-4o (английские слова, потому что для них нашлись отдельные токены):
Если верить этим числам, «каталог» примерно в девять раз ближе к «коту», чем «котёнок». А в русском тексте «·котёнок» вообще распадается на три токена — ·кот, ён, ок, — и ни один из их номеров не говорит, что это молодой кот. Любая арифметика над ID была бы арифметикой над случайностями нумерации, и ничто выученное про «кота» не перенеслось бы на «котёнка».
Модели нужно другое: такое описание каждого токена, в котором у похожих токенов похожие числа. Одного числа для этого мало: котёнок живой, это животное, кошачье, детёныш, маленький и ещё много чего. Поэтому каждый токен получает целый список чисел — вектор, в котором хватает места для многих свойств сразу.
Что означают числа
Представьте, что на каждое слово заполняется анкета: живое ли оно? животное? кошачье? детёныш? королевское? женское? техника? На каждый вопрос отвечает одно число. У слов с похожим смыслом похожие анкеты: «кот» и «котёнок» различаются только строкой «детёныш», а у «машины» с ними почти ничего общего.
🌱 живое🐾 животное🐱 кошачье🍼 детёныш👑 королевское♀ женское⚙️ техника
Каждое число отвечает на один вопрос о слове. Таблицу можно читать как анкету.
Настоящие модели устроены так же, но с одним важным отличием: вопросы никто не выбирает. Числа сначала случайные, а обучение шаг за шагом подправляет их, оставляя то, что помогает предсказать следующий токен. Токены, которые употребляются похоже, получают похожие векторы, потому что так предсказывать проще. Получается как в выученном виде на рисунке.
Этот вид — та же анкета после случайного поворота всего пространства: поворот перемешивает все числа между собой, но не меняет углов между векторами, поэтому все сходства сохраняются. Информация на месте, просто размазана сразу по всем числам. Отдельное число, скажем 1 234-е в векторе ·cat, обычно не означает ничего, чему можно дать название. Смысл несёт весь узор целиком — направление, в котором смотрит вектор. (Исследователям всё же удаётся находить направления с понятным смыслом — об этом глава 6.)
Списки чисел как стрелки
Почему про список чисел говорят, что он куда-то «смотрит»? Потому что вектор — упорядоченный набор чисел, например , — можно нарисовать. Вектор из двух чисел — это стрелка на бумаге из начала координат в точку (x, y), из трёх — стрелка в комнате. Два списка с похожими числами — это две стрелки, которые смотрят почти в одну сторону.
Языковые модели используют куда больше трёх чисел:
Число с буквой B в названии модели — количество параметров в миллиардах: у Llama 3 8B их около 8 миллиардов.
Представить 4 096 измерений невозможно, но геометрия работает точно так же: у векторов есть длина, они куда-то направлены, а угол между двумя векторами говорит, насколько они похожи.
Таблица эмбеддингов
Значит, модели нужен вектор для каждого токена словаря. Все они хранятся в одной большой матрице — таблице эмбеддингов, по строке на токен. Превратить токен в вектор значит просто прочитать его строку: ID по-прежнему нужен, но только как адрес строки, а не как смысл.
Пусто: нажмите «пуск».
Токенизатор превратил текст в ID. ID — это просто номер строки, никакого смысла в нём пока нет.
Таблица для словаря в 200 000 токенов и 4 096 измерений содержит 819 миллионов чисел — заметную долю параметров небольшой модели. Как и все остальные веса, таблица начинает со случайных значений и выучивается при обучении.
Запишите токен 3 как one-hot-вектор: всюду нули, кроме единицы на позиции 3. Умножение его на таблицу эмбеддингов выбирает строку 3: при умножении вектора на матрицу каждая строка матрицы умножается на соответствующее число вектора, и строки складываются, а здесь все строки, кроме третьей, умножаются на 0. Значит, «взять строку» и «умножить на » — одна и та же операция, и поэтому таблицу можно обучать теми же градиентами (сигналами, по которым обучение подправляет каждое число), что и всё остальное.
Как измерить сходство: скалярное произведение
Мы всё время говорим о «похожих векторах». Чтобы с этим считать, модели нужно число, которое говорит, насколько два вектора похожи. Инструмент, которым она пользуется везде, — скалярное произведение: перемножить соответствующие числа и сложить.
Здесь — длина стрелки (по теореме Пифагора ), а — угол между стрелками. Вторая форма объясняет смысл: скалярное произведение велико, когда векторы длинные и смотрят в одну сторону. Если разделить на длины, останется — косинусное сходство. Оно меняется от (противоположные направления) через (перпендикулярны, не связаны) до (одно направление).
Например, возьмём и — с этих стрелок начинается рисунок ниже. Скалярное произведение: . Длины: и , значит, : стрелки расходятся примерно на 38° и смотрят в целом в одну сторону.
- a
- (3.0, 2.0)
- b
- (1.0, 3.0)
- a · b
- 3.0×1.0 + 2.0×3.0 = 9.00
- |a|, |b|
- 3.61, 3.16
- угол
- 38°
- cos θ
- 0.79
смотрят в одну сторону: похожий смысл
Скалярное произведение встретится в следующих главах ещё не раз: внимание построено на скалярных произведениях между токенами, а последний шаг модели оценивает каждый токен словаря скалярным произведением с последним вектором. Этот последний шаг, обратный эмбеддинг (unembedding), — вторая таблица с одной строкой на токен. Многие модели просто переиспользуют для него таблицу эмбеддингов (связывание весов, weight tying): токен получает высокую оценку, когда итоговый вектор смотрит туда же, куда эмбеддинг самого токена.
Смысл становится геометрией
Вернёмся к утверждению из начала главы: обучение даёт похожие векторы токенам, которые употребляются похоже. Почему? Допустим, и после «кошки», и после «котёнка» часто идёт «мурлычет». Оценка для «мурлычет» — это скалярное произведение с вектором, который модель строит из уже прочитанных слов, поэтому проще всего дать высокую оценку после любого из двух слов, если их векторы смотрят в одну сторону. Повторите это на миллиардах предложений — и «кошка» окажется рядом с «котёнком», а «Париж» — недалеко от «Рима». Никто не велит модели так делать: это просто самый дешёвый способ хорошо предсказывать следующий токен.
Ещё удивительнее, что смысл приобретают направления. Шаг от «мужчины» к «женщине» — примерно та же стрелка, что шаг от «короля» к «королеве». Это знаменитая аналогия из word2vec (Mikolov et al., 2013) — раннего метода, который выучивает по одному неизменному вектору на слово:
Ниже — построенное вручную трёхмерное пространство с такими свойствами. Настоящие пространства эмбеддингов выучиваются и устроены сложнее, но кластеры и параллельные стрелки — реальные явления. (Это упрощение: в настоящих пространствах word2vec аналогия выполняется лишь приблизительно и не для всех отношений, а ближайшее слово ищут среди всех, кроме трёх исходных, — как и на рисунке.)
В этом игрушечном пространстве направления «женское», «королевское» и «молодое» расставлены вручную. Но даже здесь это не оси: шаг к «женскому», например, меняет сразу все три координаты. Таблица настоящей модели похожа на выученный вид рисунка 3.1: ни у одного отдельного измерения нет чистого смысла, и единица смысла — направление, то есть смесь измерений. Поиском таких направлений занимаются исследования интерпретируемости — попытки понять, что происходит внутри обученных моделей.
Одно слово — разные векторы
Таблица эмбеддингов даёт каждому токену ровно один вектор, где бы он ни встретился. Это статический эмбеддинг. Но «ключ» во фразе «из-под камня бил ключ» и «ключ» в замке — разные слова с одинаковым написанием. Таблица не может знать, какое из них имеется в виду, и её вектор для «ключа» оказывается компромиссом между обоими значениями.
Трансформер исправляет это по ходу чтения. В каждом слое (одном блоке трансформера; в модели их десятки) внимание подмешивает в вектор каждого токена информацию от соседей (глава 5). К средним слоям вектор «ключа» в одной фразе притянут к «воде», а в другой — к «замку». С такими контекстными эмбеддингами и работает остальная модель.
косинусное сходство
Прямо из таблицы эмбеддингов у «ключа» один вектор — компромисс между обоими значениями. Он висит между двумя группами и не близок ни к одной.
В этом главное отличие от старых векторов слов вроде word2vec, которые на поиске в таблице и останавливались. В трансформере поиск — лишь отправная точка.
Эмбеддинги для поиска
Та же идея работает и для целых текстов. Модель эмбеддингов читает предложение или абзац и выдаёт один вектор на весь текст — обычно усредняя итоговые векторы токенов или беря вектор специального токена. Её обучают так, чтобы тексты с похожим смыслом оказывались рядом, даже если у них нет ни одного общего слова: «Как сбросить пароль?» попадает рядом с «Я забыл логин».
Так работает семантический поиск: один раз получить эмбеддинги всех документов, получить эмбеддинг вопроса и вернуть документы с наибольшим косинусным сходством. Это поисковая половина генерации с извлечением (RAG), о которой рассказывает глава 15.
Итоги
- ID токенов — произвольные метки, поэтому каждый токен описывается вектором: списком чисел, в котором у похожих токенов похожие значения.
- Числа выучиваются, а не выбираются; смысл несёт направление вектора, а не отдельное число.
- Каждый ID токена выбирает одну выученную строку таблицы эмбеддингов — вектор из сотен или тысяч чисел.
- Скалярное произведение и косинусное сходство измеряют, насколько два вектора смотрят в одну сторону.
- Обучение раскладывает пространство так, что связанные токены оказываются рядом, а устойчивые отношения превращаются в параллельные направления.
- Векторы из таблицы статичны; внимание превращает их в контекстные, зависящие от окружающих слов.
У таблицы эмбеддингов есть слепое пятно: вектор слова «мать» один и тот же, стоит ли оно первым или последним. Следующая глава добавляет позицию.