Обратное распространение ошибки
Глава 7 оставила один вопрос открытым. Градиентному спуску нужен наклон потерь для каждого параметра ; его записывают : насколько меняются потери на маленький сдвиг именно этого параметра, пока все остальные стоят на месте (фигурная и означает «остальные не двигаем»). Измерять каждый наклон подталкиванием можно, но это не масштабируется: подвинуть один параметр, заново запустить модель, сравнить потери — и так для следующего. Миллиард параметров — миллиард прямых проходов на один шаг. Безнадёжно.
Обратное распространение ошибки (backpropagation) получает их все за один обратный проход, который стоит всего примерно вдвое больше одного прямого. Это не что иное, как цепное правило из математического анализа, применённое в удачном порядке.
Цепное правило на графе
Любое вычисление, включая целый трансформер, можно разбить на маленькие шаги: сложить, умножить, применить функцию. Нарисуйте каждый шаг узлом — получится вычислительный граф. У LLM входы слева — это токены и все до единого параметры, а единственный выход справа — функция потерь. Вот совсем маленький граф с четырьмя входами:
Промежуточные результаты получают имена: , потом , потом . Считайте , , , параметрами, а — потерями. (Настоящая перекрёстная энтропия никогда не бывает отрицательной, а здесь получится −8, но механика та же.) Пройдите рисунок по шагам: сначала прямой проход заполнит значения, начиная с , , , , потом обратный проход подпишет градиент под каждым узлом.
Четыре входа и три операции. Считайте a, b, c, f весами, а L — функцией потерь, которую мы хотим уменьшить.
Каждый узел знает только свою маленькую производную:
( — S-образная кривая, которая сжимает любое число в диапазон от −1 до 1.)
Цепное правило говорит: чтобы получить градиент входа, нужно перемножить эти локальные производные вдоль пути от выхода назад:
Читайте это как цепочку курсов обмена. Увеличим на 0,01 — тогда сдвинется в раз сильнее, на −0,03. передаёт этот сдвиг без изменений. умножает его на , и вырастает на +0,06. Курсы вдоль цепочки перемножаются: 6 единиц потерь на единицу . Это легко проверить напрямую: , на 0,06 выше, чем −8. Эта шестёрка — ровно тот наклон из главы 7: он положительный, значит, градиентный спуск уменьшит .
Обратное распространение идёт по графу от выхода назад и переиспользует каждое промежуточное произведение. Градиент, пришедший в , вычисляется один раз и потом достаётся и , и . Именно это переиспользование делает метод дешёвым. Если значение питает несколько последующих узлов, градиенты, возвращающиеся от каждого из них, складываются.
Один нейрон
Теперь граф — настоящий кусочек нейросети. Нейрон умножает вход на вес , прибавляет смещение (bias — второй параметр, просто сдвиг) и пропускает результат через tanh: , где . У этого нейрона одна задача: выдавать при входе . Его функция потерь — квадрат ошибки , более простой родственник перекрёстной энтропии для числового выхода: 0, когда ответ верен, и тем больше, чем сильнее промах.
Получается модель ровно с двумя параметрами, как ландшафт на рисунке 7.2. Кривая на рисунке — это срез такого ландшафта вдоль при неподвижном . Цепное правило проходит назад через три шага нейрона:
y = tanh(w·1,5 + b) = −0,905
L = (y − 0,5)² = 1,974
У трёх множителей ясный смысл:
- : насколько неверен выход и в какую сторону.
- : насколько нейрон чувствителен прямо сейчас (наклон tanh).
- : насколько этот вес на самом деле повлиял на результат. Вес, подключённый к нулевому входу, никакой вины не получает.
Средний множитель — это предупреждение. Глубокая сеть на обратном пути перемножает по такому множителю на каждый слой, и если многие из них малы, произведение стремится к нулю, а ранние слои перестают учиться. Остаточные связи трансформера дают градиенту путь в обход этих множителей.
Обучаем настоящую (крошечную) сеть
Соберите нейроны в слои, и те же правила применятся к каждому весу. Каждый шаг обучения — и у этой игрушки, и у LLM — состоит из одних и тех же четырёх ходов:
- Прямой проход: запустить модель на батче и запомнить все промежуточные значения.
- Потери: сравнить предсказания с правильными ответами и получить одно число.
- Обратный проход: пройти граф в обратную сторону и получить наклон каждого параметра.
- Обновление: сдвинуть каждый параметр на маленький шаг против его наклона, , как в главе 7.
Потом всё повторяется на следующем батче. У сети ниже два входа (координаты точки), два скрытых слоя (между входом и выходом) по 16 нейронов с tanh и один выход: вероятность того, что точка относится к классу акцентного цвета, а не янтарного. Она начинает со случайных весов. Нажмите «Обучить»: на каждом шаге сеть делает прямой проход по всем точкам, считает перекрёстную энтропию из главы 7, выполняет обратное распространение и подталкивает все 337 параметров.
Никто не говорил сети, как выглядит луна или спираль. Каждый её скрытый нейрон выучивает простую наклонную границу, а следующий слой собирает из них кривые. Трансформер делает то же самое с гораздо большим числом параметров, только выучивает признаки языка, а не признаки двумерной плоскости.
Что на самом деле делает PyTorch
Движок за рисунком 8.1 — это около сотни строк на TypeScript в духе micrograd Андрея Карпаты:
PyTorch (самая популярная библиотека для создания и обучения нейросетей), JAX и любой другой фреймворк глубокого обучения делают ровно это, с двумя отличиями, важными для скорости:
- Тензоры, а не числа. Каждый узел — целая матричная операция, так что одно «умножение» — это умножение матриц на миллионах чисел, выполняемое на GPU. Локальные правила становятся матричными: например, градиент по равен .
- Память под активации. Обратному проходу нужны значения прямого (заметьте, граф выше их сохранял). У большой модели эти сохранённые активации занимают больше памяти, чем сами веса, поэтому применяют приёмы вроде контрольных точек активаций (activation checkpointing), которые часть из них пересчитывают вместо хранения.
Когда вы пишете loss.backward() в PyTorch, он строит такой граф по мере выполнения вашего кода, а затем проходит его в обратном порядке, накапливая .grad для каждого параметра — точно как в пошаговом примере выше.
Итоги
- Обратное распространение вычисляет градиент функции потерь по каждому параметру за один обратный проход.
- Это цепное правило: перемножаем локальные производные вдоль путей от выхода и складываем там, где пути сходятся.
- Каждый шаг обучения — прямой проход, потери, обратный проход, обновление. Обратное распространение — это обратный проход, градиентный спуск — обновление.
- Одна и та же процедура обучает игрушечную сеть из 337 параметров и LLM на триллион параметров; меняется только размер тензоров.
Токены, векторы, внимание и обучение уже на месте. Следующая часть рассказывает, как обученной моделью пользуются, начиная с того, как она выбирает токен: сэмплирование.