Tensorflow: Einfach zu verwendende Batch-Norm-Schicht.

Erstellt am 16. Feb. 2016  ·  127Kommentare  ·  Quelle: tensorflow/tensorflow

Viele Nicht-Experten verwenden den folgenden Code: http://stackoverflow.com/questions/33949786/how-could-i-use-batch-normalization-in-tensorflow?answertab=votes#tab -top.

Es wäre schön, eine offizielle Chargennormschicht zu haben, da diese für das Training von DNNs wichtig ist.

contributions welcome docs-bug

Hilfreichster Kommentar

Alle 127 Kommentare

Ich arbeite an einigen Teilen davon.

Ich denke, mit dieser Schicht stimmt etwas nicht. Im Training ist alles in Ordnung und der Verlust nimmt sehr gut ab. aber beim Testen bekomme ich keine Genauigkeit.
Übrigens bekomme ich beim Testen, wenn ich is_training = False benutze, null gem.
Ich weiß, dass sich die Chargennormalisierung in der Zug- und Testphase unterschiedlich verhält, wie unter Wie verhält sich die Chargennormalisierung zur Trainings- und Testzeit unterschiedlich?

Gleich hier habe ich ein unerwartetes Verhalten mit is_training = False erlebt. Was ist der richtige Weg, um dieses Flag zu ändern? Ich verwende derzeit ein tf.cond da es nicht tf.placeholders alleine benötigt.

@pawni Sie müssen einen Python-Booleschen is_training für tf.cond .

@ppwwyyxx Nun, ich mache tf.cond(placeholder, batch_norm(.., is_training = True), batch_norm(.., is_training = False)) oder soll man nur ein batch_norm(.., is_training=variable) und das bei Bedarf außerhalb des Diagramms ändern?

Oh, ich dachte du machst batch_norm(.., is_training=tf.cond(placeholder)) , was falsch ist.
Ihr aktueller Weg könnte ebenfalls Probleme haben. Sie müssen überprüfen, ob die beiden batch_norm Ihnen erstellten

Dazu könnte das Argument reuse hilfreich sein, aber ich bin mir nicht sicher, da ich meine eigene Version der BN-Schicht verwende.

Ich verwende den gleichen Bereich und reuse=True . Es scheint manchmal zu funktionieren, aber ich bin mir nicht sicher. Es wäre großartig, wenn die Ebene der Dokumentation mit einer kurzen Erklärung hinzugefügt werden könnte, wie der Wechsel vom Training zum Test am besten gehandhabt werden kann.

@guada FYI

Derzeit erfordert batch_norm einen Python-Booleschen Wert, wir arbeiten jedoch daran, die Option zum Übergeben eines Tensors hinzuzufügen.

@pawni Wenn Sie sich keine Gedanken über das Aktualisieren von Moving_Mean und Moving_Varianz machen möchten, setzen Sie updates_collections = None, um sicherzustellen, dass sie aktualisiert werden. Andernfalls müssen Sie sicherstellen, dass die zu tf.GraphKeys.UPDATE_OPS hinzugefügten update_ops während des Trainings ausgeführt werden.

Ich denke, Tensorflow benötigt 2 Hyper-Methoden, die den Modellzustand ändern, so etwas wie Fackel. Modellstatus ändern . Ich denke es ist sehr einfach.

Gibt es ein kleines Skript mit einem sehr einfachen NN, das zeigt, wie diese "offizielle" BN-Ebene richtig verwendet wird? Ich würde es wirklich schätzen.

Es tut uns leid, wenn sich dies ein wenig wiederholt, aber es scheint, dass die API in einer anderen Oberfläche über BN spricht: https://www.tensorflow.org/versions/r0.9/api_docs/python/nn.html#batch_normalization

Ist das nicht der offizielle Weg, BN zu benutzen? Ich bin verwirrt darüber, wie man es benutzt und die SO scheint veraltet zu sein und dann gibt es eine Ebene in einem anderen Link als die API. Wie genau macht man das? Ich bin mir nicht sicher, ob ich zu SO gehen oder hier fragen soll.

Entschuldigung für das Spam, aber was ist falsch daran, nur so etwas zu verwenden:

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

Dann ist es einfach, Tensorflow mitzuteilen, welches mit einem Feed-Wörterbuch verwendet werden soll, wie in:

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

Da unklar ist, ob sich die Implementierung ändern wird, wollte ich einen Vorschlag machen (beachten Sie, dass es einfach ist, sich auf Windungen und Dinge auszudehnen, bei denen ich diesen Code einfach nicht eingefügt habe).

@pawni @ppwwyyxx habt ihr euch entschieden, ob ihr die Wiederverwendung verwenden müsste , um das Scoping-Problem zu lösen?

@ brando90 derzeit

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

Ich denke jedoch, dass # 3265 es grundsätzlich so implementieren möchte. Eine Referenz könnte die Dropout-Implementierung hier sein: https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/layers/python/layers/layers.py#L433 -L435

Wenn die updates_collections = None sind, werden die Updates direkt durchgeführt und es ist einfacher, tf.cond () zu verwenden, um zu ermöglichen, dass is_training ein Tensor ist. Etwas komplizierter ist es, wenn die Updates verzögert werden und die update_ops später ausgeführt werden.
Ich werde versuchen, den ersten Teil bald zu bekommen.

@ brando90 @pawni er Code funktioniert gut, muss aber wie unten ändern

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

Und wenn Sie in der Trainings- oder Testzeit laufen,

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

Dieser Code funktioniert, aber wie # 3265 sagt, ist es großartig, wenn tf.contrib.layers.batch_norm is_training als tf.plcaeholer .

@nmhkahn @pawni danke für die Code-Schnipsel. Sie waren sehr nützlich, um meinem Faltungsnetzwerk eine Batch-Normalisierung hinzuzufügen. Das Training scheint sehr gut zu funktionieren. Testen ist nicht. In einigen Versionen des Codes sind die Trainingsgenauigkeiten viel höher als die Testgenauigkeiten, was wahrscheinlich bedeutet, dass ich keine Batch-Normalisierungsparameter teile. In anderen Versionen des Codes wird "ValueError: Variable conv1 / beta ist bereits vorhanden, nicht zulässig. Wollten Sie in VarScope die Wiederverwendung = True setzen?" Dies scheint darauf hinzudeuten, dass ich versuche, den Parameter neu zu lernen ... als ich versuchte, ihn wiederzuverwenden.

Kann jemand ein Beispiel dafür geben, wie die Funktion "def BatchNorm" während des Trainings und Testens aufgerufen wird, damit die gemeinsame Nutzung von Variablen korrekt erfolgt?

Vielen Dank für jede Hilfe.

UPDATE 25. Juli 2016:

@nmhkahn @pawni danke für deine Kommentare. Nachdem ich mir den Code in Contrib genauer angesehen hatte, wurde mir klar, was mein Problem war. Während des Trainings und Testens aktualisieren oder verwenden wir vier Variablen (Beta, Gamma, Moving_Mean und Moving_Varianz). Um diese einzigartig zu machen, musste ich einen Bereich pro Ebene festlegen. Ich habe es so gemacht:

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

Dabei ist batch_norm_layer den Beispielen aus @nmhkahn @pawni ähnlich , conv2d_stride2_valid ist nur ein Def, um eine Faltungsschicht zu definieren, und W_conv1 und b_conv1 sind Variablen, die die Gewichte und Verzerrungen enthalten. Ich könnte wahrscheinlich den Bias-Term entfernen, weil wir die Batch-Normalisierung verwenden.

