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.
Ich arbeite an einigen Teilen davon.
Es gibt jetzt eine batch_norm
-Ebene:
https://github.com/tensorflow/tensorflow/blob/b826b79718e3e93148c3545e7aa3f90891744cc0/tensorflow/contrib/layers/python/layers/layers.py#L100
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:
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:
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
Die Testergebnisse mit decay=0.999
( decay=0.999
ist die Standardeinstellung in tf.contrib.layers.batch_norm
)
(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:
@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)
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.
updates_collections=None
wenn Sie train_op keine Steuerungsabhängigkeiten von update op hinzufügen möchtenreuse
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.
Hilfreichster Kommentar
Es gibt jetzt eine
batch_norm
-Ebene:https://github.com/tensorflow/tensorflow/blob/b826b79718e3e93148c3545e7aa3f90891744cc0/tensorflow/contrib/layers/python/layers/layers.py#L100