Tensorflow: Couche de norme de lot facile à utiliser.

Créé le 16 févr. 2016  ·  127Commentaires  ·  Source: tensorflow/tensorflow

De nombreux non-experts utilisent le code suivant http://stackoverflow.com/questions/33949786/how-could-i-use-batch-normalization-in-tensorflow?answertab=votes#tab -top.

Ce serait bien d'avoir une couche de norme de lot officielle étant donné son importance dans la formation des DNN.

contributions welcome docs-bug

Commentaire le plus utile

Tous les 127 commentaires

Je travaille sur certaines parties de cela.

Je pense que quelque chose ne va pas avec cette couche. à l'entraînement, tout va bien et les pertes diminuent très bien. mais lors des tests, je n'obtiens aucune précision.
Au fait, en testant lorsque j'utilise is_training = False, j'obtiens zéro acc.
Je sais que la normalisation des lots se comporte différemment en phase de test et de test, comme décrit dans Comment la normalisation par lots se comporte-t-elle différemment au moment de la formation et du test?

Idem ici, j'ai rencontré un comportement inattendu avec is_training = False. Quelle est la bonne façon de changer cet indicateur? J'utilise actuellement un tf.cond car il ne prend pas tf.placeholders par lui-même.

@pawni Vous devez utiliser un booléen Python pour is_training . Ce ne peut pas être un tf.cond .

@ppwwyyxx eh bien, je fais tf.cond(placeholder, batch_norm(.., is_training = True), batch_norm(.., is_training = False)) ou est-ce que quelqu'un est juste censé faire un batch_norm(.., is_training=variable) et le changer en dehors du graphique si nécessaire?

Oh, je pensais que vous faisiez batch_norm(.., is_training=tf.cond(placeholder)) , ce qui est incorrect.
Votre façon actuelle pourrait également avoir des problèmes. Vous devrez vérifier que les deux batch_norm op que vous avez créés partagent la même portée, sinon ils ne partageront pas les statistiques de moyenne / variance sous-jacentes.

Pour ce faire, l'argument reuse peut aider, mais je n'en suis pas sûr car j'utilise ma propre version de bn layer.

J'utilise la même portée et reuse=True . Cela semble fonctionner parfois mais je ne suis pas trop sûr. Ce serait formidable si la couche pouvait être ajoutée à la documentation avec une brève explication sur la meilleure façon de gérer le changement de la formation au test.

@sguada FYI

Actuellement, batch_norm nécessite un booléen python, mais nous travaillons à ajouter l'option de passer un Tensor.

@pawni Si vous ne voulez pas vous soucier de la mise à jour de moving_mean et moving_variance set updates_collections = None pour vous assurer qu'ils sont mis à jour en place, sinon vous devez vous assurer que les update_ops ajoutés à tf.GraphKeys.UPDATE_OPS sont exécutés pendant l'entraînement.

Je pense que tensorflow a besoin de 2 hyper méthodes qui changent l'état du modèle, quelque chose comme la torche. changer l'état du modèle . Je pense que c'est très simple.

y a-t-il un petit script avec un NN très simple qui montre quelle est la bonne façon d'utiliser cette couche BN "officielle"? J'apprécierais vraiment.

désolé si c'est un peu répétitif, mais il semble que l'API parle de BN dans une interface différente: https://www.tensorflow.org/versions/r0.9/api_docs/python/nn.html#batch_normalization

n'est-ce pas la manière officielle d'utiliser BN? Je ne sais pas comment l'utiliser et le SO semble être obsolète et puis il y a une couche dans un lien différent de l'API, comment fait-on exactement cela? Je ne sais pas si je dois aller à SO ou demander ici.

désolé pour le spam, mais quel est le problème avec l'utilisation de quelque chose comme ceci:

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

alors il est simple de dire à tensorflow lequel utiliser avec un dictionnaire de flux comme dans:

feed_dict = {x: Xminibatch, y_: Yminibatch, phase_train: True}
sess.run(fetches=[merged,train_step], feed_dict=feed_dict)

comme il n'est pas clair si l'implémentation changera, je voulais donner une suggestion (notez qu'il est facile d'étendre aux convolutions et aux trucs que je n'ai simplement pas collé ce code).

@pawni @ppwwyyxx avez-vous décidé si vous deviez utiliser la réutilisation sur true pour résoudre le problème de portée?

@ brando90 actuellement, je fais quelque chose comme:

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))

Cependant, je pense que # 3265 voudrait essentiellement l'implémenter comme ça. Une référence pourrait être l'implémentation d'abandon ici: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/layers/python/layers/layers.py#L433 -L435

Lorsque les updates_collections = None alors les mises à jour se produisent sur place et il est plus facile d'utiliser un tf.cond () pour permettre à is_training d'être un Tensor un peu plus compliqué lorsque les mises à jour sont retardées et les update_ops sont exécutés plus tard.
J'essaierai de faire entrer la première partie bientôt.

@ brando90 @pawni son code fonctionne bien, mais doit changer comme ci-dessous

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))  

Et lorsqu'il est exécuté en période d'entraînement ou de test,

# 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})  

Ce code fonctionne, mais comme # 3265 dit que ce sera génial si tf.contrib.layers.batch_norm obtient is_training comme une variable tf.plcaeholer .

@nmhkahn @pawni merci pour les extraits de code. Ils ont été très utiles pour ajouter la normalisation par lots à mon réseau de convolution. La formation semble très bien fonctionner. Le test ne l'est pas. Dans certaines versions du code, les précisions d'entraînement sont beaucoup plus élevées que celles des tests, ce qui signifie probablement que je ne partage pas les paramètres de normalisation par lots. Dans les autres versions du code, j'obtiens "ValueError: la variable conv1 / beta existe déjà, non autorisée. Vouliez-vous définir reuse = True dans VarScope?" qui semblent indiquer que j'essaye de réapprendre le paramètre ... quand j'essayais de réutiliser.

Quelqu'un peut-il fournir un exemple de la façon d'appeler la fonction "def BatchNorm" pendant la formation et les tests afin que le partage de variables se produise correctement.

Merci pour toute aide.

MISE À JOUR 25 juillet 2016:

@nmhkahn @pawni merci pour vos commentaires. Après avoir examiné de plus près le code dans contrib, j'ai réalisé quel était mon problème. Pendant la formation et les tests, nous mettons à jour ou réutilisons quatre variables (beta, gamma, moving_mean et moving_variance). Pour les rendre uniques, j'ai dû définir une portée par couche. Je l'ai fait comme ça:

conv1 = tf.nn.relu (batch_norm_layer (conv2d_stride2_valid (données, W_conv1) + b_conv1, train_phase, scope = "conv1"))

où batch_norm_layer est similaire aux exemples de @nmhkahn @pawni , conv2d_stride2_valid est juste une def pour définir une couche convolutionnelle, et W_conv1 et b_conv1 sont des variables contenant les poids et les biais. Je pourrais probablement supprimer le terme de biais car nous utilisons la normalisation par lots.