Das Netz funktioniert jetzt gut. Nachdem ich die Genauigkeiten im Trainings- und Testmodus aufgezeichnet hatte, bemerkte ich, dass die Testgenauigkeiten nach den Trainingsgenauigkeiten zu steigen beginnen. Rückblickend ist dies sinnvoll, da wir Datensatzstatistiken zum Testen sammeln. Aber es schien, als hätte ich bei meinen ersten Tests etwas falsch gemacht. Vielen Dank für Ihre Kommentare und die Bereitstellung der Batch-Normalisierung für die Community.

@nmhkahn wie unterscheidet es sich von pawnis vorschlag?

@ brando90 Ich hatte einen kleinen Fehler in meiner Version, der von nmhkahn behoben wurde (Änderung von isTraining in is_training )

@diegoAtAlpine Ich habe die gleichen Probleme gefunden - nicht sicher, warum dies der Fall ist. Der ValueError sollte jedoch durch das Code-Snippet aufgelöst werden. Sie sind sich nicht sicher, wie Sie es nennen wollen, da nmhkahns Beispiele den Job zu machen scheinen?

@nmhkahn @pawni @ wenn Sie tun:

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

Bedeutet das nicht, dass Sie is_training als Platzhalter verwenden? Die Leute haben kommentiert, dass sie wollen, dass is_training ein Placer-Inhaber ist, aber das war es, was ich für meine Version davon hatte:

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

ist das nicht richtig

Ich habe tf.contrib.layers.batch_norm bereits erweitert, um das Übergeben eines Tensors oder eines Platzhalters für is_training zu ermöglichen. Es wird in Kürze in TF Contrib zusammengeführt.

Jetzt erhältlich in
https://github.com/tensorflow/tensorflow/commit/9da5fc8e6425cabd61fc36f0dcc1823a093d5c1d#diff -94bbcef0ec8a5cdef55f705e99c2b2ed

bin ich es nur oder verlangsamt das Hinzufügen dieser BN-Schicht das Training einer einzelnen Epoche merklich?

@ brando90 Es verlangsamt auch das Training für mich, aber ich denke, dass dies erwartet wird, da es einige Statistiken berechnen muss. Und deine Version sieht für mich gut aus.

BatchNorm ist derzeit sehr langsam (aufgrund aller berechneten Statistiken), aber sie arbeiten daran, wie hier beschrieben eine cudnn-Batchnorm-Operation hinzuzufügen.

@nmhkahn kurze Frage. Als Sie geschrieben haben (zum Testen):

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

Kann bx und by theoretisch ein beliebiger Datensatz sein? dh es kann immer noch das Trainingsset sein , obwohl wir nicht trainieren? (dh nur um den Zugfehler zu verfolgen)

@ brando90 du hast recht.

Ich bin auch verwirrt in Bezug auf is_training und Wiederverwendungsflags. Ich habe ein Programm nach dem CIFAR-Beispiel erstellt, in dem mein Code wie in CIFAR strukturiert ist:

  • Inferenz
  • Verlust
  • Zug

Und ich betreibe es mit mehreren GPUs (für das Training).
Ich habe also ein Skript zum Trainieren (ähnlich wie cifar10_multigpu.py) und eines zum Testen (ähnlich wie cifar10_eval.py).
Damit

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

Die Inferenz erfolgt mit der Funktion MyModel. (unten ist ein Beispiel für die Funktion, in Wirklichkeit verwende ich mehr Schichten und Neuronen).

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

Ich möchte eine Chargennominierung durchführen. Also, als ich es tat:

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)

Ich habe in der Trainingsphase folgenden Fehler erhalten:
Variable bnormalization / beta existiert nicht, nicht erlaubt. Wollten Sie in VarScope die Wiederverwendung = Keine festlegen?

Nach dem, was ich in der Trainingsphase in diesem Thread gelesen habe, sollte ich Wiederverwendung = Keine verwenden. Habe ich diesen Teil richtig verstanden? Wenn dies zutrifft, sollte ich dann, da ich zwei GPUS verwende, in der ersten GPU wiederverwenden = Keine und in der zweiten wiederverwenden = wahr? Oder da ich tf.get_variable_scope (). Reuse_variables () mache, kümmert es sich um sich selbst?

Sollte ich in der Testphase schließlich is_training = False und reuse = True haben?

Jede Hilfe wird sehr geschätzt.

Jetzt akzeptiert tf.contrib.layers.batch_norm einen Tensor, eine Variable oder einen Platzhalter als is_training

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

Ist es normal, dass die Chargennormalisierung meine Experimente verschlechtert ? Ich habe es in einem zweischichtigen NN-Netzwerk versucht, das auf dem MNIST-Anfänger-Tutorial basiert, und ich erhalte durchweg schlechtere Ergebnisse, wenn BN vorhanden ist: Mit BN (eines mit Skalierung und Mitte trainiert und das andere nicht) beträgt die Genauigkeit 0,8423, 0,8221 und ohne BN-Genauigkeit 0,9477.

Mein Skript ist hier verfügbar https://github.com/brando90/tensor_flow_experiments/blob/master/tf_tutorials/beginner_tutorial_MNIST_BN.py

Jemand hat diese Probleme erlebt oder ist BN einfach so und ich muss etwas anderes tun, damit es funktioniert?

Die neueste Version von tf.contrib.layers.batch_norm akzeptiert jetzt einen Platzhalter für is_training, sodass Sie dies nicht selbst tun müssen.

Es ist jedoch wichtig, dass Sie entweder updates_collections = None übergeben, damit move_mean und move_variance direkt aktualisiert werden. Andernfalls müssen Sie update_ops sammeln und sicherstellen, dass sie ausgeführt werden.

Ich möchte Sie ermutigen, tf.contrib.layers oder tf.contrib.slim zu verwenden, um Ihr Modell zu erstellen.

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 Ich habe mein altes geändert, wo ich es manuell

Außerdem habe ich festgestellt, dass Sie sagten, es sei ein Platzhalter, und ich musste es nicht manuell tun. Als ich jedoch einen Platzhalter für is_training übergeben habe, hieß es

TypeError: Using a tf.Tensor as a Python bool is not allowed. Use wenn t nicht None ist: instead of wenn t: to test if a tensor is defined, and use the logical TensorFlow ops to test the value of a tensor.

und zeigte auf batch_norm Code. Vielleicht könnte es schön sein zu zeigen, wie dieses Platzhalter-Ding verwendet werden sollte, weil ich anscheinend nicht verstehe, wie es verwendet werden soll. Vielen Dank! :) :)

@ brando90
Der relevante Teil des Codes ist hier L227-256 .

Wie Sie feststellen werden, gibt es eine with ops.control_dependencies -Anweisung, die die Aktualisierungen erzwingt. Ich glaube, dass für die Verwendung des Codes "sofort einsatzbereit" der Standardwert "Keine" sein sollte.

Für meinen Kommentar über 1122 habe ich herausgefunden, dass tf.get_variable_scope (). Reuse_variables () das Problem behebt, daher sollte in der Trainingsphase das Argument der Wiederverwendung von batch_norm None sein. Es hat mit der Anweisung variable_op_scope zu tun (lesen Sie die Dokumentation in Tensorflow)

Verwendung von batch_norm mit 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})

