🔴 Сложный ⏱️ 55 минут

Стохастический градиентный спуск

📋 Содержание урока

Стохастический градиентный спуск

Открой любой учебный ноутбук по обучению нейросети на PyTorch или TensorFlow, и почти наверняка увидишь одну из двух строчек: torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9) или torch.optim.Adam(model.parameters(), lr=0.001). За этими короткими вызовами стоит вся математика сегодняшнего урока — и это не случайное совпадение, а прямое следствие того, что именно эти методы оказались практическим стандартом обучения нейросетей, от простого многослойного перцептрона до многомиллиардных языковых моделей.

В прошлом уроке ты разобрался с обычным (пакетным, batch) градиентным спуском: на каждом шаге вычисляешь градиент функции потерь по абсолютно всем примерам обучающей выборки, затем делаешь один маленький шаг против этого градиента. Идея безупречна с точки зрения математики — градиент, посчитанный по всем данным, действительно указывает точное направление наискорейшего убывания усреднённой ошибки. Но у этой безупречности есть цена, и цена эта становится непереносимой ровно тогда, когда датасет перестаёт помещаться в оперативную память одной видеокарты. Современные датасеты для обучения нейросетей — это миллионы изображений, миллиарды токенов текста, петабайты видео. Пересчитывать градиент по всем этим данным перед каждым (!) шагом обновления весов означало бы: за то время, пока ты сделаешь один шаг классическим batch-градиентным спуском, стохастический метод успеет сделать тысячи шагов.

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

Сегодняшний план такой: сначала разберём, в чём именно состоит проблема полного batch-градиентного спуска и как рождается идея стохастической оценки градиента. Затем — mini-batch градиентный спуск как практический компромисс, которым реально пользуются на практике, и выбор размера батча как отдельный гиперпараметр со своими компромиссами. После этого — момент: накопление инерции движения, которое сглаживает шумные, дёргающиеся шаги SGD (ты уже видел этот механизм в университетском курсе как решение линейного дифференциального уравнения второго порядка — затухающего осциллятора). И в конце — краткое знакомство с адаптивными методами RMSProp и Adam, которые подстраивают скорость обучения индивидуально под каждый параметр модели, и разбор того, почему шум в оценке градиента иногда действительно помогает найти более качественное решение.

История

Формальные корни стохастической оптимизации уходят в 1951 год, когда американские статистики Герберт Роббинс и Саттон Монро опубликовали статью «A Stochastic Approximation Method» в журнале Annals of Mathematical Statistics. Задача, которую они решали, была далека от нейросетей — им нужно было найти корень неизвестной функции, зная только зашумлённые измерения её значений в разных точках, например, найти дозу препарата, дающую заданный биологический эффект, когда каждое измерение эффекта содержит случайную ошибку. Роббинс и Монро доказали удивительный факт: если делать шаги, пропорциональные зашумлённой оценке, но постепенно уменьшать размер шага по определённому правилу (сумма шагов расходится, а сумма квадратов шагов сходится), процесс всё равно гарантированно сойдётся к истинному корню, несмотря на то что каждый отдельный шаг сделан «в темноте», на основе неточной информации. Это и есть теоретический фундамент всего SGD: точность на каждом отдельном шаге не обязательна, если процесс правильно устроен в целом.

Стохастическую аппроксимацию градиентного спуска для обучения адаптивных систем предложили независимо чуть позже — Фрэнк Розенблатт в 1958 году применил похожую идею для обучения перцептрона, обновляя веса после каждого отдельного примера, а не после прогона по всей выборке. Но по-настоящему массовое применение стохастический градиентный спуск получил лишь спустя десятилетия, когда объёмы данных для обучения статистических моделей начали расти быстрее, чем объёмы доступной памяти. В 1990-х и 2000-х годах SGD стал стандартом для обучения линейных моделей на больших текстовых корпусах (например, для спам-фильтров и поисковых ранжирующих моделей), а окончательное признание пришло с революцией глубокого обучения начала 2010-х: обучить свёрточную сеть вроде AlexNet на миллионах изображений ImageNet, пересчитывая точный градиент по всей выборке на каждом шаге, было бы попросту невозможно ни по памяти, ни по времени.

Момент как техника ускорения численной оптимизации появился ещё раньше, в 1964 году, когда советский математик Борис Поляк предложил «метод тяжёлого шарика» — тот самый, что ты уже встречал в университетском курсе применительно к обыкновенным дифференциальным уравнениям. А адаптивные методы — AdaGrad (2011), RMSProp (неопубликованная, но широко известная идея Джеффри Хинтона из его курса на Coursera, 2012) и, наконец, Adam, предложенный Дидериком Кингмой и Джимми Ба в 2014 году — довели идею mini-batch SGD с моментом до состояния, в котором она используется практически без изменений на большинстве современных задач глубокого обучения по сей день. Статья про Adam стала одной из самых цитируемых работ во всём машинном обучении именно потому, что метод «просто работает» на огромном разнообразии архитектур и задач почти без ручной настройки.

Проблема полного batch-градиентного спуска и идея SGD

Интуиция: зачем платить за точность, которая тебе не нужна

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

Именно эта интуиция стоит за стохастическим градиентным спуском. Функция потерь на всём датасете — это, по сути, среднее значение ошибки по каждому отдельному примеру:

$$L(\theta)=\frac1N\sum_{i=1}^N \ell(\theta;x_i,y_i)$$

Точный градиент этой функции требует просуммировать градиенты по всем $N$ примерам:

$$\nabla L(\theta)=\frac1N\sum_{i=1}^N \nabla\ell(\theta;x_i,y_i)$$

Если $N$ равно миллиону или миллиарду, то один-единственный шаг обновления весов требует миллиона или миллиарда вычислений градиента по отдельным примерам, прежде чем сделать хотя бы один шаг. Идея SGD прямая: вместо усреднения по всем $N$ примерам, выбери один случайный пример $i$ (или маленькое случайное подмножество) и используй его градиент как несмещённую оценку истинного градиента.

Формула

Стохастический градиентный спуск. На каждой итерации $t$ случайно выбирается один пример $(x_i,y_i)$ из обучающей выборки, и обновление весов производится по формуле

$$\theta_{t+1}=\theta_t-\eta\,\nabla\ell(\theta_t;x_i,y_i)$$

где $\eta$ — скорость обучения (learning rate). Ключевое свойство: математическое ожидание такой стохастической оценки градиента по случайному выбору примера равно истинному градиенту по всей выборке:

$$\mathbb E_i\bigl[\nabla\ell(\theta;x_i,y_i)\bigr]=\nabla L(\theta)$$

Почему это свойство несмещённости так важно: оно означает, что, хотя каждый отдельный шаг SGD «целится» неточно (в случайном, но каждый раз немного отличающемся от истинного направлении), в среднем по множеству шагов направление движения совпадает с направлением настоящего градиента. Это ровно тот же принцип, который доказали Роббинс и Монро в 1951 году: отдельные шаги шумные, но процесс в целом устроен так, что шум не накапливается систематически, а гасится усреднением по множеству итераций.

