Перейти к содержимому
Ступень 44.1 Языковое моделирование

Что такое языковая модель

Языковая модель как распределение над текстами, цепное правило и авторегрессия, n-граммы и их пределы, и как из «предсказателя следующего токена» вырастают ChatGPT и DeepSeek.

УРОКstage-4/4-1-language-modeling/01-what-is-lm.mdx1 ч 10 минУрок 1 из 5
После урока вы сможете
  • Записать вероятность текста через цепное правило и объяснить, что именно предсказывает LLM на каждом шаге
  • Объяснить авторегрессионную генерацию и почему один текст из TT токенов даёт TT обучающих примеров
  • Построить n-граммную модель подсчётом и назвать три её фундаментальные проблемы
  • Описать путь от базовой модели к ассистенту (претрейн → SFT → RL) и показать, что везде остаётся предсказание следующего токена

ChatGPT, DeepSeek, Qwen и Kimi устроены по-разному, но внутри у всех крутится один и тот же цикл. Модель получает текст, выдаёт вероятности следующего токена, из них выбирается один токен, он дописывается в конец текста, и всё повторяется. Ответ на вопрос, код, рассуждение DeepSeek-R1 длиной в тысячи токенов — всё это собирается по одному кусочку.

Штука, которая выдаёт эти вероятности, называется языковая модельязыковая модельEN language model (LM)Распределение вероятностей над последовательностями токенов. На практике — функция «контекст → вероятности следующего токена».. Это центральное понятие всей ступени: дальше мы построим языковую модель на подсчётах (урок 2), научимся генерировать из неё текст (урок 3), а к концу ступени соберём GPT с нуля. Сегодня — фундамент: что именно модель предсказывает, почему достаточно предсказывать только следующий токен, и как из такого «автодополнения» получается ассистент.

Языковая модель — это распределение над текстами

Заголовок раздела «Языковая модель — это распределение над текстами»

Пусть текст — это последовательность токеновтокенEN tokenВ разговорной речи и статьях китайцы чаще всего пишут просто «token». x1,x2,…,xTx_1, x_2, \dots, x_T из словаря размера VV. Как текст режется на токены, разберём в модуле 4.2; пока считайте токеном слово или букву.

Языковая модель назначает каждой последовательности вероятность P(x1,…,xT)P(x_1, \dots, x_T). Хорошая модель даёт высокую вероятность осмысленным текстам и низкую — бессмыслице:

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

Такие оценки нужны не только чат-ботам. Распознавание речи выбирает из акустически похожих вариантов самый правдоподобный, проверка орфографии предлагает исправление, машинный перевод выбирает естественный порядок слов. Десятилетиями языковые модели работали именно «оценщиками», а не генераторами.

Сразу видна проблема: возможных текстов астрономически много. Даже при словаре в 50 00050\,000 слов предложений из 10 слов 50 00010≈104750\,000^{10} \approx 10^{47}. Таблицу «текст → вероятность» не построить, нужен способ разложить задачу на части.

Из теории вероятностей (модуль 1.3) мы знаем, что P(A,B)=P(A) P(B∣A)P(A, B) = P(A)\,P(B \mid A). Применяя это правило снова и снова, получаем цепное правило вероятностицепное правило вероятностиEN chain rule of probabilityP(x₁, …, x_T) = ∏ P(x_t | x₁, …, x_{t−1}). Точное тождество, а не приближение.:

P(x1,…,xT)=P(x1) P(x2∣x1) P(x3∣x1,x2)⋯=∏t=1TP(xt∣x<t)P(x_1, \dots, x_T) = P(x_1)\,P(x_2 \mid x_1)\,P(x_3 \mid x_1, x_2) \cdots = \prod_{t=1}^{T} P(x_t \mid x_{<t})

Здесь x<tx_{<t} — все токены до позиции tt (контекст). У первого токена контекст пуст, поэтому первый множитель — просто P(x1)P(x_1): насколько вероятно, что текст начинается с этого токена. Пример с выдуманными, но правдоподобными числами:

P(мама мыла раму)=P(мама)⏟0.01⋅P(мыла∣мама)⏟0.05⋅P(раму∣мама мыла)⏟0.3=1.5⋅10−4\begin{aligned} P(\text{мама мыла раму}) &= \underbrace{P(\text{мама})}_{0.01} \cdot \underbrace{P(\text{мыла} \mid \text{мама})}_{0.05} \\ &\quad \cdot \underbrace{P(\text{раму} \mid \text{мама мыла})}_{0.3} = 1.5 \cdot 10^{-4} \end{aligned}

