Comment faire l'initialisation de Xavier sur TensorFlow

85

Je porte mon réseau Caffe vers TensorFlow mais il ne semble pas avoir d'initialisation xavier. J'utilise truncated_normalmais cela semble rendre l'entraînement beaucoup plus difficile.

Alejandro
la source
2
Xavier est l'initialisation par défaut. Voir stackoverflow.com/questions/37350131/…
Thomas Ahle

Réponses:

12

Dans tensorflow 2.0 et en outre à la fois tf.contrib.*et tf.get_variable()sont obsolètes. Pour effectuer l'initialisation de Xavier, vous devez maintenant passer à:

init = tf.initializers.GlorotUniform()
var = tf.Variable(init(shape=shape))
# or a oneliner with a little confusing brackets
var = tf.Variable(tf.initializers.GlorotUniform()(shape=shape))

L'uniforme Glorot et l'uniforme Xavier sont deux noms différents du même type d'initialisation. Si vous souhaitez en savoir plus sur l'utilisation des initialisations dans TF2.0 avec ou sans Keras, reportez-vous à la documentation .

y.selivonchyk
la source
J'ai utilisé le code ci-dessus et j'obtiens une erreur comme ci-dessous; _init_xavier = tf.Variable (init (shape = shape)) NameError: le nom 'shape' n'est pas défini
Chiranga
119

Depuis la version 0.8, il existe un initialiseur Xavier, voir ici pour la documentation .

Vous pouvez utiliser quelque chose comme ceci:

W = tf.get_variable("W", shape=[784, 256],
           initializer=tf.contrib.layers.xavier_initializer())
Sung Kim
la source
3
savez-vous faire cela sans donner la forme à get_variablemais la donner à l'initialiseur? J'avais l'habitude d'avoir tf.truncated_normal(shape=[dims[l-1],dims[l]], mean=mu[l], stddev=std[l], dtype=tf.float64)et j'ai spécifié la forme là-bas, mais maintenant votre suggestion a en quelque sorte anéanti mon code. Avez-vous des suggestions?
Pinocchio
1
@Pinocchio vous pouvez simplement écrire vous-même un wrapper qui a la même signature tf.Variable(...)et utilisetf.get_variable(...)
jns
2
Lien "actuel" sans version: tensorflow.org/api_docs/python/tf/contrib/layers/…
scipilot
28

Juste pour ajouter un autre exemple sur la façon de définir un tf.Variableinitialisé en utilisant la méthode de Xavier et Yoshua :

graph = tf.Graph()
with graph.as_default():
    ...
    initializer = tf.contrib.layers.xavier_initializer()
    w1 = tf.Variable(initializer(w1_shape))
    b1 = tf.Variable(initializer(b1_shape))
    ...

Cela m'a empêché d'avoir des nanvaleurs sur ma fonction de perte en raison d'instabilités numériques lors de l'utilisation de plusieurs couches avec des RELU.

Saullo GP Castro
la source
2
Ce format correspondait le mieux à mon code - et il m'a permis de ramener mon taux d'apprentissage à 0,5 (j'ai dû le réduire à 0,06 lors de l'ajout d'une autre couche relu'd). Une fois que j'ai appliqué cet initialiseur à TOUTES les couches cachées, j'obtiens des taux de validation incroyablement élevés dès les premières centaines d'époques. Je ne peux pas croire la différence que cela a fait!
scipilot
12

@ Aleph7, l'initialisation de Xavier / Glorot dépend du nombre de connexions entrantes (fan_in), du nombre de connexions sortantes (fan_out) et du type de fonction d'activation (sigmoïde ou tanh) du neurone. Voir ceci: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf

Alors maintenant, à votre question. Voici comment je le ferais dans TensorFlow:

(fan_in, fan_out) = ...
    low = -4*np.sqrt(6.0/(fan_in + fan_out)) # use 4 for sigmoid, 1 for tanh activation 
    high = 4*np.sqrt(6.0/(fan_in + fan_out))
    return tf.Variable(tf.random_uniform(shape, minval=low, maxval=high, dtype=tf.float32))

Notez que nous devrions échantillonner à partir d'une distribution uniforme, et non de la distribution normale comme suggéré dans l'autre réponse.