Важная плата за экономию: на каждом отдельном шаге направление движения может значительно отличаться от истинного градиента по всей выборке — вплоть до противоположного знака у отдельных компонент. Траектория SGD на графике функции потерь выглядит не как плавная гладкая линия, спускающаяся к минимуму, а как «пьяная» ломаная, дёргающаяся из стороны в сторону, но в целом всё же смещающаяся в сторону минимума.

Разбор примеров

Пример 1 (простая линейная регрессия, полный batch против одного примера). Пусть модель — простая прямая $\hat y=wx$, обучающая выборка из трёх точек: $(1,2)$, $(2,3)$, $(3,7)$, функция потерь на одном примере — квадратичная ошибка $\ell=(wx-y)^2$, её градиент по $w$ равен $\nabla\ell=2x(wx-y)$. Пусть текущий вес $w=1$.

Точный градиент по всей выборке (batch): среднее по трём примерам.

  • Пример 1: $2\cdot1\cdot(1\cdot1-2)=2\cdot1\cdot(-1)=-2$
  • Пример 2: $2\cdot2\cdot(1\cdot2-3)=4\cdot(-1)=-4$
  • Пример 3: $2\cdot3\cdot(1\cdot3-7)=6\cdot(-4)=-24$

Среднее: $\nabla L(1)=\dfrac{-2-4-24}{3}=\dfrac{-30}{3}=-10$.

Теперь представим SGD: на этом шаге случайно выбран только пример 2. Стохастическая оценка градиента равна $-4$ — она заметно отличается от истинного значения $-10$ (и по величине, и качественно недооценивает направление движения). Но если посчитать среднее значение стохастической оценки по всем трём возможным вариантам случайного выбора: $\dfrac{-2-4-24}{3}=-10$ — оно в точности совпадает с истинным градиентом. Это и есть несмещённость на практике: конкретная оценка на одном шаге может сильно «промахнуться», но усреднённая по множеству случайных выборов оценка честная.

Пример 2 (сравнение числа вычислений на эпоху). Пусть датасет содержит $N=1\,000\,000$ примеров, а обучение проводится на $E=10$ эпохах (полных проходов по данным). При полном batch-градиентном спуске на каждую эпоху приходится один шаг обновления весов, но этот шаг требует вычислить градиент по всем миллиону примеров — итого $10\times1\,000\,000=10\,000\,000$ вычислений градиента на отдельных примерах, и всего $10$ обновлений весов за всё обучение.

При чистом SGD (по одному примеру за шаг) за одну эпоху делается $1\,000\,000$ обновлений весов, а за $10$ эпох — $10\,000\,000$ обновлений. Число вычислений градиента по отдельным примерам то же самое ($10\,000\,000$), но число обновлений весов различается в миллион раз: $10$ против $10\,000\,000$. Поскольку каждое обновление немного продвигает веса к минимуму, SGD за то же количество «просмотренных» примеров делает на порядки больше полезных шагов — и потому сходится к разумному решению значительно быстрее в реальном времени, даже несмотря на шумность каждого отдельного шага.

Пример 3 (когда несмещённость всё-таки не спасает — коррелированные примеры). Пусть датасет отсортирован по классам: сначала идут тысяча примеров класса «кошка», затем тысяча примеров класса «собака». Если выбирать примеры не случайно, а строго по порядку (без перемешивания), то на протяжении первой тысячи шагов SGD будет видеть только примеры класса «кошка» — оценка градиента окажется систематически смещена в сторону этого класса, несмотря на то, что формула несмещённости требует случайного, равновероятного выбора примера из всей выборки. Этот пример показывает, почему перемешивание (shuffling) данных перед каждой эпохой — не техническая деталь для галочки, а необходимое условие, без которого теоретическая гарантия несмещённости стохастической оценки градиента попросту не выполняется.

Почему это важно

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

Mini-batch градиентный спуск: практический компромисс

Интуиция: середина между крайностями

Чистый SGD (один пример за шаг) и полный batch-градиентный спуск (все примеры сразу) — это два противоположных полюса одного и того же спектра. У чистого SGD оценка градиента предельно шумная, но шаги предельно дешёвые; у полного batch оценка идеально точная, но шаги предельно дорогие. На практике почти никогда не используют ни один из этих крайних вариантов — вместо этого берут mini-batch: небольшое случайное подмножество примеров (типично от 32 до нескольких тысяч), по которому усредняется градиент перед каждым шагом обновления.

Представь фокус-группу для тестирования нового продукта. Опросить одного случайного человека — это дёшево, но крайне ненадёжно: мнение одного человека может быть нетипичным. Опросить весь город — надёжно, но безумно дорого и долго. Собрать фокус-группу из 50 человек — практичный компромисс: результат достаточно надёжен, чтобы принимать решения, а стоимость опроса остаётся разумной. Mini-batch градиентный спуск — это в точности такая фокус-группа, только для оценки направления градиента.

Формула

Mini-batch градиентный спуск. На каждой итерации случайным образом (без возвращения, обычно после перемешивания всей выборки) выбирается подмножество $B$ из $m$ примеров, и обновление весов производится по среднему градиенту на этом подмножестве:

$$\theta_{t+1}=\theta_t-\eta\cdot\frac1m\sum_{i\in B}\nabla\ell(\theta_t;x_i,y_i)$$

Дисперсия такой оценки градиента обратно пропорциональна размеру батча $m$:

$$\mathrm{Var}\bigl[\text{оценка градиента}\bigr]\propto\frac{\sigma^2}{m}$$

где $\sigma^2$ — дисперсия градиента на одном отдельном примере.

Формула дисперсии — прямое следствие классической статистики: усреднение $m$ независимых случайных величин уменьшает дисперсию среднего в $m$ раз по сравнению с дисперсией одной величины (при условии, что примеры выбраны независимо и равновероятно). Именно поэтому увеличение batch size снижает шум оценки градиента — но снижение это происходит с убывающей отдачей: чтобы уменьшить стандартное отклонение шума вдвое, нужно увеличить размер батча не в два, а в четыре раза, поскольку стандартное отклонение пропорционально $1/\sqrt m$, а не $1/m$.

Разбор примеров

Пример 1 (числовая трассировка на маленьком датасете). Датасет из шести точек для той же модели $\hat y=wx$: $(1,2)$, $(2,3)$, $(3,7)$, $(4,8)$, $(5,11)$, $(6,12)$. Текущий вес $w=2$. Разобьём датасет на два mini-batch по три примера: $B_1=\{(1,2),(2,3),(3,7)\}$, $B_2=\{(4,8),(5,11),(6,12)\}$.

Градиенты для $B_1$ (используя $\nabla\ell=2x(wx-y)$ при $w=2$):

  • $(1,2)$: $2\cdot1\cdot(2\cdot1-2)=2\cdot1\cdot0=0$
  • $(2,3)$: $2\cdot2\cdot(2\cdot2-3)=4\cdot1=4$
  • $(3,7)$: $2\cdot3\cdot(2\cdot3-7)=6\cdot(-1)=-6$

Средний градиент по $B_1$: $\dfrac{0+4-6}{3}=\dfrac{-2}{3}\approx-0{,}67$.