Das Problem zuvor war, dass Sie die moving_mean und moving_variance nach jedem Schritt nicht aktualisiert haben. Wenn updates_collections None ist, werden die Aktualisierungen als Teil der Berechnung erzwungen.
Wenn ein Netzwerk jedoch über viele Batch_Norm-Ebenen verfügt, ist es effizienter, alle Update-Operationen zu sammeln und zusammen auszuführen, sodass jede Ebene nicht auf den Abschluss des Updates warten muss.

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

Wurden Fortschritte bei der Beschleunigung der Chargennorm erzielt?

Ich habe versucht, die Batch-Norm mit einem zweischichtigen, dicht verbundenen NN mit dem Datensatz (flache) MNIST (und Relu-Einheiten) für die Aufgabe der automatischen Codierung zu verwenden, und es wird immer wieder ein NaN-Fehler angezeigt. Weiß jemand warum das sein könnte? Ist das mit BN jemals möglich? scheinen faul zu sein, aber es konnte nicht mein Lernaufbau, meine Bewertung usw. sein (aber ich würde annehmen, dass dies nicht der Fall sein sollte, da BN eine Art Rubust dazu sein sollte)

@sguada Ich verstehe nicht die richtige Art und Weise, batch_norm speziell für die Flagge updates_collections . Wenn ich richtig verstanden habe, dass das Flag None das Netzwerk nicht effizient, also sollte ich updates_collections=tf.GraphKeys.UPDATE_OPS und dann alle Batch_Norm-Updates sammeln und zusammen ausführen.

Sie sammeln die Batch_Norms-Updates wie folgt: update_ops = tf.group(tf.get_collection(tf.GraphKeys.UPDATE_OPS)) .

Ich habe viele verschiedene Modelle, die verschiedene Batch_Norm-Ebenen verwenden. Das würde nicht funktionieren, oder?:

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

Könnten Sie diesen Teil mit etwas mehr Details erklären? Vielen Dank.

Legen Sie es einfach in separate Sammlungsschlüssel:

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

Trotzdem scheint die Dokumentation veraltet zu sein. Es sagt Folgendes aus:

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)

Aber:

  • _tf.group () _ akzeptiert keine Liste. Ich habe es durch _tf.tuple () _ ersetzt
  • Ich weiß nicht, wie ich auf _control_flow_ops.with_dependencies () _ zugreifen soll. Ich habe andere Beispiele gesehen, die nur tf.with_dependecies () verwenden, aber ich kann das mit Tensorflow 0.10 nicht tun. Ich habe es hier gefunden: _tf.python.control_flow_ops.with_dependencies () _

BEARBEITEN:

Die Dokumentation sollte auf s.th. so was:

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)

EDIT 2:

Nach einigen Läufen in meinem Netzwerk muss ich sagen, dass ich keinen Leistungsunterschied zwischen der Verwendung von _updates_collections = None_ im Gegensatz zum manuellen Abrufen von _tf.GraphKeys.UPDATE_OPS_ während der Diagrammkonstruktion feststellen kann . Selbst bei starker Verwendung der Batch-Normalisierung (insgesamt gibt meine _tf.get_collection (tf.GraphKeys.UPDATE_OPS) _ 140 Update-Ops zurück, alle sind nur BN-Ops)

Bearbeiten: Schwer zu sagen, ob meine Ergebnisse korrekt sind, aber das gesamte Netzwerk scheint tatsächlich 1,5x schneller zu sein. Soweit ich weiß, werden BN-Statistiken auf der CPU berechnet, bisher nicht auf der GPU.

Kann jemand von Ihnen auch Leistungsvorteile sehen? Bitte teilen Sie Ihre Ergebnisse :)

Wenn wir auf das Leistungsproblem zurückkommen, profitiert die aktuelle Batch-Norm-Schicht überhaupt von der GPU-Nutzung? Hat jemand Vorteile von GPUs mit dieser Batch-Norm-Implementierung erfahren?

Entschuldigung für den Spam, aber die Dokumentation erklärt nicht wirklich, wie man diesen BN mit Faltung verwendet (sollte er vielleicht irgendwo bereitgestellt werden?). Kurz gesagt, wie stellt sich heraus, dass es dieselben Parameter pro Feature (und nicht pro Aktivierung) anwenden und lernen sollte?

(Gibt es dafür mindestens ein Code-Snippet?)

Der schlanke Batch_Norm-Wrapper normalisiert sich über die letzte Dimension Ihres Eingabetensors. Wenn es sich also um einen 2D-Eingangstensor handelt, der von einer vollständig verbundenen Schicht stammt, normalisiert er sich über den Stapel und führt somit eine Normalisierung pro Aktivierung durch. Wenn es sich um einen 4D-Tensor handelt, der aus einer Faltung stammt, normalisiert er sich über die drei ersten Dimensionen (Stapel, Breite, Tiefe) und führt somit eine Normalisierung pro Merkmal durch. @sguada vielleicht etwas ausführlicher darüber.

@nmhkahn In Bezug auf Ihr Code-Snippet darf ich fragen, warum reuse auf None wenn is_training=True ? Würde das nicht dazu führen, dass der Skalierungsparameter gamma und der Offset-Parameter beta in jedem Trainingsschritt neu initialisiert werden? Ich dachte in der Originalarbeit, dass beta und gamma "zusammen mit den ursprünglichen Modellparametern gelernt" werden. Sollten sie dazu nicht nur einmal initialisiert und dann in allen Trainingsschritten wiederverwendet werden?

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

Ich schätze die Arbeit, die das TF-Team hier geleistet hat, um batch_norm verfügbar und effektiv zu machen, sehr. Nach meiner Suche ist dieser Thread die beste Ressource für die Verwendung. Hier gibt es viele verschiedene Probleme und Ideen, und es ist schwierig, die Konsensempfehlungen für den einfachsten Standardfall für die Verwendung der Ebene batch_norm zu finden. Ich denke, es wäre sehr wertvoll, die Dokumentation zu erweitern, um die genaue empfohlene Verwendung anzugeben.

Mein bester Versuch, das herauszufinden, brachte mich zu folgendem Code:

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

Dann setze ich is_training_ph für das Training auf True und für das Testen auf False. Das funktioniert bei mir nicht. Das Modell trainiert gut, aber die Testleistung ist schrecklich. Im Gegensatz dazu funktioniert es hervorragend, wenn ich für die Testzeit is_training_ph = True behalte. Daher schätze ich, dass ich immer noch ein Scope-Problem habe, sodass nicht die richtigen vorhandenen Variablen gefunden werden.

@ davek44 Ich verwende dasselbe Code-Framework, das Sie verwenden, und habe dasselbe beobachtet: Wenn is_training=True während der Trainingsphase aktiviert und is_training=False für die Validierungs- und / oder Testphase deaktiviert wird, Das Modell trainiert gut wie das beschriebene Papier (das Modell konvergiert schneller und ich konnte eine größere Lernrate verwenden), jedoch ist die Testleistung schrecklich. Wenn ich is_training=True ganze Zeit einschalte, trainiert das Modell genauso wie ohne Einfügen einer Batch-Norm-Ebene. Ich habe nicht herausgefunden, was ich falsch gemacht habe. Ich plane, TensorBoard zur Überwachung der Parameter zu verwenden. Würden Sie bitte aktualisieren, wenn Sie die Ursache für dieses Verhalten diagnostizieren?

tf.contrib.layers.batch_norm kann Tensor als is_training annehmen, muss also nichts Besonderes tun.

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

Ich sehe die gleiche schlechte Testleistung mit diesem Code.

Ohne weitere Details ist es unmöglich zu wissen, meine Vermutungen sind, dass Sie nur für ein paar Iterationen trainieren, so dass das Moving_Mean und das Moving_average noch nicht konvergieren.

