Установите "training = False" из "tf.layers.batch_normalization", когда обучение получит лучший результат проверки - PullRequest
0 голосов
/ 26 апреля 2018

Я использую TensorFlow для обучения DNN. Я узнал, что нормализация партии очень полезна для DNN, поэтому я использовал ее в DNN.

Я использую «tf.layers.batch_normalization» и следую инструкциям документа API для построения сети: когда training , установите его параметр « training = True » и когда подтвердить , установите " training = False ". И добавьте tf.get_collection (tf.GraphKeys.UPDATE_OPS) .

Вот мой код:

# -*- coding: utf-8 -*-
import tensorflow as tf
import numpy as np

input_node_num=257*7
output_node_num=257

tf_X = tf.placeholder(tf.float32,[None,input_node_num])
tf_Y = tf.placeholder(tf.float32,[None,output_node_num])
dropout_rate=tf.placeholder(tf.float32)
flag_training=tf.placeholder(tf.bool)
hid_node_num=2048

h1=tf.contrib.layers.fully_connected(tf_X, hid_node_num, activation_fn=None)
h1_2=tf.nn.relu(tf.layers.batch_normalization(h1,training=flag_training))
h1_3=tf.nn.dropout(h1_2,dropout_rate)

h2=tf.contrib.layers.fully_connected(h1_3, hid_node_num, activation_fn=None)
h2_2=tf.nn.relu(tf.layers.batch_normalization(h2,training=flag_training))
h2_3=tf.nn.dropout(h2_2,dropout_rate)

h3=tf.contrib.layers.fully_connected(h2_3, hid_node_num, activation_fn=None)
h3_2=tf.nn.relu(tf.layers.batch_normalization(h3,training=flag_training))
h3_3=tf.nn.dropout(h3_2,dropout_rate)

tf_Y_pre=tf.contrib.layers.fully_connected(h3_3, output_node_num, activation_fn=None)

loss=tf.reduce_mean(tf.square(tf_Y-tf_Y_pre))

update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
with tf.control_dependencies(update_ops):
    train_step = tf.train.AdamOptimizer(1e-4).minimize(loss)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    for i1 in range(3000*num_batch):
        train_feature=... # Some processing
        train_label=...  # Some processing
        sess.run(train_step,feed_dict={tf_X:train_feature,tf_Y:train_label,flag_training:True,dropout_rate:1}) # when train , set "training=True" , when validate ,set "training=False" , get a bad result . However when train , set "training=False" ,when validate ,set "training=False" , get a better result .

        if((i1+1)%277200==0):# print validate loss every 0.1 epoch
            validate_feature=... # Some processing
            validate_label=... # Some processing

            validate_loss = sess.run(loss,feed_dict={tf_X:validate_feature,tf_Y:validate_label,flag_training:False,dropout_rate:1})
            print(validate_loss)

Есть ли ошибка в моем коде? если мой код верен, я думаю, что получаю странный результат:

когда training , я устанавливаю " training = True ", когда validate , устанавливаю " training = False ", результат не хорошо . Я печатаю потери подтверждения каждые 0,1 эпохи, потери подтверждения с 1-й по 3-ю эпоху составляют

 0.929624
 0.992692
 0.814033
 0.858562
 1.042705
 0.665418
 0.753507
 0.700503
 0.508338
 0.761886
 0.787044
 0.817034
 0.726586
 0.901634
 0.633383
 0.783920
 0.528140
 0.847496
 0.804937
 0.828761
 0.802314
 0.855557
 0.702335
 0.764318
 0.776465
 0.719034
 0.678497
 0.596230
 0.739280
 0.970555

Однако, когда я меняю код " sess.run (train_step, feed_dict = {tf_X: train_feature, tf_Y: train_label, flag_training: True, dropout_rate: 1}) ", это: set " training = False"когда training , установите« training = False », когда подтвердите . Результат хорош. Подтверждение потери в 1-ю эпоху

 0.474313
 0.391002
 0.369357
 0.366732
 0.383477
 0.346027
 0.336518
 0.368153
 0.330749
 0.322070
 0.335551

Почему появляется этот результат? Нужно ли устанавливать «training = True» при обучении, установить «training = False» при проверке?

Ответы [ 2 ]

0 голосов
/ 30 сентября 2018

Причина, по которой вы установили Training = False, повышает производительность в том, что нормализация партии имеет четыре переменные (бета, гамма, среднее значение, дисперсия). Это правда, что среднее значение и дисперсия не обновляются, когда Training = False. Однако гамма и бета все еще обновляются. Таким образом, ваша модель имеет две дополнительные переменные и, следовательно, имеет лучшую производительность.

Кроме того, я полагаю, что ваша модель имеет относительно хорошую производительность без пакетной нормализации.

0 голосов
/ 28 апреля 2018

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.

...