Градиенты для $B_2$:

  • $(4,8)$: $2\cdot4\cdot(2\cdot4-8)=8\cdot0=0$
  • $(5,11)$: $2\cdot5\cdot(2\cdot5-11)=10\cdot(-1)=-10$
  • $(6,12)$: $2\cdot6\cdot(2\cdot6-12)=12\cdot0=0$

Средний градиент по $B_2$: $\dfrac{0-10+0}{3}=\dfrac{-10}{3}\approx-3{,}33$.

Истинный градиент по всей выборке из шести примеров — среднее всех шести значений: $\dfrac{0+4-6+0-10+0}{6}=\dfrac{-12}{6}=-2$. Видно, что ни $B_1$ ($-0{,}67$), ни $B_2$ ($-3{,}33$) по отдельности не совпадают с истинным градиентом $-2$, но их среднее $\dfrac{-0{,}67-3{,}33}{2}=-2$ в точности совпадает — ровно то же свойство несмещённости, только теперь применённое не к отдельным примерам, а к mini-batch целиком.

Пример 2 (как размер батча влияет на разброс оценки). Пусть на некотором шаге обучения истинный градиент функции потерь по параметру равен $\nabla L=10$, а дисперсия градиента на одном отдельном примере $\sigma^2=64$ (то есть стандартное отклонение шума одного примера — $8$). Тогда стандартное отклонение шума оценки градиента для батча размера $m$ вычисляется как $\sigma/\sqrt m$.

  • При $m=1$: стандартное отклонение $8/\sqrt1=8$ — оценка градиента может колебаться в диапазоне примерно от $2$ до $18$, то есть относительная погрешность огромна.
  • При $m=16$: стандартное отклонение $8/\sqrt{16}=8/4=2$ — диапазон разумных значений сужается до примерно $8$–$12$.
  • При $m=64$: стандартное отклонение $8/\sqrt{64}=8/8=1$ — диапазон сужается до примерно $9$–$11$.
  • При $m=256$: стандартное отклонение $8/\sqrt{256}=8/16=0{,}5$ — диапазон сужается до примерно $9{,}5$–$10{,}5$.

Обрати внимание на темп улучшения: увеличение batch size в $4$ раза (с $16$ до $64$) уменьшает шум только в $2$ раза, а не в $4$. Это прямое следствие корня в формуле — именно поэтому на практике очень большие батчи дают всё меньшую и меньшую отдачу за каждый дополнительный пример, при том что вычислительная стоимость шага растёт линейно с размером батча.

Пример 3 (память и вычисления: почему нельзя просто взять batch побольше). Пусть одна картинка занимает в памяти видеокарты $10$ МБ вместе со всеми промежуточными активациями, необходимыми для обратного распространения ошибки. При batch size $32$ требуется примерно $32\times10=320$ МБ памяти только на хранение активаций для этого шага (не считая веса модели и оптимизатора). Если увеличить batch size до $512$ (в $16$ раз), потребление памяти вырастет примерно до $512\times10=5120$ МБ, то есть более $5$ ГБ — и легко может не поместиться на одной видеокарте, даже если сама модель компактна. При этом, как показал предыдущий пример, увеличение batch size в $16$ раз снижает шум оценки градиента лишь в $\sqrt{16}=4$ раза — то есть плата (память) растёт быстрее, чем выгода (снижение шума).

Почему это важно

Mini-batch — это не произвольный «средний вариант для перестраховки», а математически обоснованный оптимум с учётом реальных вычислительных ограничений: GPU эффективнее всего работают с параллельными матричными вычислениями по батчу примеров сразу (а не по одному примеру за раз, что плохо использует параллелизм железа, и не по всему датасету сразу, что не помещается в память), а корневая зависимость дисперсии оценки от размера батча означает, что после определённого размера дальнейшее увеличение батча приносит всё меньше пользы за единицу дополнительной памяти и времени. Понимание этого компромисса — прямая практическая основа того, почему стандартные batch size в реальных задачах глубокого обучения почти всегда лежат в диапазоне от $32$ до нескольких тысяч, а не в тысячи раз больше или меньше.

Размер mini-batch как гиперпараметр

Интуиция: скорость, память и шум тянут в разные стороны

Размер mini-batch — это не деталь реализации, а полноценный гиперпараметр, который нужно осознанно подбирать, потому что он одновременно влияет на три разные вещи: сколько шумно направление отдельного шага, сколько памяти требует один шаг, и сколько шагов в секунду можно сделать. Маленький batch size даёт зашумлённые, но частые и дешёвые шаги; большой batch size даёт точные, но редкие и дорогие шаги. Ни один из полюсов не является универсально «правильным» — оптимальный выбор зависит от конкретной архитектуры модели, объёма доступной видеопамяти и характера самой задачи.

Формула (эмпирическое правило масштабирования learning rate)

Линейное масштабирование скорости обучения при изменении batch size. Если batch size увеличивается в $k$ раз (например, за счёт использования нескольких видеокарт параллельно), эмпирическое правило (не строгая теорема, но широко подтверждённый практикой ориентир) рекомендует пропорционально увеличить скорость обучения:

$$\eta_{\text{новое}}=k\cdot\eta_{\text{старое}}$$

Логика: усреднение по $k$ раз большему батчу снижает шум (и, соответственно, эффективный «случайный разброс» направления шага) в $\sqrt k$ раз, что позволяет позволить себе более крупный шаг без риска разболтать обучение — а сам шаг делается в $k$ раз реже за то же число просмотренных примеров, что тоже подталкивает компенсировать это большим $\eta$.

Разбор примеров

Пример 1 (маленький batch size на скромном железе). Обучение модели классификации текста на ноутбуке с $4$ ГБ видеопамяти. Одна текстовая последовательность с учётом всех промежуточных активаций занимает около $50$ МБ. Максимально допустимый batch size по памяти: $4000/50=80$ примеров, но с запасом на веса модели и оптимизатор разумно взять $m=16$ или $m=32$. При таком маленьком батче шаги дешёвые и частые, но заметно шумные — типичное решение на практике: снизить скорость обучения по сравнению с большими батчами и, возможно, добавить момент (о котором пойдёт речь дальше), чтобы сгладить эту шумность.

Пример 2 (большой batch size на кластере). Обучение крупной модели компьютерного зрения на восьми видеокартах с общим объёмом видеопамяти $8\times40=320$ ГБ. Здесь можно позволить batch size $m=1024$ или даже больше, распределив его по видеокартам (каждая карта обрабатывает часть батча, а градиенты усредняются между картами). Если базовая скорость обучения для batch size $128$ была подобрана как $\eta=0{,}01$, то при переходе к batch size $1024$ (увеличение в $1024/128=8$ раз) по правилу линейного масштабирования новая скорость обучения составит $\eta_{\text{новое}}=8\times0{,}01=0{,}08$.

Пример 3 (слишком большой batch size — потеря обобщающей способности). Экспериментально многократно подтверждено (начиная с влиятельной работы Кескара и соавторов 2016 года «On Large-Batch Training for Deep Learning»), что чрезмерно большие батчи (скажем, вся видеопамять кластера отдана под один гигантский batch size в десятки тысяч примеров) часто приводят модель к «острым» (sharp) минимумам функции потерь — таким, где небольшое отклонение параметров резко увеличивает ошибку. Такие минимумы обычно хуже обобщаются на новые данные, чем «плоские» (flat) минимумы, к которым чаще приводит умеренный шум небольших батчей. Другими словами: слишком большой batch size, устраняя почти весь полезный шум SGD, может незаметно ухудшить итоговое качество модели на тестовых данных — даже при том же самом числе эпох обучения.

