VKВлад КуликовОткрытые лекции
Современные LLM2 / 20

Модуль 2. Токенизация и эмбеддинги

Сначала попробуйте решить упражнение. Ответы, подробные решения и проектные ориентиры раскрываются отдельно и сохраняют своё состояние при переключении RU/EN.

Скачать файлы курса (.zip) 2588,1 КБ

Архив содержит файлы на обоих языках и вспомогательные материалы с сохранением структуры каталогов.

У1. Байтовая арифметика

Сколько базовых byte-level токенов дают Привет, мир!, Hello, world!, наивный 🚀?

Показать ответ и решение

Решение. До BPE-слияний каждый байт UTF-8 является отдельным базовым токеном. В Привет, мир! девять кириллических букв (Привет — 6, мир — 3) занимают 9⋅2=189\cdot2=18 байт; запятая, пробел и ! добавляют ещё 3. Итого 21. Hello, world! целиком состоит из 13 ASCII-символов, поэтому даёт 13 байтов. В наивный 🚀 семь кириллических букв дают 14 байт, пробел — 1, эмодзи — 4: всего 19. Проверка без токенизатора: len(text.encode("utf-8")).

У2. Encode по рангам

Реализуйте кодирование, которое на каждом шаге выбирает присутствующую пару с минимальным рангом.

Показать ответ и решение

Решение.

Python
def encode_by_rank(text, merges):
    chunks = re.findall(PAT, text)
    out = []
    for chunk in chunks:
        ids = list(chunk.encode("utf-8"))
        while len(ids) > 1:
            pairs = set(zip(ids[:-1], ids[1:]))
            best = min(pairs, key=lambda pair: merges.get(pair, float("inf")))
            if best not in merges:
                break
            ids = merge([ids], best, merges[best])[0]
        out.extend(ids)
    return out

На инференсе нет частот корпуса: порядок задаётся рангами, сформированными во время обучения.

Алгоритм сначала применяет предварительное разбиение и обрабатывает каждый чанк независимо. Внутри чанка он перечисляет соседние пары, выбирает пару с минимальным числовым рангом и сливает все её допустимые вхождения. Если ни одной присутствующей пары нет в merges, обработка чанка завершена. Частоту пары заново считать нельзя: частоты использовались при обучении BPE, а при кодировании их результат уже зафиксирован в рангах.

У3. Протокол fertility

Зафиксируйте корпус, правило определения слова и способ агрегации. Считайте отношение суммарных токенов к суммарным словам и рядом публикуйте bytes/token. Объясните, почему среднее fertility по строкам может дать иной вес коротким примерам.

Показать ответ и решение

Решение. Воспроизводимый протокол должен фиксировать: точный снимок корпуса и его срезы, нормализацию и правило выделения слов, имя и ревизию токенизатора, а также режим добавления специальных токенов. Для каждой строки считаем число UTF-8-байтов bib_i, слов wiw_i и токенов tit_i (обычно без служебных маркеров начала и конца последовательности — BOS, beginning of sequence, и EOS, end of sequence), после чего агрегируем

fertility=∑iti∑iwi,bytes/token=∑ibi∑iti.\text{fertility}=\frac{\sum_i t_i}{\sum_i w_i},\qquad \text{bytes/token}=\frac{\sum_i b_i}{\sum_i t_i}.

Это micro-агрегация: каждое слово имеет одинаковый вес. Среднее 1N∑iti/wi\frac1N\sum_i t_i/w_i даёт каждой строке одинаковый вес, поэтому короткая строка из одного слова влияет так же, как длинное предложение; строки с wi=0w_i=0 дополнительно требуют отдельного правила. В отчёте нужно опубликовать также ∑wi\sum w_i, ∑ti\sum t_i, ∑bi\sum b_i и число исключённых строк — тогда результат можно перепроверить.

У4 [проект]. Многоязычная карта

Возьмите FLORES-200 и опубликованные токенизаторы o200k_base, Llama 4, Qwen3, Gemma 3, DeepSeek V4 и Kimi K3. Постройте таблицу «язык × fertility» и обязательно запишите revision каждого артефакта. Не задавайте заранее ожидаемого победителя: сравнение должно быть результатом эксперимента.

Демо и критерии проекта

Демо к этому проектному упражнению: русскоязычный проектный ноутбук модуля 2, раздел «1. Что именно стоит в знаменателе?». Он показывает компактный воспроизводимый пример на малых данных, а не готовое решение полномасштабного проекта.

Для каждого языка задайте подходящее правило сегментации слов либо сравнивайте токены на выровненное предложение. Регулярное выражение непрерывных букв считает китайскую строку одним фрагментом; это не одно лингвистическое слово. Демо показывает знаменатели и число единиц на предложение, а его wordrun_proxy не является WordPiece.

У5 [проект]. Аудит Harmony

В необязательной сетевой ячейке основного ноутбука загрузите o200k_harmony, посчитайте имена и уникальные ID, найдите алиас 200018 и разделите имена на протокольные и reserved.

Демо к этому проектному упражнению: русскоязычный проектный ноутбук модуля 2, раздел «2. Почему число имён не равно числу ID?». Он показывает компактный воспроизводимый пример на малых данных, а не готовое решение полномасштабного проекта.

Демо и критерии проекта

Ожидаемый результат для снимка 11 октября 2026: 1091 имя, 1090 уникальных специальных ID, 10 протокольных имён, 1081 имя reserved; вместе с 199 998 обычных ID получается n_vocab=201088.

У6. Эмбеддинг и один шаг обучения

Для EE из §11 вычислите E[[0,2,0]], E[0] @ E.T и BF16-память связанных весов при V=16384,d=512V=16384,d=512. Затем минимизируйте L=12∑t∥Eit−Yt∥2L=\frac12\sum_t\|E_{i_t}-Y_t\|^2 для нулевых целевых векторов YY и ID [0,2,0]: чему равен градиент по каждой строке E?

Показать ответ и решение

Решение. Выбранные строки равны [[1,0],[0,1],[1,0]], логиты — [1,2,0], максимум имеет ID 1. Параметров 16384⋅512=838860816384\cdot512=8388608, BF16-память равна 1677721616777216 байт = 16 MiB. Повторяющийся ID 0 накапливает два вклада: градиент [[2,0],[0,0],[0,1]]. При шаге 0.1 новая таблица [[0.8,0],[2,0],[0,0.9]], а LL уменьшается с 1.5 до 1.045. В ноутбуке градиент независимо проверяется конечными разностями; упражнение показывает, как выбор строк передаёт градиент таблице; семантические свойства этой игрушечной целью не проверяются.