Ответ 1
Хороший вопрос.
Я наткнулся на это явление несколько раз. Вот мои наблюдения:
Включение градиента
Причина: большие градиенты бросают процесс обучения вне траектории.
Что вы ожидаете:. Посмотрев на журнал выполнения, вы должны посмотреть на значения потерь для каждой итерации. Вы заметите, что потеря начинает значительно возрастать от итерации до итерации, в конце концов потеря будет слишком большой, чтобы быть представленной переменной с плавающей запятой, и она станет nan
.
Что вы можете сделать: Уменьшите base_lr
(в файле solver.prototxt) на порядок (по крайней мере). Если у вас есть несколько уровней потерь, вы должны проверить журнал, чтобы увидеть, какой слой отвечает за раздутие градиента, и уменьшить loss_weight
(в train_val.prototxt) для этого конкретного слоя вместо общего base_lr
.
Политика и параметры скорости плохого обучения
Причина: caffe не может вычислить действительную скорость обучения и вместо этого получает 'inf'
или 'nan'
, эта недопустимая скорость умножает все обновления и тем самым аннулирует все параметры.
Что вы должны ожидать:. Посмотрев на журнал выполнения, вы должны увидеть, что скорость обучения сама становится 'nan'
, например:
... sgd_solver.cpp:106] Iteration 0, lr = -nan
Что вы можете сделать: исправить все параметры, влияющие на скорость обучения в вашем файле 'solver.prototxt'
.
Например, если вы используете lr_policy: "poly"
, и вы забыли определить параметр max_iter
, вы получите lr = nan
...
Для получения дополнительной информации о скорости обучения в кафе см. эту тему.
Функция Faulty Loss
Причина: Иногда вычисления потери в слоях потерь приводят к появлению nan
. Например, подача InfogainLoss
слоя с ненормированными значениями, использование пользовательского уровня потерь с ошибками и т.д.
Что вы ожидаете:. Посмотрев на журнал времени выполнения, вы, вероятно, не заметите ничего необычного: потеря постепенно уменьшается, и вдруг появляется nan
.
Что вы можете сделать: Посмотрите, можете ли вы воспроизвести ошибку, добавить распечатку на уровень потерь и отладить ошибку.
Например: как только я использовал потерю, которая нормализовала штраф за частоту появления метки в пакете. Так получилось, что если одна из ярлыков обучения вообще не появлялась в партии - вычисленная потеря производила nan
s. В этом случае достаточно работать с достаточно большими партиями (относительно количества меток в наборе), чтобы избежать этой ошибки.
Неисправный ввод
Причина: у вас есть вход с nan
в нем!
Что вам следует ожидать:, как только процесс обучения "ударит" по этому ошибочному вводу - вывод будет nan
. Глядя на журнал времени выполнения, вы, вероятно, не заметите ничего необычного: потеря постепенно уменьшается, и вдруг появляется nan
.
Что вы можете сделать: перестроить свои входные наборы данных (lmdb/leveldn/hdf5...), убедитесь, что у вас нет файлов с плохими изображениями в вашем наборе обучения/проверки. Для отладки вы можете создать простую сеть, которая читает входной уровень, имеет фиктивную потерю поверх нее и проходит через все входы: если один из них неисправен, эта фиктивная сеть также должна создавать nan
.
шаг больше размера ядра в слое "Pooling"
По какой-то причине выбор stride
> kernel_size
для объединения может привести к nan
s. Например:
layer {
name: "faulty_pooling"
type: "Pooling"
bottom: "x"
top: "y"
pooling_param {
pool: AVE
stride: 5
kernel: 3
}
}
результат с nan
в y
.
Неустойчивости в "BatchNorm"
Сообщалось, что при некоторых настройках "BatchNorm"
уровень может выводить nan
из-за числовых неустойчивостей.
Эта проблема была поднята в bvlc/caffe и PR # 5136 пытается его исправить.
В последнее время мне стало известно о debug_info
: установка debug_info: true
в 'solver.prototxt'
сделает печать caffe для записи дополнительной информации об отладке (включая градиентные величины и значения активации) во время обучения: эта информация может помочь в выявлении градиентных раздутий и других проблем в процессе обучения.