Le net fonctionne bien maintenant. J'ai remarqué après avoir tracé les précisions en mode entraînement et en mode test que les précisions des tests commencent à grimper après les précisions d'entraînement. Rétrospectivement, cela a du sens puisque nous recueillons des statistiques sur les ensembles de données à des fins de test. Mais il me semblait que je faisais quelque chose de mal lors de mes premiers tests. Merci pour vos commentaires et pour la mise à disposition de la normalisation des lots à la communauté.

@nmhkahn en quoi est-ce différent de la suggestion de pawni?

@ brando90 J'ai eu une petite erreur dans ma version qui a été corrigée par nmhkahn (en changeant isTraining en is_training )

@diegoAtAlpine J'ai trouvé les mêmes problèmes - je ne sais pas pourquoi c'est le cas. Cependant, ValueError doit être résolu par l'extrait de code. Vous ne savez pas ce que vous voulez voir comment l'appeler car les exemples de nmhkahn semblent faire le travail?

@nmhkahn @pawni @ lorsque vous faites:

sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=True})

cela ne signifie-t-il pas que vous utilisez is_training comme espace réservé? Les gens ont commenté qu'ils voulaient que is_training soit un détenteur de placers, mais c'est ce que j'avais pour ma version:

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

n'est-ce pas correct?

J'ai déjà étendu tf.contrib.layers.batch_norm pour permettre le passage d'un Tensor ou d'un Placeholder pour is_training. Il sera bientôt fusionné dans TF contrib.

Maintenant disponible en
https://github.com/tensorflow/tensorflow/commit/9da5fc8e6425cabd61fc36f0dcc1823a093d5c1d#diff -94bbcef0ec8a5cdef55f705e99c2b2ed

est-ce juste moi ou est-ce que l'ajout de cette couche BN ralentit sensiblement la formation d'une seule époque?

@ brando90 Cela ralentit la formation pour moi aussi mais je pense que cela est attendu car il faut calculer des statistiques. Et votre version me va bien.

BatchNorm est actuellement très lent (à cause de toutes les statistiques calculées), mais ils travaillent sur l'ajout d'une opération batchnorm cudnn comme indiqué ici .

@nmhkahn question rapide. Quand vous avez écrit (pour tester):

sess.run([opt, loss], feed_dict={x: bx, y: by, is_training=False})

en théorie, est-ce que bx et by peuvent être n'importe quel ensemble de données? c'est-à-dire que cela peut encore être l'ensemble de formation même si nous ne sommes pas en formation? (c'est-à-dire juste pour suivre l'erreur de train)

@ brando90 vous avez raison.

Je suis également confus concernant is_training et réutilisation des drapeaux. J'ai créé un programme suivant l'exemple CIFAR, où mon code est structuré comme dans CIFAR:

  • Inférence
  • Perte
  • Train

Et je l'exécute de manière multi-gpu (pour l'entraînement).
J'ai donc un script pour la formation (similaire à cifar10_multigpu.py) et un pour les tests (similaire à cifar10_eval.py).
Alors

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()

L'inférence se produit avec la fonction MyModel. (ci-dessous est un exemple de la fonction, en réalité j'utilise plus de couches et de neurones).

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

Je souhaite effectuer la nomalisation des lots. Alors quand je l'ai fait:

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)

J'ai eu l'erreur suivante lors de la phase de formation:
La bnormalisation / bêta de variable n'existe pas, n'est pas autorisée. Vouliez-vous dire définir reuse = None dans VarScope?

D'après ce que j'ai lu dans ce fil lors de la phase de formation, je devrais utiliser reuse = None. Ai-je bien compris cette partie? Si cela est vrai, alors que j'utilise deux GPUS, dois-je faire réutiliser = None dans le premier GPU et réutiliser = True dans le second? Ou puisque je fais tf.get_variable_scope (). Reuse_variables () il prend soin de lui-même?

Enfin, dans la phase de test, devrais-je avoir is_training = False et reuse = True?

Toute aide est grandement appréciée.

Maintenant, tf.contrib.layers.batch_norm accepte un Tensor, Variable ou Placeholder comme is_training

https://github.com/tensorflow/tensorflow/commit/9da5fc8e6425cabd61fc36f0dcc1823a093d5c1d#diff -94bbcef0ec8a5cdef55f705e99c2b2ed

Est-il normal que la normalisation par lots aggrave mes expériences? Je l'ai essayé sur un réseau NN à 2 couches basé sur le tutoriel pour débutants MNIST et j'obtiens systématiquement de pires résultats lorsque BN est présent: avec BN (l'un avec échelle et centre formés et l'autre non) la précision est de 0,8423, 0,8221 et sans BN la précision 0.9477.

Mon script est présent ici https://github.com/brando90/tensor_flow_experiments/blob/master/tf_tutorials/beginner_tutorial_MNIST_BN.py

quelqu'un a connu ces problèmes ou est-ce que BN est comme ça et je dois faire autre chose pour que ça marche?

La dernière version de tf.contrib.layers.batch_norm accepte désormais un espace réservé pour is_training donc pas besoin de le faire vous-même.

Mais ce qui est important, c'est que soit vous transmettez updates_collections = None pour que le Moving_mean et le Moving_variance soient mis à jour sur place, sinon vous devrez rassembler les update_ops et vous assurer qu'ils sont exécutés.

Je voudrais vous encourager à utiliser tf.contrib.layers ou tf.contrib.slim pour créer votre modèle.

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 J'ai changé mon ancien où je lui dis manuellement de s'entraîner ou non (basé sur un tf.cond) et maintenant il semble que la précision soit à nouveau à ~ 95. Pourquoi devais-je changer updates_collections en None? Cela vous dérange-t-il de m'expliquer pourquoi cela a donné une si grande différence de précision? Cela semble être un changement non trivial (devrait-il être sa valeur par défaut, alors si cela compte tellement?). Merci! :)

De plus, j'ai remarqué que vous aviez dit que c'était un espace réservé et que je n'avais pas besoin de le faire manuellement. Cependant, quand j'ai passé un espace réservé pour is_training, il a dit

TypeError: Using a tf.Tensor as a Python bool is not allowed. Use si t n'est pas 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.

et pointé sur le code batch_norm. Peut-être que cela pourrait être bien de montrer comment cet espace réservé devrait être utilisé car il semble que je ne comprends pas comment il est supposé être utilisé. Merci! :)

@ brando90
La partie pertinente du code est ici L227-256 .

Comme vous le remarquerez, il existe une instruction with ops.control_dependencies qui force les mises à jour. Je crois que pour que le code soit utilisé «dès la sortie de la boîte», la valeur par défaut doit être Aucun.

Quant à mon commentaire ci-dessus 1122 , j'ai compris que tf.get_variable_scope (). Reuse_variables () s'occupe du problème, donc dans la phase d'apprentissage, l'argument réutilisation de batch_norm devrait être None. Cela a à voir avec l'instruction variable_op_scope (lire sa documentation dans tensorflow)

