Ich möchte die Chargennormalisierung in TensorFlow verwenden. Ich habe den zugehörigen C ++ - Quellcode in gefunden core/ops/nn_ops.cc
. Ich fand es jedoch nicht auf tensorflow.org dokumentiert.
BN hat unterschiedliche Semantiken in MLP und CNN, daher bin ich mir nicht sicher, was genau diese BN tut.
Ich habe auch keine Methode namens gefunden MovingMoments
.
python
tensorflow
Shawn Lee
quelle
quelle
Antworten:
Update Juli 2016 Der einfachste Weg, die Batch-Normalisierung in TensorFlow zu verwenden, sind die übergeordneten Schnittstellen, die entweder in Contrib / Layer , Tflearn oder Slim bereitgestellt werden .
Vorherige Antwort, wenn Sie DIY möchten : Die Dokumentationszeichenfolge hierfür hat sich seit der Veröffentlichung verbessert. Lesen Sie den Dokumentkommentar im Hauptzweig anstelle des gefundenen. Es wird insbesondere klargestellt, dass es sich um die Ausgabe von handelt
tf.nn.moments
.Sie können ein sehr einfaches Beispiel für die Verwendung im Testcode batch_norm sehen . Für ein realistischeres Anwendungsbeispiel habe ich unten die Hilfsklasse angegeben und Hinweise verwendet, die ich für meinen eigenen Gebrauch notiert habe (keine Garantie!):
"""A helper class for managing batch normalization state. This class is designed to simplify adding batch normalization (http://arxiv.org/pdf/1502.03167v3.pdf) to your model by managing the state variables associated with it. Important use note: The function get_assigner() returns an op that must be executed to save the updated state. A suggested way to do this is to make execution of the model optimizer force it, e.g., by: update_assignments = tf.group(bn1.get_assigner(), bn2.get_assigner()) with tf.control_dependencies([optimizer]): optimizer = tf.group(update_assignments) """ import tensorflow as tf class ConvolutionalBatchNormalizer(object): """Helper class that groups the normalization logic and variables. Use: ewma = tf.train.ExponentialMovingAverage(decay=0.99) bn = ConvolutionalBatchNormalizer(depth, 0.001, ewma, True) update_assignments = bn.get_assigner() x = bn.normalize(y, train=training?) (the output x will be batch-normalized). """ def __init__(self, depth, epsilon, ewma_trainer, scale_after_norm): self.mean = tf.Variable(tf.constant(0.0, shape=[depth]), trainable=False) self.variance = tf.Variable(tf.constant(1.0, shape=[depth]), trainable=False) self.beta = tf.Variable(tf.constant(0.0, shape=[depth])) self.gamma = tf.Variable(tf.constant(1.0, shape=[depth])) self.ewma_trainer = ewma_trainer self.epsilon = epsilon self.scale_after_norm = scale_after_norm def get_assigner(self): """Returns an EWMA apply op that must be invoked after optimization.""" return self.ewma_trainer.apply([self.mean, self.variance]) def normalize(self, x, train=True): """Returns a batch-normalized version of x.""" if train: mean, variance = tf.nn.moments(x, [0, 1, 2]) assign_mean = self.mean.assign(mean) assign_variance = self.variance.assign(variance) with tf.control_dependencies([assign_mean, assign_variance]): return tf.nn.batch_norm_with_global_normalization( x, mean, variance, self.beta, self.gamma, self.epsilon, self.scale_after_norm) else: mean = self.ewma_trainer.average(self.mean) variance = self.ewma_trainer.average(self.variance) local_beta = tf.identity(self.beta) local_gamma = tf.identity(self.gamma) return tf.nn.batch_norm_with_global_normalization( x, mean, variance, local_beta, local_gamma, self.epsilon, self.scale_after_norm)
Beachten Sie, dass ich es a genannt habe,
ConvolutionalBatchNormalizer
weil es die Verwendung vontf.nn.moments
zur Summe über die Achsen 0, 1 und 2 festnagelt, während Sie für die Verwendung ohne Faltung möglicherweise nur die Achse 0 möchten.Feedback wird geschätzt, wenn Sie es verwenden.
quelle
bn = Conv...er(args); ... createSubgraph(bn, args);
und dann einfachbn.normalize
innerhalb des Untergraphen aufrufen .if train:
) werden Mittelwert und Standardwert des Eingabestapels (tf.nn.moments(x, [0, 1, 2])
) berechnet . Während der Auswertung / Prüfung wird der gespeicherte gleitende Durchschnitt extrahiert (self.ewma_trainer.average(self.mean)
). Das Verwirrende kann sein, dass der Aufruf der ewma-average
Methode den gespeicherten Durchschnitt zurückgibt und ihn nicht aktualisiert. Die Aktualisierung erfolgt durch dieself.mean.assign(mean)
Zeile, in der der aktuelle Batch-Mittelwert in 'self.mean' gespeichert ist, und dann durch die Zeile, dieewma_trainer.apply
die EWMA basierend aufself.mean
Ab TensorFlow 1.0 (Februar 2017) ist auch die High-Level-
tf.layers.batch_normalization
API in TensorFlow selbst enthalten.Es ist super einfach zu bedienen:
# Set this to True for training and False for testing training = tf.placeholder(tf.bool) x = tf.layers.dense(input_x, units=100) x = tf.layers.batch_normalization(x, training=training) x = tf.nn.relu(x)
... außer dass es dem Diagramm zusätzliche Operationen hinzufügt (um seine Mittelwert- und Varianzvariablen zu aktualisieren), so dass sie keine Abhängigkeiten von Ihrer Trainingsoperation sind. Sie können die Operationen entweder einfach separat ausführen:
oder fügen Sie die Update-Operationen manuell als Abhängigkeiten Ihrer Trainingsoperation hinzu und führen Sie dann Ihre Trainingsoperation wie gewohnt aus:
extra_update_ops = tf.get_collection(tf.GraphKeys.UPDATE_OPS) with tf.control_dependencies(extra_update_ops): train_op = optimizer.minimize(loss) ... sess.run([train_op], ...)
quelle
extra_update_ops
) "manuell" bei jeder Trainingsiteration zusammen mit der regulären Trainingsoperation ausführen, oder Sie können die Trainingsoperation abhängig machenextra_update_ops
(mithilfe einescontrol_dependencies()
Blocks) ). Hoffe das hilft.update_ups
Wenn man bedenkt, dass dies zum Aktualisieren des gleitenden Mittelwerts und der beweglichen Varianz dient, ist es nicht sinnvoll, ihn überhaupt einzubeziehen, wenn wir nur ein vorab trainiertes Netzwerk testen. Ist das richtig?axis
sollte in Faltungsnetzwerken verwendet werden?Das Folgende funktioniert gut für mich, es erfordert nicht das Aufrufen von EMA-apply außerhalb.
import numpy as np import tensorflow as tf from tensorflow.python import control_flow_ops def batch_norm(x, n_out, phase_train, scope='bn'): """ Batch normalization on convolutional maps. Args: x: Tensor, 4D BHWD input maps 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): beta = tf.Variable(tf.constant(0.0, shape=[n_out]), name='beta', trainable=True) gamma = tf.Variable(tf.constant(1.0, shape=[n_out]), name='gamma', trainable=True) batch_mean, batch_var = tf.nn.moments(x, [0,1,2], 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
Beispiel:
import math n_in, n_out = 3, 16 ksize = 3 stride = 1 phase_train = tf.placeholder(tf.bool, name='phase_train') input_image = tf.placeholder(tf.float32, name='input_image') kernel = tf.Variable(tf.truncated_normal([ksize, ksize, n_in, n_out], stddev=math.sqrt(2.0/(ksize*ksize*n_out))), name='kernel') conv = tf.nn.conv2d(input_image, kernel, [1,stride,stride,1], padding='SAME') conv_bn = batch_norm(conv, n_out, phase_train) relu = tf.nn.relu(conv_bn) with tf.Session() as session: session.run(tf.initialize_all_variables()) for i in range(20): test_image = np.random.rand(4,32,32,3) sess_outputs = session.run([relu], {input_image.name: test_image, phase_train.name: True})
quelle
control_flow_ops.cond
? Ist estf.control_flow_ops.cond
? Ich habe es nicht im Tensorflow gefunden. Haben Sie den Leistungsunterschied berücksichtigt? Wenn die Steuerelementabhängigkeit in der Ebene angewendet wird, muss die Berechnung möglicherweise auf jede Ebene warten, anstatt auf jede Iteration, und könnte es zu viel Wartezeit geben? Ich verwende tatsächlich Ihre Version, die in Schicht eins, da es einfacher ist, aber ich werde die globale später versuchen.ema_apply_op
es auch beim Testen aufgerufen. Ich habe meine Antwort bearbeitet undphase_train
von einemtf.Variable
zu einem Python-Booleschen Wert gewechselt . Jetzt müssen Sie jedoch separate Diagramme für Training und Test erstellen. Vielen Dank für Ihr Feedback und entschuldigen Sie meine späte Antwort.Es gibt auch eine "offizielle" Batch-Normalisierungsschicht, die von den Entwicklern codiert wurde. Sie haben keine sehr guten Dokumente, wie man es benutzt, aber hier ist, wie man es benutzt (meiner Meinung nach):
from tensorflow.contrib.layers.python.layers import batch_norm as batch_norm def batch_norm_layer(x,train_phase,scope_bn): bn_train = batch_norm(x, decay=0.999, center=True, scale=True, updates_collections=None, 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, updates_collections=None, 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
Um es tatsächlich zu verwenden, müssen Sie einen Platzhalter erstellen
train_phase
, der angibt, ob Sie sich in der Trainings- oder Inferenzphase befinden (wie intrain_phase = tf.placeholder(tf.bool, name='phase_train')
). Sein Wert kann während der Inferenz oder des Trainings mit einemtf.session
wie folgt gefüllt werden :test_error = sess.run(fetches=cross_entropy, feed_dict={x: batch_xtest, y_:batch_ytest, train_phase: False})
oder während des Trainings:
sess.run(fetches=train_step, feed_dict={x: batch_xs, y_:batch_ys, train_phase: True})
Ich bin mir ziemlich sicher, dass dies gemäß der Diskussion in Github richtig ist .
Es scheint einen weiteren nützlichen Link zu geben:
http://r2rt.com/implementing-batch-normalization-in-tensorflow.html
quelle
updates_collections=None
wichtig ist. Ich verstehe nicht warum, aber es ist. Die beste Erklärung, die ich kenne, ist,But what it is important is that either you pass updates_collections=None so the moving_mean and moving_variance are updated in-place, otherwise you will need gather the update_ops and make sure they are run.
aber ich verstehe nicht ganz, warum das eine Erklärung ist, aber empirisch habe ich beobachtet, dass MNIST gut funktioniert, wenn es keine ist, und schrecklich, wenn es nicht ist.Sie können einfach die integrierte Ebene batch_norm verwenden:
batch_norm = tf.cond(is_train, lambda: tf.contrib.layers.batch_norm(prev, activation_fn=tf.nn.relu, is_training=True, reuse=None), lambda: tf.contrib.layers.batch_norm(prev, activation_fn =tf.nn.relu, is_training=False, reuse=True))
Dabei ist prev die Ausgabe Ihrer vorherigen Ebene (kann sowohl eine vollständig verbundene als auch eine Faltungsebene sein) und is_train ein boolescher Platzhalter ist. Verwenden Sie dann einfach batch_norm als Eingabe für die nächste Ebene.
quelle
is_train
als Platzhalter übergeben werden? Ich kann das nicht tun, das Übergeben von Python Boolean funktioniert nicht mittf.cond
und das Definieren von zwei Batch-Normen in, wenn Zweige mir "Wiederverwendung = True kann nicht ohne name_or_scope verwendet werden" (selbst wenn ich einen variablen Bereich für sie spezifiziere) ...tf.cast(True/False, tf.bool)
Operation verwenden.var1 = True or False
sagen: und dann sagen :tf.cast(var1, tf.bool)
. Dies sollte gut funktionierenreuse=True
und nur in der Testphase?Da dies kürzlich von jemandem bearbeitet wurde, möchte ich klarstellen, dass dies kein Problem mehr ist.
Diese Antwort scheint nicht korrekt zu sein. Wenn sie
phase_train
auf false gesetzt ist, werden der Ema-Mittelwert und die Varianz weiterhin aktualisiert. Dies kann mit dem folgenden Codefragment überprüft werden.x = tf.placeholder(tf.float32, [None, 20, 20, 10], name='input') phase_train = tf.placeholder(tf.bool, name='phase_train') # generate random noise to pass into batch norm x_gen = tf.random_normal([50,20,20,10]) pt_false = tf.Variable(tf.constant(True)) #generate a constant variable to pass into batch norm y = x_gen.eval() [bn, bn_vars] = batch_norm(x, 10, phase_train) tf.initialize_all_variables().run() train_step = lambda: bn.eval({x:x_gen.eval(), phase_train:True}) test_step = lambda: bn.eval({x:y, phase_train:False}) test_step_c = lambda: bn.eval({x:y, phase_train:True}) # Verify that this is different as expected, two different x's have different norms print(train_step()[0][0][0]) print(train_step()[0][0][0]) # Verify that this is same as expected, same x's (y) have same norm print(train_step_c()[0][0][0]) print(train_step_c()[0][0][0]) # THIS IS DIFFERENT but should be they same, should only be reading from the ema. print(test_step()[0][0][0]) print(test_step()[0][0][0])
quelle
ema_apply_op
auch dann aufgerufen wurdephase_train=False
.Unter Verwendung des in TensorFlow integrierten Batch_Norm-Layers finden Sie unten den Code zum Laden von Daten, zum Erstellen eines Netzwerks mit einem versteckten ReLU-Layer und zur L2-Normalisierung sowie zum Einführen einer Batch-Normalisierung für den versteckten und den Out-Layer. Das läuft gut und trainiert gut. Nur zu Ihrer Information: Dieses Beispiel basiert hauptsächlich auf den Daten und dem Code aus dem Udacity DeepLearning-Kurs. PS Ja, Teile davon wurden früher in Antworten auf die eine oder andere Weise besprochen, aber ich habe beschlossen, alles in einem Code-Snippet zusammenzufassen, damit Sie ein Beispiel für den gesamten Netzwerk-Trainingsprozess mit Batch-Normalisierung und deren Auswertung haben
# These are all the modules we'll be using later. Make sure you can import them # before proceeding further. from __future__ import print_function import numpy as np import tensorflow as tf from six.moves import cPickle as pickle pickle_file = '/home/maxkhk/Documents/Udacity/DeepLearningCourse/SourceCode/tensorflow/examples/udacity/notMNIST.pickle' with open(pickle_file, 'rb') as f: save = pickle.load(f) train_dataset = save['train_dataset'] train_labels = save['train_labels'] valid_dataset = save['valid_dataset'] valid_labels = save['valid_labels'] test_dataset = save['test_dataset'] test_labels = save['test_labels'] del save # hint to help gc free up memory print('Training set', train_dataset.shape, train_labels.shape) print('Validation set', valid_dataset.shape, valid_labels.shape) print('Test set', test_dataset.shape, test_labels.shape) image_size = 28 num_labels = 10 def reformat(dataset, labels): dataset = dataset.reshape((-1, image_size * image_size)).astype(np.float32) # Map 2 to [0.0, 1.0, 0.0 ...], 3 to [0.0, 0.0, 1.0 ...] labels = (np.arange(num_labels) == labels[:,None]).astype(np.float32) return dataset, labels train_dataset, train_labels = reformat(train_dataset, train_labels) valid_dataset, valid_labels = reformat(valid_dataset, valid_labels) test_dataset, test_labels = reformat(test_dataset, test_labels) print('Training set', train_dataset.shape, train_labels.shape) print('Validation set', valid_dataset.shape, valid_labels.shape) print('Test set', test_dataset.shape, test_labels.shape) def accuracy(predictions, labels): return (100.0 * np.sum(np.argmax(predictions, 1) == np.argmax(labels, 1)) / predictions.shape[0]) #for NeuralNetwork model code is below #We will use SGD for training to save our time. Code is from Assignment 2 #beta is the new parameter - controls level of regularization. #Feel free to play with it - the best one I found is 0.001 #notice, we introduce L2 for both biases and weights of all layers batch_size = 128 beta = 0.001 #building tensorflow graph graph = tf.Graph() with graph.as_default(): # Input data. For the training data, we use a placeholder that will be fed # at run time with a training minibatch. tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size)) tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels)) tf_valid_dataset = tf.constant(valid_dataset) tf_test_dataset = tf.constant(test_dataset) #introduce batchnorm tf_train_dataset_bn = tf.contrib.layers.batch_norm(tf_train_dataset) #now let's build our new hidden layer #that's how many hidden neurons we want num_hidden_neurons = 1024 #its weights hidden_weights = tf.Variable( tf.truncated_normal([image_size * image_size, num_hidden_neurons])) hidden_biases = tf.Variable(tf.zeros([num_hidden_neurons])) #now the layer itself. It multiplies data by weights, adds biases #and takes ReLU over result hidden_layer = tf.nn.relu(tf.matmul(tf_train_dataset_bn, hidden_weights) + hidden_biases) #adding the batch normalization layerhi() hidden_layer_bn = tf.contrib.layers.batch_norm(hidden_layer) #time to go for output linear layer #out weights connect hidden neurons to output labels #biases are added to output labels out_weights = tf.Variable( tf.truncated_normal([num_hidden_neurons, num_labels])) out_biases = tf.Variable(tf.zeros([num_labels])) #compute output out_layer = tf.matmul(hidden_layer_bn,out_weights) + out_biases #our real output is a softmax of prior result #and we also compute its cross-entropy to get our loss #Notice - we introduce our L2 here loss = (tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits( out_layer, tf_train_labels) + beta*tf.nn.l2_loss(hidden_weights) + beta*tf.nn.l2_loss(hidden_biases) + beta*tf.nn.l2_loss(out_weights) + beta*tf.nn.l2_loss(out_biases))) #now we just minimize this loss to actually train the network optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss) #nice, now let's calculate the predictions on each dataset for evaluating the #performance so far # Predictions for the training, validation, and test data. train_prediction = tf.nn.softmax(out_layer) valid_relu = tf.nn.relu( tf.matmul(tf_valid_dataset, hidden_weights) + hidden_biases) valid_prediction = tf.nn.softmax( tf.matmul(valid_relu, out_weights) + out_biases) test_relu = tf.nn.relu( tf.matmul( tf_test_dataset, hidden_weights) + hidden_biases) test_prediction = tf.nn.softmax(tf.matmul(test_relu, out_weights) + out_biases) #now is the actual training on the ANN we built #we will run it for some number of steps and evaluate the progress after #every 500 steps #number of steps we will train our ANN num_steps = 3001 #actual training with tf.Session(graph=graph) as session: tf.initialize_all_variables().run() print("Initialized") for step in range(num_steps): # Pick an offset within the training data, which has been randomized. # Note: we could use better randomization across epochs. offset = (step * batch_size) % (train_labels.shape[0] - batch_size) # Generate a minibatch. batch_data = train_dataset[offset:(offset + batch_size), :] batch_labels = train_labels[offset:(offset + batch_size), :] # Prepare a dictionary telling the session where to feed the minibatch. # The key of the dictionary is the placeholder node of the graph to be fed, # and the value is the numpy array to feed to it. feed_dict = {tf_train_dataset : batch_data, tf_train_labels : batch_labels} _, l, predictions = session.run( [optimizer, loss, train_prediction], feed_dict=feed_dict) if (step % 500 == 0): print("Minibatch loss at step %d: %f" % (step, l)) print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels)) print("Validation accuracy: %.1f%%" % accuracy( valid_prediction.eval(), valid_labels)) print("Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
quelle
Ein einfaches Beispiel für die Verwendung dieser Batchnorm-Klasse:
from bn_class import * with tf.name_scope('Batch_norm_conv1') as scope: ewma = tf.train.ExponentialMovingAverage(decay=0.99) bn_conv1 = ConvolutionalBatchNormalizer(num_filt_1, 0.001, ewma, True) update_assignments = bn_conv1.get_assigner() a_conv1 = bn_conv1.normalize(a_conv1, train=bn_train) h_conv1 = tf.nn.relu(a_conv1)
quelle