Почему это важно

Выбор batch size — одна из первых настроек, с которой сталкивается любой практик глубокого обучения, и неверный выбор (например, слепое копирование batch size из чужого примера кода без учёта своего железа и задачи) может стоить и времени обучения, и итогового качества модели. Понимание того, что batch size одновременно управляет скоростью, памятью и шумом — причём эти три эффекта тянут в разные стороны, — превращает подбор этого гиперпараметра из слепого перебора значений $16$, $32$, $64$, $128$ в осознанное инженерное решение с ясным пониманием, чем ты жертвуешь и что получаешь взамен.

Момент: накопление инерции движения

Интуиция: шарик с массой вместо капли без инерции

Обычный SGD (даже с mini-batch) обновляет веса, глядя исключительно на текущий шумный градиент — как капля воды, которая мгновенно и полностью меняет направление при малейшем изменении наклона поверхности. Из-за шума mini-batch эта капля дёргается из стороны в сторону, особенно в «оврагах» функции потерь — узких вытянутых впадинах, где крутизна в одном направлении намного больше, чем в другом (такая форма чрезвычайно типична для функций потерь реальных нейросетей). В таком овраге шаги SGD мечутся от одной стенки к другой, вместо того чтобы плавно скользить вдоль дна оврага к минимуму.

Момент решает эту проблему, добавляя инерцию: вместо того чтобы мгновенно следовать за текущим шумным градиентом, обновление весов накапливает «скорость» — своего рода скользящее среднее прошлых градиентов, которое постепенно подстраивается под изменения направления, но не реагирует резко на единичный шумный всплеск. Это ровно та самая идея, с которой ты уже встречался в университетском курсе применительно к затухающему гармоническому осциллятору: момент в непрерывном времени описывается линейным дифференциальным уравнением второго порядка $\mu\ddot w+\gamma\dot w+\nabla L(w)=0$, и то, будет ли обучение плавно сходиться или колебаться вокруг минимума, определяется тем же самым дискриминантом характеристического уравнения, что и для пружинного маятника с трением.

Формула

Градиентный спуск с моментом. Вводится вспомогательная переменная «скорость» $v$ (изначально $v_0=0$), и обновление происходит в два шага:

$$v_{t+1}=\beta v_t+(1-\beta)\,\nabla\ell(\theta_t)$$

$$\theta_{t+1}=\theta_t-\eta\,v_{t+1}$$

где $\beta\in[0,1)$ — коэффициент момента (типичные значения $0{,}9$ или $0{,}99$). При $\beta=0$ формула в точности сводится к обычному SGD без момента; при $\beta$, близком к единице, скорость $v$ «помнит» очень долгую историю прошлых градиентов и слабо реагирует на отдельный шумный шаг.

Раскрыв рекурсию, легко увидеть, что $v_t$ — это экспоненциально взвешенное скользящее среднее прошлых градиентов, где более свежие градиенты имеют вес $(1-\beta)$, градиент на шаг раньше — вес $(1-\beta)\beta$, ещё на шаг раньше — вес $(1-\beta)\beta^2$, и так далее. Поскольку $\beta<1$, вклад далёких по времени градиентов экспоненциально затухает, но никогда не обнуляется полностью — именно это и создаёт эффект «инерции», сглаживающей шумные скачки, но не игнорирующей смену тренда навсегда.

Разбор примеров

Пример 1 (полная трассировка накопления скорости на пяти шагах). Пусть коэффициент момента $\beta=0{,}9$, скорость обучения $\eta=0{,}1$, начальный вес $\theta_0=0$, а последовательность шумных градиентов mini-batch на пяти шагах составляет (специально с чередующимся знаком, чтобы показать сглаживание): $g_1=4$, $g_2=-2$, $g_3=5$, $g_4=-1$, $g_5=3$.

Шаг 1: $v_1=0{,}9\cdot0+0{,}1\cdot4=0{,}4$. Обновление: $\theta_1=0-0{,}1\cdot0{,}4=-0{,}04$.

Шаг 2: $v_2=0{,}9\cdot0{,}4+0{,}1\cdot(-2)=0{,}36-0{,}2=0{,}16$. Обновление: $\theta_2=-0{,}04-0{,}1\cdot0{,}16=-0{,}056$.

Шаг 3: $v_3=0{,}9\cdot0{,}16+0{,}1\cdot5=0{,}144+0{,}5=0{,}644$. Обновление: $\theta_3=-0{,}056-0{,}1\cdot0{,}644=-0{,}1204$.

Шаг 4: $v_4=0{,}9\cdot0{,}644+0{,}1\cdot(-1)=0{,}5796-0{,}1=0{,}4796$. Обновление: $\theta_4=-0{,}1204-0{,}1\cdot0{,}4796=-0{,}16836$.

Шаг 5: $v_5=0{,}9\cdot0{,}4796+0{,}1\cdot3=0{,}43164+0{,}3=0{,}73164$. Обновление: $\theta_5=-0{,}16836-0{,}1\cdot0{,}73164=-0{,}241524$.

Обрати внимание: несмотря на то, что градиент $g_2=-2$ был отрицательным (что при обычном SGD без момента развернуло бы шаг обновления в противоположную сторону), скорость $v_2=0{,}16$ осталась положительной — момент от предыдущего шага «перетянул» знак, не дав траектории резко развернуться из-за единичного шумного значения. Это и есть сглаживающий эффект инерции в действии.

Пример 2 (момент помогает пройти узкий овраг). Пусть функция потерь имеет форму вытянутого оврага: по одному направлению (назовём его $x$) кривизна маленькая, а по другому ($y$) — очень большая. При обычном SGD без момента шаги по $y$ будут большими и знакопеременными (перелёт через дно оврага туда-сюда), а шаги по $x$ — маленькими и однонаправленными. Допустим, градиенты по $y$ на пяти последовательных шагах равны $6,-6,6,-6,6$ (классические колебания поперёк оврага), а градиенты по $x$ равны $1,1,1,1,1$ (стабильное движение вдоль дна оврага). При $\beta=0{,}9$ скорость по $y$ на каждом шаге частично гасит предыдущее значение, не давая накопиться большой амплитуде колебаний (аналогично примеру 1 выше, знакопеременные слагаемые взаимно уменьшают итоговую сумму), тогда как скорость по $x$, где все градиенты одного знака, стабильно нарастает от шага к шагу — $v_1^{(x)}=0{,}1\cdot1=0{,}1$, $v_2^{(x)}=0{,}9\cdot0{,}1+0{,}1\cdot1=0{,}19$, $v_3^{(x)}=0{,}9\cdot0{,}19+0{,}1=0{,}271$ — то есть эффективная скорость движения вдоль дна оврага растёт, а поперёк оврага — гасится. Именно это и делает момент таким полезным для функций потерь с сильно вытянутой формой, которая типична для реальных нейросетей.

