Разделить микробатч, обратный проход и обновление
Микробатч — это группа примеров, обрабатываемая одним прямым проходом на реплике. Обратный проход вычисляет его вклад в градиенты. Обновление оптимизатора использует доступные градиенты для изменения параметров. При накоплении этому обновлению предшествуют несколько прямых и обратных проходов; параметры остаются неизменными в течение группы.
В PyTorch градиенты накапливаются в предназначенных для этого тензорах. Поэтому обнуление градиентов после каждого микробатча отменило бы желаемое накопление. И наоборот, забыв обнулить их между двумя группами, вы заставите примеры из предыдущего обновления внести свой вклад.
Определите единицу журналирования: номер микробатча, обновление оптимизатора, увиденные примеры или токены. Одно лишь слово «step» неоднозначно. Кривая потери не сравнивается корректно, если на оси в одном из экспериментов представлено в восемь раз больше примеров.
Технические источники: PyTorch — накопление и обнуление градиентов
Вычислить эффективный батч, не считая GPU дважды
Обозначим m число примеров на микробатч и на реплику, A — число накопленных микробатчей, D — число реплик параллелизма данных. Если эти размеры постоянны и примеры распределены правильно, число примеров, вносящих вклад в одно глобальное обновление, равно m × A × D.
Множитель D не обязательно обозначает все карты машины. GPU, которые делят одну и ту же модель через тензорный или конвейерный параллелизм, не становятся от этого репликами данных. Указывайте реально настроенные группы, а не просто коммерческое количество в партии.
Арифметический пример: два примера на микробатч, восемь накоплений и две реплики дают 32 примера на глобальное обновление. Каждая реплика обрабатывает шестнадцать примеров в этой группе. Таблица сравнивает количества; она не ранжирует их по памяти или скорости.
| m | A | D | Примеров на глобальное обновление |
|---|---|---|---|
| 2 | 8 | 2 | 32 |
| 1 | 16 | 2 | 32 |
| 4 | 4 | 2 | 32 |
| 2 | 8 | 1 | 16 |
Технические источники: PyTorch — эффективный батч и накопление в смешанной точности · PyTorch — поведение реплик DistributedDataParallel
Нормализуйте потерю по фактически оцениваемым элементам
Для усреднённой потери по микробатчам с одинаковым числом значимых элементов деление каждого вклада на A даёт среднее по группе. Это правило предполагает, что фреймворк уже не выполняет такую нормализацию. Если инструмент сам управляет накоплением, перечитайте его контракт, прежде чем добавлять ручное деление.
Для средней потери на токен разная длина меняет знаменатель. Нужно относить сумму потерь к фактически контролируемым токенам группы, исключая padding и игнорируемые позиции. Среднее от средних по микробатчам, как правило, не даёт ту же целевую величину.
Теоретический пример: в одном микробатче 512 контролируемых токенов со средней потерей 2; в другом — 1 536 со средней 4. Взвешенное среднее равно (512 × 2 + 1 536 × 4) ÷ 2 048 = 3,5. Невзвешенное среднее равно 3 и придаёт слишком большой вес маленькой группе. Эти значения иллюстрируют только сам расчёт.
Технические источники: Hugging Face Accelerate — накопление с примерами переменной длины
Организуйте полную группу накопления
Сначала подготовьте границы группы и её знаменатель. Для каждого микробатча вычислите выход, нормализованную потерю и обратный проход без промежуточного обновления. Освобождайте выходы, которые больше не нужны; хранение потерь, привязанных к их графу, в списке может продлить жизнь аллокаций.
После последнего вклада примените предусмотренные операции над полным градиентом, затем обновление. После этого сбросьте градиенты для следующей группы. Если проход завершается с числом микробатчей меньше A, явно выберите: обработать эту частичную группу с её настоящим знаменателем или отбросить её; зафиксируйте затронутые примеры.
При смешанной точности с GradScaler масштабирующий множитель остаётся постоянным во время накопления. Реальное обратное масштабирование и возможный clipping выполняются после вкладов; обновление scaler следует за попыткой шага. Проверки на неконечные значения могут воспрепятствовать изменению параметров.
Планировщик должен следовать единице, объявленной вашим циклом. Если он определён по обновлению оптимизатора, вызов его на каждом микробатче изменил бы расписание. Фиксируйте отдельно попытки и фактически применённые обновления, если ваша система может их пропускать.
Технические источники: PyTorch — графы autograd и тензоры, сохраняемые для backward · PyTorch — накопление, unscale, clipping и GradScaler
В multi-GPU проверьте редукцию и распределение примеров
DistributedDataParallel синхронизирует градиенты между репликами. В своём обычном поведении редукция их усредняет; поэтому суммированная потеря и локально усреднённая потеря имеют разный масштаб. При разном числе токенов по репликам глобальный знаменатель и эта редукция должны рассматриваться вместе.
Проверьте, какие ID фактически обрабатываются: непреднамеренное дублирование одних и тех же примеров на всех картах не увеличивает информативность группы настолько же. Чтобы отложить промежуточные коммуникации, можно использовать no_sync на микробатчах, предшествующих финальной синхронизации; его контекст должен охватывать также прямой проход.
Не переносите это правило на все распределённые системы. Шардинг состояний, pipeline, хуки коммуникации и фреймворки могут менять фактические операции. Начните с конфигурации, поддерживаемой вашим инструментом, затем проверьте полную группу на каждой реплике.
Технические источники: PyTorch — редукция градиентов и область действия no_sync в DDP
Почему одинаковый эффективный батч не гарантирует одинаковый опыт
Равенство m × A × D — это подсчёт. Чтобы воспроизвести градиент большого батча, нужны, в частности, корректно взвешенные вклады, одинаковое состояние параметров в течение группы и операции, совместимые с таким разложением. Числовая близость проверяется с подходящим допуском; её нельзя вывести из одного лишь произведения.
BatchNorm вычисляет статистики по входным данным своего прохода: несколько маленьких микробатчей предъявляют ему не те же группы, что один большой батч. Случайные операции, порядок вычислений и округления тоже могут различаться. Не обещайте побитово идентичные итоговые веса.
Изменение глобального батча может также изменить число обновлений при одном и том же числе просмотренных примеров. Заранее задайте ось сравнения и ваше правило оценки качества. Не меняйте одновременно скорость обучения, scheduler и длительность, не документируя эти новые допущения.
Технические источники: PyTorch — статистики BatchNorm1d · PyTorch — ограничения воспроизводимости
Контролировать память и решать, что дальше
Инструментируйте группу, включающую обратные проходы и первое обновление, а затем последующие группы. Успех на прямом проходе не подтверждает корректность градиентов или состояний, созданных оптимизатором. Счётчики должны сохранять свой периметр по device. Досье по памяти даёт метод чтения baseline и пиков.
Если группа не проходит, уменьшите микробатч и пересчитайте A, чтобы сохранить целевой эффективный батч, когда такой выбор остаётся уместным. Это изменение не гарантирует ни пропорционального снижения пика, ни лучшей длительности. Если доминируют веса или состояния, одного накопления может быть недостаточно.
Перед кампанией проверьте одно обновление на небольшом контролируемом наборе: те же примеры, взвешенная потеря, конечные градиенты, граница группы и число шагов. Затем оцените качество по выбранному протоколу. Небольшой MLP для инференса из загружаемого досье не выполняет этот рецепт обучения; он не заменяет такую проверку.
Ваша итоговая карточка объединяет m, A, D, supervised-токены, точность, нормализацию, обработку последней группы и наблюдаемые пики. Затем вернитесь к выбору конфигурации и бюджету экспериментов, разделяя подготовку, пробы и реально принятые результаты.
- Аномально малая потеря: ищите двойное деление на накопление.
- Результат меняется при разбиении: проверьте игнорируемые токены и усреднение средних.
- Накопление без эффекта: проверьте zero_grad и optimizer.step.
- Растущая память: ищите ссылки, сохраняемые между микробатчами.
- Смещённый календарь: различайте обратные проходы и обновления.
Технические источники: Hugging Face — места памяти при обучении
Практические вопросы
Умножает ли накопление шестнадцати микробатчей память на шестнадцать?
Не обязательно: вклады обрабатываются последовательно. Градиенты сохраняются, а ненужные активации могут освобождаться. Однако пик зависит от модели, сохраняемых ссылок и состояний оптимизатора; измеряйте полную группу.
Всегда ли два GPU удваивают эффективный батч?
Только если эти GPU участвуют как две реплики данных с заявленным микробатчем. Карты, которые совместно используют одну и ту же модель, автоматически не образуют две реплики. Проверяйте распределённые группы и обработанные примеры.
Можно ли разделить все потери на число накоплений?
Это простое правило соответствует микробатчам с равным весом, когда нормализация уже обрабатывается фреймворком. При переменном числе supervised-токенов или незавершённой последней группе используйте реальный знаменатель целевой функции.