Перейти к содержимому
Ступень 11.3 Вероятность и теория информации

Случайные величины и распределения

Язык вероятностей, на котором говорит LLM — распределения, матожидание и дисперсия, условная вероятность и формула Байеса, а главное — как модель «бросает кубик» по своему категориальному распределению.

УРОКstage-1/1-3-probability/01-probability.mdx1 ч 40 минУрок 1 из 4
После урока вы сможете
  • Объяснить, что такое случайная величина и распределение, и отличить вероятность (дискретный случай) от плотности (непрерывный)
  • Считать матожидание, дисперсию и стандартное отклонение по формулам и в NumPy и понимать, почему loss — это матожидание
  • Решать задачи на условную вероятность и формулу Байеса через «естественные частоты»
  • Сэмплировать токен из категориального распределения через накопленные суммы — так, как это делает генерация в LLM

Задайте DeepSeek или Qwen один и тот же вопрос дважды — ответы будут разными. Дело не в поломке: большая языковая модельбольшая языковая модель (БЯМ, LLM)EN large language model (LLM)В китайском «большая модель» («да мосин») — разговорное общее название для LLM и вообще foundation models. не выдаёт «единственно верное» слово. На каждом шаге она выдаёт распределение вероятностей на всех токенах словаря, а потом «бросает кубик». Чтобы понимать, что происходит при генерации, обучении и оценке моделей, нужен язык вероятностей.

Вероятность в LLM повсюду:

  • генерация — это сэмплирование из распределения модели;
  • loss — это среднее по случайным батчам, то есть математическое ожидание;
  • оценка — случайна: модель решает задачу «в 7 случаях из 10», и надо понимать, насколько верить этому числу;
  • обучение с подкреплением (GRPO у DeepSeek) генерирует группу случайных ответов и сравнивает их между собой.

В этом уроке пять идей: случайная величина, распределение (дискретное и непрерывное), матожидание и дисперсия, условная вероятность с формулой Байеса и, наконец, категориальное распределение — то, что выдаёт языковая модель.

случайная величинаслучайная величинаEN random variableЧисло (или токен), значение которого определяется случаем. Обозначают заглавной буквой — X, Y. — это число (или токен), которое определяется случаем. Её обозначают заглавной буквой: XX, YY. Примеры:

  • XX — что выпало на кубике: 1, 2, …, 6;
  • RR — верен ли ответ модели на задачу: 1 (верно) или 0 (неверно);
  • LL — длина ответа модели в токенах;
  • TT — номер следующего токена в словаре из 151 936 токенов Qwen.

распределение вероятностейраспределение вероятностейEN probability distributionВсе значения случайной величины с их вероятностями (или плотностью). Сумма вероятностей равна 1. — полный список: какие значения может принять величина и с какой вероятностью. Запись P(X=3)=16P(X = 3) = \frac{1}{6} читается «вероятность того, что XX равно 3, — одна шестая». Короче пишут p(3)p(3).

У любого распределения два железных правила:

  1. каждая вероятность лежит от 0 до 1: 0≤p(x)≤10 \le p(x) \le 1;
  2. сумма по всем значениям равна 1: ∑xp(x)=1\sum_x p(x) = 1 — что-то обязательно произойдёт.

Откуда берутся вероятности? Самый практичный взгляд — частотный: если повторять опыт много раз, доля исходов xx приближается к p(x)p(x). В уроке 0.3.3 вы видели это на нечестной монете: при n=100 000n = 100\,000 бросков частота орлов отличалась от 0.7 меньше чем на 0.001. Это закон больших чиселзакон больших чиселEN law of large numbersПри большом числе независимых повторений среднее (и частота) приближается к матожиданию (и вероятности)., и на нём держится вся статистика ML: мы никогда не знаем «истинных» вероятностей, но можем оценить их по большой выборке.

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

РаспределениеЗначенияПараметрыГде в LLM
Бернуллираспределение БернуллиEN Bernoulli distributionВеличина принимает 1 с вероятностью p и 0 с вероятностью 1 − p. Пример — награда «верно/неверно».0 или 1pp — вероятность единицынаграда «верно/неверно» в RL
Равномерное дискретное1,…,K1, \dots, KKKсвежая модель «не знает ничего»
Биномиальноебиномиальное распределениеEN binomial distributionЧисло успехов в n независимых испытаниях Бернулли; P(k) = C(n, k)·pᵏ·(1 − p)ⁿ⁻ᵏ.0,1,…,n0, 1, \dots, nnn попыток, ppсколько из nn ответов верны
Категориальноекатегориальное распределениеEN categorical distributionРаспределение на K исходах с вероятностями p₁…p_K. Выход softmax в LLM — категориальное распределение на словаре. Не путать с мультиномиальным (multinomial) — это число исходов каждого типа за n бросков.1,…,K1, \dots, Kp1,…,pKp_1, \dots, p_Kследующий токен