Пример 3 (связь с дифференциальным уравнением: критическое демпфирование против колебаний). Как ты уже разбирал в уроке про линейные дифференциальные уравнения, непрерывная версия момента вблизи квадратичного минимума с кривизной $k$ описывается уравнением $\mu\ddot x+\gamma\dot x+kx=0$, где дискриминант характеристического уравнения $D=\gamma^2-4\mu k$ определяет режим. Пусть эффективная «масса» (связанная с коэффициентом момента) $\mu=1$, кривизна потерь $k=4$. Если эффективное трение (связанное с $1-\beta$ и скоростью обучения) $\gamma=2$, дискриминант $D=4-16=-12<0$ — недодемпфирование, веса будут колебаться вокруг минимума с затухающей амплитудой, прежде чем успокоятся. Если же подобрать $\gamma=4$ (критическое демпфирование при $\gamma^2=4\mu k=16$, то есть $\gamma=4$), веса подойдут к минимуму максимально быстро без единого колебания. На практике это означает: слишком большой коэффициент момента $\beta$ (например, $\beta=0{,}999$ вместо стандартных $0{,}9$) может «раскачать» обучение точно так же, как чрезмерная масса раскачивает физический маятник с недостаточным трением — и именно поэтому $\beta=0{,}9$ выбран как разумный практический дефолт для большинства задач, а не $\beta$, близкое к единице.

Почему это важно

Момент — это не косметическое улучшение, а практически обязательный компонент почти любого современного оптимизатора: он сглаживает шумность mini-batch SGD, ускоряет движение вдоль стабильных направлений (дно оврага) и одновременно гасит колебания в направлениях с высокой кривизной. Тот факт, что эта техника напрямую соответствует физике затухающего осциллятора — точно такой же математике, которая описывает пружинный маятник или разрядку электрического контура, — не просто красивая аналогия: она даёт готовый, проверенный веками инженерный язык для понимания того, почему обучение иногда «раскачивается» и как именно нужно скорректировать гиперпараметры, чтобы это исправить.

Адаптивные методы: RMSProp и Adam

Интуиция: у каждого параметра своя подходящая скорость обучения

До сих пор скорость обучения $\eta$ была одним общим числом для всех параметров модели сразу. Но у разных параметров градиенты могут сильно отличаться по масштабу: у одних весов градиент почти всегда маленький и стабильный, у других — большой и резко меняющийся. Единая скорость обучения для всех — это как выдать одинаковый размер шага и марафонцу, и человеку, который только учится ходить: для одного шаг окажется слишком робким, для другого — слишком рискованным.

Идея адаптивных методов в том, чтобы у каждого параметра была своя, индивидуально подстраиваемая эффективная скорость обучения, зависящая от истории его собственных градиентов. RMSProp (предложенный Джеффри Хинтоном в 2012 году) делит скорость обучения каждого параметра на скользящее среднеквадратичное значение его недавних градиентов — параметры с исторически большими градиентами получают меньший эффективный шаг, а параметры со стабильно маленькими градиентами получают шаг побольше. Adam (Kingma & Ba, 2014) объединяет эту идею с моментом: он одновременно накапливает и «направление» движения (момент, как в предыдущем разделе), и индивидуальный «масштаб» шага для каждого параметра (как в RMSProp).

Формула

Adam (сжатое описание). Вводятся два скользящих среднего: momentum-подобная оценка первого момента градиента $m_t$ и оценка второго момента (среднего квадрата) $v_t$:

$$m_t=\beta_1 m_{t-1}+(1-\beta_1)\,g_t,\qquad v_t=\beta_2 v_{t-1}+(1-\beta_2)\,g_t^2$$

После коррекции смещения на первых шагах (bias correction) обновление параметра происходит по формуле

$$\theta_{t+1}=\theta_t-\eta\cdot\frac{\hat m_t}{\sqrt{\hat v_t}+\varepsilon}$$

где типичные значения гиперпараметров $\beta_1=0{,}9$, $\beta_2=0{,}999$, $\varepsilon\approx10^{-8}$ (маленькая константа для избежания деления на ноль).

Углублённый разбор Adam, RMSProp и вывода bias correction — тема отдельного, более позднего урока курса; здесь важно зафиксировать саму идею: деление шага на $\sqrt{\hat v_t}$ автоматически уменьшает эффективный шаг для параметров с исторически большими градиентами и увеличивает его для параметров с исторически маленькими градиентами, избавляя от необходимости вручную подбирать разную скорость обучения для каждого веса модели.

Разбор примеров

Пример 1 (интуитивная иллюстрация масштабирования шага RMSProp, упрощённо). Пусть у параметра A недавние градиенты были: $8,-9,10,-8$ (среднеквадратичное значение примерно $\sqrt{(64+81+100+64)/4}=\sqrt{77{,}25}\approx8{,}79$), а у параметра B недавние градиенты были: $0{,}5,-0{,}4,0{,}6,-0{,}3$ (среднеквадратичное значение примерно $\sqrt{(0{,}25+0{,}16+0{,}36+0{,}09)/4}=\sqrt{0{,}215}\approx0{,}46$). При единой скорости обучения $\eta=0{,}1$ шаг без адаптации для A составил бы (например, если бы текущий градиент A был $8$) $0{,}1\times8=0{,}8$ — потенциально огромный скачок. С адаптацией по RMSProp эффективный шаг делится примерно на $8{,}79$, давая $0{,}1\times8/8{,}79\approx0{,}091$ — куда более сдержанное обновление. Для параметра B, наоборот, шаг без адаптации при градиенте $0{,}5$ составил бы всего $0{,}1\times0{,}5=0{,}05$, а с адаптацией — примерно $0{,}1\times0{,}5/0{,}46\approx0{,}109$, то есть даже немного увеличивается. Итог: параметр с исторически «буйными» градиентами получает более осторожный шаг, а параметр со стабильно маленькими градиентами — более смелый.

Пример 2 (почему Adam не требует ручной настройки скорости обучения под каждый слой). В глубоких сетях градиенты для весов первых слоёв (близких к входу) и последних слоёв (близких к выходу) часто отличаются на порядки из-за эффекта затухающего или взрывающегося градиента при обратном распространении ошибки. Если бы использовался обычный SGD с одной общей скоростью обучения, пришлось бы вручную подбирать разные $\eta$ для разных частей сети (что на практике почти никто не делает вручную). Поскольку Adam делит шаг каждого параметра на его собственную адаптивную оценку масштаба $\sqrt{\hat v_t}$, единая базовая скорость обучения $\eta$ (например, стандартное значение $0{,}001$) автоматически даёт разумные по масштабу эффективные шаги и для первых, и для последних слоёв сети — одна из главных причин, почему Adam так широко используется как «дефолтный» оптимизатор без долгой ручной настройки.

Пример 3 (компромисс Adam: быстрая сходимость против обобщающей способности). На практике многократно наблюдается (и это активно исследуется в академической литературе), что Adam обычно сходится к низкому значению функции потерь на обучающей выборке заметно быстрее, чем SGD с моментом, но иногда даёт чуть худшее качество на тестовых данных по сравнению с тщательно настроенным SGD с моментом, особенно для некоторых задач компьютерного зрения. Это одна из причин, почему выбор оптимизатора остаётся эмпирическим инженерным решением, а не универсальным правилом «всегда бери Adam»: для быстрого старта и большинства задач (особенно в обработке естественного языка) Adam — отличный дефолт, но для финальной, тщательно настроенной модели иногда стоит попробовать и SGD с моментом.

