2017-09-27 7 views
1

Étant donné les valeurs d'entrée [1, 5] et en les normalisant, devrait donner quelque chose comme [-1, 1]if I understand correctly, parce quecouche BatchNormalization en Keras donne des valeurs de sortie inattendues

mean = 3 
var = 4 
result = (x - mean)/sqrt(var) 

Cependant cet exemple minimal

import numpy as np 

import keras 
from keras.models import Model 
from keras.layers import Input 
from keras.layers.normalization import BatchNormalization 
from keras import backend as K 

shape = (1,2,1) 
input = Input(shape=shape) 
x = BatchNormalization(center=False)(input) # no beta 
model = Model(inputs=input, outputs=x) 
model.compile(loss='mse', optimizer='sgd') 

# training with dummy data 
training_in = [np.random.random(size=(10, *shape))] 
training_out = [np.random.random(size=(10, *shape))] 
model.fit(training_in, training_out, epochs=10) 

data_in = np.array([[[[1], [5]]]], dtype=np.float32) 
data_out = model.predict(data_in) 

print('gamma :', K.eval(model.layers[1].gamma)) 
#print('beta :', K.eval(model.layers[1].beta)) 
print('moving_mean:', K.eval(model.layers[1].moving_mean)) 
print('moving_variance:', K.eval(model.layers[1].moving_variance)) 

print('epsilon :', model.layers[1].epsilon) 
print('data_in :', data_in) 
print('data_out:', data_out) 

produit la sortie suivante :

gamma : [ 0.80644524] 
moving_mean: [ 0.05885344] 
moving_variance: [ 0.91000736] 
epsilon : 0.001 
data_in : [[[[ 1.] 
    [ 5.]]]] 
data_out: [[[[ 0.79519051] 
    [ 4.17485714]]]] 

Donc c'est [0.79519051, 4.17485714] au lieu de [-1, 1]. J'ai regardé source, et les valeurs semblent être transmises à tf.nn.batch_normalization. Et ce looks comme le résultat devrait être ce que j'excepte, mais évidemment ce n'est pas le cas.

Alors, comment les valeurs de sortie sont-elles calculées?

Répondre

1

Si vous utilisez gamma, l'équation à droite est en fait result = gamma * (x - mean)/sqrt(var) pour la normalisation des lots, MAISmean et var ne sont pas toujours les mêmes:

  • Au cours de la formation (adapter), ils sont mean_batch et var_batch calculé en utilisant les valeurs d'entrée du lot (ils sont juste la moyenne et la variance de votre lot)), tout comme vous le faites. Dans le même temps, un moving_mean et moving_variance sont apprises de cette façon: moving_mean = alpha * moving_mean + (1-alpha) * mean_batch, avec alpha est une sorte de taux d'apprentissage, en (0,1), généralement au-dessus de 0,9. moving_mean et moving_variance sont des approximations de la moyenne et de la variance réelles de toutes vos données de formation. Gamma est également appris, par la descente de gradient habituelle, pour s'adapter au mieux à votre sortie.

  • Au cours de l'inférence (prédire), il suffit d'utiliser les valeurs apprises de moving_mean et moving_variance, pas du tout mean_batch et var_batch. Vous utilisez également le gamma appris.

Alors 0.05885344 est juste une approximation de la moyenne de vos données d'entrée aléatoire, 0.91000736 de sa variance, et que vous utilisez ce pour normaliser vos nouvelles données [1, 5]. Vous pouvez facilement vérifier que [0.79519051, 4.17485714]=gamma * ([1, 5] - moving_mean)/sqrt(moving_var)

éditer: alpha est appelé momentum dans keras, si vous voulez le vérifier.

+0

Impressionnant, merci beaucoup. Pourriez-vous également me dire où bêta s'inscrit dans la formule quand 'center = True'?Ma conjecture aurait été 'sortie = gamma * (input - moving_mean)/sqrt (moving_variance) + beta' mais quand je [activer centre] (https://ideone.com/TNRlFH) la [sortie] (https: // ideone.com/d3rROd) ne correspond pas. –

+1