Обратите внимание на третий множитель: после «мама мыла» слово «раму» очень вероятно, потому что фраза знакома каждому, кто учился читать по русскому букварю. Модель, которая это «знает», даст фразе высокую вероятность.

На практике перемножать маленькие числа неудобно, поэтому берут логарифмы и складывают: −ln⁡P=4.605+2.996+1.204≈8.80-\ln P = 4.605 + 2.996 + 1.204 \approx 8.80. В среднем на токен это 2.932.93, а перплексияперплексияEN perplexity e2.93≈18.8e^{2.93} \approx 18.8 (модуль 1.3): модель в среднем «колеблется» между ~19 вариантами. Средний −ln⁡P-\ln P на токен — это та же перекрёстная энтропияперекрёстная энтропияEN cross-entropy из модуля 1.3.

Главный вывод: цепное правило — точное тождество, а не приближение. Чтобы задать вероятность любого текста, достаточно уметь для любого контекста выдавать распределение следующего токена. Поэтому вся задача языкового моделирования сводится к предсказание следующего токенапредсказание следующего токенаEN next-token predictionГлавная задача языковой модели — по началу текста оценить вероятности следующего токена. Ответ чат-бота собирается из таких шагов по одному токену.: это обычная классификация на VV классов, где классы — токены словаря, а признаки — весь предыдущий текст. Логиты, softmax и cross-entropy вы уже умеете считать.

Авторегрессия: генерация по одному токену

Заголовок раздела «Авторегрессия: генерация по одному токену»

Если модель умеет выдавать P(xt∣x<t)P(x_t \mid x_{<t}), генерировать текст просто:

flowchart LR
A["Контекст: «Мама мыла»"] --> B["Языковая модель"]
B --> C["P(следующий токен)<br/>раму 0.3, посуду 0.2, …"]
C --> D["Выбрать токен<br/>(урок 3)"]
D --> E["Дописать «раму»<br/>в контекст"]
E -->|"повторять до конца текста"| B
Авторегрессионная генерация: выход модели становится её входом

Такая модель называется авторегрессионнойавторегрессионная модель (авторегрессия)EN autoregressive modelГенерирует последовательность по одному элементу, подавая каждый сгенерированный токен обратно на вход. Так работают GPT, Qwen, DeepSeek.: «регрессия на саму себя», каждый следующий элемент предсказывается по предыдущим собственным выходам. Термин пришёл из анализа временных рядов, где AR-модели предсказывают значение по прошлым значениям того же ряда. GPT, Llama, Qwen, DeepSeek — все авторегрессионные.

Генерация последовательная, а обучение — нет. Из одного текста получается столько обучающих примеров, сколько в нём токенов. Возьмём «мама мыла раму .» и служебный токен начала <s>:

Вход (контекст)Правильный ответ
<s>мама
<s> мамамыла
<s> мама мылараму
<s> мама мыла раму.

Входы и ответы — один и тот же текст, сдвинутый на одну позицию. Модель видит настоящий префикс, а не свои предсказания; такой режим называется teacher forcingteacher forcing (обучение на верном префиксе)EN teacher forcingПри обучении модель на каждом шаге видит настоящий текст, а не свои предсказания. Поэтому все позиции можно обучать параллельно.. Благодаря ему все позиции считаются за один проход: трансформер с причинной маскойпричинная (каузальная) маскаEN causal maskЗапрещает токену смотреть на будущие позиции — оценки выше диагонали заменяются на −∞ до softmax. Нужна, чтобы GPT-подобная модель училась предсказывать следующий токен на всех позициях сразу. (модуль 4.4) не даёт позиции tt подсмотреть будущие токены, и мы получаем TT предсказаний сразу. Loss — средняя cross-entropy по всем позициям.

Масштаб впечатляет: DeepSeek-V3 обучали на 14.8 трлн токенов — это 14.8 трлн задачек «угадай следующий токен».

Контекст x<tx_{<t} растёт с длиной текста, и запомнить распределение для каждого возможного контекста нельзя. Классическое решение — марковское допущениемарковское допущениеEN Markov assumptionСледующий токен зависит только от n−1 предыдущих. На нём построены n-граммные модели.: будем считать, что следующий токен зависит только от n−1n-1 предыдущих.