Utilisation de batch_norm avec 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})

Le problème avant était que vous ne mettiez pas à jour les moving_mean et moving_variance après chaque étape, lorsque updates_collections vaut None, cela force les mises à jour dans le cadre du calcul.
Cependant, lorsqu'un réseau a de nombreuses couches batch_norm, il est plus efficace de collecter toutes les opérations de mise à jour et de les exécuter ensemble, de sorte que chaque couche n'a pas besoin d'attendre la fin de la mise à jour.

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])

Y a-t-il eu des progrès dans l'accélération de la norme des lots?

J'essayais d'utiliser la norme de lot avec un NN à 2 couches densément connecté avec l'ensemble de données (aplatir) MNIST (et les unités relu) pour la tâche de codage automatique et je continue à recevoir une erreur NaN. Quelqu'un sait pourquoi cela pourrait-il être? Est-ce possible avec BN? Cela semble louche, mais cela ne peut pas être ma configuration d'apprentissage, mon taux, etc.

@sguada Je ne comprends pas la bonne façon d'utiliser batch_norm spécialement en ce qui concerne le drapeau updates_collections . Si j'ai bien compris si l'indicateur est None le réseau n'est pas efficace, donc je devrais laisser updates_collections=tf.GraphKeys.UPDATE_OPS et ensuite je devrais collecter toutes les mises à jour batch_norm et les exécuter ensemble.

Vous collectez les mises à jour batch_norms en faisant: update_ops = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS)) .

J'ai de nombreux modèles différents qui utilisent différentes couches batch_norm, cela ne fonctionnerait pas correctement?:

#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])

Pourriez-vous expliquer cette partie avec un peu plus de détails? Merci beaucoup.

Mettez-le simplement dans des clés de collection séparées:

# 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])

Néanmoins, la documentation semble obsolète. Il dit de faire ce qui suit:

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)

Mais:

  • _tf.group () _ n'accepte pas de liste. Je l'ai remplacé par _tf.tuple () _
  • Je ne sais pas comment accéder à _control_flow_ops.with_dependencies () _. J'ai vu d'autres exemples utilisant simplement tf.with_dependecies (), mais je ne peux pas le faire avec Tensorflow 0.10. Je l'ai trouvé ici: _tf.python.control_flow_ops.with_dependencies () _

ÉDITER:

La documentation doit être mise à jour à s.th. comme ça:

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)

MODIFIER 2:

Après avoir effectué quelques exécutions sur mon réseau, je dois dire que je ne vois aucune différence de performances entre l'utilisation de _updates_collections = None_ par rapport à la récupération manuelle de _tf.GraphKeys.UPDATE_OPS_ lors de la construction du graphique . Même avec une utilisation intensive de la normalisation par lots (au total, mon _tf.get_collection (tf.GraphKeys.UPDATE_OPS) _ renvoie 140 Update-Ops, tous sont uniquement BN-ops)

Edit: Difficile à dire, si mes résultats sont corrects, mais l'ensemble du réseau semble en effet 1,5 fois plus rapide. Pour autant que je sache, les statistiques BN sont calculées sur le CPU, pas sur le GPU jusqu'à présent.

Quelqu'un parmi vous peut-il également voir des avantages en termes de performances? Veuillez partager vos résultats :)

Pour en revenir au problème de performances, la couche de norme de lot actuelle bénéficie-t-elle de l'utilisation du GPU? Quelqu'un a-t-il bénéficié des avantages des GPU avec cette implémentation de norme par lots?

Désolé pour le spam, mais la documentation n'explique pas vraiment comment utiliser ce BN avec convolution (peut-être devrait-il être fourni quelque part?). En bref, comment comprend-il qu'il doit appliquer et apprendre les mêmes paramètres par fonctionnalité (plutôt que par activation)?

(Y a-t-il au moins un extrait de code pour faire cela?)

Le wrapper slim batch_norm se normalise sur la dernière dimension de votre tenseur d'entrée. Donc, s'il s'agit d'un tenseur d'entrée 2D provenant d'une couche entièrement connectée, il se normalise par lots, et effectue ainsi une normalisation par activation. S'il s'agit d'un tenseur 4D issu d'une convolution, il se normalisera sur les trois premières dimensions (lot, largeur, profondeur), et effectuera ainsi une normalisation par fonction. @sguada sera peut-être un peu plus descriptif à ce sujet.

@nmhkahn En reuse défini sur None quand is_training=True ? Cela ne déclencherait-il pas la réinitialisation du paramètre de mise à l'échelle gamma et du paramètre de décalage beta à chaque étape d'entraînement? J'ai pensé que dans l'article original, beta et gamma sont "appris avec les paramètres du modèle d'origine". Pour ce faire, ne devraient-ils pas être initialisés une seule fois, puis réutilisés dans toutes les étapes de la formation?

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))

J'apprécie beaucoup le travail que l'équipe TF a mis ici pour rendre batch_norm disponible et efficace. D'après ma recherche, ce fil est la meilleure ressource pour savoir comment l'utiliser. Il y a beaucoup de problèmes et d'idées différents qui volent ici, et il est difficile de comprendre les conseils consensuels pour le cas standard le plus simple d'utilisation de la couche batch_norm. Je pense qu'il y aurait beaucoup de valeur à étendre la documentation pour spécifier l'utilisation exacte recommandée.

Ma meilleure tentative pour comprendre cela m'a amené au code suivant:

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))

Ensuite, j'ai défini is_training_ph sur True pour l'entraînement et False pour les tests. Cela ne fonctionne pas pour moi. Le modèle s'entraîne bien, mais les performances du test sont terribles. En revanche, si je maintiens is_training_ph = True pour le temps de test, cela fonctionne très bien. Ainsi, je suppose que j'ai toujours un problème de portée afin qu'il ne trouve pas les bonnes variables existantes.

@ davek44 J'utilise le même framework de code que vous utilisez et j'ai observé la même chose: lorsque s'allume is_training=True pendant la phase d'entraînement et désactive is_training=False pour la phase de validation et / ou de test, le modèle s'entraîne bien comme le papier décrit (le modèle converge plus rapidement et j'ai pu utiliser un taux d'apprentissage plus élevé), mais les performances des tests sont terribles. Si j'active is_training=True tout le temps, le modèle s'entraîne de la même manière que sans insérer de couche de norme de lot. Je n'ai pas compris ce que j'ai fait de mal, je prévois d'utiliser TensorBoard pour surveiller les paramètres. Souhaitez-vous mettre à jour si vous diagnostiquez la cause de ce comportement?

tf.contrib.layers.batch_norm peut prendre tenseur comme is_training, donc pas besoin de faire quoi que ce soit de spécial.

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'),

Je vois les mêmes performances de test médiocres avec ce code.