Почему это важно

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

Почему шум SGD иногда помогает

Интуиция: шум как случайный «толчок», выбивающий из ловушек

Может показаться, что шум оценки градиента — это исключительно недостаток, который приходится терпеть ради скорости. Но у него есть и содержательная польза: реальные функции потерь глубоких нейросетей не выпуклые, они полны седловых точек (где градиент равен нулю, но точка не является ни минимумом, ни максимумом — вдоль одних направлений поверхность идёт вверх, вдоль других вниз) и неглубоких локальных минимумов. Точный градиентный спуск, попав в седловую точку или мелкую впадину, движется крайне медленно (градиент там близок к нулю почти во всех направлениях), а иногда и вовсе застревает.

Шум SGD добавляет к движению своего рода случайный «дребезг», который с определённой вероятностью толкает траекторию в сторону от плоского участка достаточно сильно, чтобы она снова попала в область с содержательным градиентом и продолжила спуск. Представь шарик, который закатился в мелкую ямку на склоне холма: без вибрации он там и останется, а лёгкая тряска всей поверхности (аналог шума SGD) с большой вероятностью вытолкнет его дальше вниз по склону, к более глубокой впадине.

Формула (эвристическое объяснение через масштаб шума)

Шум SGD как эффективная температура. Дисперсия шума одного шага SGD с mini-batch размера $m$ и скоростью обучения $\eta$ примерно пропорциональна

$$\text{«эффективная температура»}\propto\frac{\eta\cdot\sigma^2}{m}$$

где $\sigma^2$ — дисперсия градиента на одном примере. Чем выше эта эффективная «температура», тем сильнее случайные блуждания траектории вокруг детерминированного направления градиента, и тем больше шансов «выбить» траекторию из мелкой ловушки (седловой точки, острого локального минимума) — ценой, разумеется, менее точного следования точному направлению спуска на каждом отдельном шаге.

Эта аналогия с физической температурой не случайна: она напрямую перекликается с методом имитации отжига (simulated annealing) в оптимизации, где случайный тепловой шум специально добавляется в процесс поиска именно для того, чтобы избежать застревания в плохих локальных решениях, а затем постепенно уменьшается («отжигается») по мере приближения к финальному решению.

Разбор примеров

Пример 1 (застревание в седловой точке при нулевом шуме). Рассмотрим упрощённую функцию потерь $L(x,y)=x^2-y^2$ вблизи начала координат — классическая седловая точка: вдоль $x$ функция растёт (значит, минимум по $x$), а вдоль $y$ убывает (значит, вдоль $y$ это максимум, а не минимум). Градиент в самой точке $(0,0)$ равен $(0,0)$ — точный градиентный спуск, стартовавший ровно в этой точке, вообще не сдвинется с места, сколько бы шагов ни делал, потому что $\nabla L(0,0)=(0,0)$ буквально не даёт никакого сигнала о направлении движения.

Пример 2 (шум SGD выбивает траекторию из седловой точки). В той же ситуации представим, что вместо точного нулевого градиента SGD на каждом шаге добавляет к движению случайный шум с небольшой амплитудой (из-за оценки градиента по mini-batch, где отдельные примеры дают немного разные направления даже в теоретической седловой точке общей функции потерь). Пусть, например, шум сдвигает точку на первом шаге в положение $(0{,}01,-0{,}01)$ — крошечное, но ненулевое отклонение от седловой точки. В этой новой точке градиент уже не нулевой: $\nabla L(0{,}01,-0{,}01)=(2\cdot0{,}01,-2\cdot(-0{,}01))=(0{,}02,0{,}02)$ — обновление весов начинает двигать точку по $x$ в сторону уменьшения (к нулю, к минимуму) и по $y$ в сторону, где функция дальше убывает (то есть прочь от седловой точки, в область более низкой функции потерь). За несколько таких шагов, усиленных экспоненциальным нарастанием отклонения вдоль неустойчивого направления седловой точки, траектория полностью выходит из окрестности седла — то, что было бы невозможно при абсолютно точном (нулевом) градиенте в самой седловой точке.

Пример 3 (шум помогает найти более плоский минимум — связь с обобщающей способностью). Возвращаясь к обсуждению больших и маленьких батчей: умеренный шум небольших mini-batch не только помогает выбраться из седловых точек, но и статистически чаще приводит оптимизацию к «плоским» минимумам функции потерь — таким, где небольшое отклонение параметров почти не меняет значение функции. Интуитивно: острый, узкий минимум легко «выбить» шумным шагом наружу (шарик выскакивает из узкой ямки при лёгкой тряске), а широкий плоский минимум устойчив к такому шуму (шарик остаётся в широкой чаше даже при тряске) — поэтому оптимизация с достаточным уровнем шума статистически «отфильтровывает» узкие минимумы и чаще останавливается именно в широких. А широкие минимумы, как показывают многочисленные эмпирические исследования, в среднем лучше обобщаются на новые, не встречавшиеся в обучении данные — прямое практическое следствие того факта, что шум SGD не просто «мешает», а выполняет полезную регуляризирующую роль.

Почему это важно

Понимание того, что шум SGD не только терпимый побочный эффект экономии вычислений, но и полезный механизм, объясняет несколько важных практических наблюдений: почему очень большие батчи (с их подавленным шумом) иногда дают худшее качество на тестовых данных при том же числе эпох, почему полностью убирать шум (переходя к полному batch-градиентному спуску) в задачах глубокого обучения почти никогда не является хорошей идеей даже при наличии достаточной вычислительной мощности, и почему многие практики намеренно используют относительно небольшие батчи не только из-за ограничений памяти, но и как форму неявной регуляризации.

Практика: 30 заданий

Базовые задания (1–10)

Задание 1: Датасет содержит $N=500\,000$ примеров. Сколько вычислений градиента по отдельным примерам потребуется для одного шага полного batch-градиентного спуска?


Задание 2: Что означает утверждение «стохастическая оценка градиента несмещённая»? Сформулируй одним предложением, используя понятие математического ожидания.


Задание 3: Модель $\hat y=wx$, текущий вес $w=1$, пример $(x,y)=(2,5)$. Функция потерь на примере $\ell=(wx-y)^2$, градиент $\nabla\ell=2x(wx-y)$. Найти стохастическую оценку градиента по этому единственному примеру.


Задание 4: Дисперсия градиента на одном примере $\sigma^2=100$. Чему равно стандартное отклонение шума оценки градиента для mini-batch размера $m=25$?


Задание 5: Во сколько раз нужно увеличить размер mini-batch, чтобы уменьшить стандартное отклонение шума оценки градиента ровно в $3$ раза?


Задание 6: При $\beta=0$ в формуле градиентного спуска с моментом $v_{t+1}=\beta v_t+(1-\beta)\nabla\ell(\theta_t)$, во что превращается алгоритм?