Incidemment, j'ai écrit un article hier pour quelque chose de différent en utilisant TensorFlow qui utilise également l'initialisation de Xavier. Si vous êtes intéressé, il existe également un bloc-notes python avec un exemple de bout en bout: https://github.com/delip/blog-stuff/blob/master/tensorflow_ufp.ipynb

Délip
la source
1
Comment pouvons-nous l'utiliser avec la fonction d'activation relu.
gautam840 le
Cet article étudie le comportement des gradients de poids sous différentes fonctions d'activation avec l'initialisation couramment utilisée. Ensuite, ils proposent une initialisation universelle quelle que soit la fonction d'activation. De plus, votre méthode ne dépend pas non plus de la fonction d'activation, il est donc préférable d'utiliser l'initialisation Xavier intégrée dans Tensorflow.
Vahid Mirjalili
8

Un joli wrapper autour de tensorflowappelé prettytensordonne une implémentation dans le code source (copié directement à partir d' ici ):

def xavier_init(n_inputs, n_outputs, uniform=True):
  """Set the parameter initialization using the method described.
  This method is designed to keep the scale of the gradients roughly the same
  in all layers.
  Xavier Glorot and Yoshua Bengio (2010):
           Understanding the difficulty of training deep feedforward neural
           networks. International conference on artificial intelligence and
           statistics.
  Args:
    n_inputs: The number of input nodes into each output.
    n_outputs: The number of output nodes for each input.
    uniform: If true use a uniform distribution, otherwise use a normal.
  Returns:
    An initializer.
  """
  if uniform:
    # 6 was used in the paper.
    init_range = math.sqrt(6.0 / (n_inputs + n_outputs))
    return tf.random_uniform_initializer(-init_range, init_range)
  else:
    # 3 gives us approximately the same limits as above since this repicks
    # values greater than 2 standard deviations from the mean.
    stddev = math.sqrt(3.0 / (n_inputs + n_outputs))
    return tf.truncated_normal_initializer(stddev=stddev)
Accroché
la source
8

TF-contrib a xavier_initializer. Voici un exemple comment l'utiliser:

import tensorflow as tf
a = tf.get_variable("a", shape=[4, 4], initializer=tf.contrib.layers.xavier_initializer())
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print sess.run(a)

En plus de cela, tensorflow a d'autres initialiseurs:

Salvador Dali
la source
merci, monsieur, cela a été très utile, je veux vous demander si je peux initialiser le biais en utilisant xavier_initializer
Sakhri Houssem
4

J'ai cherché et je n'ai rien trouvé de intégré. Cependant, d'après ceci:

http://andyljones.tumblr.com/post/110998971763/an-explanation-of-xavier-initialization

L'initialisation de Xavier consiste simplement à échantillonner une distribution (généralement gaussienne) où la variance est fonction du nombre de neurones. tf.random_normalpouvez le faire pour vous, il vous suffit de calculer le stddev (c'est-à-dire le nombre de neurones représentés par la matrice de poids que vous essayez d'initialiser).

Vince Gatto
la source
Vince, vous devriez échantillonner à partir d'une distribution uniforme.
Delip
4

Via le kernel_initializerparamètre à tf.layers.conv2d, tf.layers.conv2d_transpose, tf.layers.Dense etc

par exemple

layer = tf.layers.conv2d(
     input, 128, 5, strides=2,padding='SAME',
     kernel_initializer=tf.contrib.layers.xavier_initializer())

https://www.tensorflow.org/api_docs/python/tf/layers/conv2d

https://www.tensorflow.org/api_docs/python/tf/layers/conv2d_transpose

https://www.tensorflow.org/api_docs/python/tf/layers/Dense

xilef
la source
3

Juste au cas où vous voudriez utiliser une ligne comme vous le faites avec:

W = tf.Variable(tf.truncated_normal((n_prev, n), stddev=0.1))

Tu peux faire:

W = tf.Variable(tf.contrib.layers.xavier_initializer()((n_prev, n)))
Tony Power
la source
0

Tensorflow 1:

W1 = tf.get_variable("W1", [25, 12288],
    initializer = tf.contrib.layers.xavier_initializer(seed=1)

Tensorflow 2:

W1 = tf.get_variable("W1", [25, 12288],
    initializer = tf.random_normal_initializer(seed=1))
mruanova
la source