Глава 6 из 14 30 мин
Токены
Буква — слишком мелкий кусок, слово — слишком крупный. Разберёмся, как Росток режет текст, откуда взялись его 8 192 токена и почему русский текст он видит как россыпь байтов.
В этой главе
- объяснить, зачем модели токены и почему не буквы и не слова
- прогнать алгоритм BPE вручную и прочитать настоящий токенизатор Ростка
- понимать, во что обходится размер словаря и почему нелатинские языки для маленькой модели дороже
Модель из прошлой главы видит восемь последних букв. Восемь букв — это «the litt»: даже слово целиком не помещается, не то что предложение. А что, если в каждую из восьми ячеек класть не букву, а кусок побольше — целое частое слово или хотя бы слог?
Так и поступают все большие языковые модели. Текст режут на токены — кусочки разной длины, — и каждый кусочек получает свой номер и свой эмбеддинг. У Ростка токенов 8 192. Прежде чем разбираться, откуда они взялись, посмотрите, как он режет текст.
Как Росток читает
Ниже — настоящий токенизатор Ростка, тот же, с которым он обучался. Каждый цвет — отдельный токен. Напишите что угодно или нажмите на готовые примеры, в том числе на русский текст и эмодзи.
Несколько вещей бросаются в глаза сразу.
- Частые слова — это один токен, причём вместе с пробелом перед ними: «·time», «·little», «·garden». Для модели «·the» в середине фразы и «The» в начале — разные токены.
- Редкое слово собирается из кусков: antidisestablishmentarianism превращается в девять токенов — «·ant | id | is | est | ab | lish | ment | arian | ism». Модель никогда не встречала такого слова целиком, но его части ей знакомы.
- Числа идут по одной цифре. Это не случайность, а правило, о нём ниже.
- Русский текст рассыпается: почти каждая буква — два токена-осколка. В примере «Жили-были дед да баба…» 49 символов и 86 токенов. Эмодзи — по четыре осколка на каждый.
Внизу виджета видно, что мы выиграли. Окно из восьми букв — это обрывок слова. Окно из восьми токенов в английском тексте — это почти целая фраза: на нашем проверочном тексте в среднем 4,085 символа на токен, так что в восемь ячеек помещается около 33 символов. А в русском окно становится даже меньше буквенного: восемь токенов — всего четыре-пять букв. Почему так вышло — главная интрига этой главы.
Буквы — мелко, слова — крупно
Прежде чем изобретать токены, разберёмся с двумя очевидными вариантами.
Буквы. Словарь крошечный — 97 символов, и в английском тексте незнакомых букв не бывает. Но текст получается длинным: сказка в тысячу символов — это тысяча шагов, и на каждом модель решает крошечную задачу «какая буква следующая». Всё, что модель должна помнить, приходится растягивать на огромное число позиций. В главе 7 мы увидим, что цена внимания растёт как квадрат длины текста: вчетверо более длинный текст обходится в шестнадцать раз дороже.
Слова. Текст короткий, каждая ячейка — целое слово. Но словарь разбухает. Только в нашем проверочном тексте — 7,2 миллиона токенов простых историй и диалогов — мы насчитали 28 666 разных слов, и 6 357 из них встречаются ровно один раз. Каждому слову нужна своя строка в таблице эмбеддингов, а редкие строки почти не учатся. Хуже того, любое новое слово — имя, опечатка, «Росток» — оказывается вне словаря, и модели остаётся только метка «неизвестное».
Кусочки слов — золотая середина. Частые слова целиком, редкие — из частей, а совсем незнакомое слово — хоть по буквам. Неизвестных слов не бывает вовсе. На нашем проверочном тексте слово с пробелом перед ним в 95% случаев оказывается ровно одним токеном — почти как в словаре слов, но без его проблем.
В самом низу — байты
С чего начинать нарезку? Можно было бы начать с символов, но их в мире десятки тысяч: буквы всех алфавитов, иероглифы, стрелки, эмодзи. Поэтому токенизатор Ростка, как и токенизаторы GPT-2 и многих современных моделей, начинает с байтов.
Чаще всего компьютер хранит текст в кодировке UTF-8: каждый символ — от одного до четырёх байтов, а байт — число от 0 до 255. Латинские буквы без диакритики, цифры и знаки препинания занимают один байт. Русские буквы — два: первый (обычно D0 или D1 в шестнадцатеричной записи) говорит «дальше кириллица», второй уточняет, какая именно буква. Эмодзи занимают четыре байта.
Всего возможных байтов 256, и все они — первые 256 токенов словаря Ростка. Поэтому любой текст на любом языке токенизатор хоть как-то да запишет: в худшем случае байт за байтом. Ещё 7 932 токена — склеенные пары, выученные на корпусе. Как их выбирали — дальше.
Склеить самую частую пару
Алгоритм называется BPE, byte pair encoding — «кодирование пар байтов». Он поразительно простой:
- Запишите весь обучающий текст байтами.
- Посчитайте, какая пара соседних токенов встречается чаще всего.
- Объявите эту пару новым токеном и замените все её вхождения.
- Повторяйте, пока словарь не вырастет до нужного размера.
Попробуйте сами на крошечном тексте. Каждое нажатие — одна склейка.
Сначала склеиваются пары, которых больше всего: «a»+«t», «t»+«h», затем «th»+«e» — и вот уже «the» стал одним токеном. Потом к нему прилипает пробел. Слова, которые часто повторяются, быстро становятся целыми токенами, а редкие так и остаются кусками. Никакой лингвистики — только подсчёт.
Вот тот же алгоритм на чистом Python — всего три десятка строк. Запустите его и сравните склейки с виджетом: они совпадут.
Сначала режем на куски
Одна тонкость. Если склеивать пары по всему тексту подряд, BPE охотно выучит токены вроде «g.» или «d the»: в текстах такие сочетания тоже частые. Но они смешивают конец одного слова с началом другого, и словарь тратится впустую. Поэтому перед обучением текст режут на куски регулярным выражением, и склейки никогда не выходят за границы куска. Переключите виджет в начале главы на «Куски», чтобы увидеть эти границы.
Вот это регулярное выражение — прямо из tokenizer.py:
Разберём его по частям; вертикальная черта означает «или»:
'(?:[sdmt]|ll|ve|re)— английские сокращения: 's, 't, 'll, 've, 're. «didn't» режется на «didn» и «'t».?\p{L}+— слово из букв любого алфавита вместе с одним пробелом перед ним. Вот откуда «·little».?\p{N}— одна цифра. Поэтому 2024 — это четыре токена. Так модели легче видеть разряды, и числа не превращаются в тысячи случайных токенов.?[^\s\p{L}\p{N}]+— знаки препинания подряд, например «!"» или «...».\s+(?!\S)|\s+— пробелы и переводы строк.
А вот сам цикл обучения. Он делает ровно то же, что наш мини-BPE, но хитрее считает: помнит, в каких кусках встречается каждая пара, и после склейки пересчитывает только их. Без этого 7 932 склейки на 120 тысячах документов шли бы часами, а так токенизатор Ростка обучился за 19 секунд.
Вывод — настоящий, из обучения Ростка (журнал считает склейки с нуля): самая первая — «·t», к шагу 500 токенизатор уже склеивает целые слова вроде «·flow», а шаг 7 000 даёт «·ambulance».
Как собирается слово
Словарь выучен. Как теперь разрезать новый текст? Кодирование просто повторяет склейки в том порядке, в котором они были выучены: пока в куске есть пара из словаря, склеиваем ту, что выучена раньше всех.
Результат удобно рисовать деревом: внизу байты, над ними склейки, наверху готовый токен. Номер у каждой склейки — это её место в очереди обучения.
Посмотрите на «·the»: склейка № 1 — «·t», № 2 — «he», и уже седьмой склейкой выучен целый «·the». Длинные слова ждут своей очереди долго: «·butterfly» появился только на склейке № 2 095, а «·Congratulations» (16 байтов, один из двух самых длинных токенов словаря; второй — «·recommendations») — только на № 4 312. Любопытно, что «·sprout» со строчной буквы — один токен, а «·Sprout» с заглавной — три: заглавный вариант в историях встречался реже. А «·Росток» — тринадцать байтов (пробел и по два на каждую букву) и ни одной склейки.
Что лежит в словаре
Пройдёмся по словарю от первой склейки до последней. Сдвигайте ползунок: в начале — пары букв и короткие частые слова, дальше — всё более длинные и редкие слова и имена.
Первые склейки — «·t», «he», «·a», «·s», «·w», «in», и седьмая — «·the». В самом конце — «·mushrooms», «Josh», «·armcha» (полкресла: целиком «armchair» не успел стать токеном), «·recommendations». Больше половины словаря — токены вида «пробел и буквы», то есть целые слова или их начала.
Последние четыре номера — 8188–8191 — занимают служебные токены: <|endoftext|>, <|user|>, <|assistant|> и <|end|>. Из обычного текста они никогда не получаются — их вставляет программа. Первый отделяет одну историю от другой, остальные понадобятся в главе 12, когда мы будем учить Ростка разговаривать. Попробуйте пример «служебные» в виджете в начале главы: каждая метка — один цельный токен-плашка.
Сколько токенов нужно
Почему именно 8 192, а не 1 000 или 100 000? Больше словарь — короче текст, но дороже модель. Ползунок ниже показывает, что было бы с меньшим словарём. Заново обучать токенизатор для этого не нужно: BPE учится жадно, по одной склейке, и если бы мы остановили обучение раньше, получили бы ровно первые склейки нашего словаря.
| Словарь | Символов на токен | Таблица эмбеддингов ×384 |
|---|---|---|
| 256 (только байты) | 1,00 | 98 304 |
| 512 | 2,21 | 196 608 |
| 1 024 | 2,91 | 393 216 |
| 2 048 | 3,50 | 786 432 |
| 4 096 | 3,88 | 1 572 864 |
| 8 192 | 4,09 | 3 145 728 |
Первые 256 склеек укорачивают текст больше чем вдвое. Каждое следующее удвоение словаря даёт всё меньше: переход от 4 096 к 8 192 токенам экономит лишь 5% длины, а таблица эмбеддингов при этом удваивается. У Ростка она и так весит 3,15 миллиона параметров — почти пятую часть модели.
Есть и вторая цена. Чем больше словарь, тем реже встречается каждый токен и тем хуже учится его эмбеддинг. Даже при 8 192 токенах 137 выученных склеек ни разу не встретились в 7,2 миллиона токенов проверочного текста, а 506 — меньше десяти раз. Для модели на 17 миллионов параметров, которая пишет простые английские истории, 8 192 — разумный компромисс.
Как сравнивать модели с разными токенами
Раз уж длина текста зависит от словаря, появляется ловушка. Модель в конце этой главы устроена так же, как в прошлой: тот же класс MLP из snapshots.py, только другого размера — MLP(8192, 8, 48, [384]), восемь токенов по 48 чисел и один скрытый слой на 384 нейрона. На проверочном тексте её удивление — 3,31 ната на токен. У буквенной модели было 1,103 ната на букву. Стало втрое хуже?
Нет: мы сравниваем разные вещи. Угадать следующий токен — значит угадать сразу около четырёх символов, и удивление за них складывается. Честное сравнение — на одну и ту же единицу текста. Если у токена в среднем $c$ символов, то
$$\text{наты на символ} = \frac{\text{наты на токен}}{c} = \frac{3{,}31}{4{,}085} \approx 0{,}81.$$Это заметно лучше, чем 1,103 у буквенной модели. Та же ловушка подстерегает и исследователей: перплексию моделей с разными токенизаторами напрямую сравнивать нельзя, её пересчитывают на символ или на байт.
Закон Ципфа
Токены встречаются очень неравномерно. Лингвист Джордж Ципф заметил это для слов ещё в 1930–1940-х: второе по частоте слово встречается примерно вдвое реже первого, третье — втрое, и так далее. Частота обратно пропорциональна рангу. Если нарисовать это в логарифмическом масштабе по обеим осям, получится почти прямая.
Картина у токенов почти ципфовская: наклон нашей кривой в средней части около −1,2 против −1 у идеала. На практике это значит, что горстка токенов делает почти всю работу. Самый частый токен — точка — это 7,2% текста. Первые десять токенов покрывают 27,9% текста, первые сто — 56,2%, первая тысяча — 86,1%. Остальные семь тысяч делят между собой меньше седьмой части текста. Именно поэтому огромный словарь окупается плохо: каждая новая склейка — всё более редкое слово.
Честно о русском
Теперь понятно, почему русский текст рассыпается на осколки. Токенизатор Ростка учился только на английских историях. Кириллицы в корпусе практически не было — при чистке мы убирали неанглийские тексты, — и ни одна из 7 932 склеек не содержит байта больше 127. Поэтому для русского текста у токенизатора есть только 256 байтовых токенов: каждая буква — два токена, каждый пробел — ещё один.
- «Once upon a time there lived an old man and an old woman. They had a hen.» — 73 символа, 20 токенов: 3,65 символа на токен.
- «Жили-были старик со старухой. Была у них курочка.» — 49 символов, 88 токенов: 0,56 символа на токен.
- «Росток» — 6 букв, 12 токенов.
- 🌱 — один символ, 4 токена.
Одна и та же история по-русски выходит для Ростка вчетверо длиннее. Контекст Ростка — 512 токенов: это около 2 100 символов английского текста, но меньше 300 символов русского — пара абзацев против пары фраз. И это ещё не всё. В проверочном тексте на 7,2 миллиона токенов байты больше 127 встретились всего 30 раз. Эмбеддинги этих токенов почти не обучались: для Ростка русская буква — это два почти пустых вектора подряд.
Так устроены все модели: язык, которого мало в обучающем корпусе, дорого обходится и в токенизаторе. Токенизаторы больших многоязычных моделей учат на текстах сразу на многих языках, и у них есть склейки и для кириллицы. Но «налог на токены» для языков, которых в корпусе меньше, чем английского, не исчезает — только уменьшается.
Токенизатор — это словарь частых кусочков, выученный подсчётом. Всё, чего в корпусе было много, он читает крупно и дёшево; всё, чего было мало, — мелко и дорого.
Почему Росток тратит на русское слово «кот» шесть токенов, а на английское « cat» — один?
BPE выучил только те пары, которые часто встречались в обучающем тексте. Кириллицы там почти не было, поэтому русские буквы остаются парами байтов, а « cat» склеился в один токен ещё в начале обучения.
А если в тексте встретится что-то совсем странное?
Ничего страшного не случится: любой текст — это байты, а все 256 байтов есть в словаре. Китайский иероглиф станет тремя токенами-байтами, редкий эмодзи — четырьмя, а составной эмодзи «семья из четырёх человек» — двадцатью пятью. Модель может такого не понимать, но записать и прочитать обратно без потерь сумеет всегда. Поэтому у byte-level BPE не бывает «неизвестного токена».
Росток сейчас
Устройство Ростка почти не изменилось — окно из восьми ячеек, эмбеддинги, скрытый слой, — но в каждую ячейку теперь ложится токен, и окно охватывает около 33 символов вместо восьми. Удивление на токен — 3,31 ната на проверочном тексте, или около 0,81 ната на символ против 1,103 у буквенной модели. Параметров стало больше: из 3,7 миллиона около 3,15 миллиона занимает выходной слой, который оценивает каждый из 8 192 токенов. Проза стала связнее, но восемь токенов — это всё ещё одна фраза. Как заглянуть дальше, не раздувая сеть, расскажет следующая глава — о внимании.