Что забывают сделать с данными на CUDA, что может привести к переполнению памяти при обучении?
Что проверяют
Ловили ли вы переполнение памяти руками и понимаете ли, что на видеокарте память держат не только веса и батч, но и граф вычислений, состояние оптимизатора и кэш аллокатора. Вопрос сформулирован про данные, поэтому ждут именно про то, что забывают сделать с тензорами.
Как отвечать
Перечислите типичные забытые действия:
- не отцепили тензор от графа при сборе метрик:
losses.append(loss)держит весь граф итерации, нужноloss.item()илиloss.detach(); - забыли
torch.no_grad()илиinference_modeна валидации, из-за чего сохраняются активации под обратный проход; - держат на видеокарте то, чему место на процессоре: весь датасет, накопленные предсказания и логиты для подсчёта метрики; перед объединением их переносят на процессор;
- не освобождают ссылки на прошлый батч перед следующей итерацией, и пик складывается из двух;
- обнуляют градиенты нулями вместо
zero_grad(set_to_none=True), буферы не возвращаются аллокатору; - переменная длина последовательностей: пик задаёт самый длинный пример в батче, помогает сортировка по длине и жёсткий предел длины;
- фрагментация кэширующего аллокатора: свободной памяти много, непрерывного блока нужного размера нет.
Дальше структурные приёмы: меньший батч с накоплением градиента, смешанная точность, перевычисление активаций.
Где спотыкаются
Ставят диагноз по nvidia-smi. Освобождённые тензоры остаются в кэше аллокатора, и утилита показывает занятое процессом, а не живые данные. Смотреть надо memory_allocated и memory_reserved, а empty_cache() лишь возвращает кэш системе и настоящий рост не лечит.
Валят всё на размер батча. Батч это регулятор, а не диагноз: если падение приходит не на первом шаге, а на сотом, значит что-то накапливается от итерации к итерации, и уменьшение батча только отодвинет момент.
Считают, что обнуление градиентов спасает от переполнения. Оно нужно для корректности шага, а память растёт от удержанного графа; накопление градиента по нескольким шагам как раз и работает без обнуления, при этом в память укладывается.