P(xt∣x<t)≈P(xt∣xt−n+1,…,xt−1)P(x_t \mid x_{<t}) \approx P(x_t \mid x_{t-n+1}, \dots, x_{t-1})

Последовательность из nn соседних токенов называется n-граммаn-граммаEN n-gramПоследовательность из n подряд идущих токенов. В d2l-zh — буквально «одноэлементная», «двухэлементная» и «трёхэлементная грамматика» (unigram, bigram, trigram).. При n=2n = 2 получаем биграммнуюбиграммаEN bigramПара соседних токенов. Биграммная модель оценивает P(x_t | x_{t−1}) — таблица V × V. модель P(xt∣xt−1)P(x_t \mid x_{t-1}), при n=3n = 3 — триграммную. Обучение сводится к подсчёту — это и есть метод максимального правдоподобия из модуля 1.3:

P(мыла∣мама)=count(мама мыла)count(мама)P(\text{мыла} \mid \text{мама}) = \frac{\text{count}(\text{мама мыла})}{\text{count}(\text{мама})}

Если «мама» встретилась в корпусе 4 раза, а «мама мыла» — 2 раза, то P(мыла∣мама)=0.5P(\text{мыла} \mid \text{мама}) = 0.5. С 1980-х до начала 2010-х n-граммные модели работали внутри систем распознавания речи и статистического машинного перевода, а к концу этой эпохи их обучали на корпусах из сотен миллиардов и даже триллионов слов. Но у них три фундаментальные проблемы.

При словаре V=50 000V = 50\,000 возможных биграмм V2=2.5⋅109V^2 = 2.5 \cdot 10^9, а триграмм 1.25⋅10141.25 \cdot 10^{14}. Даже корпус в триллион слов покрывает ничтожную долю, причём частоты распределены по закону Ципфазакон ЦипфаEN Zipf's lawЧастота слова примерно обратно пропорциональна его месту в частотном списке, поэтому немногие частые слова покрывают большую часть любого текста.: несколько n-грамм встречаются постоянно, а огромный «хвост» — один-два раза или никогда. Это разреженность данныхразреженность данныхEN data sparsityБольшинство возможных n-грамм ни разу не встречается в корпусе, и подсчёт даёт им вероятность 0..

Невиданная n-грамма получает вероятность ноль, а с ней и весь текст. Если в корпусе не было «мыла машину», модель объявит фразу «мама мыла машину» невозможной, хотя в ней нет ничего странного. Лечат это сглаживанием — подробно в следующем уроке.

Чтобы выбрать окончание, иногда нужно заглянуть далеко назад:

«Девушка, с которой я познакомился вчера на остановке у старого кинотеатра, оказалась …»

Род глагола «оказалась» определяется словом, от которого его отделяют 10 слов. Триграммная модель, выбирая следующее слово, видит только два предыдущих — «старого кинотеатра» — и не может знать, нужно «оказался» или «оказалась». Увеличить nn нельзя: число возможных n-грамм и разреженность растут экспоненциально.

Пусть в корпусе есть «кот ест рыбу», но нет «кошка ест рыбу». Для n-граммной модели «кот» и «кошка» — два несвязанных символа, и знание про кота никак не переносится на кошку. Человек же понимает, что слова похожи.

Нейросетевые модели решают эту проблему через эмбеддингиэмбеддинг, векторное представлениеEN embedding: похожие слова получают похожие векторы, и знание переносится само (модуль 4.3). Первая такая модель — «A Neural Probabilistic Language Model» Йошуа Бенджио и соавторов (2003): эмбеддинги нескольких предыдущих слов подавались в многослойную сеть.

n-граммная модельнейросетевая модель
Обучениеподсчёт частотградиентный спуск
Контекстn−1n - 1 токенов, обычно 2–4от сотен тысяч до миллиона токенов у современных LLM
Невиданные сочетаниявероятность 0 без сглаживанияразумная оценка за счёт похожих слов
Памятьтаблица растёт как VnV^nчисло параметров почти не зависит от длины контекста
ГодСобытие
1913Марков считает переходы букв в «Евгении Онегине»
1948Шеннон генерирует текст из n-граммных приближений английского
1980–2000-еn-граммные модели — стандарт в распознавании речи и машинном переводе
2003Нейросетевая языковая модель Бенджио: эмбеддинги + MLP
2010Рекуррентные языковые модели (RNN LM, Томаш Миколов)
2013word2vec — эмбеддинги слов как отдельный продукт
2017Трансформер — внимание вместо рекуррентности
2018–2020GPT, GPT-2 (1.5 млрд параметров), GPT-3 (175 млрд)
2022ChatGPT — языковая модель, дообученная быть ассистентом
2024–2025Открытые китайские DeepSeek-V3, DeepSeek-R1, Qwen3 конкурируют с лучшими закрытыми моделями