Sans plus de détails, il est impossible de savoir, je suppose que vous ne vous entraînez que pour quelques itérations, de sorte que les paramètres moving_mean et moving_average n'ont pas encore convergé.

Vous pouvez modifier la valeur batch_size pendant le test pour voir comment les performances se dégradent lorsque vous réduisez votre lot.

Je vois les mêmes performances de test médiocres avec ce code.

J'ai eu exactement le même problème soit avec tf.slim batchnorm ou avec tf.cond et l'entrée is_training comme espace réservé.
Dans le premier cas, en examinant le modèle entraîné, j'ai découvert que la moyenne mobile et la variance mobile se composent de tous les zéros.
Dans ce dernier cas, la moyenne mobile et la variance semblent plus raisonnables (avec des valeurs différentes), mais si j'utilise is_training = False dans le temps de test, les performances sont également très mauvaises. En utilisant is_training = True, cela fonctionne mieux mais je pense qu'il n'utilise que la moyenne mobile et la variance à l'intérieur du lot de test.

@nmduc @ davek44 J'ai écrit du code pour suivre la moyenne mobile et la variance mobile calculées en tf.contrib.layers.batch_norm pendant l'entraînement et les tests. J'ai découvert que la valeur de decay compte beaucoup (ils utilisent la décroissance exponentielle pour calculer la moyenne mobile et la variance mobile), avec un paramètre decay plus proche de 1,0 (c'est- decay=.999 dire decay dans le tf.contrib.layers.batch_norm , et mes précisions de validation / test semblaient plus raisonnables.

Les résultats du test avec decay=0.9
screen shot 2016-11-16 at 1 51 51 pm

Les résultats du test avec decay=0.999 ( decay=0.999 est le paramètre par défaut dans tf.contrib.layers.batch_norm )
screen shot 2016-11-16 at 2 03 58 pm

(Il semble également qu'une plus grande valeur de décroissance obligerait le modèle à s'entraîner plus longtemps pour voir le changement de précision de validation)

Ouais, ça l'a corrigé. Merci de partager votre analyse @zhongyuk!

J'encourage les développeurs à envisager de faire de decay = 0.9 la valeur par défaut. Même 0.99 ne fonctionne pas bien pour moi. C'est aussi la valeur par défaut dans l'implémentation de Torch; voir le paramètre momentum dans https://github.com/torch/nn/blob/master/BatchNormalization.lua

@zhongyuk Merci beaucoup pour le partage. Ça marche pour moi maintenant.

Cela semble important. @sguada, nous devrions envisager la bonne marche à suivre avant la version 1.0. À court terme, l'une des parties intéressées peut-elle m'envoyer un PR documentant le fait que decay pourrait devoir être considérablement réduit en cas de mauvaise performance d'évaluation? Je suis presque sûr que je n'ai jamais eu à modifier ce paramètre, mais cela pourrait être un effet secondaire du paramètre distribué.

Nous pourrions changer la valeur par défaut en 0.9 ou mieux documenter son impact dans des ensembles de données plus petits ou quelques mises à jour.
@vincentvanhoucke dans notre configuration distribuée, nous faisons généralement des millions de mises à jour, donc c'est correct, mais dans d'autres cas comme celui ici qui ne fait que quelques centaines de mises à jour, cela fait une grande différence:
Par exemple, l'utilisation de decay = 0.999 a un biais de 0,36 après 1000 mises à jour, mais ce biais descend à 0,000045 après 10000 mises à jour et à 0,0 après 50000 mises à jour.

Je voulais juste noter que j'ai également le problème de performances de test médiocres, en particulier en utilisant de petites tailles de lots (tout ce qui est inférieur à 10 au lieu des 200 que j'ai utilisés pour la formation diminue la précision des tests). J'ai utilisé un tf.placeholder pour basculer entre le mode test / entraînement.

C'est formidable que cette couche de normalisation par lots fonctionne pour une meilleure convergence de formation, mais si vous ne pouvez pas appliquer le modèle en production, il ne sert à rien de l'utiliser. Quelqu'un peut-il confirmer de bonnes performances de test avec des échantillons de données petits ou uniques en utilisant cette couche de norme de lot?

Je peux confirmer que les performances du test sont bonnes lorsque vous utilisez is_training = False avec de petits lots et même avec batch_size = 1, car il n'utilise pas la statistique du lot, mais la statistique apprise pendant la formation. Il suffit de s'assurer que les statistiques ont convergé avec une décroissance par défaut = 0,999 qui implique au moins 50k mises à jour.

Pour suivre la confirmation du développeur TF, je surveille la convergence des statistiques avec deux paramètres decay (et la formation batch_size = 1). Avec decay=0.99 , les statistiques convergent (biais <0,001) après 550 ~ 600 étapes d'apprentissage / mises à jour. Avec decay=0.9 , les statistiques convergent (biais <0,001) dans les 100 étapes d'apprentissage / mises à jour.

@sguada merci, cela signifie-t-il également que la sortie est réellement indépendante de la taille du lot? car je remarque de très légers changements avec un grand impact sur ma précision (peut-être que ma définition des performances est simplement plus facilement affectée par ce léger changement). Pour être précis, toutes les valeurs de mon tenseur de sortie à 128 dimensions augmentent de sorte que la longueur totale du vecteur évolue presque linéairement avec la taille du lot. Par valeur, ce n'est pas une grande différence, mais cela a un impact important lors du calcul des distances vectorielles dans les espaces latents.

@zhongyuk merci, j'ai exécuté environ 5k mises à jour avec decay=0.9 , donc cela aurait dû converger et tester les performances en utilisant de grandes tailles de lots est bien. Mais même si ce n'était pas le cas, cela entraînerait-il une différence entre la formation d'un test? Je verrais de mauvaises performances pendant l'entraînement et les tests si cela n'avait pas convergé, non?

Je vais étudier un peu plus et voir si je peux reproduire le problème sur une autre tâche. Merci pour le retour rapide jusqu'à présent!

@dominikandreas Si vos mauvaises performances de test sont causées par des statistiques non convergentes, vous verrez des performances d'entraînement raisonnablement bonnes mais de mauvaises performances de test. Parce que pendant l'entraînement, la normalisation des lots est effectuée à l'aide des statistiques de lots d'entraînement uniquement. Cependant, pendant le temps de test, il utilise les statistiques de moyenne mobile de tous les lots d'entraînement pour normaliser le tenseur d'entrée.

J'ai trouvé une erreur dans mon code, la normalisation des lots fonctionne bien maintenant :-) merci pour votre soutien

Salut @zhongyuk , comment avez-vous suivi la moyenne et la variance mobiles?
Merci!

@rogertrullo En général, je configure TensorBoard pour suivre la moyenne et la variance mobiles. En dehors de cela, j'ai également essayé de récupérer des statistiques via tf.get_variable("moving_mean") dans la portée pendant la formation et de faire référence pour surveiller le biais.