Sie können die Größe von batch_s während des Tests ändern, um festzustellen, wie sich die Leistung verschlechtert, wenn Sie Ihren Stapel verkleinern.

Ich sehe die gleiche schlechte Testleistung mit diesem Code.

Ich hatte genau das gleiche Problem, entweder mit tf.slim batchnorm oder mit tf.cond und der Eingabe is_training als Platzhalter.
Im ersteren Fall stellte ich bei der Untersuchung des trainierten Modells fest, dass der gleitende Mittelwert und die bewegliche Varianz aus allen Nullen bestehen.
Im letzteren Fall sehen der gleitende Mittelwert und die Varianz vernünftiger aus (mit unterschiedlichen Werten), aber wenn ich in der Testzeit is_training = False verwende, ist die Leistung auch sehr schlecht. Mit is_training = True funktioniert es besser, aber ich denke, es werden nur der gleitende Mittelwert und die Varianz innerhalb des Teststapels verwendet.

@nmduc @ davek44 Ich habe einen Code geschrieben, um den sich bewegenden Mittelwert und die sich bewegende Varianz zu verfolgen, die während des Trainings und Testens in tf.contrib.layers.batch_norm berechnet wurden. Ich fand heraus, dass der Wert von decay wichtig ist (sie verwenden den exponentiellen Zerfall, um den gleitenden Durchschnitt und die gleitende Varianz zu berechnen), wobei eine Einstellung von decay näher an 1,0 liegt (dh decay=.999 Ich habe 2 Testläufe mit genau demselben Code, aber unterschiedlichen decay -Einstellungen in den tf.contrib.layers.batch_norm , und meine Validierungs- / Testgenauigkeiten schienen vernünftiger zu sein.

Der Testlauf ergibt decay=0.9
screen shot 2016-11-16 at 1 51 51 pm

Die Testergebnisse mit decay=0.999 ( decay=0.999 ist die Standardeinstellung in tf.contrib.layers.batch_norm )
screen shot 2016-11-16 at 2 03 58 pm

(Es scheint auch, als würde ein größerer Abklingwert erfordern, dass das Modell länger trainiert, um eine Änderung der Validierungsgenauigkeit zu sehen.)

Ja, das hat es behoben. Vielen Dank für Ihre Analyse @zhongyuk!

Ich ermutige die Entwickler, in Betracht zu ziehen, Zerfall = 0,9 als Standard festzulegen. Selbst 0,99 funktioniert bei mir nicht gut. Dies ist auch der Standardwert in der Implementierung von Torch. Siehe den Momentum-Parameter in https://github.com/torch/nn/blob/master/BatchNormalization.lua

@zhongyuk Vielen Dank für das Teilen. Es funktioniert jetzt für mich.

Das scheint wichtig zu sein. @sguada wir sollten hier vor 1.0 die richtige Vorgehensweise berücksichtigen. Kann mir eine der interessierten Parteien kurzfristig eine PR schicken, in der dokumentiert wird, dass decay bei einer schlechten Bewertungsleistung möglicherweise erheblich gesenkt werden muss? Ich bin mir ziemlich sicher, dass ich diesen Parameter nie anpassen musste, aber es könnte ein Nebeneffekt der verteilten Einstellung sein.

Wir könnten die Standardeinstellung auf 0,9 ändern oder die Auswirkungen in kleineren Datensätzen oder wenigen Aktualisierungen besser dokumentieren.
@vincentvanhoucke In unserer verteilten Einstellung führen wir normalerweise Millionen von Updates durch, daher ist Ordnung. In anderen Fällen wie dem hier, in dem nur einige Hundert Updates durchgeführt werden, macht dies jedoch einen großen Unterschied:
Zum Beispiel hat die Verwendung von Decay = 0,999 nach 1000 Aktualisierungen eine Abweichung von 0,36, diese Abweichung sinkt jedoch nach 10000 Aktualisierungen auf 0,000045 und nach 50000 Aktualisierungen auf 0,0.

Ich wollte nur darauf hinweisen, dass ich auch das Problem einer schlechten Testleistung habe, insbesondere bei Verwendung kleiner Chargengrößen (alles, was kleiner als 10 anstelle der 200 ist, die ich für das Training verwendet habe, verringert die Testgenauigkeit). Ich habe einen tf.placeholder verwendet, um zwischen dem Test- / Trainingsmodus zu wechseln.

Es ist großartig, dass diese Batch-Normalisierungsschicht für eine bessere Trainingskonvergenz funktioniert. Wenn Sie das Modell jedoch nicht in der Produktion anwenden können, ist es nicht sinnvoll, es zu verwenden. Kann jemand eine gute Testleistung mit kleinen oder einzelnen Datenproben unter Verwendung dieser Chargennormschicht bestätigen?

Ich kann bestätigen, dass die Testleistung gut ist, wenn is_training = False mit kleinen Stapeln und sogar mit batch_size = 1 verwendet wird, da keine Statistik aus dem Stapel verwendet wird, sondern die während des Trainings erlernte Statistik. Stellen Sie nur sicher, dass die Statistiken mit dem Standardabfall = 0,999 konvergiert haben, was mindestens 50.000 Aktualisierungen impliziert.

Um die Bestätigung des TF-Entwicklers zu erhalten, verfolge ich die Konvergenz der Statistiken mit zwei verschiedenen decay -Einstellungen (und trainiere batch_size = 1). Mit decay=0.99 konvergieren die Statistiken (Bias <0,001) nach 550 ~ 600 Lern- / Aktualisierungsschritten. Mit decay=0.9 konvergieren die Statistiken innerhalb von 100 Schritten nach dem Lernen / Aktualisieren (Verzerrung <0,001).

@sguada danke, bedeutet das auch, dass die Ausgabe tatsächlich unabhängig von der

@zhongyuk danke, ich habe ungefähr 5.000 Updates mit decay=0.9 , daher sollte es konvergiert haben und das Testen der Leistung mit großen Stapelgrößen ist in Ordnung. Aber selbst wenn dies nicht der Fall wäre, würde dies zu einem Unterschied zwischen dem Training und dem Testen führen? Ich würde beim Training und Testen schlechte Leistungen sehen, wenn sie nicht konvergiert hätten, oder?

Ich werde weitere Untersuchungen durchführen und prüfen, ob ich das Problem bei einer anderen Aufgabe reproduzieren kann. Vielen Dank für die schnelle Rückmeldung bisher!

@dominikandreas Wenn Ihre schlechte

Ich habe einen Fehler in meinem Code gefunden, die Batch-Normalisierung funktioniert jetzt einwandfrei :-) Vielen Dank für Ihre Unterstützung

Hallo @zhongyuk , wie haben Sie den gleitenden Mittelwert und die Varianz verfolgt?
Vielen Dank!

@rogertrullo Im Allgemeinen tf.get_variable("moving_mean") abzurufen, um die Verzerrung zu überwachen.

Hallo,
Ich habe das gleiche Problem wie andere beschrieben, dass ich gute Trainingsergebnisse habe, aber die Validierung / Prüfung nach Verwendung von batch_norm schlecht ist.
Ich benutze die Funktion wie folgt:
conv_normed1 = tf.contrib.layers.batch_norm (conv1 + block1_layer3_1_biases, updates_collections = Keine, scale = True, zerfall = batch_norm_decay, center = True, is_training = is_training)
Der Abklingwert beträgt 0,9
muss ich das Wiederverwendungsflag setzen?
Ich freue mich über jede Hilfe.

