Многие неспециалисты используют следующий код http://stackoverflow.com/questions/33949786/how-could-i-use-batch-normalization-in-tensorflow?answertab=votes#tab -top.
Было бы неплохо иметь официальный слой пакетных норм, учитывая его важность для обучения DNN.
Я работаю над некоторыми частями этого.
Я думаю, что с этим слоем что-то не так. на тренировках все в порядке и потери снижаются очень хорошо. но при тестировании я получаю нулевую точность.
Кстати, при тестировании при использовании is_training = False я получаю ноль соотв.
Я знаю, что пакетная нормализация ведет себя по-разному на этапе обучения и тестирования, как описано в разделе Как по-разному ведет себя пакетная нормализация во время обучения и во время тестирования?
То же самое, я испытал неожиданное поведение с is_training = False. Как правильно изменить этот флаг? В настоящее время я использую tf.cond
потому что он сам по себе не занимает tf.placeholders
.
@pawni Вы должны использовать логическое значение Python для is_training
. Это не может быть tf.cond
.
@ppwwyyxx хорошо, я делаю tf.cond(placeholder, batch_norm(.., is_training = True), batch_norm(.., is_training = False))
или нужно просто сделать batch_norm(.., is_training=variable)
и при необходимости изменить это за пределами графика?
О, я думал, вы делаете batch_norm(.., is_training=tf.cond(placeholder))
, что неверно.
У вашего нынешнего пути тоже могут быть проблемы. Вам нужно будет дважды проверить, что две созданные вами операции batch_norm
имеют одну и ту же область действия, иначе они не будут разделять базовую статистику среднего / отклонения.
Для этого может помочь аргумент reuse
, но я не уверен, потому что использую свою версию bn layer.
Я использую ту же область видимости и reuse=True
. Иногда это срабатывает, но я не уверен. Было бы здорово, если бы слой можно было добавить в документацию с кратким объяснением, как лучше всего справиться с переходом от обучения к тесту.
@sguada FYI
В настоящее время для batch_norm требуется логическое значение python, но мы работаем над добавлением возможности передачи Tensor.
@pawni Если вы не хотите беспокоиться об обновлении moving_mean и moving_variance, установите updates_collections = None, чтобы убедиться, что они обновляются на месте, иначе вам нужно убедиться, что update_ops, добавленные в tf.GraphKeys.UPDATE_OPS, запускаются во время обучения.
Я думаю, что для tensorflow нужны 2 гиперметода, которые меняют состояние модели, что-то вроде torch. изменить состояние модели . Я думаю, это очень просто.
есть ли небольшой сценарий с очень простым NN, который показывает, как правильно использовать этот "официальный" слой BN? Я был бы очень признателен.
извините, если это немного повторяется, но похоже, что API говорит о BN в другом интерфейсе: https://www.tensorflow.org/versions/r0.9/api_docs/python/nn.html#batch_normalization
это не официальный способ использования BN? Я не понимаю, как его использовать, и кажется, что SO устарел, а затем есть слой в другой ссылке из API, как именно это сделать? Я не понимаю, идти ли в SO или спрашивать здесь.
извините за спам, но что плохого в том, чтобы просто использовать что-то вроде этого:
def standard_batch_norm(l, x, n_out, phase_train, scope='BN'):
"""
Batch normalization on feedforward maps.
Args:
x: Vector
n_out: integer, depth of input maps
phase_train: boolean tf.Varialbe, true indicates training phase
scope: string, variable scope
Return:
normed: batch-normalized maps
"""
with tf.variable_scope(scope+l):
#beta = tf.Variable(tf.constant(0.0, shape=[n_out], dtype=tf.float64 ), name='beta', trainable=True, dtype=tf.float64 )
#gamma = tf.Variable(tf.constant(1.0, shape=[n_out],dtype=tf.float64 ), name='gamma', trainable=True, dtype=tf.float64 )
init_beta = tf.constant(0.0, shape=[n_out], dtype=tf.float64)
init_gamma = tf.constant(1.0, shape=[n_out],dtype=tf.float64)
beta = tf.get_variable(name='beta'+l, dtype=tf.float64, initializer=init_beta, regularizer=None, trainable=True)
gamma = tf.get_variable(name='gamma'+l, dtype=tf.float64, initializer=init_gamma, regularizer=None, trainable=True)
batch_mean, batch_var = tf.nn.moments(x, [0], name='moments')
ema = tf.train.ExponentialMovingAverage(decay=0.5)
def mean_var_with_update():
ema_apply_op = ema.apply([batch_mean, batch_var])
with tf.control_dependencies([ema_apply_op]):
return tf.identity(batch_mean), tf.identity(batch_var)
mean, var = tf.cond(phase_train, mean_var_with_update, lambda: (ema.average(batch_mean), ema.average(batch_var)))
normed = tf.nn.batch_normalization(x, mean, var, beta, gamma, 1e-3)
return normed
то просто указать тензорному потоку, какой из них использовать со словарем каналов, как в:
feed_dict = {x: Xminibatch, y_: Yminibatch, phase_train: True}
sess.run(fetches=[merged,train_step], feed_dict=feed_dict)
так как неясно, изменится ли реализация, я хотел дать предложение (обратите внимание, что его легко распространить на свертки и прочее, я просто не вставлял этот код).
@pawni @ppwwyyxx , ребята, вы решили, нужно ли использовать reuse to true для решения проблемы с областью видимости?
@ brando90 сейчас я делаю что-то вроде:
def BatchNorm(inputT, is_training=True, scope=None):
return tf.cond(isTraining,
lambda: batch_norm(inputT, is_training=True,
center=False, updates_collections=None, scope=scope),
lambda: batch_norm(inputT, is_training=False,
updates_collections=None, center=False, scope=scope, reuse = True))
Однако я думаю, что # 3265 в основном хотел бы реализовать это вот так. Ссылкой может быть реализация отсева здесь: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/layers/python/layers/layers.py#L433 -L435
Когда updates_collections = None, обновления происходят на месте, и проще использовать tf.cond (), чтобы разрешить is_training быть тензором, немного сложнее, когда обновления задерживаются, а update_ops запускаются позже.
Постараюсь в ближайшее время получить первую часть.
@ brando90 @pawni он код работает хорошо, но его нужно изменить, как
def BatchNorm(inputT, is_training=True, scope=None):
# Note: is_training is tf.placeholder(tf.bool) type
return tf.cond(is_training,
lambda: batch_norm(inputT, is_training=True,
center=False, updates_collections=None, scope=scope),
lambda: batch_norm(inputT, is_training=False,
updates_collections=None, center=False, scope=scope, reuse = True))
И во время тренировки или тестирования,
# when training
sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=True})
# when test
sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=False})
Этот код работает, но, как и в # 3265, сказано, что будет здорово, если tf.contrib.layers.batch_norm
получит переменную is_training
как tf.plcaeholer
.
@nmhkahn @pawni спасибо за фрагменты кода. Они были очень полезны при добавлении пакетной нормализации в мою сверточную сеть. Кажется, обучение работает очень хорошо. Тестирования нет. В некоторых версиях кода точность обучения намного выше, чем точность тестирования, что, вероятно, означает, что я не делюсь параметрами пакетной нормализации. В других версиях кода я получаю сообщение «ValueError: переменная conv1 / beta уже существует, запрещена. Вы хотели установить reuse = True в VarScope?» которые, кажется, указывают на то, что я пытаюсь заново изучить параметр ... когда я пытался повторно использовать.
Может ли кто-нибудь привести пример того, как вызвать функцию def BatchNorm во время обучения и тестирования, чтобы совместное использование переменных происходило правильно.
Спасибо за любую помощь.
ОБНОВЛЕНИЕ 25 июля 2016 г .:
@nmhkahn @pawni спасибо за ваши комментарии. Присмотревшись к коду в contrib, я понял, в чем моя проблема. Во время обучения и тестирования мы либо обновляем, либо повторно используем четыре переменные (бета, гамма, moving_mean и moving_variance). Чтобы сделать их уникальными, мне пришлось установить область видимости для каждого слоя. У меня так получилось:
conv1 = tf.nn.relu (batch_norm_layer (conv2d_stride2_valid (data, W_conv1) + b_conv1, train_phase, scope = "conv1"))
где batch_norm_layer аналогичен примерам из @nmhkahn @pawni , conv2d_stride2_valid - это просто определение для определения сверточного слоя, а W_conv1 и b_conv1 - переменные, содержащие веса и смещения. Я, вероятно, мог бы удалить термин смещения, потому что мы используем пакетную нормализацию.
Сеть сейчас работает хорошо. Я заметил после построения графиков точности в режиме обучения и тестирования, что точность тестирования начинает расти после точности обучения. Оглядываясь назад, это имеет смысл, поскольку мы собираем статистику набора данных для тестирования. Но казалось, что во время первых тестов я делал что-то не так. Спасибо за ваши комментарии и за то, что сделали пакетную нормализацию доступной для сообщества.
@nmhkahn чем это отличается от предложения pawni?
@ brando90 В моей версии была небольшая ошибка, которую исправил nmhkahn (изменение isTraining
на is_training
)
@diegoAtAlpine Я обнаружил те же проблемы, но не уверен, почему это так. Однако ошибка ValueError должна быть устранена с помощью фрагмента кода. Не уверены, что вы хотите увидеть, как это назвать, поскольку примеры nmhkahn, кажется, делают свою работу?
@nmhkahn @pawni @ когда вы делаете:
sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=True})
не означает ли это, что вы используете is_training
в качестве заполнителя? Люди прокомментировали, что они хотят, чтобы is_training
был заполнителем, но это то, что у меня было для моей версии:
def batch_norm_layer(x,train_phase,scope_bn):
bn_train = batch_norm(x, decay=0.999, center=True, scale=True,
is_training=True,
reuse=None, # is this right?
trainable=True,
scope=scope_bn)
bn_inference = batch_norm(x, decay=0.999, center=True, scale=True,
is_training=False,
reuse=True, # is this right?
trainable=True,
scope=scope_bn)
z = tf.cond(train_phase, lambda: bn_train, lambda: bn_inference)
return z
это не правильно?
Я уже расширил tf.contrib.layers.batch_norm, чтобы разрешить передачу Tensor или Placeholder для is_training. Скоро он будет добавлен в TF contrib.
Теперь доступно в
https://github.com/tensorflow/tensorflow/commit/9da5fc8e6425cabd61fc36f0dcc1823a093d5c1d#diff -94bbcef0ec8a5cdef55f705e99c2b2ed
это только у меня или добавление этого слоя BN заметно замедляет обучение отдельной эпохи?
@ brando90 Для меня это тоже замедляет обучение, но я думаю, что это ожидаемо, так как нужно вычислить некоторую статистику. И ваша версия мне нравится.
BatchNorm в настоящее время работает очень медленно (из-за всей вычисленной статистики), но они работают над добавлением операции cudnn batchnorm, как сказано здесь .
@nmhkahn быстрый вопрос. Когда вы написали (для тестирования):
sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=False})
по идее может bx и by быть любым набором данных? т.е. это может быть обучающий набор, даже если мы не обучаемся? (т.е. просто для отслеживания ошибки поезда)
@ brando90 ты прав.
Меня также смущают флаги is_training и reuse. Я создал программу по примеру CIFAR, где мой код структурирован как в CIFAR:
И я запускаю его в режиме multi-gpu (для обучения).
Итак, у меня есть один сценарий для обучения (похожий на cifar10_multigpu.py) и один для тестирования (похожий на cifar10_eval.py).
Так
for ii in xrange(2): # Num of GPU
with tf.device('/gpu:%d' % ii):
with tf.name_scope('device_%d' % ii) as scope:
data_batch, label_batch = factory.GetShuffleBatch(batch_size)
unnormalized_logits = factory.MyModel(dataBatch=data_batch, numClasses=numClasses,
isTraining=True)
More stuff happening
tf.get_variable_scope().reuse_variables()
Вывод происходит с функцией MyModel. (ниже пример функции, на самом деле я использую больше слоев и нейронов).
def MyModel(data_batch, num_classes, feature_dim):
# Hidden Layer 1
with tf.variable_scope('hidden1') as scope:
weights = variable_on_cpu('weights',[feature_dim, 256], tf.truncated_normal_initializer(stddev=0.04))
biases = variable_on_cpu('biases', [256], tf.constant_initializer(0.001))
hidden1 = tf.nn.relu(tf.matmul(data_batch, weights) + biases, name=scope.name)
# Hidden Layer 2
with tf.variable_scope('hidden2') as scope:
weights = variable_on_cpu('weights',[256, 256], tf.truncated_normal_initializer(stddev=0.04))
biases = variable_on_cpu('biases', [256], tf.constant_initializer(0.001))
hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases, name=scope.name)
# output, unnormalized softmax
with tf.variable_scope('softmax_unnorm') as scope:
weights = variable_on_cpu('weights', [256, num_classes], tf.truncated_normal_initializer(stddev=1/num_classes))
biases = variable_on_cpu('biases', [num_classes], tf.constant_initializer(0.0))
softmax_un = tf.add(tf.matmul(hidden2, weights), biases, name=scope.name)
return softmax_un
Я хочу провести номализацию партии. Итак, когда я это сделал:
def MyModel(data_batch, num_classes, feature_dim, isTraining):
with tf.variable_scope('bnormalization') as scope:
norm_data_batch = tcl.batch_norm(inputs=dataBatch, epsilon=0.0001, is_training=isTraining,
reuse=True, scope=scope)
# Hidden Layer 1
with tf.variable_scope('hidden1') as scope:
weights = variable_on_cpu('weights',[feature_dim, 256], tf.truncated_normal_initializer(stddev=0.04))
biases = variable_on_cpu('biases', [256], tf.constant_initializer(0.001))
hidden1 = tf.nn.relu(tf.matmul(data_batch, weights) + biases, name=scope.name)
На этапе обучения я получил следующую ошибку:
Переменная bnormalization / beta не существует, запрещена. Вы хотели установить reuse = None в VarScope?
Из того, что я читал в этой ветке на этапе обучения, я должен использовать reuse = None. Я правильно понял эту часть? Если это правда, то, поскольку я использую два GPUS, следует ли мне повторно использовать = None в первом графическом процессоре и повторно использовать = True во втором? Или, поскольку я делаю tf.get_variable_scope (). Reuse_variables (), он сам о себе позаботится?
Наконец, на этапе тестирования, должен ли я иметь is_training = False и reuse = True?
Любая помощь приветствуется.
Теперь tf.contrib.layers.batch_norm принимает тензор, переменную или заполнитель как is_training
https://github.com/tensorflow/tensorflow/commit/9da5fc8e6425cabd61fc36f0dcc1823a093d5c1d#diff -94bbcef0ec8a5cdef55f705e99c2b2ed
Нормально ли, что пакетная нормализация ухудшает мои эксперименты? Я попробовал это в двухуровневой сети NN на основе учебника MNIST для начинающих, и я постоянно получаю худшие результаты, когда присутствует BN: с BN (один с обучением шкалы и центра, а другой нет) точность составляет 0,8423, 0,8221 и точность без BN составляет 0,9477.
Мой скрипт присутствует здесь https://github.com/brando90/tensor_flow_experiments/blob/master/tf_tutorials/beginner_tutorial_MNIST_BN.py
кто-нибудь сталкивался с этими проблемами или BN просто такой, и мне нужно сделать что-то еще, чтобы он работал?
Последняя версия tf.contrib.layers.batch_norm теперь принимает заполнитель для is_training, поэтому нет необходимости делать это самостоятельно.
Но что важно, так это то, что вы либо передаете update_collections = None, чтобы moving_mean и moving_variance обновлялись на месте, в противном случае вам нужно будет собрать update_ops и убедиться, что они запущены.
Я хотел бы призвать вас использовать tf.contrib.layers
или tf.contrib.slim
для построения вашей модели.
slim = tf.contrib.slim
def build_NN_two_hidden_layers(x, is_training):
batch_norm_params = {'is_training': is_training, 'decay': 0.9, 'updates_collections': None}
with slim.arg_scope([slim.fully_connected],
activation_fn=tf.nn.relu,
weigths_initializer=tf.contrib.layers.xavier_initializer(),
biases_initializer=tf.constant_initializer(0.1),
normalizer_fn=slim.batch_norm,
normalizer_params=batch_norm_params):
net = slim.fully_connected(x, 50, scope='A1')
net = slim.fully_connected(net, 49, scope='A2')
y = slim.fully_connected(net, 10, activation_fn=tf.nn.softmax, normalizer_fn=None, scope='A3')
return y
@sguada Я изменил свой старый, где я вручную
Кроме того, я заметил, что вы сказали, что это заполнитель, и мне не нужно было делать это вручную. Однако, когда я передал заполнитель для is_training, он сказал
TypeError: Using a
tf.Tensor as a Python
bool is not allowed. Use
если t не равно None: instead of
if t: to test if a tensor is defined, and use the logical TensorFlow ops to test the value of a tensor.
и указал на код batch_norm. Может быть, было бы неплохо показать, как следует использовать этот заполнитель, потому что, кажется, я не понимаю, как его предполагается использовать. Благодаря! :)
@ brando90
Соответствующая часть кода здесь L227-256 .
Как вы заметите, есть инструкция with ops.control_dependencies
которая вызывает обновления. Я считаю, что для использования кода "прямо из коробки" значение по умолчанию должно быть None.
Что касается моего комментария выше 1122 , я выяснил, что tf.get_variable_scope (). Reuse_variables () решает эту проблему, поэтому на этапе обучения повторное использование аргумента batch_norm должно быть None. Это связано с оператором variable_op_scope (прочтите его документацию в tenorflow)
Использование batch_norm с tf.placeholder
x = tf.placeholder(tf.float32, [None, 784])
is_training = tf.placeholder(tf.bool, [], name='is_training')
y = build_NN_two_hidden_layers(x, is_training)
# For training
sess.run(y, {is_training: True, x: train_data})
# For eval
sess.run(y, {is_training: False, x: eval_data})
Раньше проблема заключалась в том, что вы не обновляли moving_mean
и moving_variance
после каждого шага, когда для updates_collections установлено значение None, это заставляет обновления как часть вычислений.
Однако, когда в сети много уровней batch_norm, более эффективно собирать все операции обновления и запускать их вместе, поэтому каждому слою не нужно ждать завершения обновления.
y = build_model_with_batch_norm(x, is_training)
update_ops = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
sess.run([y, update_ops])
Достигнут ли какой-либо прогресс в повышении скорости загрузки партии?
Я пытался использовать пакетную норму с двухуровневой плотно связанной NN с набором данных (сглаженных) MNIST (и relu units) для задачи автоматического кодирования, и я продолжаю получать ошибку NaN. Кто-нибудь знает, почему это могло быть? Возможно ли такое с BN? кажется подозрительным, но это не может быть моя настройка обучения, оценка и т. д. (но я предполагаю, что этого не должно быть, потому что BN должен быть чем-то вроде этого)
@sguada Я не понимаю, как правильно использовать batch_norm
специально для флага updates_collections
. Если я правильно понял, если установлен флаг None
сеть неэффективна, поэтому я должен позволить updates_collections=tf.GraphKeys.UPDATE_OPS
а затем я должен собрать все обновления batch_norm и запустить их вместе.
Вы собираете обновления batch_norms, выполнив: update_ops = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
.
У меня много разных моделей, использующих разные слои batch_norm, это не сработает ?:
#model 1
y1 = build_model_with_batch_norm(x, is_training)
update_ops1 = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
sess.run([y1, update_ops1])
#model 2
y2 = build_model_with_batch_norm(x, is_training)
update_ops2 = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS))
sess.run([y2, update_ops2])
Не могли бы вы объяснить эту часть поподробнее? Большое спасибо.
Просто поместите его в отдельные ключи коллекции:
# While building your 1st model...
tf.contrib.layers.batch_norm(..., updates_collection="updates-model1")
# same for 2nd model with key "updates-model2"
#model 1
y1 = build_model_with_batch_norm(x, is_training)
update_ops1 = tf.group(tf.get_collection("updates-model1"))
sess.run([y1, update_ops1])
#model 2
y2 = build_model_with_batch_norm(x, is_training)
update_ops2 = tf.group(tf.get_collection("updates-model1"))
sess.run([y2, update_ops2])
Тем не менее, документация кажется устаревшей. Он говорит сделать следующее:
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
if update_ops:
updates = tf.group(update_ops)
total_loss = control_flow_ops.with_dependencies([updates], total_loss)
Но:
РЕДАКТИРОВАТЬ:
Документация должна быть обновлена до s.th. как это:
from tensorflow.python import control_flow_ops
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
if update_ops:
updates = tf.tuple(update_ops)
total_loss = control_flow_ops.with_dependencies(updates, total_loss)
РЕДАКТИРОВАТЬ 2:
После нескольких запусков в моей сети я должен сказать, что я не вижу никакой разницы в производительности между использованием _updates_collections = None_ в отличие от ручного извлечения _tf.GraphKeys.UPDATE_OPS_ при построении графика . Даже при интенсивном использовании пакетной нормализации (всего мой _tf.get_collection (tf.GraphKeys.UPDATE_OPS) _ возвращает 140 Update-Ops, все они только BN-операции)
Изменить: трудно сказать, если мои результаты верны, но вся сеть действительно работает в 1,5 раза быстрее. Насколько мне известно, BN-статистика пока рассчитывается на CPU, а не на GPU.
Может ли кто-нибудь из вас увидеть какие-либо преимущества в производительности? Поделитесь своими результатами :)
Возвращаясь к проблеме производительности, подходит ли вообще текущий уровень пакетных норм от использования графического процессора? Кто-нибудь испытал преимущества графических процессоров с этой реализацией пакетной нормы?
Извините за спам, но в документации на самом деле не объясняется, как использовать этот BN со сверткой (может быть, нужно где-то предоставить?). Короче говоря, как понять, что он должен применять и изучать одни и те же параметры для каждой функции (а не для каждой активации)?
(Есть ли хотя бы фрагмент кода для этого?)
Тонкая оболочка batch_norm нормализует последнее измерение вашего входного тензора. Таким образом, если это двумерный входной тензор, поступающий из полностью связанного слоя, он нормализуется в пакетном режиме и, таким образом, выполняет нормализацию для каждой активации. Если это 4-мерный тензор, полученный из свертки, он будет нормализоваться по трем первым измерениям (пакет, ширина, глубина) и, таким образом, выполнять нормализацию для каждой функции. @sguada, может быть, более подробно
@nmhkahn Что касается вашего фрагмента кода, могу ли я спросить, почему для reuse
установлено значение None
когда is_training=True
? Разве это не приведет к повторной инициализации параметра масштабирования gamma
и параметра смещения beta
на каждом этапе обучения? В оригинальной статье я думал, что beta
и gamma
«изучаются вместе с параметрами исходной модели». Для этого не следует ли инициализировать их только один раз, а затем повторно использовать на всех этапах обучения?
tf.cond(is_training,
lambda: batch_norm(inputT, is_training=True, updates_collections=None, scope=scope),
lambda: batch_norm(inputT, is_training=False, updates_collections=None, scope=scope, reuse = True))
Я высоко ценю работу, которую команда TF проделала здесь, чтобы сделать batch_norm доступным и эффективным. Судя по моим поискам, эта ветка - лучший ресурс о том, как ее использовать. Здесь витает много разных проблем и идей, и трудно понять консенсусный совет для простейшего стандартного случая использования слоя batch_norm. Я думаю, было бы очень полезно расширить документацию, чтобы указать точное рекомендуемое использование.
Моя лучшая попытка выяснить это привела меня к следующему коду:
is_training_ph = tf.placeholder(tf.bool)
...
with tf.variable_scope('bn_test_layer') as vs:
layer_output = tf.cond(is_training_ph,
lambda: tf.contrib.layers.batch_norm(layer_input, is_training=True, center=True, scale=True, activation_fn=tf.nn.relu, updates_collections=None, scope=vs),
lambda: tf.contrib.layers.batch_norm(layer_input, is_training=False, center=True, scale=True, activation_fn=tf.nn.relu, updates_collections=None, scope=vs, reuse=True))
Затем я установил для is_training_ph значение True для обучения и False для тестирования. У меня это не работает. Тренируется модель отлично, но на тестах ужасно. Напротив, если я поддерживаю is_training_ph = True на время тестирования, он отлично работает. Таким образом, я предполагаю, что у меня все еще есть проблема с областью видимости, так что она не может найти правильные существующие переменные.
@ davek44 Я использую ту же структуру кода, что и вы, и наблюдал то же самое: когда включает is_training=True
во время фазы обучения и выключает is_training=False
для фазы проверки и / или тестирования, модель обучается хорошо, как описано в статье (модель сходится быстрее, и я смог использовать более высокую скорость обучения), однако производительность тестирования ужасна. Если я все время включаю is_training=True
, модель обучается так же, как и без вставки слоя пакетных норм. Не разобрался, что сделал не так, планирую использовать TensorBoard для контроля параметров. Не могли бы вы обновить, если вы диагностируете причину такого поведения?
tf.contrib.layers.batch_norm может принимать тензор как is_training, поэтому ничего особенного делать не нужно.
is_training_ph = tf.placeholder(tf.bool)
outputs = tf.contrib.layers.batch_norm(layer_input, is_training=is_training_ph, center=True, scale=True, activation_fn=tf.nn.relu, updates_collections=None, scope='batch_norm'),
Я вижу такую же низкую производительность теста с этим кодом.
Без дополнительных деталей узнать невозможно, я предполагаю, что вы тренируетесь только для нескольких итераций, поэтому moving_mean и moving_average еще не сходятся.
Вы можете изменить batch_size во время теста, чтобы увидеть, как снижается производительность при уменьшении размера пакета.
Я вижу такую же низкую производительность теста с этим кодом.
У меня была точно такая же проблема либо с tf.slim batchnorm, либо с tf.cond и вводом is_training в качестве заполнителя.
В первом случае, исследуя обученную модель, я обнаружил, что скользящее среднее и скользящая дисперсия состоят из нулей.
В последнем случае скользящее среднее и дисперсия выглядят более разумными (с разными значениями), но если я использую is_training = False во время тестирования, производительность также будет очень плохой. Используя is_training = True, он работает лучше, но я думаю, что он использует только скользящее среднее и дисперсию внутри тестовой партии.
@nmduc @ davek44 Я написал код для отслеживания скользящего среднего и скользящей дисперсии, вычисленных в tf.contrib.layers.batch_norm
во время обучения и тестирования. Я обнаружил, что значение decay
имеет большое значение (они используют экспоненциальное затухание для вычисления скользящего среднего и скользящей дисперсии) с параметром decay
близким к 1.0 (т.е. decay=.999
), скользящее среднее падает до значения, близкого к 0. Я выполнил 2 тестовых прогона с одним и тем же кодом, но с разными настройками decay
в tf.contrib.layers.batch_norm
, и моя точность проверки / тестирования показалась мне более разумной.
Результаты тестового запуска с decay=0.9
Результаты тестового запуска с decay=0.999
( decay=0.999
- настройка по умолчанию в tf.contrib.layers.batch_norm
)
(также кажется, что большее значение затухания потребовало бы, чтобы модель тренировалась дольше, чтобы увидеть изменение точности проверки)
Ага, это исправило. Спасибо, что поделились своим анализом @zhongyuk!
Я рекомендую разработчикам рассмотреть возможность использования decay = 0.9 по умолчанию. Даже 0.99 мне не подходит. Это значение по умолчанию и в реализации Torch; см. параметр импульса в https://github.com/torch/nn/blob/master/BatchNormalization.lua
@zhongyuk Спасибо, что поделились. У меня это работает сейчас.
Это кажется важным. @sguada, мы должны продумать правильный decay
возможно, придется значительно снизить при низкой производительности eval? Я почти уверен, что мне никогда не приходилось настраивать этот параметр, но это может быть побочным эффектом распределенной настройки.
Мы могли бы изменить значение по умолчанию на 0,9 или лучше задокументировать его влияние в небольших наборах данных или нескольких обновлениях.
@vincentvanhoucke в нашей распределенной среде мы обычно делаем миллионы обновлений, так что это нормально, однако в других случаях, таких как здесь, где выполняется всего несколько сотен обновлений, это имеет большое значение:
Например, использование decay = 0,999 дает смещение 0,36 после 1000 обновлений, но это смещение снижается до 0,000045 после 10000 обновлений и до 0,0 после 50000 обновлений.
Просто хотел отметить, что у меня также есть проблема плохой производительности теста, особенно при использовании небольших пакетов (все, что меньше 10, а не 200, которые я использовал для обучения, снижает точность теста). Я использовал tf.placeholder для переключения между режимами тестирования / обучения.
Замечательно, что этот слой пакетной нормализации работает для лучшей сходимости обучения, но если вы не можете применить модель в производстве, нет особого смысла в ее использовании. Может ли кто-нибудь подтвердить хорошую производительность теста с небольшими или отдельными выборками данных, используя этот слой пакетных норм?
Я могу подтвердить, что производительность теста хорошая при использовании is_training = False с небольшими партиями и даже с batch_size = 1, поскольку он не использует статистику из партии, а статистику, полученную во время обучения. Просто нужно убедиться, что статистика сошлась с затуханием по умолчанию = 0,999, что подразумевает как минимум 50k обновлений.
Чтобы следить за подтверждением разработчика TF, я отслеживаю сходимость статистики с двумя разными настройками decay
(и обучающей batch_size = 1). При decay=0.99
статистика сходится (смещение <0,001) после 550 ~ 600 шагов обучения / обновления. При decay=0.9
статистика сходится (смещение <0,001) в пределах 100 шагов обучения / обновления.
@sguada, спасибо, это также означает, что вывод фактически не зависит от размера партии? потому что я замечаю очень незначительные изменения, которые сильно влияют на мою точность (возможно, это небольшое изменение повлияет на мое определение производительности). Чтобы быть точным, все значения в моем 128-мерном выходном тензоре увеличиваются так, что общая длина вектора почти линейно масштабируется с размером пакета. По значению это не такая уж большая разница, но имеет большое влияние при вычислении векторных расстояний в скрытых пространствах.
@zhongyuk, спасибо, я запустил около 5k обновлений с decay=0.9
, так что он должен был сойтись, и тестирование производительности с использованием больших пакетов в порядке. Но даже если бы этого не произошло, приведет ли это к разнице между обучением и тестированием? Я бы увидел плохую производительность во время обучения и тестирования, если бы он не сходился, верно?
Я исследую еще немного и посмотрю, смогу ли я воспроизвести проблему в другой задаче. Спасибо за быструю обратную связь!
@dominikandreas Если ваша низкая производительность тестирования вызвана
Я обнаружил ошибку в моем коде, теперь пакетная нормализация работает нормально :-) спасибо за вашу поддержку
Привет @zhongyuk , как ты отслеживал скользящее среднее и дисперсию?
Благодаря!
@rogertrullo Обычно я настраиваю TensorBoard для отслеживания скользящего среднего и дисперсии. Помимо этого, я также попытался получить статистику через tf.get_variable("moving_mean")
пределах области во время обучения и ссылку для отслеживания смещения.
Привет,
У меня такая же проблема, как и у других, описанных, что у меня хорошие результаты обучения, но проверка / тестирование плохие после использования batch_norm.
Я использую такую функцию:
conv_nformed1 = tf.contrib.layers.batch_norm (conv1 + block1_layer3_1_biases, updates_collections = None, scale = True, decay = batch_norm_decay, center = True, is_training = is_training)
значение распада 0,9
мне нужно установить флаг повторного использования?
Буду рад любой помощи.
Я использовал batch_norm, как описано в этом потоке (с tf.bool для обучения; и ops.GraphKeys.UPDATE_OPS), и все работает.
При сохранении и восстановлении используют:
saver = tf.train.Saver ()
оно работает,
но при сохранении с использованием:
saver = tf.train.Saver (tf.trainable_variables () + [global_step])
чтобы я мог сэкономить место для хранения (не сохраняя градиенты и т. д.)
при восстановлении возникает ошибка:
"неинициализированное значение unpool4 / convc / bn / moving_mean"
Очевидно, это потому, что moving_mean (и я предполагаю, что moving_variance) не был сохранен ни для одного из слоев. Поскольку у меня их много (вложено во множество слоев), как лучше всего добавить их в список значений для сохранения? Кроме того, учитывая, что это обучаемые переменные, почему они не добавляются в коллекцию trainable_variables?
Скользящее среднее и дисперсия @mshunshin не являются обучаемыми переменными: к ним не приходят градиенты, они просто накапливают статистику по мини-сериям примеров.
Чтобы сохранить / восстановить их, вы можете использовать tf.global_variables ()
у меня все начало работать, когда я использовал эту оболочку:
def batch_norm_wrapper(x, phase, decay, scope, reuse):
with tf.variable_scope(scope, reuse=reuse):
normed = tf.contrib.layers.batch_norm(x, center=True, scale=True, decay=decay, is_training=phase, scope='bn',updates_collections=None, reuse=reuse)
return normed
На мой взгляд, в этой ветке не совсем понятно использование областей видимости и повторного использования.
Большое спасибо. С tf.global_variables () файлы сохранения намного больше, поскольку я думаю, что он включает градиенты; в итоге я использовал:
saver = tf.train.Saver ([x вместо x в tf.global_variables (), если «Адам» не в x.name])
и поскольку инициализация диспетчера сеансов не инициализирует их должным образом:
сесс.run (tf.variables_initializer ([x вместо x в tf.global_variables (), если «Адам» в x.name]))
(Используя tf.train.AdamOptimizer)
Вы также можете использовать tf.model_variables (), который содержит переменные модели, например moving_mean
@sguada Извините за беспокойство, но можно ли сделать пример использования slim.batch_norm в сочетании с slim.conv2d / slim.fully_connect в readme.md?
Я использую slim.batch_norm, но получаю хорошую производительность обучения и плохую производительность проверки / тестирования. Я думаю, это должно быть из-за неправильного использования reuse
или scope
или некоторых других параметров. Хотя есть много проблем с пакетной нормализацией, трудно найти полный фрагмент кода о том, как ее использовать, особенно. о том, как передавать разные параметры в разные фазы.
Скажем, в моем коде mnist_bn я контролировал зависимости с помощью tf.GraphKeys.UPDATE_OPS
и установил is_training
в качестве заполнителя. Но эффективность проверки все равно будет низкой, если я скармливаю {is_training: False}.
Я был бы очень признателен, если бы был официальный и полный (что означает, что обучение, проверка, тестирование включены) пример пакетной нормализации.
Заранее спасибо!
Привет,
вам нужно установить разную область видимости для каждого раза, когда вы используете пакетную норму, и дать ей вход повторного использования в соответствии с фазой обучения / тестирования (ИСТИНА при тесте ЛОЖЬ при обучении), который работает для меня.
@ishaybee Спасибо за помощь. Я обнаружил свою проблему = = Это из-за холодного запуска moving_mean / moving_variance.
Поскольку я не тренировал достаточно шагов, расчетное скользящее среднее / дисперсия не так стабильно. В результате получается: модель довольно хорошо работает на обучающих мини-пакетах (вы знаете, что вначале потери быстро снижаются), но эффективность проверки нестабильна (потому что расчетное среднее / дисперсия совокупности недостаточно стабильно).
Когда я тренировал модель дольше, точность проверки также становится лучше.
Еще одна важная вещь: не забудьте использовать slim.learning.create_train_op
для создания операции поезда . Не используйте tf native tf.train.GradientDescentOptimizer(0.1).minimize(loss)
.
Итак, ответ: я правильно использую пакетную нормализацию, но не совсем понял ее динамику во время обучения.
================
Более того:
@soloice , обратите внимание, как насчет комментария следующий параметр передается внутри на уровень для вызова batch_norm:
batch_norm_params = {'is_training': is_training, 'decay': 0.9, 'updates_collections': нет}
Без updates_collections
установленного в None (так что средние обновления выполняются внутри BatchNorm), я не ожидаю, что окружающий слой (например, conv2d) каким-то образом выполнит tf.GraphKeys.UPDATE_OPS, необходимый для уровня BatchNorm для обновления текущего среднего и поэтому позже можно будет запустить тестовые данные.
Или вы можете попробовать запустить UPDATE_OPS самостоятельно как один здесь
update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS)
if update_ops:
updates = tf.group(*update_ops)
cross_entropy = control_flow_ops.with_dependencies([updates], cross_entropy)
Обновление - я обнаружил, что процитировал именно ваш код, и вы действительно используете UPDATE_OPS.
Что касается «холодного старта», как вы видите выше при обсуждении, уменьшение рабочего среднего спада BatchNorm (входной параметр) с 0,999 по умолчанию до примерно 0,95 может ускорить запуск.
@pavelbulanov Очень любезно с вашей стороны помогли мне в этом! Я попробую меньшее значение decay
чтобы увидеть, как это поможет.
================
Обновление: использование небольшого затухания (скажем, 0,9 или 0,95) очень помогает. Потери валидации уменьшаются очень быстро, когда я устанавливаю decay
на 0,9. Однако недостатком небольшого спада является то, что его эффективный диапазон невелик: в результате преобладают несколько недавних выборок, поэтому это не очень хорошая оценка среднего / дисперсии генеральной совокупности. Необходимо балансировать между быстрым запуском (небольшой спад) и более длинным эффективным диапазоном (большой спад).
Привет,
Я попытался реализовать уровень пакетной нормализации с помощью предложений в этом выпуске, но у меня все еще есть ошибка> 70% при проверке и тестировании ... У меня более низкий спад для вызовов без обучения ...
Вот мой код:
def BatchNorm(inputT, is_training=False, scope=None):
return tf.cond(
is_training,
lambda: tf.contrib.layers.batch_norm(inputT, is_training=True, reuse=None, decay=0.999, epsilon=1e-5, center=True, scale=True, updates_collections=None, scope=scope),
lambda: tf.contrib.layers.batch_norm(inputT, is_training=False, reuse=True, decay=0.900, epsilon=1e-5, center=True, scale=True, updates_collections=None, scope=scope)
)
Заранее спасибо.
@Alexivia Кажется, вы используете два разных уровня пакетной нормализации? Вы должны использовать только один слой BN (конечно, с другим параметром is_training
).
Спасибо за совет @soloice.
Я пробовал сейчас с разными параметрами is_training
и reuse
:
lambda: tf.contrib.layers.batch_norm(inputT, is_training=True, reuse=None, decay=0.9, epsilon=1e-5, center=True, scale=True, updates_collections=None, scope=scope),
lambda: tf.contrib.layers.batch_norm(inputT, is_training=False, reuse=True, decay=0.9, epsilon=1e-5, center=True, scale=True, updates_collections=None, scope=scope)
по-прежнему не получают хороших результатов валидации и тестирования ...> 70% ...
Привет,
пожалуйста, смотрите мою обертку выше.
вы должны использовать "with tf.variable_scope (scope, reuse = reuse):" Я думаю.
Привет @ishaybee!
Я последовал твоему совету, теперь мой код:
def BatchNorm(inputT, is_training=False, reuse=True, scope=None):
with tf.variable_scope(scope, reuse=reuse):
return tf.contrib.layers.batch_norm(inputT, is_training=is_training, reuse=reuse, scope=scope, updates_collections=None, decay=0.9, center=True, scale=True)
и я кормлю is_training
и reuse
через feed_dict, но теперь я получаю сообщение об ошибке ValueError("The reuse parameter must be True or False or None.")
попробуйте повторно использовать канал как переменную Python (вход модели) и как заполнитель.
Я попробовал это, и теперь он перестал жаловаться на значение ... но я думаю, что значение заполнителя не используется, потому что я не вижу изменений, если я принудительно использую значения для функции batch_norm
, а в TensorBoard это не так. подключен к графику ... (см. прикрепленное изображение)
Мой код сейчас такой:
Обертка пакетной нормализации
def BatchNorm(inputT, is_training=False, reuse=None, scope=None):
with tf.variable_scope(scope):
return tf.contrib.layers.batch_norm(inputT, is_training=is_training, reuse=reuse, scope=scope, updates_collections=None, decay=0.9, center=True, scale=True)
Определение модели
def model(data, train=False, is_training=False, reuse=None):
# 1st conv layer
with tf.name_scope('conv1') as scope:
conv = tf.nn.conv2d(
<...>
norm = BatchNorm(pool, is_training=is_training, reuse=reuse, scope=scope)
Тренировка
feed_dict = {train_data_node: batch_data,
train_labels_node: batch_labels,
is_training: True,
reuse: None}
# Run the optimizer to update weights.
sess.run(optimizer, feed_dict=feed_dict)
Проверка
batch_predictions = sess.run(eval_prediction, feed_dict={eval_data: data[-EVAL_BATCH_SIZE:, ...], is_training: False, reuse: True})
Хотя is_traning может повторное использование заполнителя, должно быть логическим значением, и оно не может быть тензором или заполнителем.
Я не уверен, что вы пытаетесь сделать, в большинстве случаев использование статических значений решает проблему. Например, хорошо работает этот паттерн:
def model(data, is_training=False, reuse=None, scope='my_model'):
# Define a variable scope to contain all the variables of your model
with tf.variable_scope(scope, 'model', data, reuse=reuse):
# 1 layer
net = tf.contrib.layers.conv2d(data, ....)
....
net = tf.contrib.layers.batch_norm(net, is_training)
return net
train_outputs = model(train_data, is_training=True)
eval_outputs = model(eval_data, is_training=False, reuse=True)
eval_predictions = sess.run(eval_outputs, feed_dict={eval_data: data[-EVAL_BATCH_SIZE:, ...]})
Если вам не нужно динамически изменять поведение модели, вам не нужно использовать заполнитель для is_training. Уловка состоит в том, чтобы построить модель дважды, но во второй раз использовать переменные.
Спасибо @sguada ! После применения ваших предложений я наконец-то заработал!
Было бы полезно, если бы в документации API 1.0 было указано, что вам нужно вручную добавлять операции обновления на график. Будучи более новым пользователем tf, я обнаружил, что моя тестовая ошибка была сумасшедшей, и затем мне пришлось потратить изрядное количество времени на отладку моего графика, пока я не понял, что проблема была в пакетной нормализации. Затем мне пришлось потратить больше времени на выяснение того, что по умолчанию переменные, отслеживающие моменты, не обновляются, если вы не используете функцию contrib для оптимизации. Поскольку в 1.0 нет возможности установить update_collections на None, в документации нет указателя на то, что это может быть проблемой. Кроме того, кажется, что имеет смысл иметь параметр для добавления зависимостей потока управления к операции, выполняемой в обучающем примере.
@danrsc Именно так. Использование слоя BN довольно запутанно. Я предложил добавить документы или полное официальное руководство по пакетной нормализации, но, к сожалению, не получил ответа = =
Полностью согласен. Я думаю, что использование BN очень сложно, а документация в настоящее время неадекватна. Это должно быть исправлено для такого часто используемого слоя.
Повторное открытие для видимости проблем с документацией.
@sguada назначает вам сортировку. Может, стоит привлечь к делу технического писателя.
Просто запутался в этой проблеме на прошлой неделе и потратил 3 дня на обучение ... Надеюсь, что документация скоро будет исправлена, и официальный пример пакетной нормализации можно будет добавить в документацию API.
@sguada Я заметил, что вы сказали: «tf.contrib.layers.batch_norm может принимать тензор как is_training, поэтому не нужно делать ничего особенного».
Howerver, комментарий в коде
Если is_training
не имеет постоянного значения, потому что это Tensor
,
# a Variable
или Placeholder
тогда is_training_value будет None и
# needs_moments
будет истинным.
Означает ли это, что nees_moments будет истинным даже на этапе тестирования, если я установлю is_training в качестве заполнителя?
Насколько я знаю, при тестировании моментов не нужно.
Итак, если is_training
- это Variable
или Placeholder
, это означает, что он может изменяться, поэтому необходим график для вычисления моментов, поэтому слой строит его.
Затем во время выполнения в зависимости от значения True
или False
будет использовать пакет moments
или moving_mean
и moving_variance
.
Поэтому во время тестирования вы должны установить значение False
а moments
не будет использоваться.
@sguada @ brando90
def batch_norm_layer(self, x,train_phase, scope_bn):
bn_train = batch_norm(x, decay=0.9, center=False, scale=True,
updates_collections=None,
is_training=True,
reuse=None,
variables_collections= [UPDATE_OPS_COLLECTION],
trainable=True,
scope=scope_bn)
bn_inference = batch_norm(x, decay=0.9, center=False, scale=True,
updates_collections=None,
is_training=False,
reuse=True,
variables_collections= [UPDATE_OPS_COLLECTION],
trainable=True,
scope=scope_bn)
z = tf.cond(train_phase, lambda: bn_train, lambda: bn_inference)
return z
Я строю такой батчнорм, однако скользящее среднее и подвижная переменная обновляются во время теста, я не могу найти причину.
Я попытался создать две модели, как сказал @sguada , однако моя модель, где is_training = False, просто дает сбой.
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key fully_connected_5/weights not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key fully_connected_6/weights not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key fully_connected_7/biases not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key fully_connected_6/biases not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key fully_connected_7/weights not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key history_embeddings_1 not found in checkpoint
W tensorflow/core/framework/op_kernel.cc:993] Not found: Key global_step_1 not found in checkpoint
Я чувствую, что, возможно, должен быть конкретный пример того, как выполнять пакетную норму с полностью подключенной сетью, а также с CNN. Отстой, что я тренировал моделей несколько дней, ожидая, что все заработает, прежде чем увидел, что все, пытающиеся использовать эту функцию, сходят с ума.
Достаточно интересно, что на восстановление модели после обучения с помощью batch_norm уходит миллион лет. Скорее всего, подождет до TF 2.0, чтобы снова попробовать что-то подобное.
@MisayaZ вам не нужно создавать два слоя batch_norm, вы можете просто передать train_phase (при условии, что это tf.bool) в batch_norm. Также вы передаете UPDATE_OPS_COLLECTION variables_collections, которые изменяют, в какие коллекции добавляются переменные.
Следующее должно работать:
z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None,
is_training=train_phase, scope=scope_bn)
@OktayGardener не уверен, какую модель вы пытаетесь создать, похоже, что переменные не сохранены в вашей контрольной точке.
batch_norm также работает с полностью подключенными слоями.
slim = tf.contrib.slim
def model(data, is_training=False, reuse=None, scope='my_model'):
# Define a variable scope to contain all the variables of your model
with tf.variable_scope(scope, 'model', data, reuse=reuse):
# Configure arguments of fully_connected layers
with slim.arg_scope([slim.fully_connected],
activation_fn=tf.nn.relu,
normalizer_fn=slim.batch_nom):
# Configure arguments of batch_norm layers
with slim.arg_scope([slim.batch_norm],
decay=0.9, # Adjust decay to the number of iterations
update_collections=None, # Make sure updates happen automatically
is_training=is_training, # Switch behavior from training to non-training):
net = slim.fully_connected(data, 100, scope='fc1')
net = slim.fully_connected(net, 200, scope='fc2')
....
# Don't use activation_fn nor batch_norm in the last layer
net = slim.fully_connected(net, 10, activation_fn=None, normalizer_fn=None, scope='fc10')
return net
@sguada Спасибо, я создаю сеть с помощью bathnorm, которая реализована, как вы упомянули выше
z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None,
is_training=train_phase, scope=scope_bn)
скорость низкая, я использую тест tenorflow, чтобы получить время вычисления, как показано ниже:
I tensorflow / core / util / stat_summarizer.cc: 392] ============================== Вверх по времени вычислений === ===========================
I tensorflow / core / util / stat_summarizer.cc: 392] [тип узла] [начало] [первый] [avg ms] [%] [cdf%] [mem KB] [Name]
I tensorflow / core / util / stat_summarizer.cc: 392] Conv2D 106.164 51.354 51.004 23.145% 23.145% 692.224 conv8 / Conv2D
I tensorflow / core / util / stat_summarizer.cc: 392] Conv2D 85.187 19.115 19.283 8.750% 31.896% 692.224 conv7 / Conv2D
I tensorflow / core / util / stat_summarizer.cc: 392] SquaredDifference 11.967 15.105 14.331 6.503% 38.399% 11075.584 conv1 / batch_norm / Moments / Достаточная_статистика / SquaredDifference
I tensorflow / core / util / stat_summarizer.cc: 392] Mul 11.970 14.162 13.495 6.124% 44.523% 11075.584 conv1 / batch_norm / batchnorm / mul_1
I tensorflow / core / util / stat_summarizer.cc: 392] Conv2D 3.948 8.170 7.986 3.624% 48.146% 11075.584 conv1 / Conv2D
I tensorflow / core / util / stat_summarizer.cc: 392] Sub 11.960 10.176 7.943 3.604% 51.751% 11075.584 conv1 / batch_norm / Moments / Достаточная_статистика / Sub
I tensorflow / core / util / stat_summarizer.cc: 392] SquaredDifference 45,570 5,908 7,177 3,257% 55,007% 5537,792 conv2 / batch_norm / Moments / Достаточная_статистика / SquaredDifference
I tenorflow / core / util / stat_summarizer.cc: 392] Mul 45,574 7,755 6,902 3,132% 58,140% 5537,792 conv2 / batch_norm / batchnorm / mul_1
I tensorflow / core / util / stat_summarizer.cc: 392] Conv2D 40,692 5,408 4,845 2,199% 60,338% 5537,792 conv2 / Conv2D
I tensorflow / core / util / stat_summarizer.cc: 392] Sub 45.563 6.067 4.784 2.171% 62.509% 5537.792 con
Я не понимаю, почему во время теста выполняются некоторые операции в момент, и это требует много времени, например, conv1 / batch_norm / moment / enough_statistics / SquaredDifference.
Момент не нужен в тесте, почему выполняются некоторые операции под моментом?
Привет,
Используя указанный выше слой batch_norm
в contrib.layers
, я получаю nan
в качестве выходных данных для графика проверки, в то время как график поездов работает без проблем. Есть ли что-нибудь, что мне может не хватать?
Я использую:
def batchnormlayer(inputs, numout, train_model):
with tf.variable_scope("batch_norm") as scope_bn:
epsilon = 1e-3
return tf.contrib.layers.batch_norm(inputs, decay=0.9, updates_collections=None,
scale=True, scope=scope_bn,
is_training=train_model, epsilon=epsilon,
fused=True, reuse=scope_bn.reuse)
благодаря
В качестве продолжения я повторно использую 16 слоев batch_norm.
Однако я обнаружил, что повторное использование 4 слоев работает.
Я только что заметил, что если я убью процесс тензорного потока и перезапущу его, моя ошибка станет хуже на несколько эпох (т.е. хуже, чем она должна быть на последней контрольной точке). Я также заметил, что если я удалю batch_norm, эта проблема исчезнет. Посмотрев на код некоторое время, я думаю, что это может быть связано с тем, что значения переменных не восстанавливаются из теневых переменных, как если бы класс ExponentialMovingAverages использовался для управления скользящими средними. Это также означает, что если я использую отдельный процесс для оценки, я получаю то, что было последним значением переменной, а не скользящее среднее. Правильно ли я интерпретирую это, и это предполагаемое поведение? Похоже, вы хотите, чтобы значения переменных тени были восстановлены ...
Я поймал проблему, скользящая дисперсия в моем случае становится отрицательной после нескольких итераций.
Вывод тензора: Model/clip_logits/batch_norm/moving_variance:0
присутствует в tf.model_variables()
есть
Moving variance (shape = (101,)) =
[ 214.70379639 95.36338043 0.57885742 189.49542236 102.72473145
137.14886475 286.57333374 111.06427002 154.98750305 167.75219727
207.83955383 211.14007568 158.23495483 171.61665344 116.81361389
115.77380371 43.59399796 137.75064087 181.75245667 161.37339783
215.21934509 92.88521576 191.23846436 336.3946228 259.85919189
299.47039795 186.23222351 165.19311523 262.82446289 170.11567688
233.56843567 209.35050964 115.96807861 154.34109497 295.5770874
123.6055603 295.76187134 296.88583374 240.88217163 247.32983398
87.15661621 217.69897461 133.00698853 -4.80375671 344.77462769
291.50601196 117.77174377 265.83712769 207.90093994 194.186203
220.21418762 178.03738403 115.27571869 196.62184143 228.8089447
191.53205872 331.36807251 151.55435181 197.2951355 179.67504883
181.09727478 90.09922791 173.30133057 102.6836853 160.9434967
236.59512329 168.05305481 403.36340332 41.14326096 185.93409729
130.57434082 266.31509399 101.44387817 163.88059998 290.25015259
244.52597046 229.86647034 158.14352417 202.68774414 187.78227234
248.78218079 126.0978241 171.41891479 274.40740967 119.84254456
202.53045654 200.20608521 214.04730225 111.53284454 222.03184509
244.81187439 172.23052979 187.09806824 194.62802124 255.26345825
293.63598633 307.91036987 210.86982727 308.88919067 144.94792175
229.69013977]
Как видите, для одного измерения существует отрицательная дисперсия. Как это вообще возможно ?
PS Уровень пакетных норм используется сразу после последнего полностью подключенного уровня сети и перед softmax.
@ raghavgoyal14 вы используете его с fused = True? Была аналогичная проблема, и она исчезла, когда я использовал слитую версию
@abred : Да, я использовал fused=True
, та же проблема.
@sguada Привет, sguada, у меня проблема.
Определение contrib.layers.batch_norm в тензорном потоке:
def batch_norm (входы,
распад = 0,999,
center = True,
scale = False,
эпсилон = 0,001,
Activation_fn = Нет,
param_initializers = Нет,
param_regularizers = Нет,
updates_collections = ops.GraphKeys.UPDATE_OPS,
is_training = Истина,
повторное использование = Нет,
variables_collections = Нет,
output_collections = Нет,
trainable = True,
batch_weights = Нет,
fused = Ложь,
data_format = DATA_FORMAT_NHWC,
zero_debias_moving_mean = Ложь,
scope = None,
renorm = Ложь,
renorm_clipping = Нет,
renorm_decay = 0,99):
scale: если True, умножить на гамму. Если false, гамма
не используется. Когда следующий слой является линейным (например, nn.relu), это может быть
отключено, поскольку масштабирование может быть выполнено на следующем слое.
Если я использую tf.contrib.layers.batch_norm (input, scale = False), «scale = False» означает, равна ли гамма нулю в «y = gamma * x + beta» во время обучения. Большое спасибо.
Когда scale = False, гамма является постоянной 1.
@ppwwyyxx Большое спасибо за вашу помощь. Я использую tf.contrib.layers.batch_norm (input, scale = False) в Tensorflow, и теперь я конвертирую batchnorm Tensorflow в Caffe. Как установить параметры BatchNormLayer и ScaleLayer в Caffe?
Большое спасибо.
@MisayaZ У меня было такое же поведение при использовании Batchnorm с заполнителем для is_training. На трассировке я вижу, что моменты вычисляются даже во время тестирования, поэтому я решил обратиться к исходному коду и обнаружил следующее:
# If `is_training` doesn't have a constant value, because it is a `Tensor`,
# a `Variable` or `Placeholder` then is_training_value will be None and
# `needs_moments` will be true.
is_training_value = utils.constant_value(is_training)
need_moments = is_training_value is None or is_training_value
if need_moments:
# here it defines the moments
Похоже, что когда «is_training» является переменной или заполнителем, моменты определяются, а также get вычисляет их во время выполнения, даже если вы устанавливаете заполнитель на «False». Я бы предпочел оставить его в качестве заполнителя, потому что таким образом я могу проводить периодическое тестирование во время обучения, не переопределяя график, но я решил использовать его как константу и определить разные поведения для обучения и тестирования, и теперь моменты не вычисляются во время теста.
@ tano297 Спасибо. Теперь я также использую is_training как константу. Оставьте его как заполнитель, и периодическое тестирование изменит значение скользящего среднего и скользящей дисперсии. И время вывода будет больше, поскольку он будет вычислять среднее значение и дисперсию входных данных и обновлять скользящее среднее и скользящую дисперсию. Правильный способ проведения тестирования - это определить разные модели поведения для обучения и тестирования, как вы упомянули.
@ tano297 @MisayaZ
но не "smart_cond" в
is_training_value = utils.constant_value(is_training)
need_updates = is_training_value is None or is_training_value
if need_updates:
...
outputs = utils.smart_cond(is_training, _force_updates, no_updates)
убедиться, что обновления рассчитываются и применяются только в том случае, если is_training имеет значение True?
@abred Да, действительно, но вы имеете в виду строку 391, где происходит обновление скользящей средней внутри _fused_batch_norm ():
# If `is_training` doesn't have a constant value, because it is a `Tensor`,
# a `Variable` or `Placeholder` then is_training_value will be None and
# `need_updates` will be true.
is_training_value = utils.constant_value(is_training)
need_updates = is_training_value is None or is_training_value
if need_updates:
...
outputs = utils.smart_cond(is_training, _force_updates, no_updates)
...
Я говорю о строке 753 в batch_norm ():
# If `is_training` doesn't have a constant value, because it is a `Tensor`,
# a `Variable` or `Placeholder` then is_training_value will be None and
# `needs_moments` will be true.
is_training_value = utils.constant_value(is_training)
need_moments = is_training_value is None or is_training_value
if need_moments:
...
mean, variance = utils.smart_cond(is_training,
_force_updates,
moving_vars_fn)
...
Умное условие в этом случае (насколько я понимаю) решает, обновлять или не обновлять скользящие средние, но моменты все равно вычисляются.
@ tano297, ты прав, я оказался не в том месте, но все же:
строка 755-770 вычисляет моменты, но моменты используются только в _force_updates, который выполняется, только если is_training оценивается как True, не так ли?
И поэтому
mean, variance = utils.smart_cond(is_training, _force_updates, moving_vars_fn)
должно быть эквивалентно строке 804:
mean, variance = moving_mean, moving_variance
если is_training принимает значение False и, следовательно, часть графика "моменты" никогда не используется и, следовательно, не должна выполняться
но я не тестировал, так что могу ошибаться :)
@ tano297 @abred вам прямо. Скользящее среднее и скользящая дисперсия изменились, когда я использовал batchnorm следующим образом:
def batch_norm_layer(self, x,train_phase, scope_bn):
bn_train = batch_norm(x, decay=0.9, center=False, scale=True,
updates_collections=None,
is_training=True,
reuse=None,
variables_collections= [UPDATE_OPS_COLLECTION],
trainable=True,
scope=scope_bn)
bn_inference = batch_norm(x, decay=0.9, center=False, scale=True,
updates_collections=None,
is_training=False,
reuse=True,
variables_collections= [UPDATE_OPS_COLLECTION],
trainable=True,
scope=scope_bn)
z = tf.cond(train_phase, lambda: bn_train, lambda: bn_inference)
return z
Если вы используете следующее:
z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None,
is_training=train_phase, scope=scope_bn)
Скользящее среднее и скользящее отклонение не изменятся во время теста, но скорость очень низкая.
Привет @zhongyuk ,
Я также столкнулся с проблемой, что я мог получить хорошие результаты при использовании is_training = True как для обучения, так и для вывода, но получить плохие результаты при установке is_training = False во время вывода (хуже, чем в случае использования is_training = True). Согласно вашему анализу, если я правильно понимаю, простая установка decay = 0.9 в BN может решить эту проблему. Я прав?
Кстати, мне нужно переучивать модель с использованием decay = 0.9 с нуля? Или возобновление обучения с контрольной точки (т.е. обучение при распаде = 0,999) тоже нормально?
Благодаря!
@nmduc @ davek44
Привет, я также столкнулся с проблемой, что я мог получить хорошие результаты при использовании is_training = True как для обучения, так и для вывода, но получить плохие результаты при установке is_training = False во время вывода (хуже, чем в случае использования is_training = True). Ребята, вы решили эту проблему? Благодаря!
@tyshiwo Я просто установил decay = 0.9 для batch_norm, и пока он работает хорошо.
Я был сбит с толку после всех этих комментариев о том, как правильно использовать Batch Norm: Итак, вот что у меня есть. Пожалуйста, поправьте меня, если я ошибаюсь.
batch_norm = tf.contrib.layers.batch_norm(conv,
center=True,
scale=True,
reuse=phase_train_py,
scope='bn',
is_training=is_training)
где phase_train_py - это логическая переменная Python, а is_training - это заполнитель, принимающий логическую переменную. Я предполагаю, что использовать tf.cond неправильно, иначе функция имела бы логические параметры. Другими словами, если tf.cond
истинно, тогда мы должны использовать функцию batch_norm
для обучения и еще одну для тестирования. Итак, разработчики позволяют нам изменять эти логические переменные, чтобы изменить поведение функции. Итак, что я делаю: устанавливаю для phase_train_py
значение False во время тренировки, а для is_training
значение True. И наоборот при тестировании. Поскольку мы можем изменять только тензоры или заполнители с помощью sess.run
, я намеренно изменил phase_train_py
перед запуском графика. Пример:
if condition:
phase_train_py = False
sess.run(to_run_list, feed_dict={phase_train: True})
else:
phase_train_py = True
sess.run(to_run_list, feed_dict={phase_train: False})
+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++
ВОЗМОЖНО, ВАМ НУЖНО ПРОЧИТАТЬ ЭТО
+++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++
Похоже, проблемы с TF v1.3 остались. Я уверен, что отмечу следующие детали, но все же не смог использовать официальный tf.contrib.layers.batch_norm
с is_training=False
во время оценки (но когда я оставляю is_training=True
неизменным во время оценки, это Хорошо):
1. decay
, экспоненциальная скользящая средняя фактически является альфа-фильтром при обработке сигнала, время сходимости составляет примерно 1 / (1-спад) шагов последовательности. При затухании = 0,999 требуется 1 / 0,001 = 1000 шагов для схождения. Поэтому установите соответствующий спад для номеров шагов тренировки.
updates_collections=None
если вы не хотите добавлять управляющие зависимости операции обновления в train_opreuse
в соответствующее значение.Кажется, единственный способ использовать официальный batch_norm - построить два графика, один для поезда и один для оценки, с is_training=True
и is_training=False
соответственно. Таким образом, вам не нужно динамически переключаться между обучением и оценкой. Но это глупый способ, так как вам нужно построить более одного графа.
Наконец, я сам составляю скользящую среднюю и считаю, что она сработала! Это выглядит следующим образом (на основе кода в Интернете и изменен мной)
def bn_layer(x, scope, is_training, epsilon=0.001, decay=0.99, reuse=None):
"""
Performs a batch normalization layer
Args:
x: input tensor
scope: scope name
is_training: python boolean value
epsilon: the variance epsilon - a small float number to avoid dividing by 0
decay: the moving average decay
Returns:
The ops of a batch normalization layer
"""
with tf.variable_scope(scope, reuse=reuse):
shape = x.get_shape().as_list()
# gamma: a trainable scale factor
gamma = tf.get_variable("gamma", shape[-1], initializer=tf.constant_initializer(1.0), trainable=True)
# beta: a trainable shift value
beta = tf.get_variable("beta", shape[-1], initializer=tf.constant_initializer(0.0), trainable=True)
moving_avg = tf.get_variable("moving_avg", shape[-1], initializer=tf.constant_initializer(0.0), trainable=False)
moving_var = tf.get_variable("moving_var", shape[-1], initializer=tf.constant_initializer(1.0), trainable=False)
if is_training:
# tf.nn.moments == Calculate the mean and the variance of the tensor x
avg, var = tf.nn.moments(x, np.arange(len(shape)-1), keep_dims=True)
avg=tf.reshape(avg, [avg.shape.as_list()[-1]])
var=tf.reshape(var, [var.shape.as_list()[-1]])
#update_moving_avg = moving_averages.assign_moving_average(moving_avg, avg, decay)
update_moving_avg=tf.assign(moving_avg, moving_avg*decay+avg*(1-decay))
#update_moving_var = moving_averages.assign_moving_average(moving_var, var, decay)
update_moving_var=tf.assign(moving_var, moving_var*decay+var*(1-decay))
control_inputs = [update_moving_avg, update_moving_var]
else:
avg = moving_avg
var = moving_var
control_inputs = []
with tf.control_dependencies(control_inputs):
output = tf.nn.batch_normalization(x, avg, var, offset=beta, scale=gamma, variance_epsilon=epsilon)
return output
def bn_layer_top(x, scope, is_training, epsilon=0.001, decay=0.99):
"""
Returns a batch normalization layer that automatically switch between train and test phases based on the
tensor is_training
Args:
x: input tensor
scope: scope name
is_training: boolean tensor or variable
epsilon: epsilon parameter - see batch_norm_layer
decay: epsilon parameter - see batch_norm_layer
Returns:
The correct batch normalization layer based on the value of is_training
"""
#assert isinstance(is_training, (ops.Tensor, variables.Variable)) and is_training.dtype == tf.bool
return tf.cond(
is_training,
lambda: bn_layer(x=x, scope=scope, epsilon=epsilon, decay=decay, is_training=True, reuse=None),
lambda: bn_layer(x=x, scope=scope, epsilon=epsilon, decay=decay, is_training=False, reuse=True),
)
Просто используйте функцию bn_layer_top
при построении графика, параметр is_training - это tf.placeholder
. Затем вы можете переключить заполнитель на True во время обучения и False во время оценки с помощью feed_dict
.
Надеюсь, это поможет сообществу.
Когда вы используете slim.batch_norm, обязательно используйте slim.learning.create_train_op вместо tf.train.GradientDecentOptimizer (lr) .minimize (loss) или другого оптимизатора. Попробуйте, чтобы убедиться, что это работает!
@vincentvanhoucke Вы писали в другом посте этой
Тонкая оболочка batch_norm нормализует последнее измерение вашего входного тензора. Таким образом, если это двумерный входной тензор, поступающий из полностью связанного слоя, он нормализуется в пакетном режиме и, таким образом, выполняет нормализацию для каждой активации. Если это 4-мерный тензор, полученный из свертки, он будет нормализоваться по трем первым измерениям (пакет, ширина, глубина) и, таким образом, выполнять нормализацию для каждой функции. @sguada, может быть, более подробно
Вы имеете в виду под "тонкой оберткой batch_norm" функцию tf.contrib.layers.batch_norm
? Если так, я бы предложил добавить эту информацию в текст документации этой функции. Таким образом, становится очень ясно, что эта функция выполняет пакетную нормализацию точно так же, как описано в документе ... как для FC-Layer, так и для Conv2D-Layer. На данный момент есть только текст «Может использоваться как функция нормализатора для conv2d и full_connected.», Где неясно, связано ли это с темой оси нормализации.
@ZahlGraf Я с радостью рассмотрю PR, который проясняет документацию. Мы занимаемся этим так долго, что у меня больше нет четкого представления о том, что очевидно, а что нет, и я был бы рад разъяснить документацию для тех, кто свежим взглядом на эту тему.
@vincentvanhoucke
Я создал PR с более подробным описанием, в основном на основе вашего высказывания в этой ветке:
https://github.com/tensorflow/tensorflow/pull/15653
Удалите правопреемника, так как эта проблема требует участия сторонних организаций. В противном случае удалите метку contributions welcome
. Спасибо.
Удалите правопреемника, так как эта проблема требует участия сторонних организаций. В противном случае удалите метку contributions welcome
. Спасибо.
Исправление этой ошибки, поскольку исходный запрос на добавление уровня пакетной нормы был исправлен. Некоторые из недавних проблем с документацией, похоже, имеют свои собственные PR.
Если вы видите какую-либо проблему с batch_norm, задайте вопрос в StackOverflow или откройте другую проблему.
Самый полезный комментарий
Теперь есть слой
batch_norm
:https://github.com/tensorflow/tensorflow/blob/b826b79718e3e93148c3545e7aa3f90891744cc0/tensorflow/contrib/layers/python/layers/layers.py#L100