salut,
J'ai le même problème que les autres décrits: j'ai de bons résultats d'entraînement mais la validation / les tests sont mauvais après l'utilisation de batch_norm.
J'utilise la fonction comme ceci:
conv_normed1 = 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)
la valeur de décroissance est de 0,9
dois-je définir l'indicateur de réutilisation?
Je serai heureux de toute aide.

J'utilise batch_norm comme décrit dans ce fil (avec un tf.bool pour la formation; et ops.GraphKeys.UPDATE_OPS) et tout fonctionne.

Lors de l'enregistrement et de la restauration à l'aide de:
économiseur = tf.train.Saver ()
Ça marche,

mais lors de l'enregistrement en utilisant:
saver = tf.train.Saver (tf.trainable_variables () + [global_step])
pour que je puisse économiser de l'espace de stockage (en ne sauvegardant pas les dégradés, etc.)
lors de la restauration, il y a une erreur:
"valeur non initialisée unpool4 / convc / bn / moving_mean"

Évidemment, c'est parce que moving_mean (et je suppose que moving_variance) n'a été enregistré pour aucun des calques. Comme j'en ai beaucoup (imbriqués dans de nombreuses couches), quel est le moyen le plus efficace de les ajouter à la liste des valeurs à enregistrer? De plus, étant donné qu'il s'agit de variables entraînables, pourquoi ne sont-elles pas ajoutées à la collection trainable_variables?

La moyenne et la variance mobiles de
Pour les sauvegarder / les restaurer, vous pouvez utiliser tf.global_variables ()

pour moi, les choses ont commencé à fonctionner lorsque j'ai utilisé ce wrapper:
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
l'ensemble de l'utilisation des portées et de la réutilisation n'est pas clair dans ce fil pour mon avis.

Merci beaucoup. Avec tf.global_variables (), les fichiers de sauvegarde sont beaucoup plus volumineux car je pense qu'il inclut les dégradés; à la fin j'ai utilisé:

saver = tf.train.Saver ([x pour x dans tf.global_variables () si 'Adam' n'est pas dans x.name])

et parce que l'initialisation du gestionnaire de session ne les initialise pas correctement:

sess.run (tf.variables_initializer ([x pour x dans tf.global_variables () si 'Adam' dans x.name]))

(Utilisation de tf.train.AdamOptimizer)

Vous pouvez également utiliser tf.model_variables () qui contient les variables du modèle, c'est-à-dire moving_mean

@sguada Désolé de vous déranger, mais est-il possible de faire un exemple sur la façon d'utiliser slim.batch_norm lorsqu'il est combiné avec slim.conv2d / slim.fully_connect dans readme.md?

J'utilise slim.batch_norm, mais j'obtiens de bonnes performances d'entraînement et de mauvaises performances de validation / test. Je pense que cela doit être dû à une mauvaise utilisation de reuse ou scope ou d'autres paramètres. Bien qu'il existe de nombreux problèmes de normalisation par lots, il est difficile de trouver un extrait de code complet sur la façon de l'utiliser, en particulier. pour savoir comment passer différents paramètres dans différentes phases.

Dites, dans mon code mnist_bn , j'ai contrôlé les dépendances en utilisant tf.GraphKeys.UPDATE_OPS et j'ai configuré is_training comme espace réservé. Mais les performances de validation sont toujours médiocres si je nourris {is_training: False}.

J'apprécierais grandement qu'il y ait un exemple de normalisation de lot officiel et complet (ce qui signifie que la formation, la validation, les tests sont tous inclus).

Merci d'avance!

salut,
vous devez définir une portée différente pour chaque fois que vous utilisez la norme de lot et lui donner l'entrée de réutilisation en fonction de la phase de formation / test (TRUE lorsque le test est FALSE lors de l'entraînement) qui fonctionne pour moi.

@ishaybee Merci pour votre aide. J'ai trouvé mon problème = = C'est dû au démarrage à froid de moving_mean / moving_variance.

Comme je n'ai pas formé suffisamment d'étapes, la moyenne / variance mobile estimée n'est pas aussi stable. Le résultat s'avère être: le modèle fonctionne plutôt bien sur les mini-lots d'entraînement (vous savez qu'au début la perte diminue rapidement), mais les performances de validation sont irrégulières (car la moyenne / variance estimée de la population n'est pas suffisamment stable).

Lorsque j'entraîne le modèle plus longtemps, la précision de la validation devient également plus jolie.

Une autre chose importante est, assurez-vous d'utiliser slim.learning.create_train_op pour créer le train op . N'utilisez pas tf native tf.train.GradientDescentOptimizer(0.1).minimize(loss) .

La réponse est donc que j'utilise correctement la normalisation par lots, mais je n'ai pas entièrement compris sa dynamique pendant l'entraînement.

================
Quoi de plus:

  1. Voici un exemple complet d'utilisation de la couche BN sur un jeu de données MNIST.
  2. Utiliser une valeur de décroissance plus petite accélérera la phase de préchauffage. La décroissance par défaut est de 0,999, pour les petits ensembles de données tels que MNIST, vous pouvez choisir 0,99 ou 0,95, et il se réchauffe en peu de temps.

@soloice , remarquez, comment dans environ comment le paramètre suivant est passé à l'intérieur de la couche pour appeler batch_norm:

batch_norm_params = {'is_training': is_training, 'decay': 0.9, 'updates_collections': Aucun}

Sans updates_collections défini sur None (donc les mises à jour sont effectuées en place dans BatchNorm), je ne m'attendrai pas à ce que la couche environnante (par exemple conv2d) exécute en quelque sorte tf.GraphKeys.UPDATE_OPS nécessaire à la couche BatchNorm pour mettre à jour la moyenne et donc être en mesure de faire fonctionner sur les données de test plus tard.

Ou vous pouvez essayer d'exécuter UPDATE_OPS vous-même explicitement ici

    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)

Mise à jour - J'ai trouvé que j'ai cité exactement votre code et que vous utilisez UPDATE_OPS.

En ce qui concerne le "démarrage à froid", comme vous le voyez ci-dessus dans la discussion, la diminution de la décroissance moyenne courante de BatchNorm (paramètre d'entrée) de 0,999 par défaut à quelque chose comme 0,95 peut accélérer le démarrage

@pavelbulanov C'est très gentil de votre part de m'aider avec ça! Je vais essayer une valeur plus petite de decay pour voir comment cela aide.

================
Mise à jour: utiliser une petite décroissance (par exemple, 0,9 ou 0,95) aide beaucoup. La perte de validation diminue très rapidement lorsque je règle decay sur 0,9. Cependant, l'inconvénient d'une petite décroissance est que sa plage effective est petite: le résultat est dominé par quelques échantillons récents, ce n'est donc pas une bonne estimation de la moyenne / variance de la population. Il faut trouver un équilibre entre un démarrage rapide (petite décroissance) et une plage efficace plus longue (grande décroissance).

Salut,
J'ai essayé d'implémenter une couche de normalisation par lots à l'aide des suggestions de ce numéro, mais j'ai toujours une erreur> 70% dans la validation et les tests ... J'ai une décroissance plus faible pour les appels non-formation ...

Voici mon code:

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)
    )

