TL; DR : использовать меньший, чем импульс по умолчанию для слоев нормализации, например:
tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
TS; WM
Когда вы устанавливаете training = False
, это означает, что слой нормализации партии будет использовать свое внутреннее сохраненное среднее значение среднего значения и дисперсию для нормализации партии, а не собственное среднее значение и дисперсию партии. Когда training = False
, эти внутренние переменные также не обновляются. Поскольку они инициализируются в mean = 0
и variance = 1
, это означает, что нормализация партии фактически отключена - слой вычитает ноль и делит результат на 1.
Так что, если вы тренируетесь с training = False
и оцениваете таким образом, это просто означает, что вы тренируете свою сеть без какой-либо пакетной нормализации вообще. Это все еще даст разумные результаты, потому что, эй, до нормализации партии была жизнь, хотя по общему признанию не столь очаровательная ...
Если вы включите нормализацию партии с помощью training = True
, это начнет нормализовать партии внутри себя и соберет скользящее среднее от среднего значения и дисперсии каждой партии. Теперь вот сложная часть. Скользящая средняя - это экспоненциальная скользящая средняя с импульсом по умолчанию 0,99 для tf.layers.batch_normalization()
. Среднее значение начинается с 0, дисперсия снова с 1. Но поскольку каждое обновление применяется с весом (1 - импульс) , оно асимптотически достигает фактического среднего значения и дисперсии в бесконечности. Например, с шагом 100 он достигнет примерно 73,4% от реального значения, поскольку 0,99 100 равно 0,366 . Если у вас есть численно большие значения, разница может быть огромной.
Так что, если у вас есть относительно небольшое количество обработанных вами партий, то сохраненные во внутренней памяти средние значения и дисперсия могут все еще значительно отключиться к моменту запуска теста. Затем ваша сеть обучается на должным образом нормализованных данных и проверяется на неверно нормализованных данных.
Чтобы ускорить сходимость внутренних значений нормализации партии, вы можете применить меньший импульс, как 0,9 :
tf.layers.batch_normalization( h1, momentum = 0.9, training=flag_training )
(повторите для всех слоев нормализации партии.) Обратите внимание, что в этом есть и обратная сторона. Случайные флуктуации в ваших данных будут «тянуть» на сохраненное среднее значение и отклонения в гораздо большей степени при таком небольшом импульсе, и на результирующие значения (которые позже будут использоваться в логическом выводе) может сильно повлиять то, где вы точно остановите обучение, что явно оптимальный. Полезно иметь как можно больший импульс. В зависимости от количества этапов обучения мы обычно используем 0,9 , 0,99 , 0,999 для 100 , 1000 , 10000 этапов обучения соответственно. Нет смысла переходить 0,999 .
Еще одна важная вещь - правильная рандомизация обучающих данных. Если вы сначала тренируетесь, скажем, с меньшими числовыми значениями всего набора данных, то нормализация будет сходиться еще медленнее. Лучше всего полностью рандомизировать порядок данных обучения и убедиться, что вы используете размер партии не менее 14 (правило большого пальца).
Примечание: известно, что нулевое сглаживание значений может значительно ускорить сходимость, и класс ExponentialMovingAverage имеет эту функцию. Но слои пакетной нормализации не имеют этой функции, за исключением tf.slim
batch_norm , если вы хотите реструктурировать свой код для slim.