Ich habe batch_norm wie in diesem Thread beschrieben verwendet (mit einem tf.bool für das Training und ops.GraphKeys.UPDATE_OPS) und alles funktioniert.

Beim Speichern und Wiederherstellen mit:
saver = tf.train.Saver ()
Es klappt,

aber beim Speichern mit:
saver = tf.train.Saver (tf.trainable_variables () + [global_step])
damit ich Speicherplatz sparen kann (indem ich die Farbverläufe usw. nicht speichere)
Bei der Wiederherstellung tritt ein Fehler auf:
"nicht initialisierter Wert unpool4 / convc / bn / move_mean"

Dies liegt offensichtlich daran, dass Moving_Mean (und ich nehme an, Moving_Varianz) für keine der Ebenen gespeichert wurde. Da ich viele davon habe (in vielen Ebenen verschachtelt) - wie kann ich sie am effizientesten zur Liste der zu speichernden Werte hinzufügen? Da es sich um trainierbare Variablen handelt, warum werden sie nicht zur Sammlung trainable_variables hinzugefügt?

@mshunshin Moving Mean und Varianz sind keine trainierbaren Variablen: Es kommen keine Gradienten zu ihnen, sie sammeln lediglich Statistiken über Minibatches von Beispielen.
Um sie zu speichern / wiederherzustellen, können Sie tf.global_variables () verwenden.

Für mich begannen die Dinge zu funktionieren, als ich diesen Wrapper benutzte:
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
Die gesamte Verwendung von Bereichen und Wiederverwendung ist in diesem Thread meiner Meinung nach nicht klar.

Danke vielmals. Mit tf.global_variables () sind die Sicherungsdateien viel größer, da sie meiner Meinung nach die Farbverläufe enthalten. Am Ende habe ich verwendet:

saver = tf.train.Saver ([x für x in tf.global_variables (), wenn 'Adam' nicht in x.name]])

und weil der Sitzungsmanager init sie nicht richtig initialisiert:

sess.run (tf.variables_initializer ([x für x in tf.global_variables () wenn 'Adam' in x.name]))

(Mit tf.train.AdamOptimizer)

Sie können auch tf.model_variables () verwenden, das die Variablen des Modells enthält, dh move_mean

@sguada Entschuldigen Sie die Probleme, aber ist es möglich, ein Beispiel für die Verwendung von slim.batch_norm in Kombination mit slim.conv2d / slim.fully_connect in readme.md zu erstellen?

Ich verwende slim.batch_norm, erhalte aber eine gute Trainingsleistung und eine schlechte Validierungs- / Testleistung. Ich denke, es muss an der unsachgemäßen Verwendung von reuse oder scope oder einigen anderen Parametern liegen. Obwohl es bei der Batch-Normalisierung viele Probleme gibt, ist es schwierig, ein vollständiges Code-Snippet zur Verwendung zu finden. für das Übergeben verschiedener Parameter in verschiedenen Phasen.

Angenommen , ich habe in meinem tf.GraphKeys.UPDATE_OPS gesteuert und is_training als Platzhalter eingerichtet. Die Validierungsleistung ist jedoch immer noch schlecht, wenn ich {is_training: False} füttere.

Ich würde es sehr begrüßen, wenn es ein offizielles und vollständiges Beispiel für die Chargennormalisierung gibt (was bedeutet, dass Schulungen, Validierungen und Tests enthalten sind).

Danke im Voraus!

Hallo,
Sie müssen für jedes Mal, wenn Sie die Chargennorm verwenden, einen anderen Bereich festlegen und ihm den Wiederverwendungseingang gemäß der für mich geeigneten Trainings- / Testphase (WAHR beim Test FALSCH beim Zug) geben.

@ishaybee Danke für Es liegt am Kaltstart von Moving_Mean / Moving_Varianz.

Da ich nicht genug Schritte trainiert habe, ist der geschätzte gleitende Mittelwert / die geschätzte Varianz nicht so stabil. Das Ergebnis stellt sich heraus: Das Modell ist beim Training von Mini-Batches ziemlich leistungsfähig (Sie wissen, dass der Verlust zu Beginn schnell abnimmt), aber die Validierungsleistung ist unregelmäßig (weil der geschätzte Populationsmittelwert / die geschätzte Varianz nicht stabil genug sind).

Wenn ich das Modell länger trainiere, wird auch die Validierungsgenauigkeit schöner.

Eine weitere wichtige Sache ist, dass Sie slim.learning.create_train_op , um Zugoperationen zu erstellen . Verwenden Sie nicht tf native tf.train.GradientDescentOptimizer(0.1).minimize(loss) .

Die Antwort lautet also: Ich verwende die Batch-Normalisierung korrekt, habe aber die Dynamik während des Trainings nicht vollständig verstanden.

================
Was ist mehr:

  1. Hier ist ein vollständiges Beispiel für die Verwendung der BN-Schicht im MNIST-Dataset.
  2. Wenn Sie einen kleineren Abklingwert verwenden, wird die Aufwärmphase beschleunigt. Der Standardabfall ist 0,999. Für kleine Datensätze wie MNIST können Sie 0,99 oder 0,95 auswählen, und es wird in kurzer Zeit warm.

@soloice , beachten Sie, wie in about comment der folgende Parameter an die Ebene zum Aufrufen von batch_norm übergeben wird:

batch_norm_params = {'is_training': is_training, 'zerfall': 0.9, 'updates_collections': Keine}

Ohne updates_collections das auf None gesetzt ist (also werden mittlere Aktualisierungen in BatchNorm durchgeführt), erwarte ich nicht, dass die umgebende Ebene (z. B. conv2d) tf.GraphKeys.UPDATE_OPS ausführt, die für die Aktualisierung der laufenden Mittelwert- und BatchNorm-Ebene erforderlich ist Daher können Sie die Testdaten später ausführen.

Oder Sie können versuchen , UPDATE_OPS sich ausdrücklich als ein laufen hier

    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 - Ich habe festgestellt, dass ich genau Ihren Code zitiert habe und Sie UPDATE_OPS verwenden.

Was den "Kaltstart" betrifft, wie Sie oben in der Diskussion sehen, kann das Verringern des laufenden BatchNorm-Durchschnittsabfalls (Eingabeparameter) von Standard 0,999 auf etwa 0,95 den Start beschleunigen

@pavelbulanov Es ist sehr nett von Ihnen, mir dabei zu helfen! Ich werde einen kleineren Wert von decay versuchen, um zu sehen, wie dies hilft.

================
Update: Die Verwendung eines kleinen Zerfalls (z. B. 0,9 oder 0,95) hilft sehr. Der Validierungsverlust sinkt sehr schnell, wenn ich decay auf 0,9 setze. Der Nachteil des kleinen Zerfalls besteht jedoch darin, dass sein effektiver Bereich gering ist: Das Ergebnis wird von einigen neueren Stichproben dominiert, daher ist es keine gute Schätzung des Populationsmittelwerts / der Populationsvarianz. Man muss zwischen einem schnellen Start (kleiner Zerfall) und einem längeren effektiven Bereich (großer Zerfall) abwägen.

Hallo,
Ich habe versucht, mithilfe der Vorschläge in dieser Ausgabe eine Batch-Normalisierungsschicht zu implementieren, aber ich habe immer noch einen Fehler von> 70% bei der Validierung und beim Testen ... Ich habe einen geringeren Zerfall für Anrufe ohne Training ...

Hier ist mein 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)
    )

Danke im Voraus.

