Что в тетради
4 листа: BCE, Categorical CE, Тренировка, Ответы. Жёлтые ячейки — входы, их можно менять: всё остальное пересчитается само. Открывается в Excel, LibreOffice Calc и Google Таблицах (Файл → Импорт).
Тетрадь учит одной цепочке, которая стоит за выходом любого классификатора: сеть выдаёт логит — любое число от $-\infty$ до $+\infty$, «переводчик» (sigmoid для двух классов, softmax для $K$ классов) превращает его в вероятность, и только вероятность попадает в формулу потерь. Каждый лист проходит эту цепочку слева направо и показывает, что будет, если пропустить средний шаг.
| Лист | Что внутри | Чему учит |
|---|---|---|
| BCE | 4 блока: расчёт для 5 объектов; те же логиты без sigmoid; таблица и график двух ветвей штрафа; как sigmoid сжимает логит | бинарная перекрёстная энтропия, NaN от логитов, роль sigmoid |
| Categorical CE | 3 блока: расчёт для 3 классов; логиты без softmax; таблица и график $-\ln x$ | категориальная перекрёстная энтропия, отрицательный лосс без дна, роль softmax |
| Тренировка | 3 задания: BCE для трёх объектов, CE после softmax, softmax вручную | посчитать самому; рядом с ответом — ✓ или ✗ (допуск ±0,005) |
| Ответы | эталонные ответы ко всем заданиям — формулами | сверить ход решения |
Цвета ячеек везде одни и те же:
- жёлтые — входы: метки $y$ и логиты $z$, их можно менять
- голубые — «переводчик» sigmoid или softmax: отдельный шаг, не часть формулы потерь
- красные — сама формула потерь; чем светлее, тем глубже внутри скобок
- зелёные и красные зоны в блоках 3 — где логарифмы существуют, а где нет
Разделы идут в порядке листов и блоков тетради. Все числа на странице посчитаны из тех же входов, что в файле, и совпадают с ним до третьего знака. Под каждым листом — «Тетрадь в браузере»: тот же расчёт, который можно менять прямо здесь. Логарифм всюду натуральный: $\ln$.
Лист BCE: расчёт по шагам
Блок 1 листа — пять объектов бинарной задачи: метка $y=1$ («да») или $y=0$ («нет») и логит $z$, который выдала сеть. Расчёт идёт в три шага, как колонки таблицы: вход → sigmoid → формула BCE.
- $y_i$
- правильный ответ для объекта $i$: 1 или 0
- $z_i$
- логит — «сырой» выход сети, любое число
- $\hat y_i=\sigma(z_i)$
- предсказанная вероятность ответа «да»
- $n$
- число объектов, здесь $n=5$
| $i$ | $y$ | логит $z$ | $\hat y=\sigma(z)$ | $y\ln\hat y$ | $(1-y)\ln(1-\hat y)$ | сумма двух |
|---|---|---|---|---|---|---|
| 1 | 1 | 2,20 | 0,900 | −0,105 | 0,000 | −0,105 |
| 2 | 0 | −1,40 | 0,198 | 0,000 | −0,220 | −0,220 |
| 3 | 1 | 0,40 | 0,599 | −0,513 | 0,000 | −0,513 |
| 4 | 0 | −0,60 | 0,354 | 0,000 | −0,437 | −0,437 |
| 5 | 1 | 1,40 | 0,802 | −0,220 | 0,000 | −0,220 |
| Σ по всем $i$ | −1,496 | |||||
| $n$ | 5 | |||||
| BCE = −Σ / n | 0,299 |
Разбор каждой строки
Шаг 2 (голубая колонка): $\hat y=1/(1+e^{-z})$. Шаг 3 (красные колонки): два слагаемых и их сумма. В каждой строке одно слагаемое обнуляется множителем $y$ или $1-y$.
Строка 1
Строка 2
Строка 3
Строка 4
Строка 5
Сумма по всем строкам $\Sigma = -1{,}496$, объектов $n=5$, поэтому $\mathrm{BCE}=-\Sigma/n = -(-1{,}496)/5 = 0{,}299$. Последняя серая строка листа считает то же другим путём — через СУММПРОИЗВ (SUMPRODUCT) обеих ветвей — и тоже даёт $0{,}299$.
При $y=1$ остаётся $\ln\hat y$, при $y=0$ — $\ln(1-\hat y)$. То есть штраф строки всегда равен $-\ln$(вероятности, которую модель дала правильному ответу). В блоке 1 эти вероятности равны $0{,}900$, $0{,}802$, $0{,}599$, $0{,}646$ и $0{,}802$. У строк 2 и 5 штраф одинаковый, $-0{,}220$: логиты $-1{,}4$ и $1{,}4$ симметричны, а $\sigma(-z)=1-\sigma(z)$.
Попробуйте (как предлагает лист)
- Логит строки 1: $2{,}2 \to 6$. Тогда $\hat y_1 = 0{,}998$, штраф строки $0{,}002$ — почти ноль, а BCE падает с $0{,}299$ до $0{,}279$.
- Логит строки 1: $2{,}2 \to -3$ при $y=1$. Тогда $\hat y_1 = 0{,}047$, штраф строки $3{,}049$ — больше, чем у четырёх остальных строк вместе ($1{,}391$). BCE вырастает до $0{,}888$: одна уверенная ошибка весит больше всего остального.
Логиты без sigmoid
Блок 2 берёт те же метки и логиты и подаёт логиты в формулу BCE напрямую — как будто $z$ уже вероятность. У BCE две ветви, $\ln z$ и $\ln(1-z)$, и в вычислении существовать должны обе, даже та, что потом умножится на ноль.
| $i$ | $y$ | $z$ | $\ln z$ | $\ln(1-z)$ | $y\ln z+(1-y)\ln(1-z)$ |
|---|---|---|---|---|---|
| 1 | 1 | 2,2 | 0,788 | нет | NaN |
| 2 | 0 | −1,4 | нет | 0,875 | NaN |
| 3 | 1 | 0,4 | −0,916 | −0,511 | −0,916 (случайно в $(0;1)$) |
| 4 | 0 | −0,6 | нет | 0,470 | NaN |
| 5 | 1 | 1,4 | 0,336 | нет | NaN |
Что вышло по строкам:
- Строка 1, $z=2{,}2$: $\ln 2{,}2 \approx 0{,}788 > 0$ — «штраф» с обратным знаком, а $\ln(1-2{,}2)=\ln(-1{,}2)$ не существует.
- Строки 2 и 4, $z<0$: не существует $\ln z$; строка 5, $z=1{,}4$: не существует $\ln(1-z)$.
- Только строка 3 ($z=0{,}4$) «случайно» попала в $(0;1)$ и дала число $\ln 0{,}4\approx-0{,}916$. Но и оно бессмысленно: $0{,}4$ — логит, а не вероятность; настоящая вероятность здесь $\sigma(0{,}4)=0{,}599$.
В строке 1 вторая ветвь умножается на $1-y=0$, и кажется, что её можно не считать. Но компьютер сначала вычисляет логарифм, а потом умножает: в числах с плавающей точкой $\ln(-1{,}2)=\mathrm{NaN}$, $\ln 0 = -\infty$, а $0\cdot\mathrm{NaN}=\mathrm{NaN}$ и $0\cdot(-\infty)=\mathrm{NaN}$. В Excel то же самое выглядит как ошибка #ЧИСЛО! (#NUM!), поэтому лист ловит её через ЕСЛИОШИБКА (IFERROR) и пишет «NaN».
Одной такой строки достаточно: среднее с NaN — NaN, градиенты — NaN, после шага оптимизатора веса сети тоже NaN. Обучение не «плохое», оно мёртвое. Итог блока: BCE без sigmoid — NaN, BCE с sigmoid — 0,299.
Sigmoid решает обе проблемы сразу: $\hat y\in(0;1)$ и $1-\hat y\in(0;1)$, поэтому оба логарифма всегда существуют и оба $\le 0$ — а значит, каждый штраф $\ge 0$.
Тетрадь в браузере
Тот же расчёт, что в листе: меняйте жёлтые ячейки — остальное пересчитается.
Две ветви и две стены
Блок 3 объясняет, почему так: таблица подставляет в обе ветви BCE разные $x$ — и вероятности, и «логитные» значения вне $(0;1)$. Жёлтые $x$ в листе можно менять, а график под таблицей (лист строит его по $\hat y$ от $0{,}02$ до $0{,}98$) показывает обе ветви целиком.
| $x$ | при $y=1$: $-\ln x$ | при $y=0$: $-\ln(1-x)$ | зона |
|---|---|---|---|
| −1 | нет | −0,693 | логит |
| 0 | нет | 0,000 | логит |
| 0,01 | 4,605 | 0,010 | вероятность |
| 0,1 | 2,303 | 0,105 | вероятность |
| 0,5 | 0,693 | 0,693 | вероятность |
| 0,9 | 0,105 | 2,303 | вероятность |
| 0,99 | 0,010 | 4,605 | вероятность |
| 1 | 0,000 | нет | логит |
| 2 | −0,693 | нет | логит |
| 10 | −2,303 | нет | логит |
У BCE две «стены». Ветвь $y=1$ — штраф $-\ln x$ — уходит в бесконечность у нуля: уверенное «нет», когда правильный ответ «да». Ветвь $y=0$ — штраф $-\ln(1-x)$ — уходит в бесконечность у единицы. Между стенами, в точке $x=0{,}5$, обе ветви дают одинаковый штраф $\ln 2 \approx 0{,}693$ — цену полной неуверенности.
Вне $(0;1)$ всё ломается: при $x\le0$ нет $\ln x$, при $x\ge1$ нет $\ln(1-x)$, при $x>1$ ветвь $y=1$ даёт отрицательный штраф (при $x=10$ он равен $-\ln 10\approx-2{,}303$ и дальше падает без дна), а при $x<0$ так же «ломается» ветвь $y=0$: при $x=-1$ её штраф $-\ln 2\approx-0{,}693$. Сеть, которой разрешили отрицательный лосс, будет просто раздувать логит.
Как sigmoid сжимает логит
Блок 4 показывает сам «переводчик». Колонки листа — промежуточные шаги формулы $\hat y = 1/(1+e^{-z})$: сначала $e^{-z}$, потом $\hat y$, потом $1-\hat y$.
| $z$ | $e^{-z}$ | $\hat y=\dfrac{1}{1+e^{-z}}$ | $1-\hat y$ |
|---|---|---|---|
| −10 | 22026,4658 | 0,0000 | 1,0000 |
| −3 | 20,0855 | 0,0474 | 0,9526 |
| −1 | 2,7183 | 0,2689 | 0,7311 |
| 0 | 1,0000 | 0,5000 | 0,5000 |
| 1 | 0,3679 | 0,7311 | 0,2689 |
| 3 | 0,0498 | 0,9526 | 0,0474 |
| 10 | 0,0000 | 1,0000 | 0,0000 |
Почему результат всегда в $(0;1)$: $e^{-z}>0$ при любом $z$, значит знаменатель $1+e^{-z}>1$ и $0<\hat y<1$. При $z=0$ ровно $\hat y=0{,}5$ — полная неуверенность; большие положительные $z$ дают уверенное «да», большие отрицательные — уверенное «нет». Таблица симметрична: $\sigma(-z)=1-\sigma(z)$, поэтому строки $z$ и $-z$ меняются колонками $\hat y$ и $1-\hat y$.
Глубже: «хоть −1000, хоть +1000» — в математике, но не в компьютере
Лист пишет, что при любом логите $\hat y$ остаётся строго между 0 и 1. Математически это так. Но в числах с плавающей точкой при $z \gtrsim 36{,}74$ (float64; в float32 уже при $z \gtrsim 16{,}64$) слагаемое $e^{-z}$ теряется рядом с единицей, $\hat y$ округляется ровно до $1$, а $1-\hat y$ — ровно до $0$. При $y=0$ штраф $-\ln(1-\hat y)$ становится $+\infty$.
С другой стороны, $e^{-z}$ переполняется при $z<-709{,}78$: в самом листе подстановка $z=-1000$ даёт ошибку #ЧИСЛО! (#NUM!) во всей строке, а $z=1000$ — ровно $\hat y=1$ и $1-\hat y=0$.
Поэтому библиотеки не считают sigmoid и логарифм по отдельности. Они сразу считают штраф из логита через устойчивую запись $\max(z,0)-yz+\ln\bigl(1+e^{-|z|}\bigr)$ — так делает nn.BCEWithLogitsLoss. Это ровно то же число, что $-[y\ln\sigma(z)+(1-y)\ln(1-\sigma(z))]$, но без переполнений.
Итог листа BCE
- BCE — это перекрёстная энтропия для двух классов, записанная через одно число $\hat y$: вероятность «да» равна $\hat y$, вероятность «нет» — $1-\hat y$.
- Формула знает только про $\hat y\in(0;1)$. Логиты живут на всей прямой: поданные напрямую, они дают NaN или штраф с обратным знаком.
- Sigmoid сжимает любой логит в $(0;1)$. Softmax для двух классов даёт ровно sigmoid: $\mathrm{softmax}(z_1,z_2)_1=\sigma(z_1-z_2)$ — это одна и та же идея.
- Деление на $n$ нужно только для того, чтобы лосс не зависел от размера батча; саму форму штрафа задаёт $-\ln$.
- В коде:
nn.BCEWithLogitsLossждёт логиты (делает sigmoid сам и численно устойчивее),nn.BCELoss— уже вероятности.
Pythonimport numpy as np
# метки и логиты из листа BCE
y = np.array([1, 0, 1, 0, 1])
z = np.array([2.2, -1.4, 0.4, -0.6, 1.4])
# шаг 2: sigmoid; шаг 3: формула BCE
p = 1 / (1 + np.exp(-z))
bce = -np.mean(y * np.log(p) + (1 - y) * np.log(1 - p))
print(round(bce, 3)) # 0.299
# то же прямо из логитов, устойчиво (так считает nn.BCEWithLogitsLoss)
s = np.maximum(z, 0) - z * y + np.log1p(np.exp(-np.abs(z)))
print(round(s.mean(), 3)) # 0.299
# PyTorch:
# nn.BCEWithLogitsLoss() ждёт логиты
# nn.BCELoss() ждёт вероятности
Лист Categorical CE: расчёт по шагам
Второй лист — та же цепочка для $K=3$ классов. На входе метки в виде «одного горячего» вектора (one-hot: $y_k=1$ только у правильного класса, здесь $k=2$) и три логита. Переводчик — softmax: он превращает логиты в вероятности, которые в сумме дают 1.
- $z_k$
- логит класса $k$
- $\hat y_k=\dfrac{e^{z_k}}{\sum_j e^{z_j}}$
- softmax: вероятность класса $k$
- $y_k$
- 1 у правильного класса, 0 у остальных
- $K$
- число классов, здесь $K=3$
| $k$ | $y$ | логит $z$ | $\hat y=\mathrm{softmax}(z)$ | $\ln\hat y$ | $y\ln\hat y$ |
|---|---|---|---|---|---|
| 1 | 0 | 1 | 0,231 | −1,464 | 0,000 |
| 2 | 1 | 2 | 0,629 | −0,464 | −0,464 |
| 3 | 0 | 0,5 | 0,140 | −1,964 | 0,000 |
| $\Sigma\hat y$ | 1,000 | Σ | −0,464 | ||
| CE = −Σ | 0,464 |
Как получаются числа голубой колонки и колонки $\ln\hat y$:
1. Экспоненты логитов и их сумма:
2. Делим каждую экспоненту на сумму — это softmax. Проверка листа $\Sigma\hat y = 1$ выполняется всегда, при любых логитах:
3. Логарифмы вероятностей. Удобно заметить, что $\ln\hat y_k = z_k - \ln\sum_j e^{z_j}$, а $\ln 11{,}756 = 2{,}464$. Поэтому все три логарифма — это логиты минус одно и то же число:
4. В колонке $y\ln\hat y$ выживает одно слагаемое — то, где $y=1$. Значит, CE — это $-\ln$ вероятности правильного класса (это и проверяет серая строка листа):
Отсюда видно, что CE зависит только от того, насколько логит правильного класса выделяется на фоне остальных: $\mathrm{CE}=\ln\sum_j e^{z_j}-z_{\text{правильного}}$.
Попробуйте (как предлагает лист)
- Логит класса 2: $2 \to 5$. Тогда $\hat y_2=0{,}971$ и $\mathrm{CE}=0{,}029$ — почти ноль.
- Логит класса 2: $2 \to -2$. Тогда $\hat y_2=0{,}030$ и $\mathrm{CE}=3{,}505$ — большой штраф. Сумма $\hat y$ в обоих случаях остаётся равной 1.
Логиты без softmax
Блок 2 снова подаёт логиты напрямую — теперь в $\mathrm{CE}=-\sum_k y_k\ln z_k$. Здесь все три логита оказались положительными, поэтому логарифмы существуют, но результат хуже ошибки: CE без softmax $= -\ln 2 \approx -0{,}693$ — отрицательный лосс, тогда как с softmax CE $= 0{,}464$.
| $k$ | $y$ | $z$ | $\ln z$ | $y\ln z$ |
|---|---|---|---|---|
| 1 | 0 | 1 | 0,000 | 0,000 |
| 2 | 1 | 2 | 0,693 | 0,693 |
| 3 | 0 | 0,5 | −0,693 | 0,000 |
| CE без softmax | −0,693 |
Перекрёстная энтропия настоящих распределений вероятностей не бывает отрицательной: $\mathrm{CE}(y,\hat y)=H(y)+\mathrm{KL}(y\,\|\,\hat y)\ge 0$, а для one-hot метки это просто $-\ln$ вероятности, которая не больше 1. Отрицательное число — верный признак того, что в формулу попали не вероятности.
- Логит правильного класса $\to 100$: без softmax лосс $= -\ln 100 \approx -4{,}605$, при $1000$ — $-6{,}908$, и дальше без дна. Сеть научится только раздувать этот логит. С softmax лосс упирается в 0 снизу.
- Логит правильного класса $\to -1$: без softmax — ошибка, логарифма отрицательного числа нет. С softmax всё считается, просто лосс большой.
Тетрадь в браузере
Тот же расчёт, что в листе: меняйте жёлтые ячейки — остальное пересчитается.
Почему только $(0;\,1]$
Блок 3 второго листа — та же «карта», что в BCE, но с одной ветвью $-\ln x$: у CE штрафуется только вероятность правильного класса. Зелёная зона — $(0;1]$: от огромного штрафа у нуля до нулевого при $x=1$. Красные зоны — логиты: при $x\le 0$ логарифма нет, при $x>1$ штраф отрицательный и падает без дна.
| $x$ | $-\ln x$ | зона |
|---|---|---|
| −1 | нет | логит |
| 0 | нет | логит |
| 0,01 | 4,605 | вероятность |
| 0,1 | 2,303 | вероятность |
| 0,5 | 0,693 | вероятность |
| 0,9 | 0,105 | вероятность |
| 1 | 0,000 | вероятность |
| 2 | −0,693 | логит |
| 10 | −2,303 | логит |
| 1000 | −6,908 | логит |
Итог листа Categorical CE
- Формула CE знает только про вероятности: числа от 0 до 1 с суммой 1.
- Логиты — любые числа от $-\infty$ до $+\infty$. Поданные в CE напрямую, они дают либо ошибку, либо отрицательный лосс без дна.
- Softmax — переводчик: сжимает любые логиты в $(0;1)$ с суммой 1. Поэтому CE и softmax всегда идут парой.
- В коде смотрите, кто делает softmax:
nn.CrossEntropyLossждёт логиты (softmax внутри),nn.NLLLoss— уже лог-вероятности (log_softmax).
Pythonimport numpy as np
# логиты из листа Categorical CE; правильный класс k = 2 (индекс 1)
z = np.array([1.0, 2.0, 0.5])
k = 1
lse = np.log(np.sum(np.exp(z))) # ln Σ e^z
p = np.exp(z - lse) # шаг 2: softmax
print(np.round(p, 3), round(p.sum(), 3))
# [0.231 0.629 0.14 ] 1.0
print(round(-np.log(p[k]), 3)) # 0.464
print(round(lse - z[k], 3)) # 0.464: CE = ln Σ e^z − z_k
# PyTorch:
# nn.CrossEntropyLoss() ждёт логиты (softmax внутри)
# nn.NLLLoss() ждёт лог-вероятности (log_softmax)
Глубже: почему BCE — это CE для двух классов
Возьмём два класса с логитами $z_1, z_2$. Softmax даёт $\hat y_1=\dfrac{e^{z_1}}{e^{z_1}+e^{z_2}}=\dfrac{1}{1+e^{-(z_1-z_2)}}=\sigma(z_1-z_2)$ и $\hat y_2=1-\hat y_1$.
CE с one-hot меткой $(y,\,1-y)$ равна $-[y\ln\hat y_1+(1-y)\ln(1-\hat y_1)]$ — ровно слагаемое BCE. Значит, бинарный классификатор с одним логитом $z$ — это softmax по паре $(z, 0)$, а BCE — частный случай CE.
Тренировка с самопроверкой
Лист «Тренировка» — три задания на калькулятор: впишите ответ в жёлтую ячейку, и рядом появится ✓ или ✗. Допуск — $\pm 0{,}005$, логарифм натуральный. Ниже — те же задания прямо на странице; числа можно писать через запятую или точку.
Чтобы уложиться в допуск, не округляйте промежуточные значения грубее трёх знаков после запятой. Ответ к слагаемому — отрицательное число (логарифм вероятности), а BCE и CE — положительные: в конце стоит минус.
Ответы и разбор (лист «Ответы»)
Задание 1. Каждое слагаемое — $\ln$ вероятности правильного ответа: при $y=1$ это $\ln\hat y$, при $y=0$ — $\ln(1-\hat y)$.
Задание 2. Вероятности уже после softmax; выживает только слагаемое правильного класса $k=3$.
Задание 3. Softmax вручную для логитов $z=(0;\,1;\,2)$, правильный класс $k=3$.
Проверка через логиты: $\mathrm{CE}=\ln\sum_j e^{z_j}-z_3=\ln 11{,}107-2=0{,}408$.
Частые ошибки
- Логиты в формулу, которая ждёт вероятности.
nn.BCELossилиnn.NLLLossповерх «сырого» выхода сети — это блоки 2 обоих листов: NaN или отрицательный лосс. - Двойной переводчик. Sigmoid перед
nn.BCEWithLogitsLossили softmax передnn.CrossEntropyLoss: функция применит его второй раз. Ошибки не будет, но вероятности окажутся сжаты к середине, лосс почти перестанет меняться, и обучение забуксует. - Не тот логарифм. В формулах — натуральный $\ln$. На калькуляторе клавиша log часто означает $\log_{10}$: $\log_{10}0{,}8\approx-0{,}097$ вместо $\ln 0{,}8\approx-0{,}223$.
- Потерянный минус. Логарифм вероятности отрицателен, поэтому сумма в колонке «сумма двух» отрицательна, а BCE и CE — положительны: $\mathrm{BCE}=-\Sigma/n$.
- Перепутанная ветвь. При $y=0$ штраф — $-\ln(1-\hat y)$, а не $-\ln\hat y$: штрафуется вероятность ответа «нет».
- Слишком раннее округление. Если округлить $e^{z}$ или $\hat y$ до одного-двух знаков, ответ выйдет за допуск $\pm0{,}005$.
Итоги
| BCE (2 класса) | Categorical CE ($K$ классов) | |
|---|---|---|
| выход сети | один логит $z$ | $K$ логитов $z_1,\dots,z_K$ |
| переводчик | $\sigma(z)=1/(1+e^{-z})$ | $\mathrm{softmax}(z)_k=e^{z_k}/\sum_j e^{z_j}$ |
| штраф объекта | $-[y\ln\hat y+(1-y)\ln(1-\hat y)]$ | $-\sum_k y_k\ln\hat y_k=-\ln\hat y_{\text{прав}}$ |
| пример тетради | $\mathrm{BCE}=0{,}299$ (5 объектов) | $\mathrm{CE}=0{,}464$ (1 объект) |
| без переводчика | NaN | $-\ln 2\approx-0{,}693$ и ниже |
| PyTorch | BCEWithLogitsLoss (логиты) | CrossEntropyLoss (логиты) |
- Логит → переводчик → формула: формула потерь понимает только вероятности.
- Штраф объекта — всегда $-\ln$ вероятности правильного ответа: $0$ при уверенном верном ответе, $\ln 2\approx0{,}693$ при полной неуверенности, $+\infty$ при уверенной ошибке.
- Подробнее о самих функциях — в шпаргалке: BCE, перекрёстная энтропия, sigmoid, softmax.