Обратите внимание: за сто с лишним лет задача не изменилась. Менялись только способ оценить P(xt∣x<t)P(x_t \mid x_{<t}) и количество данных.

От предсказателя следующего токена к ChatGPT и DeepSeek

Заголовок раздела «От предсказателя следующего токена к ChatGPT и DeepSeek»

Как из «автодополнения» получается ассистент, который отвечает на вопросы и пишет код? В три этапа.

flowchart LR
A["Претрейн<br/>триллионы токенов<br/>текстов из интернета"] --> B["Базовая модель<br/>продолжает любой текст"]
B --> C["SFT<br/>диалоги в chat-шаблоне"]
C --> D["RL / предпочтения<br/>RLHF, GRPO"]
D --> E["Ассистент<br/>ChatGPT, DeepSeek, Qwen"]
Конвейер обучения современной LLM. Везде одна и та же модель P(следующий токен | контекст)

1. Претрейн. Модель учат предсказывать следующий токен на огромном корпусе. Получается базовая модельбазовая модельEN base model: она продолжает любой документ так, как он мог бы продолжиться в интернете. Спросите её «Как сварить борщ?» — она может ответить рецептом, а может выдать ещё пять вопросов, как на странице форума. Она не «отвечает», она продолжает.

2. SFT. Модель дообучают на диалогах (обучение с учителем на инструкцияхобучение с учителем на инструкциях (SFT)EN supervised fine-tuning (SFT)). Диалог записывается одним текстом по chat-шаблонуchat-шаблонEN chat templateПравило (обычно Jinja в tokenizer_config.json), которое превращает список сообщений с ролями в одну строку со спецтокенами. со спецтокенамиспециальный токен (спецтокен)EN special tokenУправляющий токен, а не кусок текста — начало/конец текста (BOS/EOS), заполнитель для батча (PAD), разметка ролей в чате (например, <|im_start|> у Qwen).. У Qwen это ChatML:

<|im_start|>user
Как сварить борщ?<|im_end|>
<|im_start|>assistant

Модель продолжает этот текст после assistant — и это снова предсказание следующего токена. Просто теперь самое вероятное продолжение такого документа — полезный ответ ассистента, а в конце — <|im_end|>.

3. RL и предпочтения. Дальше модель учат на оценках: какой ответ люди предпочли (обучение с подкреплением на основе отзывов людейобучение с подкреплением на основе отзывов людей (RLHF)EN reinforcement learning from human feedback (RLHF), InstructGPT, 2022) или прошло ли решение проверку (GRPO в DeepSeek-R1). Правильного «следующего токена» здесь нет, есть награда за весь ответ. Но обучается всё та же функция P(xt∣x<t)P(x_t \mid x_{<t}): RL лишь сдвигает вероятности в сторону хороших продолжений. Подробно — на ступени 6.

Код ниже — биграммная модель на словах из восьми предложений, без библиотек. Он показывает цепное правило, проблему нулей и авторегрессионную генерацию. Запустите его локально (python lm_intro.py).