@Alexivia Es scheint, dass Sie zwei verschiedene Batch-Normalisierungsschichten verwenden? Sie sollten nur eine BN-Schicht verwenden (natürlich mit unterschiedlichen is_training -Parametern).

Vielen Dank für Ihren Rat @soloice.
Ich habe es jetzt mit nur verschiedenen is_training und reuse Parametern versucht:

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)

erhalten immer noch keine guten Validierungs- und Testergebnisse ...> 70% ...

Hallo,
Bitte sehen Sie meine Verpackung oben.
Sie sollten "mit tf.variable_scope (scope, reuse = reuse)" verwenden: "Ich denke.

Hallo @ishaybee ,
Ich habe Ihren Rat befolgt, jetzt lautet mein Code:

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)

und ich füttere is_training und reuse durch das feed_dict, aber jetzt erhalte ich den Fehler ValueError("The reuse parameter must be True or False or None.")

Versuchen Sie, die Wiederverwendung als Python-Variable (Eingabe des Modells) und als Platzhalter einzugeben.

Ich habe das versucht, und jetzt hat es aufgehört, sich über den Wert zu beschweren ... aber ich denke, dass der Platzhalterwert nicht verwendet wird, da ich keine Änderung sehe, wenn ich Werte auf die Funktion batch_norm erzwinge, und in TensorBoard ist dies nicht der Fall verbunden mit der Grafik ... (siehe beigefügtes Bild)
screen shot 2017-04-03 at 19 54 54

Mein Code ist jetzt so:
Batch-Normalisierungs-Wrapper

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)

Modelldefinition

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)

Ausbildung

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)

Validierung

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

Obwohl is_traning kann, muss die Wiederverwendung eines Platzhalters ein Bool sein, und es kann weder ein Tensor noch ein Platzhalter sein.

Ich bin nicht sicher, was Sie versuchen, in den meisten Fällen lösen statische Werte das Problem. Zum Beispiel funktioniert dieses Muster gut:

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

Sofern Sie das Verhalten des Modells nicht dynamisch ändern müssen, müssen Sie für is_training keinen Platzhalter verwenden. Der Trick besteht darin, das Modell zweimal zu erstellen, die Variablen jedoch beim zweiten Mal gemeinsam zu nutzen.

Danke @sguada ! Nachdem ich Ihre Vorschläge angewendet hatte, habe ich es endlich geschafft!

Es wäre hilfreich, wenn in der API 1.0-Dokumentation berücksichtigt würde, dass Sie dem Diagramm manuell Aktualisierungsoperationen hinzufügen müssen. Als neuer tf-Benutzer stellte ich fest, dass mein Testfehler verrückt war, und musste dann ziemlich viel Zeit damit verbringen, mein Diagramm zu debuggen, bis mir klar wurde, dass die Batch-Normalisierung das Problem war. Dann musste ich mehr Zeit damit verbringen, herauszufinden, dass die Variablen, die die Momente verfolgen, standardmäßig nicht aktualisiert werden, es sei denn, Sie verwenden eine Contrib-Funktion zur Optimierung. Da es in 1.0 keine Option gibt, die update_collections auf None zu setzen, gibt es in der Dokumentation keinen Hinweis darauf, dass dies möglicherweise sogar ein Problem darstellt. Darüber hinaus scheint es sinnvoll zu sein, einen Parameter zu haben, um die Kontrollflussabhängigkeiten zu der Operation hinzuzufügen, die im Trainingsfall ausgeführt wird.

@danrsc Genau. Die Verwendung der BN-Schicht ist ziemlich verwirrend. Ich schlug vor, Dokumente oder ein vollständiges offizielles Tutorial zur Batch-Normalisierung hinzuzufügen, erhielt aber leider keine Antwort = =

Stimme voll und ganz zu. Ich denke, die Verwendung von BN ist sehr schwierig und die Dokumentation ist derzeit mehr als unzureichend. Dies sollte für eine solche häufig verwendete Schicht behoben werden.

Wiedereröffnung zur Sichtbarkeit der Dokumentationsprobleme.

@sguada zugewiesen für Sie für Triaging. Es könnte sich lohnen, einen technischen Redakteur für den Fall zu gewinnen.

Ich war letzte Woche durch dieses Problem verwirrt und habe 3 Tage Training verschwendet ... Ich hoffe, die Dokumente können bald repariert werden, und ein offizielles Beispiel für die Stapelnormalisierung kann in den API-Dokumenten hinzugefügt werden.

@sguada Mir ist aufgefallen, dass Sie gesagt haben, "tf.contrib.layers.batch_norm kann Tensor als is_training annehmen, muss also nichts Besonderes tun".
Der Kommentar im Code lautet jedoch
Wenn is_training keinen konstanten Wert hat, weil es ein Tensor ,
# a Variable oder Placeholder dann ist is_training_value None und
# needs_moments wird wahr sein.
Bedeutet das, dass nees_moments auch in der Testphase wahr ist, wenn ich is_training als Platzhalter setze?
Soweit ich weiß, werden die Momente beim Testen nicht benötigt.

Wenn also is_training ein Variable oder ein Placeholder , bedeutet dies, dass es sich ändern kann, sodass das Diagramm zur Berechnung der Momente benötigt wird und die Ebene es erstellt.
Dann würde in der Laufzeit abhängig von dem Wert, der True oder False , der Stapel moments oder moving_mean und moving_variance .

Während des Testens würden Sie den Wert auf False und die moments werden nicht verwendet.

@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

Ich baue ein Batchnorm wie dieses, aber der sich bewegende Mittelwert und die sich bewegende Variable werden während des Tests aktualisiert. Ich kann den Grund nicht finden.

Ich habe versucht, zwei Modelle zu erstellen , wie

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

Ich denke, vielleicht sollte es ein konkretes Beispiel dafür geben, wie man eine Batch-Norm mit einem vollständig verbundenen Netz sowie mit CNNs erstellt. Scheiße, dass ich tagelang Models trainiert habe, in der Erwartung, dass die Dinge funktionieren, bevor ich sehe, dass jeder, der versucht, diese Funktion zu nutzen, verrückt wird.

Interessanterweise dauert es zig Jahre, bis das Modell auch nach dem Training mit batch_norm wiederhergestellt ist. Ich werde höchstwahrscheinlich bis TF 2.0 warten, um so etwas noch einmal zu versuchen.

@MisayaZ Sie müssen nicht zwei Batch_Norm-Layer erstellen. Sie können einfach train_phase (vorausgesetzt, es handelt sich um einen tf.bool) an batch_norm übergeben. Außerdem übergeben Sie UPDATE_OPS_COLLECTION variables_collections, wodurch geändert wird, zu welchen Sammlungen die Variablen hinzugefügt werden.

Folgendes sollte funktionieren:

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

@OktayGardener nicht sicher, welches Modell Sie erstellen

batch_norm funktioniert auch mit vollständig verbundenen Ebenen.

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 Danke, ich baue ein Netzwerk mit Bathnorm auf, das wie oben erwähnt implementiert ist

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