Задание 7: Коэффициент момента $\beta=0{,}8$, скорость обучения $\eta=0{,}1$, начальная скорость $v_0=0$. Первый градиент $g_1=5$. Найти $v_1$ и обновление $\theta_1$, если $\theta_0=0$.


Задание 8: Объясни своими словами, почему полный batch-градиентный спуск невозможно применить напрямую к обучению языковой модели на миллиардах токенов текста.


Задание 9: Верно ли утверждение: «увеличение mini-batch size всегда линейно уменьшает шум оценки градиента»? Обоснуй.


Задание 10: Почему перемешивание (shuffling) датасета перед каждой эпохой важно для корректной работы SGD?


Средние задания (11–20)

Задание 11: Модель $\hat y=wx$, $w=2$, три примера mini-batch: $(1,3)$, $(2,3)$, $(3,10)$. Градиент на примере $\nabla\ell=2x(wx-y)$. Найти средний градиент по этому mini-batch.


Задание 12: Видеокарта имеет $6$ ГБ свободной видеопамяти. Одна картинка с активациями занимает $30$ МБ. Найти максимально допустимый по памяти batch size (без учёта памяти на веса и оптимизатор).


Задание 13: Базовая скорость обучения $\eta=0{,}02$ подобрана для batch size $64$. По правилу линейного масштабирования найти новую скорость обучения при переходе к batch size $512$.


Задание 14: Коэффициент момента $\beta=0{,}9$, $\eta=0{,}1$, $v_0=0$, $\theta_0=0$. Градиенты на трёх шагах: $g_1=2$, $g_2=2$, $g_3=2$ (все одинаковые). Найти $v_3$ и объяснить, к чему стремится $v_t$ при неограниченном повторении такого постоянного градиента.


Задание 15: Датасет отсортирован так, что первая половина — примеры с меткой $0$, вторая половина — с меткой $1$. Объясни, что произойдёт с оценкой градиента SGD, если обучение идёт без перемешивания, строго по порядку примеров.


Задание 16: Стандартное отклонение шума градиента для батча $m=10$ равно $4$. Найти стандартное отклонение шума для батча $m=90$ (при той же дисперсии одного примера).


Задание 17: Функция потерь $L(x,y)=x^2-y^2$ имеет седловую точку в $(0,0)$. Найти градиент $\nabla L$ в этой точке и объяснить, почему точный (не шумный) градиентный спуск, стартовавший ровно в $(0,0)$, не сдвинется с места.


Задание 18: Кривизна потерь вблизи минимума $k=9$, эффективная «масса» момента $\mu=1$. Найти значение «трения» $\gamma$, дающее критическое демпфирование.


Задание 19: Параметр A имеет среднеквадратичное значение недавних градиентов $\approx12$, параметр B — $\approx1{,}2$. При единой базовой скорости обучения $\eta=0{,}05$ и текущих градиентах $g_A=12$, $g_B=1{,}2$, найти эффективные шаги RMSProp-подобной адаптации (шаг $\approx\eta\cdot g/\text{среднеквадратичное значение}$) для обоих параметров.


Задание 20: Объясни, почему batch size, равный размеру всего датасета ($m=N$), превращает mini-batch градиентный спуск обратно в полный batch-градиентный спуск.


Продвинутые задания (21–30)

Задание 21: Датасет из шести точек для модели $\hat y=wx$: $(1,1)$, $(2,5)$, $(3,4)$, $(4,9)$, $(5,8)$, $(6,13)$. Текущий вес $w=1{,}5$. Разбей на два mini-batch по три примера ($B_1$ — первые три, $B_2$ — последние три), найди средний градиент каждого батча (используя $\nabla\ell=2x(wx-y)$) и проверь, что среднее двух батчей совпадает с истинным градиентом по всей выборке.


Задание 22: Коэффициент момента $\beta=0{,}9$, $\eta=0{,}05$, $v_0=0$, $\theta_0=0$. Последовательность градиентов: $g_1=-6$, $g_2=8$, $g_3=-5$, $g_4=7$ (сильно колеблющиеся знаки). Найти $v_1,\dots,v_4$ и $\theta_4$.


Задание 23: Датасет содержит $N=2\,000\,000$ примеров, обучение идёт $E=5$ эпох с batch size $m=200$. Найти общее число шагов обновления весов за всё обучение и число обновлений на одну эпоху.


Задание 24: Видеопамять $16$ ГБ. Одна текстовая последовательность с активациями занимает $80$ МБ, но на веса модели и состояние оптимизатора Adam (который хранит два дополнительных скользящих среднего на параметр) уходит фиксированно $6$ ГБ. Найти максимально допустимый batch size для оставшейся памяти.


Задание 25: Эффективная «масса» момента $\mu=2$, кривизна потерь $k=8$, «трение» $\gamma=3$. Определить режим (передемпфирование, критическое демпфирование или недодемпфирование), посчитав дискриминант $D=\gamma^2-4\mu k$.


Задание 26: Сравни число полезных обновлений весов при одинаковом числе просмотренных примеров ($10\,000\,000$) для трёх режимов: полный batch (весь датасет $N=1\,000\,000$ за один шаг), mini-batch с $m=100$, и чистый SGD с $m=1$. Сколько шагов обновления весов сделает каждый режим?


Задание 27: Дисперсия градиента на одном примере $\sigma^2=225$. Требуется, чтобы стандартное отклонение шума оценки градиента не превышало $1$. Найти минимальный batch size, удовлетворяющий этому требованию.


Задание 28: Эксперимент показал, что batch size $m=8192$ дал более низкую ошибку на обучающей выборке, чем $m=64$, но более высокую ошибку на тестовой выборке при том же числе эпох. Предложи объяснение этому наблюдению, опираясь на понятия шума SGD и формы минимума.


Задание 29: Параметры Adam: $\beta_1=0{,}9$, $\beta_2=0{,}999$, $m_0=0$, $v_0=0$. Градиент на первом шаге $g_1=4$. Найти (без bias correction) $m_1$ и $v_1$ по формулам $m_t=\beta_1m_{t-1}+(1-\beta_1)g_t$ и $v_t=\beta_2v_{t-1}+(1-\beta_2)g_t^2$.


Задание 30: Объясни своими словами (2–3 предложения), почему связка «mini-batch SGD + момент (или Adam)» стала стандартной комбинацией по умолчанию для обучения почти любой современной нейросети, а не полный batch-градиентный спуск и не чистый SGD по одному примеру.