Il devrait être comme vous le dites selon tensorflow, compte tenu de [ceci] (https://www.tensorflow.org/api_docs/python/tf/nn/batch_normalization). [Keras] (https://keras.io/layers/normalization/) a l'air de faire 'output = gamma * ((input-moving_mean)/sqrt (moving_variance) + beta)' dans leur doc. Cependant, aucun ne correspond exactement, je ne sais pas pourquoi ... – gdelab

+0

J'ai trouvé le problème. Nous n'utilisions pas epsilon. La formule entièrement correcte est 'result = gamma * (input - moving_mean)/sqrt (moving_variance + epsilon) + beta'. –

0

La bonne formule est la suivante:

result = gamma * (input - moving_mean)/sqrt(moving_variance + epsilon) + beta 

Et voici un script pour la vérification:

import math 
import numpy as np 
import tensorflow as tf 
from keras import backend as K 

from keras.models import Model 
from keras.layers import Input 
from keras.layers.normalization import BatchNormalization 

np.random.seed(0) 

print('=== keras model ===') 
input_shape = (1,2,1) 
input = Input(shape=input_shape) 
x = BatchNormalization()(input) 
model = Model(inputs=input, outputs=x) 
model.compile(loss='mse', optimizer='sgd') 
training_in = [np.random.random(size=(10, *input_shape))] 
training_out = [np.random.random(size=(10, *input_shape))] 
model.fit(training_in, training_out, epochs=100, verbose=0) 
data_in = [[[1.0], [5.0]]] 
data_model = np.array([data_in]) 
result = model.predict(data_model) 
gamma = K.eval(model.layers[1].gamma) 
beta = K.eval(model.layers[1].beta) 
moving_mean = K.eval(model.layers[1].moving_mean) 
moving_variance = K.eval(model.layers[1].moving_variance) 
epsilon = model.layers[1].epsilon 
print('gamma:   ', gamma) 
print('beta:   ', beta) 
print('moving_mean: ', moving_mean) 
print('moving_variance:', moving_variance) 
print('epsilon:  ', epsilon) 
print('data_in:  ', data_in) 
print('result:   ', result) 

print('=== numpy ===') 
np_data = [data_in[0][0][0], data_in[0][1][0]] 
np_mean = moving_mean[0] 
np_variance = moving_variance[0] 
np_offset = beta[0] 
np_scale = gamma[0] 
np_result = [np_scale * (x - np_mean)/math.sqrt(np_variance + epsilon) + np_offset for x in np_data] 
print(np_result) 

print('=== tensorflow ===') 
tf_data = tf.constant(data_in) 
tf_mean = tf.constant(moving_mean) 
tf_variance = tf.constant(moving_variance) 
tf_offset = tf.constant(beta) 
tf_scale = tf.constant(gamma) 
tf_variance_epsilon = epsilon 
tf_result = tf.nn.batch_normalization(tf_data, tf_mean, tf_variance, tf_offset, tf_scale, tf_variance_epsilon) 
tf_sess = tf.Session() 
print(tf_sess.run(tf_result)) 

print('=== keras backend ===') 
k_data = K.constant(data_in) 
k_mean = K.constant(moving_mean) 
k_variance = K.constant(moving_variance) 
k_offset = K.constant(beta) 
k_scale = K.constant(gamma) 
k_variance_epsilon = epsilon 
k_result = K.batch_normalization(k_data, k_mean, k_variance, k_offset, k_scale, k_variance_epsilon) 
print(K.eval(k_result)) 

sortie:

gamma:   [ 0.22297101] 
beta:   [ 0.49253803] 
moving_mean:  [ 0.36868709] 
moving_variance: [ 0.41429576] 
epsilon:   0.001 
data_in:   [[[1.0], [5.0]]] 
result:   [[[[ 0.71096909] 
    [ 2.09494853]]]] 

=== numpy === 
[0.71096905498374263, 2.0949484904433255] 

=== tensorflow === 
[[[ 0.71096909] 
    [ 2.09494853]]] 

=== keras backend === 
[[[ 0.71096909] 
    [ 2.09494853]]]