Gradient accumulation — это техника обучения, при которой модель вычисляет градиенты на нескольких mini-batch подряд, а обновление оптимизатора делает только после завершения окна накопления. Она нужна прежде всего для экономии памяти: вы получаете больший effective batch size, не держа весь большой batch в памяти одновременно.
Английский термин: gradient accumulation. Также встречается: накопление градиента, накопление градиентов; рядом в документации обычно используются выражения mini-batch, micro-batch, effective batch size и gradient_accumulation_steps.
Практический вывод: используйте gradient accumulation, когда желаемый batch size не помещается в память. Не выбирайте его как способ ускорения: документация Hugging Face прямо отмечает, что по сравнению с настоящим большим batch этот приём не улучшает throughput.
Простыми словами
Грубо говоря, это похоже на ситуацию, когда вы не можете занести в лифт все коробки сразу. Вместо одной большой поездки вы делаете несколько маленьких, но итоговое решение принимаете только после того, как собрали весь объём.
В обучении модели роль «коробок» играют маленькие порции данных. Модель обрабатывает их по очереди, складывает вклад каждого прохода в градиенты и только потом делает один шаг оптимизатора.
Как это работает
Технически суть опирается на поведение autograd в PyTorch: градиенты накапливаются в .grad между вызовами backward(). Если вы не обнуляете их сразу, следующий backward добавляет новый вклад к уже посчитанному.
micro-batch 1 -> forward -> backward -> .grad += g1
micro-batch 2 -> forward -> backward -> .grad += g2
micro-batch 3 -> forward -> backward -> .grad += g3
micro-batch 4 -> forward -> backward -> .grad += g4
после окна накопления:
optimizer.step()
optimizer.zero_grad()
- Вы берёте первый mini-batch.
- Делаете прямой проход и
backward(). - Градиенты записываются в
.gradи не сбрасываются. - Повторяете то же для следующих mini-batch.
- Когда число проходов достигло нужного
gradient_accumulation_steps, вызываетеoptimizer.step(). - После шага оптимизатора вызываете
optimizer.zero_grad(), чтобы следующее окно накопления началось с нуля.
Если упростить пример: batch на устройство равен 8, а gradient_accumulation_steps=4. Тогда обновление весов произойдёт после обработки 32 примеров, хотя в памяти одновременно лежали только 8.
Отдельный нюанс касается mixed precision. В примерах PyTorch AMP сказано, что при gradient accumulation градиенты должны оставаться scaled до конца эффективного batch; если вызвать unscale_ слишком рано, следующие backward смешают scaled и unscaled градиенты. Поэтому unscale_ следует вызывать непосредственно перед step.
Где применяется
- Когда большой batch не помещается в память. Это основной сценарий: вы хотите обучать модель с более крупным effective batch size, но физическая память не позволяет загрузить его целиком.
- В Hugging Face Transformers. Официальная документация указывает, что для accumulation используются
TrainingArgumentsс параметрамиper_device_train_batch_sizeиgradient_accumulation_steps. - В пользовательских и распределённых циклах обучения. В Hugging Face Accelerate для этого есть
Accelerator(gradient_accumulation_steps=...)и контекстный менеджерwith accelerator.accumulate(model):. - Для проверки эквивалентности с большим batch. В гайде Accelerate показан практический критерий корректности: при правильной настройке запуск с accumulation и запуск без accumulation могут привести к одинаковым итоговым весам.
Практический пример
Допустим, вам нужен effective batch из 32 примеров, но в память помещается только 8. Тогда вы оставляете маленький batch на устройство и откладываете шаг оптимизатора на четыре прохода.
from accelerate import Accelerator
accelerator = Accelerator(gradient_accumulation_steps=4)
for batch in train_dataloader:
with accelerator.accumulate(model):
outputs = model(**batch)
loss = outputs.loss
accelerator.backward(loss)
optimizer.step()
optimizer.zero_grad()
Здесь важна не длина кода, а порядок действий: backward вызывается на каждом mini-batch, а синхронизацию шага берёт на себя documented API Accelerate.
Если вы используете Trainer и собственную функцию потерь, следите за нормализацией loss. В документации Transformers отдельно оговорено деление на num_items_in_batch: для causal language modeling считаются shifted labels, а для других типов потерь — полный tensor labels. Это важный практический момент: неверная нормализация ломает эквивалентность с большим batch даже тогда, когда сам accumulation настроен формально правильно.
Как проверить настройку: возьмите небольшой воспроизводимый прогон и сравните его с вариантом без accumulation, но с тем же итоговым effective batch size. Документация Accelerate использует именно такую проверку и показывает совпадение итоговых весов при корректной реализации.
Чем отличается от обычного mini-batch и большого batch
| Подход | Когда вызывается optimizer.step() |
Память | Скорость относительно true large batch | Что обычно ожидают по результату |
|---|---|---|---|---|
| Обычный mini-batch без accumulation | После каждого mini-batch | Ниже | Source pack это отдельно не детализирует | Другую динамику обновлений, чем у более крупного batch |
| Gradient accumulation | После нескольких mini-batch | Ниже, чем у настоящего большого batch | Документация Hugging Face не обещает выигрыша по throughput | При корректной реализации может совпасть с эквивалентным большим batch |
| Настоящий большой batch | После одного большого batch | Выше | Базовая точка сравнения | Эталон для сравнения с accumulation |
Если нужен смежный базовый термин, сначала освежите Backpropagation: именно через него считаются градиенты, которые затем накапливаются.
Ограничения и заблуждения
- Заблуждение: «это способ ускорить обучение». По официальной документации Hugging Face, accumulation не улучшает throughput по сравнению с настоящим большим batch. Его главная цель — обойти ограничение памяти.
- Заблуждение: «достаточно несколько раз вызвать backward()». Нет: нужно правильно выбрать момент для
optimizer.step()и не забытьoptimizer.zero_grad(), иначе градиенты продолжат складываться дальше. - Ограничение mixed precision. В AMP нельзя вызывать
unscale_слишком рано: это смешает scaled и unscaled градиенты в одном окне накопления. - Ограничение по нормализации loss. Для custom loss и особенно для token-level задач эквивалентность с большим batch зависит от того, как вы считаете количество элементов в batch. Transformers отдельно документирует
num_items_in_batchи разницу между causal LM и другими loss. - Ограничение по версиям и backend. Семантика accumulation может различаться между версиями библиотек, настройками mixed precision и распределёнными backend’ами. Даже release notes PyTorch фиксируют внутренние изменения, связанные с gradient accumulation nodes, поэтому переносить старые рецепты без проверки рискованно.
Редакционное ограничение: этот материал опирается только на официальный source pack, актуальный на 2026-08-15. Он не покрывает все нюансы конкретных оптимизаторов, а также все частные сценарии DDP, DeepSpeed, FSDP и нестандартных loss-функций, поэтому для production-настройки сверяйтесь с версионной документацией именно вашего стека.
Связанные термины и инструменты
- Backpropagation (обратное распространение) — откуда берутся градиенты, которые затем накапливаются.
- Self-attention — один из типичных компонентов трансформеров, обучаемых в тех же training loops.
- Multi-Head Attention (многоголовое внимание) — смежный термин для понимания архитектур, которые часто тренируют через Hugging Face и PyTorch.
- Prompt tuning (мягкий промпт) — соседняя тема из области дообучения моделей.
- Из инструментов смотрите официальные материалы по Hugging Face Transformers, Hugging Face Accelerate и PyTorch.
Источники
- Gradient accumulation · Hugging Face
- Performing gradient accumulation with Accelerate · Hugging Face
- Accelerator · Hugging Face
- Zeroing out gradients in PyTorch — PyTorch Tutorials
- Automatic Mixed Precision examples — PyTorch main documentation
- Releases · pytorch/pytorch · GitHub
- Accurate, Large Minibatch SGD: Training ImageNet in 1 Hour
Вопросы и ответы
Gradient accumulation — это то же самое, что большой batch?
Не совсем. Это способ приблизить обучение с большим effective batch size, не загружая весь batch в память сразу. При корректной реализации результат может совпасть с настоящим большим batch, но документация не обещает выигрыша по throughput.
Нужно ли вызывать zero_grad() после каждого backward()?
Нет, если вы специально накапливаете градиенты. В PyTorch градиенты складываются в .grad, поэтому обнулять их нужно между шагами оптимизатора, а не после каждого backward.
Работает ли gradient accumulation с mixed precision?
Да, но важно не вызывать unscale_ слишком рано. Примеры PyTorch AMP рекомендуют держать градиенты scaled до завершения эффективного batch и делать unscale_ непосредственно перед step.
Как проверить, что accumulation настроен правильно?
Самый надёжный способ из официального гайда Accelerate — сравнить прогон с accumulation и прогон без accumulation при том же effective batch size. При корректной настройке итоговые веса должны совпадать.
Когда лучше использовать Transformers, а когда Accelerate?
Если вы обучаете модель через готовый Trainer, используйте параметры per_device_train_batch_size и gradient_accumulation_steps из Transformers. Если у вас ручной training loop или более сложная схема, удобнее официальный API Accelerate с accumulate().