Частые ошибки

  • Выбирают batch size «на глаз», копируя значение из чужого кода без учёта объёма своей видеопамяти и размера своей модели — в результате либо упираются в нехватку памяти (batch size слишком большой), либо теряют скорость обучения из-за избыточного шума и низкой загрузки GPU (batch size слишком маленький).

  • Забывают, что стандартное отклонение шума оценки градиента падает как $1/\sqrt m$, а не как $1/m$ — и ожидают, что увеличение batch size в несколько раз пропорционально настолько же снизит нестабильность обучения.

  • Увеличивают batch size (например, при переходе на несколько GPU), но забывают пропорционально увеличить скорость обучения — в результате обучение внезапно замедляется, хотя вычислительных ресурсов стало больше.

  • Ставят слишком большой коэффициент момента $\beta$ (например, $0{,}999$ вместо стандартных $0{,}9$) в надежде на более гладкое обучение, но вместо этого получают колебания вокруг минимума — тот самый эффект недодемпфирования из линейного дифференциального уравнения.

  • Путают Adam с «универсальным решением, которое всегда лучше SGD с моментом» — на практике для ряда задач (особенно в компьютерном зрении) тщательно настроенный SGD с моментом иногда даёт лучшее итоговое качество на тестовых данных, чем Adam «из коробки».

  • Не перемешивают данные перед каждой эпохой (или перемешивают только один раз перед всем обучением) — из-за этого оценка градиента на отдельных шагах систематически смещается в сторону локально преобладающих в данных паттернов.

  • Считают, что шум SGD — это исключительно недостаток, который нужно полностью устранить любой ценой (например, максимально возможным batch size), не понимая, что этот же шум выполняет полезную регуляризирующую роль и помогает избегать плохих седловых точек.

Главное запомнить

  • Полный batch-градиентный спуск требует пересчёта градиента по всем примерам перед каждым шагом — на больших датасетах это делает его практически неприменимым.

  • SGD заменяет точный градиент на несмещённую, но шумную оценку по одному случайному примеру или mini-batch: $\mathbb E[\nabla\ell(\theta;x_i,y_i)]=\nabla L(\theta)$.

  • Mini-batch градиентный спуск — практический компромисс между точностью и скоростью, используемый почти во всех реальных задачах обучения нейросетей.

  • Стандартное отклонение шума оценки градиента убывает как $1/\sqrt m$, а не как $1/m$ — увеличение batch size даёт убывающую отдачу.

  • Размер batch size — гиперпараметр, одновременно управляющий скоростью, потреблением памяти и уровнем шума; слишком большой batch size может ухудшить обобщающую способность модели.

  • Момент накапливает экспоненциально взвешенное скользящее среднее прошлых градиентов, сглаживая шумные шаги SGD и ускоряя движение вдоль стабильных направлений.

  • Непрерывная версия момента — линейное дифференциальное уравнение второго порядка затухающего осциллятора, и дискриминант его характеристического уравнения определяет, будет ли обучение колебаться вокруг минимума.

  • RMSProp и Adam адаптируют эффективную скорость обучения индивидуально для каждого параметра, деля шаг на историческую оценку масштаба его градиентов.

  • Adam — фактический дефолт для обучения большинства современных нейросетей благодаря быстрой и устойчивой сходимости почти без ручной настройки.

  • Шум SGD — не только недостаток: он способен «выбивать» оптимизацию из седловых точек и узких локальных минимумов, статистически подталкивая её к более широким, лучше обобщающимся минимумам.

Связь с темами курса

Этот урок напрямую продолжает градиентный спуск: там ты разобрал базовую идею движения против градиента и формулу обновления весов, а здесь эта идея столкнулась с реальностью больших данных — и превратилась в стохастическую оценку градиента, mini-batch и адаптивные методы, без которых обучение современных нейросетей было бы попросту невозможным на практике. Момент, разобранный сегодня как накопление экспоненциально взвешенной истории градиентов, — это тот же самый механизм, который ты уже видел в университетском курсе на уроке про линейные дифференциальные уравнения: непрерывная версия момента буквально совпадает с уравнением затухающего гармонического осциллятора $\mu\ddot x+\gamma\dot x+kx=0$, а дискриминант его характеристического уравнения объясняет, почему при слишком большом коэффициенте момента обучение начинает колебаться вокруг минимума вместо плавной сходимости — ровно так же, как чрезмерно «лёгкий» маятник с недостаточным трением раскачивается вместо того, чтобы спокойно остановиться. Понимание mini-batch SGD с моментом и его адаптивных вариантов также станет прямой основой для более поздних уроков курса про архитектуры нейросетей и их обучение, включая подробный разбор Adam и других адаптивных оптимизаторов.

Интересные факты

  • Теоретический фундамент SGD — статья Роббинса и Монро 1951 года — была написана для задачи из области медицинской статистики (поиска дозы препарата по зашумлённым измерениям эффекта), а не для машинного обучения, которого в современном виде тогда попросту не существовало.

  • Название Adam не связано с именем — это сокращение от «Adaptive Moment Estimation» (адаптивная оценка моментов), отсылающее к тому, что метод одновременно оценивает первый момент (среднее) и второй момент (среднеквадратичное значение) градиентов.

  • В одной из самых влиятельных практических работ по большим батчам (Кескар и соавторы, 2016) исследователи буквально визуализировали форму найденных минимумов и показали, что модели, обученные с очень большим batch size, чаще оказываются в узких «ущельях» функции потерь, тогда как модели с умеренным batch size чаще оказываются в широких, пологих «долинах».

  • Идея добавлять случайный шум специально для того, чтобы выбраться из плохих локальных решений, независимо возникла в оптимизации задолго до глубокого обучения — в методе имитации отжига (simulated annealing), вдохновлённом реальным металлургическим процессом медленного охлаждения металла для получения более однородной, «плоской» кристаллической структуры.

Лайфхаки

  • Начинай подбор batch size с наибольшего значения, которое помещается в видеопамять без ошибки нехватки памяти (out-of-memory), а затем уменьшай при необходимости — крупный батч эффективнее использует параллелизм GPU за одно и то же время.

  • Если видеопамяти не хватает на желаемый эффективный batch size, используй приём «накопления градиента» (gradient accumulation): делай несколько mini-batch-шагов подряд, суммируя градиенты, и обновляй веса только после накопления нужного эффективного размера батча — это эмулирует больший batch size без увеличения пикового потребления памяти.

  • При переходе на батчи большего размера (например, при масштабировании на несколько GPU) сразу вспоминай про линейное масштабирование скорости обучения — иначе легко получить обманчивое замедление обучения без видимой причины.

  • Как стартовую точку для нового проекта почти всегда разумно взять Adam со стандартными значениями $\beta_1=0{,}9$, $\beta_2=0{,}999$ и скоростью обучения около $0{,}001$ — а уже потом, если нужна последняя капля качества, пробовать тщательно настроенный SGD с моментом.

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

  • Никогда не отключай перемешивание данных между эпохами ради «ускорения» — выигрыш по времени от этого пренебрежимо мал по сравнению с риском получить систематически смещённую, а значит некорректную оценку градиента.

Стохастический градиентный спуск с моментом (или его адаптивные варианты вроде Adam) — это не просто ещё один алгоритм в длинном списке методов оптимизации, а буквально тот механизм, который прямо сейчас, в эту самую секунду, крутится внутри тысяч видеокарт по всему миру, обучая языковые модели, системы рекомендаций и алгоритмы компьютерного зрения. Понимание того, почему шум в оценке градиента — это осознанный, математически обоснованный компромисс, а не досадная случайность, и того, как момент превращает дёргающуюся, «пьяную» траекторию SGD в уверенное движение к минимуму, — это ровно тот фундамент, без которого невозможно по-настоящему разобраться, что происходит внутри optimizer.step() в любом современном фреймворке глубокого обучения.

Понял тему? Закрепи в боте! 🚀

Попрактикуйся на задачах и получи персональные рекомендации от AI

💪 Начать тренировку
💬 Есть вопрос? Спроси бота!