Die Geschwindigkeit ist langsam. Ich verwende den Tensorflow-Benchmark, um die folgende Rechenzeit zu erhalten:
I tensorflow / core / util / stat_summarizer.cc: 392] ============================== Top by Computation Time === ===========================
I tensorflow / core / util / stat_summarizer.cc: 392] [Knotentyp] [Start] [zuerst] [durchschnittliche 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 / Momente / ausreichende_Statistik / 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 / Momente / ausreichende_Statistik / 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 / Momente / ausreichende_Statistik / 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

Ich verstehe nicht, warum einige Operationen im Moment während des Tests ausgeführt werden und es viel Zeit kostet, wie zum Beispiel conv1 / batch_norm / Momente / ausreichende_Statistik / SquaredDifference.

Der Moment wird im Test nicht benötigt. Warum werden einige Operationen im Moment ausgeführt?

Hallo,

Wenn ich die obige Ebene batch_norm in contrib.layers , erhalte ich nan als Ausgabe für das Validierungsdiagramm, während das Zugdiagramm nahtlos ausgeführt wird. Gibt es etwas, das mir fehlen könnte?

Ich benutze:

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)

Vielen Dank

Als Folge verwende ich 16 Ebenen von batch_norm wieder.
Ich fand jedoch, dass die Wiederverwendung von 4 Ebenen funktioniert.

Ich habe gerade bemerkt, dass sich mein Fehler für einige Epochen verschlimmert, wenn ich den Tensorflow-Prozess abbreche und neu starte (dh schlimmer als am letzten Kontrollpunkt). Ich beobachte auch, dass dieses Problem verschwindet, wenn ich batch_norm entferne. Nachdem ich mir den Code eine Weile angesehen habe, kann dies daran liegen, dass die Werte der Variablen nicht aus den Schattenvariablen wiederhergestellt werden, wie dies der Fall wäre, wenn die ExponentialMovingAverages-Klasse zum Verwalten der gleitenden Durchschnitte verwendet würde. Dies bedeutet auch, dass ich, wenn ich einen separaten Prozess zur Auswertung verwende, den letzten Wert der Variablen und nicht den gleitenden Durchschnitt erhalte. Interpretiere ich das richtig und ist das das beabsichtigte Verhalten? Anscheinend möchten Sie, dass die Werte der Schattenvariablen wiederhergestellt werden ...

Ich habe das Problem erkannt, die Bewegungsvarianz in meinem Fall wird nach einigen Iterationen negativ.

Die Ausgabe des Tensors: Model/clip_logits/batch_norm/moving_variance:0 in tf.model_variables() ist

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]

Wie Sie sehen können, gibt es für eine der Dimensionen eine negative Varianz. Wie ist das überhaupt möglich?
PS Die Batch-Norm-Schicht wird unmittelbar nach der letzten vollständig verbundenen Schicht des Netzwerks und vor Softmax verwendet.

@ raghavgoyal14 benutzt du es mit fused = True? Hatte ein ähnliches Problem und es ging weg, als ich die verschmolzene Version verwendete

@abred : Ja, ich habe fused=True , dasselbe Problem.

@sguada Hallo, sguada, ich habe ein Problem.
Die Definition von contrib.layers.batch_norm im Tensorflow:
def batch_norm (Eingaben,
Zerfall = 0,999,
center = True,
scale = False,
epsilon = 0,001,
Aktivierung_fn = Keine,
param_initializers = Keine,
param_regularizers = Keine,
updates_collections = ops.GraphKeys.UPDATE_OPS,
is_training = True,
Wiederverwendung = Keine,
variables_collections = Keine,
output_collections = Keine,
trainierbar = Richtig,
batch_weights = Keine,
verschmolzen = falsch,
data_format = DATA_FORMAT_NHWC,
zero_debias_moving_mean = False,
scope = Keine,
renorm = False,
renorm_clipping = Keine,
renorm_decay = 0,99):
Skala: Wenn True, multiplizieren Sie mit Gamma. Wenn falsch, ist Gamma
nicht benutzt. Wenn die nächste Schicht linear ist (auch zB nn.relu), kann dies sein
deaktiviert, da die Skalierung von der nächsten Ebene durchgeführt werden kann.

Wenn ich tf.contrib.layers.batch_norm (Eingabe, Skala = Falsch) verwende, bedeutet "Skala = Falsch", dass das Gamma in "y = Gamma * x + Beta" während des Trainings Null ist. Vielen Dank.

Wenn scale = False ist, ist Gamma eine Konstante 1.

@ppwwyyxx Vielen Dank für Ihre Hilfe. Ich verwende tf.contrib.layers.batch_norm (Eingabe, Skala = False) in Tensorflow und konvertiere jetzt die Batchnorm von Tensorflow in Caffe. Wie setze ich die Parameter von BatchNormLayer und ScaleLayer in Caffe?
Vielen Dank.

@MisayaZ Ich hatte das gleiche Verhalten bei der Verwendung von Batchnorm mit einem Platzhalter für "is_training". Ich sehe in der Spur, dass die Momente sogar zur Testzeit berechnet werden, also habe ich mich entschlossen, in den Quellcode zu gehen und fand dies:

    # 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

Wenn "is_training" eine Variable oder ein Platzhalter ist, werden die Momente definiert und zur Laufzeit berechnet, selbst wenn Sie den Platzhalter auf "False" setzen. Ich hätte es vorgezogen, es als Platzhalter zu belassen, da ich auf diese Weise während des Trainings regelmäßige Tests durchführen kann, ohne das Diagramm neu zu definieren, aber ich habe beschlossen, es als Konstante zu verwenden und unterschiedliche Verhaltensweisen für Zug gegen Test zu definieren, und jetzt werden die Momente nicht berechnet zur Testzeit.

@ tano297 Danke. Ich benutze jetzt auch 'is_training' als Konstante. Lassen Sie es als Platzhalter und führen Sie regelmäßige Tests durch, um den Wert des sich bewegenden Mittelwerts und der sich bewegenden Varianz zu ändern. Und die Inferenzzeit wird länger sein, da sie den Mittelwert und die Varianz der Eingaben berechnet und den gleitenden Mittelwert und die gleitende Varianz aktualisiert. Der richtige Weg, um Tests durchzuführen, besteht darin, verschiedene Verhaltensweisen für Zug und Test zu definieren, wie Sie erwähnt haben.

@ tano297 @MisayaZ
aber nicht die "smart_cond" in

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)

Stellen Sie sicher, dass die Aktualisierungen nur berechnet und angewendet werden, wenn is_training True ergibt.

@abred Ja, aber Sie beziehen sich auf Zeile 391, in der der gleitende Durchschnitt innerhalb von _fused_batch_norm () aktualisiert wird:

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

Ich spreche von Zeile 753 in 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) 
        ...

Der intelligente Zustand in diesem Fall (soweit es mich betrifft) entscheidet, ob die gleitenden Durchschnitte aktualisiert werden oder nicht, aber die Momente werden immer noch berechnet.

@ tano297 du hast recht damit, ich war am falschen
Zeile 755-770 berechnet die Momente, aber die Momente werden nur in _force_updates verwendet, die nur ausgeführt werden, wenn is_training True ergibt, nicht wahr?
Und somit

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

sollte der Zeile 804 entsprechen:

mean, variance = moving_mean, moving_variance

Wenn is_training zu False ausgewertet wird und daher der "Momente" -Teil des Diagramms niemals verwendet wird und daher nicht ausgeführt werden sollte

aber ich habe nicht getestet, also könnte ich mich irren :)

@ tano297 @abred Sie richtig. Der gleitende Mittelwert und die gleitende Varianz werden geändert, wenn ich Batchnorm wie folgt verwendet habe:

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

Wenn Sie wie folgt verwenden:

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

Der Bewegungsmittelwert und die Bewegungsvarianz werden während des Tests nicht geändert, aber die Geschwindigkeit ist sehr langsam.

Hallo @zhongyuk ,