Merci d'avance.

@Alexivia Il semble que vous utilisez deux couches de normalisation par lots différentes? Vous ne devez utiliser qu'une seule couche BN (bien sûr, avec is_training paramètre

Merci pour vos conseils @soloice.
J'ai essayé maintenant avec juste différents paramètres is_training et 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)

toujours pas de bons résultats de validation et de test ...> 70% ...

salut,
s'il vous plaît voir mon emballage ci-dessus.
vous devriez utiliser "avec tf.variable_scope (scope, reuse = reuse):" Je pense.

Salut @ishaybee ,
J'ai suivi votre conseil, maintenant mon code est:

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)

et j'alimente is_training et reuse via le feed_dict, mais maintenant j'obtiens l'erreur ValueError("The reuse parameter must be True or False or None.")

essayez d'alimenter la réutilisation en tant que variable python (entrée du modèle) et en tant qu'espace réservé.

J'ai essayé cela, et maintenant il a cessé de se plaindre de la valeur ... mais je pense que la valeur de l'espace réservé n'est pas utilisée, car je ne vois aucun changement si je force les valeurs à la fonction batch_norm , et dans TensorBoard ce n'est pas connecté au graphique ... (voir image ci-jointe)
screen shot 2017-04-03 at 19 54 54

Mon code est comme ça maintenant:
Emballage de normalisation par lots

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)

Définition du modèle

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)

Entraînement

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)

Validation

batch_predictions = sess.run(eval_prediction, feed_dict={eval_data: data[-EVAL_BATCH_SIZE:, ...], is_training: False, reuse: True})

Bien que is_traning puisse, une réutilisation d'espace réservé doit être un booléen, et il ne peut s'agir d'un tenseur ni d'un espace réservé.

Je ne sais pas ce que vous essayez de faire, dans la plupart des cas, l'utilisation de valeurs statiques résout le problème. Par exemple, ce modèle fonctionne bien:

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:, ...]})

À moins que vous n'ayez besoin de modifier le comportement du modèle de manière dynamique, vous n'avez pas besoin d'utiliser un espace réservé pour is_training. L'astuce consiste à construire le modèle deux fois, mais en partageant les variables la deuxième fois.

Merci @sguada ! Après avoir appliqué vos suggestions, je l'ai enfin fait fonctionner!

Il serait utile que la documentation de l'API 1.0 indique que vous devez ajouter manuellement des opérations de mise à jour au graphique. Étant un nouvel utilisateur tf, j'ai trouvé que mon erreur de test était folle et j'ai ensuite dû passer pas mal de temps à déboguer mon graphique jusqu'à ce que je réalise que la normalisation par lots était le problème. Ensuite, j'ai dû passer plus de temps à comprendre que par défaut, les variables de suivi des moments ne se mettent pas à jour à moins que vous n'utilisiez une fonction contrib pour l'optimisation. Étant donné que dans la version 1.0, il n'y a pas d'option permettant de définir update_collections sur None, il n'y a aucun indicateur de la documentation indiquant que cela pourrait même être un problème. De plus, il semble judicieux d'avoir un paramètre pour ajouter les dépendances de flux de contrôle à l'opération qui s'exécute dans le cas d'entraînement.

@danrsc Exactement. L'utilisation de la couche BN est assez déroutante. J'ai suggéré d'ajouter des documents ou un tutoriel officiel complet sur la normalisation par lots, mais malheureusement, je n'ai pas eu de réponse = =

Entièrement d'accord. Je pense que l'utilisation de BN est très délicate et que la documentation est actuellement au-delà de l'insuffisance. Cela devrait être corrigé pour une telle couche couramment utilisée.

Réouverture pour visibilité des problèmes de documentation.

@sguada vous attribue pour le tri. Cela pourrait valoir la peine de faire appel à un rédacteur technique sur l'affaire.

Je viens d'être confus par ce problème la semaine dernière et j'ai gaspillé 3 jours de formation ... J'espère que les documents pourront être corrigés bientôt, et qu'un exemple officiel de normalisation des lots pourra être ajouté dans les documents API.

@sguada J'ai remarqué que vous avez dit que "tf.contrib.layers.batch_norm peut prendre le tenseur comme is_training, donc pas besoin de faire quoi que ce soit de spécial".
Howerver, le commentaire dans le code est
Si is_training n'a pas de valeur constante, car c'est un Tensor ,
# a Variable ou Placeholder alors is_training_value sera None et
# needs_moments sera vrai.
Cela signifie-t-il que nees_moments sera vrai même en phase de test si je définis is_training comme espace réservé?
Autant que je sache, les moments ne sont pas nécessaires pendant les tests.

Donc, si is_training est un Variable ou un Placeholder , cela signifie qu'il peut changer, donc le graphe pour calculer les moments est nécessaire, donc la couche le construit.
Ensuite, en temps d'exécution, selon la valeur de True ou False utiliserait le lot moments ou les moving_mean et moving_variance .

Ainsi, pendant le test, vous définiriez la valeur sur False et le moments ne sera pas utilisé.

@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

Je construis batchnorm comme ça, cependant, la moyenne mobile et la variable mobile sont mises à jour pendant le test, je ne trouve pas la raison.

J'ai essayé de créer deux modèles comme @sguada dit, cependant, mon modèle où is_training = False plante juste.

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

Je pense qu'il devrait peut-être y avoir un exemple concret de la façon de créer une norme par lots avec un réseau entièrement connecté, ainsi qu'avec des CNN. Dommage que j'ai formé des modèles pendant des jours en m'attendant à ce que les choses fonctionnent avant de voir que tout le monde essayant d'utiliser cette fonctionnalité devient fou.

Fait intéressant, il faut des millions d'années pour restaurer le modèle après l'entraînement avec batch_norm également. Attendra probablement jusqu'à TF 2.0 pour réessayer quelque chose comme ça.

@MisayaZ vous n'avez pas besoin de créer deux couches batch_norm, vous pouvez simplement passer train_phase (en supposant qu'il s'agit d'un tf.bool) à batch_norm. Vous passez également UPDATE_OPS_COLLECTION variables_collections, ce qui change les collections auxquelles les variables sont ajoutées.

Les éléments suivants devraient fonctionner:

z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None, 
                             is_training=train_phase, scope=scope_bn)

@OktayGardener pas sûr du modèle que vous essayez de créer, il semble que les variables ne soient pas enregistrées dans votre point de contrôle.

batch_norm fonctionne également avec des couches entièrement_connectées.

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 Merci, j'ai construit un réseau avec bathnorm qui est implémenté comme vous l'avez mentionné ci-dessus

z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None, 
                             is_training=train_phase, scope=scope_bn)