Модель решает задачу верно с вероятностью p=0.7p = 0.7. Награда RR равна 1 при верном ответе и 0 при неверном: P(R=1)=0.7P(R = 1) = 0.7, P(R=0)=0.3P(R = 0) = 0.3. Это распределение Бернулли — самое простое из всех. Именно такие награды использовала DeepSeek-R1 при обучении рассуждениям: ответ на математическую задачу либо сошёлся с эталоном, либо нет.

Пусть модель делает n=5n = 5 независимых попыток с p=0.3p = 0.3. Сколько из них окажутся верными? Вероятность ровно kk верных попыток:

P(K=k)=(nk) pk(1−p)n−kP(K = k) = \binom{n}{k}\, p^k (1 - p)^{n - k}

Читаем: (nk)\binom{n}{k} («цэ из эн по ка», число сочетаний из урока 1.0.5) — сколькими способами можно выбрать, какие именно kk попыток удались; pkp^k — все они удались; (1−p)n−k(1-p)^{n-k} — все остальные провалились. Для n=5n = 5 и k=2k = 2 способов десять: удачными могут быть попытки 1 и 2, 1 и 3, …, 4 и 5. Формула (52)=5⋅41⋅2=10\binom{5}{2} = \frac{5 \cdot 4}{1 \cdot 2} = 10, а в Python — math.comb(5, 2). Итого P(K=2)=10⋅0.32⋅0.73=10⋅0.09⋅0.343≈0.309P(K = 2) = 10 \cdot 0.3^2 \cdot 0.7^3 = 10 \cdot 0.09 \cdot 0.343 \approx 0.309.

Полезный частный случай — «хотя бы одна попытка верна». Проще посчитать обратное событие «все неверны»: 1−0.75≈0.8321 - 0.7^5 \approx 0.832. На этом построена метрика pass@k из бенчмарков по коду (бенчмарк — стандартный набор задач для сравнения моделей, ступень 7): даже слабая модель с p=0.3p = 0.3 при пяти попытках решает задачу в 83% случаев.

Обобщение Бернулли на KK исходов. Именно его выдаёт языковая модель: логиты проходят через softmax (урок 1.3.2), и получается категориальное распределение на всём словаре. Для контекста «Карп прыгает через…» оно может выглядеть так:

Токенвратарекуволнукаменьнебо
pp0.710.120.080.050.04

На самом деле токенов не пять, а около 150 тысяч, и у большинства вероятность крошечная. Как выбрать из такого распределения один токен — в последнем разделе урока.

Вес нейросети, время ответа сервера, рост человека — непрерывные величины: между любыми двумя значениями есть бесконечно много промежуточных. Здесь возникает парадокс: вероятность того, что вес равен ровно 0.5000000…, равна нулю. Значений бесконечно много, и на каждое отдельное не достаётся ничего.

Поэтому для непрерывных величин говорят о вероятности попасть в интервал. Её задаёт плотность вероятностиплотность вероятностиEN probability density function (PDF)Для непрерывных величин — «вероятность на единицу длины». Вероятность интервала — площадь под кривой; сама плотность может быть больше 1. p(x)p(x) — кривая, площадь под которой на отрезке [a,b][a, b] и есть P(a≤X≤b)P(a \le X \le b). Вся площадь под кривой равна 1. Это та же гистограмма из урока 0.3.3, только со всё более узкими столбиками и нормировкой на площадь.

Плотность — не вероятность, это «вероятность на единицу длины». Поэтому она может быть больше 1: если вся вероятность сосредоточена на отрезке длиной 0.1, плотность там равна 10.

равномерное распределениеравномерное распределениеEN uniform distributionВсе значения на отрезке (или все K исходов) равновероятны. U[0, 1) — то, что возвращает random(). U[0,1)U[0, 1): плотность равна 1 на отрезке от 0 до 1 и 0 вне его. P(0.2≤X≤0.5)=0.3P(0.2 \le X \le 0.5) = 0.3 — просто длина отрезка. Это то, что возвращает rng.random(), и, как вы увидите ниже, из него можно получить сэмпл любого другого распределения.

