# Логистическая регрессия — градиентный спуск

Модель делает предсказание, предсказание почти всегда неточное, и нужен способ подправить веса так, чтобы промах в следующий раз стал чуть меньше. Этот способ называется градиентным спуском, а конкретный набор формул, по которому он считается для логистической регрессии, — тема этой статьи. Разберём весь путь для одного обучающего примера: от чисел на входе до обновлённых весов, — и проверим каждое число в Python.

## Оглавление

- [Три буквы, которые нужны для старта: z, σ, ŷ](#три-буквы)
- [Один полный шаг спуска: от предсказания до нового веса](#полный-шаг)
- [Что означает знак и размер dz](#знак-и-размер)
- [Два противоречивых примера: чей сигнал сильнее](#два-примера)
- [Мини-квиз: собери шаг по порядку](#мини-квиз)
- [Что дальше](#что-дальше)

## Три буквы, которые нужны для старта: z, σ, ŷ {#три-буквы}

Прежде чем говорить о спуске, нужно на пальцах понимать три величины, из которых строится предсказание логистической регрессии.

$z$ — взвешенная сумма входов. Если вход — вектор чисел $x = [x_1, x_2, \dots]$, а модель хранит вес $w_i$ для каждого признака и один общий сдвиг $b$, то:

$$z = w^T x + b = w_1 x_1 + w_2 x_2 + \dots + b$$

Это обычное число, которое может быть любым: отрицательным, нулём, огромным. Само по себе оно не годится в качестве вероятности — вероятность должна лежать между 0 и 1.

$\sigma$ (сигмоида) — функция, которая сжимает любое число в диапазон от 0 до 1:

$$\sigma(z) = \frac{1}{1 + e^{-z}}$$

Большое положительное $z$ даёт $\sigma(z)$ близкое к 1, большое отрицательное — близкое к 0, а $z = 0$ даёт ровно $\sigma(0) = 0.5$. Форма графика — плавная буква S, поэтому и название «сигмоида» (σ) (от греческого «сигма», буква S).

$\hat{y} = \sigma(z)$ — итоговое предсказание модели, число от 0 до 1, которое читается как уверенность: «на сколько процентов модель считает, что ответ — 1». В формулах ниже это же число часто обозначают буквой $a$ (от «activation», результат активации) — это одно и то же число, просто $a$ — привычное обозначение внутри вычислений, а $\hat{y}$ — обозначение снаружи, когда говорим про итоговый ответ модели.

Если можешь пересказать: $z$ — взвешенная сумма, любое число; $\sigma$ сжимает его в 0..1; $\hat{y} = a = \sigma(z)$ — итоговая уверенность модели, — двигаемся дальше.

## Один полный шаг спуска: от предсказания до нового веса {#полный-шаг}

Возьмём один обучающий пример: вход $x = [0.5,\; 0.3,\; 0.9]$ (три признака), правильный ответ $y = 1$. Стартовые веса модели — ещё не обученные, просто взяты для примера: $w = [1.2,\; -0.4,\; 2.0]$, $b = -0.9$. Скорость обучения (α) — насколько сильно двигать веса за один шаг — $\alpha = 0.1$.

Шаг градиентного спуска для одного примера состоит из четырёх частей: прямой ход, сигнал ошибки, градиенты, обновление весов. Разберём каждую по очереди, считая всё число за числом.

**Часть 1 — прямой ход.** Считаем $z$, потом $a = \sigma(z)$, потом штраф за ошибку (loss) $L$:

$$z = w^T x + b = 1.2 \cdot 0.5 + (-0.4) \cdot 0.3 + 2.0 \cdot 0.9 - 0.9 = 0.6 - 0.12 + 1.8 - 0.9 = 1.38$$

$$a = \sigma(1.38) = \frac{1}{1 + e^{-1.38}} \approx 0.799$$

Loss ($L$) для логистической регрессии — кросс-энтропия. При $y = 1$ она упрощается до $L = -\log a$ (полный вывод формулы и почему она выбрана именно такой — в отдельной статье про [вывод dL/dz](/notes/derivation-dl-dz/), здесь достаточно знать, что это способ штрафовать модель за неуверенность в правильном ответе):

$$L = -\log(0.799) \approx 0.2244$$

**Часть 2 — сигнал ошибки (dz).** Обратный ход начинается с одной короткой формулы:

$$dz = a - y$$

Здесь $dz$ — это сокращённая запись производной $L$ по $z$: число, которое говорит, в какую сторону и насколько сильно нужно подвинуть $z$, чтобы уменьшить ошибку. Формула получается из цепного правила (детально — в статье [«Вывод dL/dz»](/notes/derivation-dl-dz/)), а здесь мы просто её используем: предсказание минус правильный ответ.

$$dz = 0.799 - 1 = -0.201$$

Отрицательный знак означает: модель дала *меньше* уверенности, чем нужно было ($y=1$, а $a$ пока только 0.799), поэтому $z$ нужно увеличить.

**Часть 3 — градиенты по весам.** Из $dz$ получаются градиенты — насколько нужно двинуть каждый вес и сдвиг:

$$dw = x \cdot dz, \qquad db = dz$$

Смысл в словах: каждый вес $w_i$ отвечает за свой признак $x_i$, и вклад этого признака в общую ошибку — просто $x_i$, умноженный на общий сигнал ошибки (dz) $dz$. Признак с большим значением (0.9 у нас) тянет за собой больший градиент, чем признак с маленьким значением (0.3), — при одном и том же сигнале ошибки (dz). А сдвиг $b$ ни на что не умножается, у него нет своего признака, поэтому его градиент — это просто сам $dz$.

$$dw = [0.5,\; 0.3,\; 0.9] \cdot (-0.201) = [-0.1005,\; -0.0603,\; -0.1809]$$

$$db = -0.201$$

**Часть 4 — обновление весов.** Веса двигаются *против* градиента, на шаг размера $\alpha$:

$$w := w - \alpha \, dw, \qquad b := b - \alpha \, db$$

Минус — потому что градиент указывает направление *роста* ошибки, а нам нужно её уменьшать: значит, идём в противоположную сторону.

$$w := [1.2,\; -0.4,\; 2.0] - 0.1 \cdot [-0.1005,\; -0.0603,\; -0.1809] = [1.2101,\; -0.394,\; 2.0181]$$

$$b := -0.9 - 0.1 \cdot (-0.201) = -0.8799$$

Проверим, что шаг подействовал: если пересчитать $z$ с новыми весами, получится $z \approx 1.4232$, $a \approx 0.8058$ — уверенность подросла с 0.799 до 0.8058, ровно в ту сторону, куда мы и хотели её подвинуть.

Если можешь пересказать: прямой ход даёт $a$ и $L$; $dz = a - y$ — сигнал ошибки; $dw = x \cdot dz$, $db = dz$ — вклад каждого веса; $w := w - \alpha \, dw$ — шаг против градиента, — листай дальше.

## Что означает знак и размер dz {#знак-и-размер}

Прежде чем читать дальше: если бы правильный ответ был $y = 0$ (а не 1), а предсказание осталось тем же $a = 0.799$, каким был бы знак $dz$ (сигнал ошибки) — положительным или отрицательным? Прикинь по формуле $dz = a - y$, а потом проверь.

<details>
<summary>Ответ</summary>

Положительным: $dz = 0.799 - 0 = 0.799$. Знак $dz$ (сигнал ошибки) всегда показывает, в какую сторону промахнулась модель: отрицательный — недооценила (предсказание меньше нужного), положительный — переоценила.

</details>

Размер $|dz|$ тоже несёт смысл: чем ближе предсказание $a$ к правильному ответу $y$, тем меньше $|dz|$, и тем меньше шаг у весов. У идеального предсказания ($a = y$ точно) $dz = 0$ — и веса вовсе не двигаются, потому что двигать их уже не нужно.

## Два противоречивых примера: чей сигнал сильнее {#два-примера}

Что если в наборе не один пример, а два, с одним и тем же входом $x = [0.5, 0.3, 0.9]$, но противоречивыми ответами: у одного $y = 1$, у другого $y = 0$?

Представь двух людей, которые тянут одно одеяло в разные стороны: кто сильнее не прав в этот момент, тот и тянет сильнее. При тех же стартовых весах $w = [1.2, -0.4, 2.0]$, $b = -0.9$ предсказание для обоих одинаковое, $\hat{y} = 0.799$ (это тот же $z = 1.38$, что и в основном примере выше), но сигналы ошибки противоположны. Для первого примера: $dz_1 = 0.799 - 1 = -0.201$ (веса нужно поднять). Для второго: $dz_2 = 0.799 - 0 = 0.799$ (веса нужно опустить).

Угадай сначала: во сколько раз второй пример тянет «одеяло» сильнее первого — в 2 раза, в 4 раза или в 10 раз? Прикинь по числам $dz_1$ и $dz_2$ выше, а потом проверь.

<details>
<summary>Ответ</summary>

Примерно в 4 раза: $dz_2 / |dz_1| = 0.799 / 0.201 \approx 3.97$.

</details>

![Два значения dz как противоположно направленные полосы: dz1=−0.201 (пример 1, y=1) короткая влево, dz2=+0.799 (пример 2, y=0) почти в 4 раза длиннее и вправо](/notes/logistic-regression-gradient-descent/pulling-blanket.png)

Твоя очередь: что произойдёт с $dz_2$, если правильный ответ $y$ для второго примера перевернётся с $0$ на $1$ (то есть оба примера станут согласны, $y=1$)? Посчитай — формула та же, $dz = a - y$, только $y$ теперь другое.

<details>
<summary>Ответ</summary>

$dz_2 = 0.799 - 1 = -0.201$ — то есть станет точно равен $dz_1$: оба примера теперь согласны и тянут в одну сторону с одинаковой силой.

</details>

Когда примеров несколько, спуск не использует градиент одного из них — он усредняет градиенты всех. Для двух примеров выше усреднённый градиент по весам получается $dw_{avg} = [0.1495,\; 0.0897,\; 0.2691]$, $db_{avg} = 0.299$: спуск идёт в сторону, заданную вторым примером, потому что его ошибка почти вчетверо сильнее. Противоречивые примеры не «побеждают» друг друга поровну, а тянут спуск пропорционально тому, насколько каждый из них неправ. (Как это усреднение выглядит для целого набора из многих примеров, а не только двух, — тема статьи [«Градиентный спуск на m примерах»](/notes/gradient-descent-on-m-examples/).)

Если можешь пересказать: два примера с общим входом, но разными $y$, тянут веса в разные стороны с силой, пропорциональной своему $|dz|$; усреднённый градиент идёт за тем, чей сигнал сильнее, — листай дальше.

## Мини-квиз: собери шаг по порядку {#мини-квиз}

Возьми свои числа: $x = [1.0,\; 0.2]$, $y = 0$, $w = [0.5,\; -0.3]$, $b = 0.1$, $\alpha = 0.1$. Посчитай по порядку: $z$, затем $a = \sigma(z)$, затем $dz = a - y$, затем $dw$ и $db$, затем новые $w$ и $b$.

<details>
<summary>Ответ</summary>

$z = 0.5 \cdot 1.0 + (-0.3) \cdot 0.2 + 0.1 = 0.5 - 0.06 + 0.1 = 0.54$

$a = \sigma(0.54) \approx 0.6318$

$dz = 0.6318 - 0 = 0.6318$ (модель переоценила: правильный ответ 0, а уверенность за него высокая)

$dw = [1.0 \cdot 0.6318,\; 0.2 \cdot 0.6318] = [0.6318,\; 0.1264]$, $db = 0.6318$

$w := [0.5,\; -0.3] - 0.1 \cdot [0.6318,\; 0.1264] = [0.4368,\; -0.3126]$

$b := 0.1 - 0.1 \cdot 0.6318 = 0.0368$

</details>

## Что дальше {#что-дальше}

Один шаг спуска для логистической регрессии — это четыре считаемые части: прямой ход даёт предсказание $a$, сигнал ошибки (dz) $dz = a - y$ говорит, куда промахнулись, градиенты $dw = x \cdot dz$ и $db = dz$ раскладывают этот промах по весам, и обновление $w := w - \alpha \, dw$ двигает веса против ошибки. Повторённый много раз на многих примерах, этот шаг и есть всё обучение логистической регрессии.

Формула $dz = a - y$ выглядит как трюк — слишком короткая для того, что она делает. На самом деле это результат честного вывода по цепному правилу, и он показывает, почему кросс-энтропия так хорошо сочетается с сигмоидой. Полный вывод — в статье [«Вывод dL/dz»](/notes/derivation-dl-dz/).

Если можешь пересказать: прямой ход → $dz = a-y$ → $dw, db$ → обновление весов — это и есть один шаг обучения, — тема усвоена.