la vitesse est lente, j'utilise le benchmark tensorflow pour obtenir le temps de calcul comme ci-dessous:
Je tensorflow / core / util / stat_summarizer.cc: 392] ============================== Top par temps de calcul === ============================
I tensorflow / core / util / stat_summarizer.cc: 392] [type de nœud] [début] [premier] [ms moy] [%] [cdf%] [mem KB] [nom]
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 / suffisant_statistics / 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 / suffisant_statistics / 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 / suffisant_statistics / SquaredDifference
I tensorflow / 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

Je ne comprends pas pourquoi certaines op in moment sont exécutées pendant le test et cela coûte beaucoup de temps, comme conv1 / batch_norm / moments / suffisant_statistics / SquaredDifference.

Le moment n'est pas nécessaire dans le test, pourquoi certaines opérations en cours d'exécution sont-elles exécutées?

Salut,

En utilisant la couche batch_norm ci-dessus dans contrib.layers , j'obtiens nan comme sortie pour le graphe de validation tandis que le graphe de train fonctionne de manière transparente. Y a-t-il quelque chose que je pourrais manquer?

J'utilise:

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)

Merci

En guise de suivi, je réutilise 16 couches de batch_norm.
Cependant, j'ai trouvé que la réutilisation de 4 couches fonctionne.

Je viens de remarquer que si je tue le processus tensorflow et le redémarre, mon erreur s'aggrave pendant quelques époques (c'est-à-dire pire qu'elle ne devrait l'être au dernier point de contrôle). J'observe également que si je supprime batch_norm, ce problème disparaît. Après avoir examiné le code pendant un moment, je pense que cela peut être dû au fait que les valeurs des variables ne sont pas restaurées à partir des variables d'ombre comme elles le seraient si la classe ExponentialMovingAverages était utilisée pour gérer les moyennes mobiles. Cela signifie également que si j'utilise un processus distinct pour évaluer, j'obtiens quelle que soit la dernière valeur de la variable et non la moyenne mobile. Est-ce que j'interprète cela correctement et est-ce le comportement prévu? Il semble que vous souhaitiez restaurer les valeurs de la variable shadow ...

J'ai attrapé le problème, la variance mobile dans mon cas devient négative après quelques itérations.

La sortie du tenseur: Model/clip_logits/batch_norm/moving_variance:0 présent dans tf.model_variables() est

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]

Comme vous pouvez le voir, il existe une variance négative pour l'une des dimensions. Comment est-ce possible ?
PS La couche de norme batch est utilisée juste après la dernière couche entièrement connectée du réseau et avant softmax.

@ raghavgoyal14 l' utilisez-vous avec fused = True? J'ai eu un problème similaire et il a disparu lorsque j'ai utilisé la version fusionnée

@abred : Oui, j'ai utilisé fused=True , même problème.

@sguada Salut, sguada, j'ai un problème.
La définition de contrib.layers.batch_norm dans tensorflow:
def batch_norm (entrées,
désintégration = 0,999,
center = Vrai,
échelle = Faux,
epsilon = 0,001,
activation_fn = Aucun,
param_initializers = Aucun,
param_regularizers = Aucun,
updates_collections = ops.GraphKeys.UPDATE_OPS,
is_training = Vrai,
réutiliser = Aucun,
variables_collections = Aucun,
sorties_collections = Aucun,
trainable = Vrai,
batch_weights = Aucun,
fused = Faux,
data_format = DATA_FORMAT_NHWC,
zero_debias_moving_mean = Faux,
scope = Aucun,
renorm = Faux,
renorm_clipping = Aucun,
renorm_decay = 0,99):
échelle: si Vrai, multipliez par gamma. Si False, gamma est
non utilisé. Lorsque la couche suivante est linéaire (également par exemple nn.relu), cela peut être
désactivé car la mise à l'échelle peut être effectuée par la couche suivante.

Si j'utilise tf.contrib.layers.batch_norm (input, scale = False), "scale = False" signifie si le gamma est nul dans "y = gamma * x + beta" pendant l'entraînement. Merci beaucoup.

Lorsque scale = False, gamma est une constante 1.

@ppwwyyxx Merci beaucoup pour votre aide. J'utilise tf.contrib.layers.batch_norm (input, scale = False) dans Tensorflow, et maintenant je converge le batchnorm de Tensorflow vers Caffe. Comment définir le paramètre de BatchNormLayer et ScaleLayer dans Caffe?
Merci beaucoup.

@MisayaZ J'avais le même comportement en utilisant Batchnorm avec un espace réservé pour "is_training". Je vois dans la trace que les moments sont calculés même au moment du test, j'ai donc décidé d'aller dans le code source et j'ai trouvé ceci:

    # 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

Il semble que lorsque "is_training" est une variable ou un espace réservé, les moments sont définis et sont également calculés lors de l'exécution, même lorsque vous définissez l'espace réservé sur "False". J'aurais préféré le laisser comme espace réservé car de cette façon je peux faire des tests périodiques pendant l'entraînement sans redéfinir le graphique, mais j'ai décidé de l'utiliser comme une constante et de définir différents comportements pour train vs test, et maintenant les moments ne sont pas calculés au moment du test.

@ tano297 Merci. J'utilise maintenant aussi «is_training» comme constante. Laissez-le comme espace réservé et faire des tests périodiques changera la valeur de la moyenne mobile et de la variance mobile. Et le temps d'inférence sera plus long car il calculera la moyenne et la variance des entrées et mettra à jour la moyenne mobile et la variance mobile. La bonne façon de faire des tests est de définir différents comportements pour l'entraînement et le test, comme vous l'avez mentionné.

@ tano297 @MisayaZ
mais pas le "smart_cond" dans

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)

assurez-vous que les mises à jour ne sont calculées et appliquées que si is_training a la valeur True?

@abred Oui en effet, mais vous faites référence à la ligne 391, où elle fait la mise à jour de la moyenne mobile dans _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)
        ...

Je parle de la ligne 753 dans 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) 
        ...

La condition intelligente dans ce cas (en ce qui me concerne) décide de mettre à jour ou non les moyennes mobiles, mais les moments sont toujours calculés.

@ tano297 vous avez raison à ce sujet, j'étais au mauvais endroit, mais quand même:
ligne 755-770 calcule les moments, mais les moments ne sont utilisés que dans _force_updates qui n'est exécuté que si is_training est évalué à True, n'est-ce pas?
Et ainsi

mean, variance = utils.smart_cond(is_training, _force_updates, moving_vars_fn) 

devrait être équivalent à la ligne 804:

mean, variance = moving_mean, moving_variance

si is_training évalue à False et donc la partie "moments" du graphe n'est jamais utilisée et ne devrait donc pas être exécutée

mais je n'ai pas testé, donc je me trompe peut-être à ce sujet :)

@ tano297 @abred vous avez raison. La moyenne mobile et la variance mobile sont modifiées lorsque j'utilise batchnorm comme ceci:

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

Si vous utilisez comme suit:

z = batch_norm(x, decay=0.9, center=False, scale=True, updates_collections=None, 
                         is_training=train_phase, scope=scope_bn)

La moyenne mobile et la variance mobile ne seront pas modifiées pendant le test, mais la vitesse est très lente.

Salut @zhongyuk ,

J'ai également rencontré le problème que je pouvais obtenir de bons résultats en utilisant is_training = True pour l'entraînement et l'inférence, mais obtenir de mauvais résultats lors de la définition de is_training = False lors de l'inférence (pire que le cas utilisant is_training = True). Selon votre analyse, si je comprends bien, en fixant simplement la décroissance = 0,9 en BN peut résoudre ce problème. Ai-je raison?

BTW, dois-je recycler le modèle en utilisant decay = 0.9 à partir de zéro? Ou reprendre l'entraînement à partir du point de contrôle (c.-à-d. Entraîné lorsque décroissance = 0,999) est également acceptable?

Merci!

@nmduc @ davek44

Salut, j'ai également rencontré le problème que je pouvais obtenir de bons résultats en utilisant is_training = True pour l'entraînement et l'inférence, mais obtenir de mauvais résultats lors de la définition de is_training = False lors de l'inférence (pire que le cas utilisant is_training = True). Avez-vous résolu ce problème les gars? Merci!

@tyshiwo Je viens de définir decay = 0.9 pour batch_norm et cela fonctionne bien jusqu'à présent.

J'étais confus après tous ces commentaires sur la façon d'utiliser correctement Batch Norm: Voici donc ce que j'ai. Corrigez-moi si j'ai tort, s'il-vous plait.

batch_norm = tf.contrib.layers.batch_norm(conv, center=True, scale=True, reuse=phase_train_py, scope='bn', is_training=is_training)

où phase_train_py est une variable booléenne python et is_training est un espace réservé prenant une variable booléenne. Je suppose que l'utilisation de tf.cond est erronée, sinon la fonction serait-elle fournie avec des paramètres booléens. En d'autres termes, si tf.cond est vrai, alors nous devrions une fonction batch_norm pour l'entraînement et une autre pour les tests. Ainsi, les développeurs nous permettent de changer ces variables booléennes afin de changer le comportement de la fonction. Donc ce que je fais, c'est: définir phase_train_py sur False pendant l'entraînement tandis que is_training sur True. Et le contraire lors des tests. Puisque nous ne pouvons changer que les tenseurs ou les espaces réservés avec sess.run , j'ai changé phase_train_py intentionnellement avant d'exécuter le graphique. Ex:

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})

++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++
VOUS AVEZ BESOIN DE LIRE CECI
++++++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++++++++++

Il semble qu'il y ait encore des problèmes avec TF v1.3. Je suis sûr que je note les détails suivants, mais je n'ai toujours pas utilisé le tf.contrib.layers.batch_norm officiel, avec is_training=False pendant l'évaluation (mais quand je garde is_training=True inchangé pendant l'évaluation, c'est D'accord):
1. decay , la moyenne mobile exponentielle est en fait un filtre alpha dans le traitement du signal, le temps de convergence est d'environ 1 / (1-décroissance) pas du train. Pour la décroissance = 0,999, vous avez besoin de 1 / 0,001 = 1000 pas pour converger. Définissez donc la décroissance appropriée pour vos numéros d'étape d'entraînement.

  1. utilisation d'un espace réservé pour basculer entre l'évaluation du train et du test
  2. utilisez updates_collections=None si vous ne voulez pas ajouter les dépendances de contrôle de update op à train_op
  3. définir reuse à la valeur appropriée.

Il semble que la seule façon d'utiliser le batch_norm officiel est de créer deux graphiques, un pour le train et un pour l'évaluation, avec respectivement is_training=True et is_training=False . De cette façon, vous n'avez pas besoin de basculer dynamiquement entre le train et l'évaluation. Mais c'est une manière stupide car vous devez créer plus d'un graphique.

Enfin, j'écris moi-même une moyenne mobile et je trouve que cela a fonctionné! C'est comme suit (basé sur du code sur le web et modifié par moi-même)

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),
    )

Utilisez simplement la fonction bn_layer_top lors de la construction d'un graphe, le paramètre is_training est un tf.placeholder
. Ensuite, vous êtes libre de basculer l'espace réservé sur True pendant le train et False pendant l'évaluation, avec feed_dict .

J'espère que cela aide la communauté.

Lorsque vous utilisez slim.batch_norm, veillez à utiliser "slim.learning.create_train_op" au lieu de "tf.train.GradientDecentOptimizer (lr) .minimize (loss)" ou un autre optimiseur. Essayez-le pour voir si cela fonctionne!

@vincentvanhoucke Vous avez écrit dans un autre article de ce fil:

Le wrapper slim batch_norm se normalise sur la dernière dimension de votre tenseur d'entrée. Donc, s'il s'agit d'un tenseur d'entrée 2D provenant d'une couche entièrement connectée, il se normalise par lots, et effectue ainsi une normalisation par activation. S'il s'agit d'un tenseur 4D issu d'une convolution, il se normalisera sur les trois premières dimensions (lot, largeur, profondeur), et effectuera ainsi une normalisation par fonction. @sguada sera peut-être un peu plus descriptif à ce sujet.

Voulez-vous dire avec "slim batch_norm wrapper" la fonction tf.contrib.layers.batch_norm ? Si tel est le cas, je suggère d'ajouter ces informations au texte de documentation de cette fonction. Ainsi, il devient très clair que cette fonction effectue la normalisation par lots exactement comme décrit dans l'article ... pour FC-Layer et Conv2D-Layer. Pour le moment, il n'y a que le texte "Peut être utilisé comme fonction de normalisation pour conv2d et complètement_connecté.", Où il n'est pas clair si cela est lié au sujet de l'axe de normalisation.

@ZahlGraf J'envisagerai volontiers un PR qui clarifie la documentation. Nous sommes là depuis si longtemps que je n'ai plus une bonne idée de ce qui est évident ou non, et je serais heureux de clarifier la documentation pour quelqu'un avec une nouvelle perspective sur le sujet.

@vincentvanhoucke
J'ai créé un PR avec une description plus détaillée, principalement basée sur votre déclaration dans ce fil:
https://github.com/tensorflow/tensorflow/pull/15653

Veuillez supprimer le cessionnaire, car ce problème appelle des contributions externes. Sinon, supprimez l'étiquette contributions welcome . Je vous remercie.

Veuillez supprimer le cessionnaire, car ce problème appelle des contributions externes. Sinon, supprimez l'étiquette contributions welcome . Je vous remercie.

La fermeture de ce bogue depuis la demande initiale d'ajout d'une couche de norme de lot a été résolue. Certains des problèmes de documentation les plus récents semblent avoir leurs propres PR
Si vous rencontrez un problème avec batch_norm, veuillez poser une question sur StackOverflow ou ouvrir un autre problème.

Cette page vous a été utile?
0 / 5 - 0 notes