нормальное (гауссовское) распределениенормальное (гауссовское) распределениеEN normal (Gaussian) distribution«Колокол» N(μ, σ²). Правило 68–95–99.7 — доля значений в пределах 1, 2 и 3 σ от среднего. N(μ,σ2)\mathcal{N}(\mu, \sigma^2) — знаменитый «колокол»:

p(x)=1σ2πexp⁡ ⁣(−(x−μ)22σ2)p(x) = \frac{1}{\sigma \sqrt{2\pi}} \exp\!\left(-\frac{(x - \mu)^2}{2\sigma^2}\right)

Читаем: μ\mu («мю») — центр колокола, σ\sigma («сигма») — его ширина. Запись exp⁡(…)\exp(\ldots) — та же экспонента e…e^{\ldots} (урок 1.0.2), так пишут, когда показатель длинный. Экспонента от минус квадрата расстояния быстро гасит всё, что далеко от центра: в точке x=μx = \mu показатель равен 0 и e0=1e^0 = 1, а уже при x=μ+2σx = \mu + 2\sigma он равен −2-2 и e−2≈0.135e^{-2} \approx 0.135. Множитель перед экспонентой нормирует площадь на 1. Запоминать формулу не нужно. Нужно правило 68–95–99.7: в пределах μ±σ\mu \pm \sigma лежит 68% значений, μ±2σ\mu \pm 2\sigma — 95%, μ±3σ\mu \pm 3\sigma — 99.7%.

Пример из практики: в GPT-2 и nanoGPT веса линейных слоёв инициализируют — задают перед обучением случайными числами — из N(0,0.022)\mathcal{N}(0, 0.02^2), то есть с μ=0\mu = 0 и σ=0.02\sigma = 0.02. Значит, 95% весов лежат в [−0.04,0.04][-0.04, 0.04]. Пик плотности при этом равен 10.022π≈19.9\frac{1}{0.02\sqrt{2\pi}} \approx 19.9 — наглядное доказательство того, что плотность бывает больше единицы. Чем уже колокол, тем он выше: площадь обязана остаться равной 1.