Ich bin auch auf das Problem gestoßen, dass ich gute Ergebnisse erzielen kann, wenn ich is_training = True sowohl für das Training als auch für die Inferenz verwende, aber schlechte Ergebnisse erhalte, wenn ich is_training = False während der Inferenz setze (schlimmer als bei is_training = True). Laut Ihrer Analyse kann dieses Problem gelöst werden, wenn ich es richtig verstehe, indem Sie einfach Zerfall = 0,9 in BN einstellen. Habe ich recht?

Übrigens, muss ich das Modell mit Decay = 0.9 von Grund auf neu trainieren? Oder ist es auch in Ordnung, das Training vom Checkpoint aus fortzusetzen (dh trainiert, wenn Zerfall = 0,999)?

Vielen Dank!

@nmduc @ davek44

Hallo, ich bin auch auf das Problem gestoßen, dass ich gute Ergebnisse erzielen kann, wenn ich is_training = True sowohl für das Training als auch für die Inferenz verwende, aber schlechte Ergebnisse erhalte, wenn ich is_training = False während der Inferenz setze (schlimmer als bei is_training = True). Habt ihr dieses Problem gelöst? Vielen Dank!

@tyshiwo Ich habe gerade Decay = 0.9 für batch_norm gesetzt und es funktioniert soweit gut.

Nach all diesen Kommentaren zur richtigen Verwendung von Batch Norm war ich verwirrt: Also hier ist, was ich habe. Bitte korrigieren Sie mich, wenn ich falsch liege.

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

Dabei ist phase_train_py eine boolesche Python-Variable und is_training ein Platzhalter, der eine boolesche Variable verwendet. Ich denke, die Verwendung von tf.cond ist falsch, sonst würde die Funktion mit einem booleschen Parameter geliefert. Mit anderen Worten, wenn tf.cond wahr ist, sollten wir eine batch_norm -Funktion für das Training und eine andere zum Testen verwenden. Entwickler erlauben uns also, diese booleschen Variablen zu ändern, um das Verhalten der Funktion zu ändern. Was ich also mache, ist: phase_train_py während des Trainings auf False zu setzen, während is_training auf True gesetzt wird. Und das Gegenteil beim Testen. Da wir Tensoren oder Platzhalter nur mit sess.run ändern können, habe ich phase_train_py absichtlich geändert, bevor ich das Diagramm ausgeführt habe. 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})

++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++
Vielleicht müssen Sie dies lesen
++++++++++++++++++++++++++++++++++++++++++++++++++++++ ++++++++++++++++++++++++++++++++

Es scheint immer noch Probleme mit TF v1.3 zu geben. Ich bin mir sicher, dass ich die folgenden Details notiere, aber immer noch nicht die offiziellen tf.contrib.layers.batch_norm mit is_training=False während der Evaluierung verwendet habe (aber wenn ich is_training=True während der Evaluierung unverändert lasse, ist dies der Fall in Ordnung):
1. decay , exponentieller gleitender Durchschnitt ist tatsächlich Alpha-Filter in der Signalverarbeitung, die Zeit zur Konvergenz beträgt ungefähr 1 / (1-Zerfall) Zugschritte. Für Zerfall = 0,999 benötigen Sie 1 / 0,001 = 1000 Schritte, um zu konvergieren. Stellen Sie also den geeigneten Zerfall für Ihre Trainingsschrittnummern ein.

  1. Verwenden eines Platzhalters zum Umschalten zwischen Zug- und Testauswertung
  2. Verwenden Sie updates_collections=None wenn Sie train_op keine Steuerungsabhängigkeiten von update op hinzufügen möchten
  3. Setzen Sie reuse auf den entsprechenden Wert.

Es scheint, dass die einzige Möglichkeit, die offizielle batch_norm zu verwenden, darin besteht, zwei Diagramme zu erstellen, eines für den Zug und eines für die Auswertung, mit is_training=True und is_training=False . Auf diese Weise müssen Sie nicht dynamisch zwischen Zug und Auswertung wechseln. Dies ist jedoch ein dummer Weg, da Sie mehr als ein Diagramm erstellen müssen.

Schließlich schreibe ich selbst einen gleitenden Durchschnitt und finde, dass es funktioniert hat! Es ist wie folgt (basierend auf Code im Web und von mir modifiziert)

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

Verwenden Sie beim Erstellen eines Diagramms einfach die Funktion bn_layer_top Der Parameter is_training ist ein tf.placeholder
. Dann können Sie den Platzhalter während des Zuges auf True und während der Auswertung auf False mit feed_dict .

Hoffe es hilft der Community.

Wenn Sie slim.batch_norm verwenden, müssen Sie "slim.learning.create_train_op" anstelle von "tf.train.GradientDecentOptimizer (lr) .minimize (loss)" oder einem anderen Optimierer verwenden. Probieren Sie es aus, um zu sehen, ob es funktioniert!

@vincentvanhoucke Du hast in einem anderen Beitrag in diesem Thread geschrieben:

Der schlanke Batch_Norm-Wrapper normalisiert sich über die letzte Dimension Ihres Eingabetensors. Wenn es sich also um einen 2D-Eingangstensor handelt, der von einer vollständig verbundenen Schicht stammt, normalisiert er sich über den Stapel und führt somit eine Normalisierung pro Aktivierung durch. Wenn es sich um einen 4D-Tensor handelt, der aus einer Faltung stammt, normalisiert er sich über die drei ersten Dimensionen (Stapel, Breite, Tiefe) und führt somit eine Normalisierung pro Merkmal durch. @sguada vielleicht etwas ausführlicher darüber.

Meinen Sie mit "slim batch_norm wrapper" die Funktion tf.contrib.layers.batch_norm ? In diesem Fall würde ich vorschlagen, diese Informationen zum Dokumentationstext dieser Funktion hinzuzufügen. Somit wird sehr deutlich, dass diese Funktion die Chargennormalisierung genau wie im Artikel beschrieben durchführt ... sowohl für FC-Layer als auch für Conv2D-Layer. Im Moment gibt es nur den Text "Kann als Normalisiererfunktion für conv2d und full_connected verwendet werden.", Wo nicht klar ist, ob dies mit dem Thema der Normalisierungsachse zusammenhängt.

@ZahlGraf Ich werde gerne eine PR in Betracht ziehen, die die Dokumentation verdeutlicht. Wir sind schon so lange dabei, dass ich nicht mehr genau weiß, was offensichtlich ist oder nicht, und würde es begrüßen, wenn die Dokumentation für jemanden mit einer neuen Perspektive auf das Thema geklärt würde.

@ Vincentvanhoucke
Ich habe eine PR mit einer detaillierteren Beschreibung erstellt, hauptsächlich basierend auf Ihrer Aussage in diesem Thread:
https://github.com/tensorflow/tensorflow/pull/15653

Bitte entfernen Sie den Empfänger, da dieses Problem externe Beiträge einlädt. Entfernen Sie andernfalls das Label contributions welcome . Vielen Dank.

Bitte entfernen Sie den Empfänger, da dieses Problem externe Beiträge einlädt. Entfernen Sie andernfalls das Label contributions welcome . Vielen Dank.

Das Schließen dieses Fehlers seit der ursprünglichen Anforderung zum Hinzufügen einer Batch-Norm-Ebene wurde behoben. Einige der neueren Probleme mit der Dokumentation scheinen ihre eigenen PRs zu haben
Wenn Sie ein Problem mit batch_norm feststellen, stellen Sie entweder eine Frage zu StackOverflow oder öffnen Sie ein anderes Problem.

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen