Tensorflow: Простой в использовании пакетный слой норм.

Созданный на 16 февр. 2016  ·  127Комментарии  ·  Источник: tensorflow/tensorflow

Многие неспециалисты используют следующий код http://stackoverflow.com/questions/33949786/how-could-i-use-batch-normalization-in-tensorflow?answertab=votes#tab -top.

Было бы неплохо иметь официальный слой пакетных норм, учитывая его важность для обучения DNN.

contributions welcome docs-bug

Самый полезный комментарий

Все 127 Комментарий

Я работаю над некоторыми частями этого.

Я думаю, что с этим слоем что-то не так. на тренировках все в порядке и потери снижаются очень хорошо. но при тестировании я получаю нулевую точность.
Кстати, при тестировании при использовании 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)

Но:

  • _tf.group () _ не принимает список. Я заменил его на _tf.tuple () _
  • Я не знаю, как получить доступ к _control_flow_ops.with_dependencies () _. Я видел другие примеры, просто используя tf.with_dependecies (), но я не могу этого сделать с Tensorflow 0.10. Я нашел это здесь: _tf.python.control_flow_ops.with_dependencies () _

РЕДАКТИРОВАТЬ:

Документация должна быть обновлена ​​до 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
screen shot 2016-11-16 at 1 51 51 pm

Результаты тестового запуска с decay=0.999 ( decay=0.999 - настройка по умолчанию в tf.contrib.layers.batch_norm )
screen shot 2016-11-16 at 2 03 58 pm

(также кажется, что большее значение затухания потребовало бы, чтобы модель тренировалась дольше, чтобы увидеть изменение точности проверки)

Ага, это исправило. Спасибо, что поделились своим анализом @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) .

Итак, ответ: я правильно использую пакетную нормализацию, но не совсем понял ее динамику во время обучения.

================
Более того:

  1. Вот полный пример того, как использовать слой BN в наборе данных MNIST.
  2. Использование меньшего значения затухания ускорит фазу разогрева. Распад по умолчанию - 0,999, для небольших наборов данных, таких как MNIST, вы можете выбрать 0,99 или 0,95, и он нагревается за короткое время.

@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 это не так. подключен к графику ... (см. прикрепленное изображение)
screen shot 2017-04-03 at 19 54 54

Мой код сейчас такой:
Обертка пакетной нормализации

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 шагов для схождения. Поэтому установите соответствующий спад для номеров шагов тренировки.

  1. использование заполнителя для переключения между оценкой обучения и тестирования
  2. используйте updates_collections=None если вы не хотите добавлять управляющие зависимости операции обновления в train_op
  3. установите reuse в соответствующее значение.

Кажется, единственный способ использовать официальный 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 или откройте другую проблему.

Была ли эта страница полезной?
0 / 5 - 0 рейтинги