xychart-beta
title "Плотность нормального распределения: σ = 1 и σ = 0.25"
x-axis "x" -3 --> 3
y-axis "плотность p(x)" 0 --> 1.7
line [0, 0.01, 0.01, 0.01, 0.02, 0.02, 0.03, 0.04, 0.05, 0.07, 0.09, 0.11, 0.13, 0.16, 0.18, 0.21, 0.24, 0.27, 0.3, 0.33, 0.35, 0.37, 0.39, 0.4, 0.4, 0.4, 0.39, 0.37, 0.35, 0.33, 0.3, 0.27, 0.24, 0.21, 0.18, 0.16, 0.13, 0.11, 0.09, 0.07, 0.05, 0.04, 0.03, 0.02, 0.02, 0.01, 0.01, 0.01, 0]
line [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.02, 0.07, 0.22, 0.52, 0.97, 1.41, 1.6, 1.41, 0.97, 0.52, 0.22, 0.07, 0.02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Низкий широкий колокол — σ = 1, пик 0.4. Высокий узкий — σ = 0.25, пик 1.6: плотность больше единицы, но площадь под каждой кривой равна 1
Дискретная величинаНепрерывная величина
Значенияможно перечислитьлюбые на отрезке
Описаниевероятности p(x)p(x)плотность p(x)p(x)
Нормировка∑xp(x)=1\sum_x p(x) = 1площадь под кривой =1= 1
P(X=x)P(X = x)может быть больше 0всегда 0
Примеры в LLMтокены, награды 0/1веса, шум, эмбеддинги

Сколько в среднем выпадает на кубике? Повторите бросок миллион раз и усредните — получится около 3.5. Это число называется математическое ожиданиематематическое ожидание (матожидание)EN expected value (expectation)E[X] = Σ x·p(x) — среднее значение «в долгую», центр тяжести распределения. и считается без экспериментов, как взвешенная сумма:

E[X]=∑xx⋅p(x)\mathbb{E}[X] = \sum_x x \cdot p(x)

Читаем: «каждое значение умножаем на его вероятность и складываем». Для кубика E[X]=(1+2+3+4+5+6)⋅16=3.5\mathbb{E}[X] = (1 + 2 + 3 + 4 + 5 + 6) \cdot \frac{1}{6} = 3.5. Обратите внимание: на кубике 3.5 не выпадает никогда. Матожидание — это не «самое вероятное значение», а центр тяжести распределения.

Пример с LLM. Модель отвечает коротко (100 токенов) с вероятностью 0.5, средне (200) — с вероятностью 0.3 и длинно, с рассуждениями (1000), — с вероятностью 0.2. Средняя длина ответа:

E[L]=100⋅0.5+200⋅0.3+1000⋅0.2=50+60+200=310 токенов.\begin{aligned} \mathbb{E}[L] &= 100 \cdot 0.5 + 200 \cdot 0.3 + 1000 \cdot 0.2 \\ &= 50 + 60 + 200 = 310 \text{ токенов}. \end{aligned}

Редкие длинные ответы дают почти две трети средней длины. Именно так инженеры прикидывают стоимость инференса.

Для непрерывных величин сумма превращается в интеграл: E[X]=∫x p(x) dx\mathbb{E}[X] = \int x\, p(x)\, dx. Значок ∫\int — вытянутая буква S от слова «сумма»: интеграл — это сумма по бесконечно тонким столбикам гистограммы, то есть площадь под кривой. Считать интегралы в курсе не придётся, достаточно читать их как «взвешенную сумму по всем значениям». У нормального распределения E[X]=μ\mathbb{E}[X] = \mu.

E[aX+b]=a E[X]+b,E[X+Y]=E[X]+E[Y]\mathbb{E}[aX + b] = a\,\mathbb{E}[X] + b, \qquad \mathbb{E}[X + Y] = \mathbb{E}[X] + \mathbb{E}[Y]

Второе равенство верно всегда, даже если XX и YY зависят друг от друга. Это сильно упрощает выкладки: средняя длина диалога из двух ответов — сумма средних длин ответов.

В уроке 1.0.3 вы встречали запись Ex∼D[L]\mathbb{E}_{x \sim D}[\mathcal{L}]. Теперь её можно прочитать полностью: «матожидание функции потерь L\mathcal{L}, когда пример xx выбирается из распределения данных DD». Настоящая цель обучения — средняя ошибка по всем возможным текстам. Посчитать её нельзя, поэтому её оценивают средним по батчу:

Ex∼D[L(x)]≈1B∑i=1BL(xi)\mathbb{E}_{x \sim D}[\mathcal{L}(x)] \approx \frac{1}{B} \sum_{i=1}^{B} \mathcal{L}(x_i)

Закон больших чисел обещает, что при большом батче BB оценка близка к истине. На этой идее стоит стохастический градиентный спуск (урок 1.4.1).

Дисперсия: насколько разбросаны значения

Заголовок раздела «Дисперсия: насколько разбросаны значения»

Две модели дают ответы средней длины 310 токенов. Но первая всегда пишет примерно 310, а вторая — то 100, то 1000. Разницу измеряет дисперсиядисперсияEN varianceVar[X] = E[(X − E[X])²] — средний квадрат отклонения от матожидания. — средний квадрат отклонения от матожидания:

Var[X]=E[(X−E[X])2]=E[X2]−(E[X])2\mathrm{Var}[X] = \mathbb{E}\big[(X - \mathbb{E}[X])^2\big] = \mathbb{E}[X^2] - \big(\mathbb{E}[X]\big)^2

Читаем первую форму: «отклонение от среднего, в квадрате, усреднённое по распределению» — та же дисперсия, что в уроке 1.0.3, только вместо деления на nn каждое значение взвешено своей вероятностью. Вторая форма, «среднее квадрата минус квадрат среднего», — та же величина после раскрытия скобок; ей удобнее считать руками.

У дисперсии неудобные единицы — «токены в квадрате». Поэтому чаще смотрят на стандартное отклонениестандартное отклонениеEN standard deviationКорень из дисперсии; измеряется в тех же единицах, что и сама величина. σ=Var[X]\sigma = \sqrt{\mathrm{Var}[X]}: оно в тех же единицах, что и сама величина.

Для примера с длинами: E[L2]=1002⋅0.5+2002⋅0.3+10002⋅0.2=217 000\mathbb{E}[L^2] = 100^2 \cdot 0.5 + 200^2 \cdot 0.3 + 1000^2 \cdot 0.2 = 217\,000, Var[L]=217 000−3102=120 900\mathrm{Var}[L] = 217\,000 - 310^2 = 120\,900, σ≈348\sigma \approx 348 токенов. Разброс больше самого среднего — типичная картина для моделей, которые иногда «задумываются».

Для Бернулли с параметром pp: E[R]=1⋅p+0⋅(1−p)=p\mathbb{E}[R] = 1 \cdot p + 0 \cdot (1 - p) = p. Значения 0 и 1 в квадрате не меняются, поэтому и E[R2]=p\mathbb{E}[R^2] = p, а по второй форме Var[R]=p−p2=p(1−p)\mathrm{Var}[R] = p - p^2 = p(1 - p). При p=0.7p = 0.7 дисперсия равна 0.7⋅0.3=0.210.7 \cdot 0.3 = 0.21. Максимум p(1−p)p(1-p) — при p=0.5p = 0.5: монета 50 на 50 самая непредсказуемая.

  • Var[aX]=a2 Var[X]\mathrm{Var}[aX] = a^2\,\mathrm{Var}[X] — масштаб входит в квадрате.
  • Если XX и YY независимынезависимость (случайных событий и величин)EN statistical independenceP(A ∩ B) = P(A)·P(B) — знание одного не меняет вероятность другого. Токены в тексте зависимы. (значение одной ничего не говорит о другой, как два броска монеты; точное определение — в разделе «Независимость» ниже), то Var[X+Y]=Var[X]+Var[Y]\mathrm{Var}[X + Y] = \mathrm{Var}[X] + \mathrm{Var}[Y].

Из этого следует важный факт. Среднее nn независимых величин с дисперсией σ2\sigma^2 имеет дисперсию σ2/n\sigma^2 / n и стандартное отклонение σ/n\sigma / \sqrt{n}. Откуда: сумма nn величин имеет дисперсию nσ2n\sigma^2 (второе свойство), а деление на nn уменьшает её в n2n^2 раз (первое свойство с a=1/na = 1/n): nσ2/n2=σ2/nn\sigma^2 / n^2 = \sigma^2 / n. Числа: у награды с p=0.7p = 0.7 стандартное отклонение 0.21≈0.46\sqrt{0.21} \approx 0.46, а у средней награды по 100 попыткам — 0.46/10=0.0460.46 / 10 = 0.046. Отсюда формула p(1−p)/n\sqrt{p(1-p)/n} из урока 0.3.3. Отсюда же правило для обучения: увеличили батч в 4 раза — шум оценки градиента уменьшился в 2 раза, а не в 4.

Проверим всё в NumPy — теорию и симуляцию:

import numpy as np
lengths = np.array([100, 200, 1000]) # длина ответа в токенах
p = np.array([0.5, 0.3, 0.2]) # вероятности
mean = np.sum(lengths * p) # E[X]
var = np.sum((lengths - mean) ** 2 * p) # Var[X] = E[(X − E[X])²]
print(mean, var, np.sqrt(var))
rng = np.random.default_rng(42)
sample = rng.choice(lengths, size=100_000, p=p) # 100 000 «ответов»
print(sample.mean(), sample.var(), sample.std())
310.0 120900.0 347.7067730142742
309.609 120441.76711900001 347.0472116571462

Симуляция на 100 000 сэмплах почти совпала с формулами.

Вероятность меняется, когда мы что-то узнаём. Вероятность слова «врата» в случайном месте текста ничтожна, а после «Карп прыгает через» — велика. Это условная вероятностьусловная вероятностьEN conditional probabilityP(A | B) = P(A ∩ B) / P(B) — вероятность A, если известно, что B произошло. В общем случае P(A | B) ≠ P(B | A).: P(A∣B)P(A \mid B) читается «вероятность AA при условии BB» — та самая вертикальная черта из урока 1.0.3.

P(A∣B)=P(A∩B)P(B)P(A \mid B) = \frac{P(A \cap B)}{P(B)}

Здесь P(A∩B)P(A \cap B) — совместная вероятностьсовместная вероятностьEN joint probabilityP(A ∩ B) или P(A, B) — вероятность того, что произошли оба события., вероятность того, что произошли оба события. Смысл формулы: узнав BB, мы оставляем только те исходы, где BB случилось, и смотрим, какую долю среди них занимает AA.

Пример. В корпусе 1000 документов:

с кодомбез кодавсего
русский60540600
китайский80320400
всего1408601000
  • P(код)=140/1000=0.14P(\text{код}) = 140 / 1000 = 0.14;
  • P(код∣китайский)=80/400=0.20P(\text{код} \mid \text{китайский}) = 80 / 400 = 0.20 — среди китайских документов код встречается чаще;
  • P(китайский∣код)=80/140≈0.57P(\text{китайский} \mid \text{код}) = 80 / 140 \approx 0.57.

Последние два числа разные: в общем случае P(A∣B)≠P(B∣A)P(A \mid B) \ne P(B \mid A). Путать их — самая частая ошибка в теории вероятностей.

От условной вероятности к языковой модели

Заголовок раздела «От условной вероятности к языковой модели»

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

p(x1,…,xT)=∏t=1Tp(xt∣x<t)p(x_1, \dots, x_T) = \prod_{t=1}^{T} p(x_t \mid x_{<t})

Вероятность текста — произведение вероятностей каждого токена при условии всех предыдущих. Если p(прыгает∣Карп)=0.2p(\text{прыгает} \mid \text{Карп}) = 0.2, p(через∣Карп прыгает)=0.5p(\text{через} \mid \text{Карп прыгает}) = 0.5 и p(врата∣Карп прыгает через)=0.71p(\text{врата} \mid \text{Карп прыгает через}) = 0.71, то продолжение «прыгает через врата» после слова «Карп» имеет вероятность 0.2⋅0.5⋅0.71=0.0710.2 \cdot 0.5 \cdot 0.71 = 0.071. Языковая модель (ступень 4) учится выдавать именно эти условные вероятности.

События независимы, если знание одного не меняет вероятность другого: P(A∣B)=P(A)P(A \mid B) = P(A), или, что то же самое, P(A∩B)=P(A) P(B)P(A \cap B) = P(A)\,P(B). Броски монеты независимы. Токены в тексте — нет: иначе контекст был бы бесполезен и языковые модели не работали бы. В примере с корпусом язык и наличие кода зависимы, потому что 0.20≠0.140.20 \ne 0.14.

Часто известно P(свидетельство∣гипотеза)P(\text{свидетельство} \mid \text{гипотеза}), а нужно наоборот. Переворачивает условие формула (теорема) Байесаформула (теорема) БайесаEN Bayes' theoremP(H | E) = P(E | H)·P(H) / P(E) — переворачивает условие. Апостериорная ∝ правдоподобие × априорная.:

P(H∣E)=P(E∣H) P(H)P(E),P(E)=P(E∣H) P(H)+P(E∣¬H) P(¬H)\begin{gathered} P(H \mid E) = \frac{P(E \mid H)\, P(H)}{P(E)}, \\ P(E) = P(E \mid H)\,P(H) + P(E \mid \neg H)\,P(\neg H) \end{gathered}

У каждой части есть имя:

  • P(H)P(H) — априорная вероятностьаприорная вероятность (prior)EN prior probabilityВероятность гипотезы до наблюдения данных.: во что мы верили до наблюдения;
  • P(E∣H)P(E \mid H) — правдоподобие (likelihood): насколько ожидаемо наблюдение, если гипотеза верна. Это то же слово, что в методе максимального правдоподобия из урока 1.3.2;
  • P(H∣E)P(H \mid E) — апостериорная вероятностьапостериорная вероятность (posterior)EN posterior probabilityВероятность гипотезы после наблюдения данных — результат формулы Байеса.: во что стоит верить после наблюдения;
  • P(E)P(E) — полная вероятность наблюдения; знак ¬H\neg H читается «не HH».

Пример: детектор ИИ-текста. В университете 1% эссе написаны нейросетью. Детектор ловит 99% таких эссе и ошибочно помечает 5% честных. Детектор сработал. Какова вероятность, что эссе действительно написал ИИ?

Интуиция кричит «99%». Посчитаем на естественных частотах — представим 10 000 эссе:

  • ИИ-эссе: 1%1\% от 10 000 = 100. Детектор пометит 99 из них.
  • Честных эссе: 9 900. Детектор по ошибке пометит 5%5\% = 495.
  • Всего пометок: 99+495=59499 + 495 = 594, из них настоящих — 99.
P(ИИ∣сработал)=0.99⋅0.010.99⋅0.01+0.05⋅0.99=99594≈0.167P(\text{ИИ} \mid \text{сработал}) = \frac{0.99 \cdot 0.01}{0.99 \cdot 0.01 + 0.05 \cdot 0.99} = \frac{99}{594} \approx 0.167

Только 17%: пять срабатываний из шести — ложные. Виновата маленькая априорная вероятность: честных эссе так много, что даже 5% ложных тревог от них перевешивают все настоящие находки. Та же логика работает при фильтрации данных для претрейна (урок 5.1.2): если «плохих» документов мало, классификатор качества будет часто выбрасывать хорошие. В уроке 2.2.3 вы узнаете, что P(ИИ∣сработал)P(\text{ИИ} \mid \text{сработал}) — это метрика precision.

Категориальное распределение: как LLM «бросает кубик»

Заголовок раздела «Категориальное распределение: как LLM «бросает кубик»»

Соберём всё вместе. На каждом шаге генерации модель делает одно и то же:

flowchart LR
A["Контекст"] --> B["Модель"]
B --> C["Логиты"]
C --> D["softmax"]
D --> E["Категориальное<br/>распределение"]
E --> F["Сэмпл u ~ U[0,1)<br/>→ токен"]
F -->|"добавить к контексту"| A
Цикл генерации: каждый токен — сэмпл из категориального распределения

Как выбрать токен по вероятностям, если в компьютере есть только равномерное random()? Работает метод обратной функции распределения:

  1. Выложите вероятности в ряд на отрезке [0,1)[0, 1): «врата» занимают [0,0.71)[0, 0.71), «реку» — [0.71,0.83)[0.71, 0.83), «волну» — [0.83,0.91)[0.83, 0.91) и так далее. Длина каждого кусочка равна вероятности токена.
  2. Концы кусочков — это накопленные суммы ci=p1+⋯+pic_i = p_1 + \dots + p_i. Вместе они образуют функцию распределенияфункция распределения (CDF)EN cumulative distribution function (CDF)F(x) = P(X ≤ x); для дискретной величины — накопленные суммы вероятностей. Через неё сэмплируют методом обратной функции.: [0.71,0.83,0.91,0.96,1.0][0.71, 0.83, 0.91, 0.96, 1.0].
  3. Бросьте uu из U[0,1)U[0, 1) и найдите кусочек, куда оно попало, — это первый ii, у которого ci>uc_i > u.

При u=0.85u = 0.85 первая сумма больше 0.85 — это 0.91, то есть токен «волну». Чем длиннее кусочек, тем чаще в него попадает uu, поэтому токены выпадают ровно с нужными частотами. Именно так устроен rng.choice(..., p=p), обещанный в уроке 0.3.3:

import numpy as np
tokens = ["врата", "реку", "волну", "камень", "небо"]
p = np.array([0.71, 0.12, 0.08, 0.05, 0.04])
cdf = np.cumsum(p) # накопленные суммы: [p1, p1+p2, p1+p2+p3, …]
print(cdf)
u = 0.85 # «бросок»: равномерное число из [0, 1)
# searchsorted ищет в отсортированном массиве место для u; side="right" даёт первый индекс, где cdf > u
i = np.searchsorted(cdf, u, side="right")
print(i, tokens[i])
rng = np.random.default_rng(0)
u = rng.random(100_000) # сразу 100 000 бросков
idx = np.searchsorted(cdf, u, side="right") # 100 000 номеров токенов
# bincount считает, сколько раз встретился каждый номер 0, 1, 2, …; делим на число бросков — получаем частоты
print(np.bincount(idx, minlength=5) / len(idx))
[0.71 0.83 0.91 0.96 1. ]
2 волну
[0.71084 0.12096 0.07939 0.04906 0.03975]

В PyTorch то же самое делается в одну строку. torch.distributions.Categorical принимает логиты прямо с выхода модели:

import torch
torch.manual_seed(0)
logits = torch.tensor([3.2, 1.6, 1.1, 0.3, -0.4]) # выход модели для 5 токенов (логиты, урок 1.0.3)
probs = torch.softmax(logits, dim=-1) # категориальное распределение; dim=-1 — по последней оси
print(probs)
dist = torch.distributions.Categorical(logits=logits) # «кубик» с этими вероятностями
samples = dist.sample((10_000,)) # 10 000 «следующих токенов» (номера от 0 до 4)
print(samples[:10]) # первые 10 бросков
print(torch.bincount(samples, minlength=5) / 10_000) # частоты, как np.bincount выше
tensor([0.7109, 0.1435, 0.0871, 0.0391, 0.0194])
tensor([3, 0, 0, 2, 0, 1, 0, 0, 0, 0])
tensor([0.7080, 0.1395, 0.0911, 0.0411, 0.0203])

Конкретные сэмплы могут отличаться в другой версии PyTorch, но частоты всегда будут близки к вероятностям. Если вместо сэмпла всегда брать самый вероятный токен (argmax), получится «жадная» генерация — детерминированная, но склонная к повторам. Распределение перед броском можно «подкрутить»: температуру разберём в уроке 1.3.3, а фильтры top-k и top-p — в уроке 4.1.3.

Реализуйте сэмплирование из категориального распределения на чистом Python — без NumPy, через накопленные суммы. Заодно напишите матожидание и дисперсию. Тесты проверят границы отрезков, токены с нулевой вероятностью, защиту от ошибок округления и то, что частоты сходятся к вероятностям.

Сэмплирование токена и матожидание7 тестов
import random

# Распределение модели после контекста «Карп прыгает через…»
TOKENS = ["врата", "реку", "волну", "камень", "небо"]
PROBS = [0.71, 0.12, 0.08, 0.05, 0.04]


def cumulative(probs):
    """Накопленные суммы: [0.5, 0.3, 0.2] → [0.5, 0.8, 1.0].

    Элемент номер i — сумма probs[0] + ... + probs[i].
    """
    # TODO: ваш код
    ...


def sample_index(probs, u):
    """Номер токена для «броска» u из [0, 1) — метод обратной функции распределения.

    Верните первый индекс i, у которого накопленная сумма СТРОГО больше u.
    Если такого нет (сумма probs из-за округления чуть меньше 1), верните последний индекс.
    """
    # TODO: ваш код
    ...


def sample(probs, n, seed=0):
    """n независимых сэмплов (список индексов).

    Создайте генератор rng = random.Random(seed) и n раз вызовите sample_index(probs, rng.random()).
    """
    # TODO: ваш код
    ...


def mean_var(values, probs):
    """Матожидание и дисперсия дискретной случайной величины: (E[X], Var[X]).

    E[X] = Σ x·p,   Var[X] = Σ (x − E[X])²·p
    """
    # TODO: ваш код
    ...


# Проверьте себя кнопкой «Запустить»:
print(cumulative(PROBS))                       # ≈ [0.71, 0.83, 0.91, 0.96, 1.0]
print(sample_index(PROBS, 0.85))               # 2 — это TOKENS[2] = «волну»
s = sample(PROBS, 10_000, seed=1)
if s:                                          # частоты покажутся, когда sample заработает
    print([round(s.count(i) / len(s), 3) for i in range(len(PROBS))])   # близко к PROBS
print(mean_var([1, 2, 3, 4, 5, 6], [1 / 6] * 6))                    # (3.5, 2.9166…)
Проверь себя6 вопросов
1 Какой из списков может быть категориальным распределением?
2 Модель решает задачу верно с вероятностью 0.7 (награда 1), иначе награда 0. Чему равна дисперсия награды?
3 Спама в корпусе 2%. Фильтр ловит 90% спама и ошибочно помечает 5% нормальных документов. Документ помечен. Какова вероятность, что это спам? Округлите до двух знаков.
4 Какие утверждения верны?Можно выбрать несколько ответов
5 Накопленные суммы распределения: [0.71,0.83,0.91,0.96,1.0][0.71, 0.83, 0.91, 0.96, 1.0] для токенов «врата», «реку», «волну», «камень», «небо». Выпало u=0.93u = 0.93. Какой токен выбран?
6 В GRPO на вопрос генерируют группу из G=8G = 8 ответов. Модель решает задачу с вероятностью p=0.9p = 0.9. С какой вероятностью все ответы группы получат одинаковую награду (и группа не даст сигнала)? Округлите до двух знаков.
  • Распределение — все значения случайной величины с их вероятностями: каждая от 0 до 1, сумма равна 1. У непрерывных величин вместо вероятностей — плотность, и единице равна площадь под ней.
  • Матожидание — центр тяжести распределения, дисперсия — средний квадрат отклонения от него. Loss — это матожидание, а среднее по батчу — его оценка с шумом σ/B\sigma / \sqrt{B}.
  • Условная вероятность P(A∣B)≠P(B∣A)P(A \mid B) \ne P(B \mid A). Формула Байеса переворачивает условие, и при маленькой априорной вероятности даже точный детектор чаще ошибается, чем попадает.
  • Выход LLM — категориальное распределение; генерация — сэмплирование через накопленные суммы и равномерный бросок.

Дальше: откуда берутся эти вероятности — softmax, метод максимального правдоподобия и cross-entropy (урок 1.3.2).