import math
import random
from collections import Counter
corpus = """
мама мыла раму . папа мыл машину . мама мыла посуду .
папа читал газету . мама читала книгу . кот спал на окне .
кот ловил мышь . мама кормила кота .
""".split()
tokens = ["."] + corpus # «.» — граница предложения и начало текста
prev_counts = Counter(tokens[:-1]) # сколько раз слово стояло «перед» чем-то
bigrams = Counter(zip(tokens, tokens[1:])) # счётчик пар соседних слов: {(«мама», «мыла»): 2, …}
def p(word, prev):
"""Оценка максимального правдоподобия: count(prev, word) / count(prev)."""
return bigrams[(prev, word)] / prev_counts[prev]
def sentence_prob(sentence):
prob, prev = 1.0, "." # предложение начинается после границы «.»
for w in sentence.split():
prob *= p(w, prev) # цепное правило + марковское допущение
prev = w
return prob
print(f"P(мыла | мама) = {p('мыла', 'мама'):.2f}")
for s in ["мама мыла раму .", "раму мыла мама .", "мама мыла машину ."]:
pr = sentence_prob(s)
nll = -math.log(pr) if pr > 0 else float("inf")
print(f"P(«{s}») = {pr:.3f} −ln P = {nll:.2f}")
# Авторегрессия: каждое сгенерированное слово становится контекстом для следующего
rng = random.Random(7) # свой генератор с seed=7 → одинаковый результат при каждом запуске
prev, out = ".", [] # начинаем с границы предложения
for _ in range(12): # 12 шагов = 12 слов
cands = [w for (a, w) in bigrams if a == prev] # все слова, которые хоть раз шли после prev
weights = [bigrams[(prev, w)] for w in cands] # их счётчики: чем чаще, тем вероятнее
prev = rng.choices(cands, weights=weights)[0] # случайный выбор с весами; [0] — choices возвращает список
out.append(prev) # выбранное слово становится новым контекстом
print(" ".join(out))

Ожидаемый вывод:

P(мыла | мама) = 0.50
P(«мама мыла раму .») = 0.125 −ln P = 2.08
P(«раму мыла мама .») = 0.000 −ln P = inf
P(«мама мыла машину .») = 0.000 −ln P = inf
мама мыла посуду . папа мыл машину . мама мыла раму .

Разберите результат:

  • P(мама мыла раму .)=0.5⋅0.5⋅0.5⋅1=0.125P(\text{мама мыла раму .}) = 0.5 \cdot 0.5 \cdot 0.5 \cdot 1 = 0.125: из 8 начал предложений 4 — «мама», после «мама» в половине случаев «мыла», после «мыла» в половине случаев «раму», после «раму» всегда точка.
  • Перестановка слов даёт ноль — это правильно.
  • «мама мыла машину» тоже получает ноль, хотя фраза нормальная. Это разреженность в чистом виде.
  • Генерация выдаёт только предложения, собранные из уже виденных пар слов. Модель с крошечным корпусом не может придумать ничего нового.

Попробуйте сами.

  1. Добавьте в корпус «папа мыл раму .» и пересчитайте вероятности. Какие выросли, какие упали?
  2. Сделайте триграммную версию: ключом счётчика станет пара предыдущих слов. Что случится с нулями?
  3. Посчитайте среднее −ln⁡P-\ln P на токен для всего корпуса и perplexity eNLLe^{\text{NLL}}.
Проверь себя6 вопросов
1 Какое утверждение верно?
2 Модель дала P(мама)=0.01P(\text{мама}) = 0.01, P(мыла∣мама)=0.05P(\text{мыла} \mid \text{мама}) = 0.05, P(раму∣мама мыла)=0.3P(\text{раму} \mid \text{мама мыла}) = 0.3. Чему равно −ln⁡P-\ln P всей фразы? Округлите до двух знаков.
3 Сколько обучающих примеров «контекст → следующий токен» даёт один текст из 1000 токенов при обучении GPT?
4 Выберите все проблемы n-граммных моделей.Можно выбрать несколько ответов
5 Сколько возможных триграмм при словаре V=1000V = 1000? Ответ дайте в миллиардах.
6 Что меняется при SFT базовой модели в чат-ассистента?
  • Языковая модель задаёт вероятность текста. По цепному правилу P(x1,…,xT)=∏tP(xt∣x<t)P(x_1, \dots, x_T) = \prod_t P(x_t \mid x_{<t}), поэтому достаточно уметь предсказывать следующий токен — это классификация на VV классов.
  • Генерация авторегрессионная: выбранный токен дописывается в контекст. Обучение параллельное: текст из TT токенов даёт TT примеров (teacher forcing), loss — средняя cross-entropy.
  • N-граммы оценивают вероятности подсчётом при марковском допущении. Их пределы — нули, короткий контекст и отсутствие обобщения. Нейросети с эмбеддингами снимают все три ограничения.
  • ChatGPT и DeepSeek — те же языковые модели: претрейн даёт базовую модель, SFT учит продолжать диалоги, RL сдвигает вероятности к хорошим ответам.

Дальше: строим первую настоящую модель — биграммную модель на русских именах: подсчёт, сэмплирование, оценка через NLL и та же модель в виде нейросети — Биграммная модель на русских именах.