Cómo hacer la inicialización de Xavier en TensorFlow

Estoy transfiriendo mi red de Caffe a TensorFlow pero no parece tener una inicialización xavier. Estoy usando truncated_normal pero esto parece hacer que sea mucho más difícil entrenar.

Desde la versión 0.8 hay un inicializador Xavier, vea aquí para los documentos .

Puedes usar algo como esto:

 W = tf.get_variable("W", shape=[784, 256], initializer=tf.contrib.layers.xavier_initializer()) 

Solo para agregar otro ejemplo sobre cómo definir una tf.Variable inicializada usando el método de Xavier y 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)) ... 

Esto me impidió tener valores nan en mi función de pérdida debido a inestabilidades numéricas al usar capas múltiples con RELU.

@ Aleph7, la inicialización de Xavier / Glorot depende del número de conexiones entrantes (fan_in), del número de conexiones salientes (fan_out) y del tipo de función de activación (sigmoide o tanh) de la neurona. Vea esto: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf

Así que ahora, a tu pregunta. Así es como lo haría en 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)) 

Tenga en cuenta que debemos muestrear desde una distribución uniforme, y no desde la distribución normal como se sugiere en la otra respuesta.

Por cierto, ayer escribí una publicación para algo diferente usando TensorFlow que también usa la inicialización de Xavier. Si está interesado, también hay un cuaderno de Python con un ejemplo de extremo a extremo: https://github.com/delip/blog-stuff/blob/master/tensorflow_ufp.ipynb

TF-contrib tiene xavier_initializer . Aquí hay un ejemplo de cómo usarlo:

 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) 

Además de esto, tensorflow tiene otros inicializadores:

  • xavier_initializer_conv2d
  • variance_scaling_initializer
  • constante_inicializador
  • zeros_initializer
  • ones_initializer
  • uniform_unit_scaling_initializer
  • truncado_normal_inicializador
  • random_uniform_initializer
  • random_normal_initializer
  • Inicializador ortogonal
  • así como muchos inicializadores de keras.

Un bonito envoltorio alrededor de tensorflow llamado prettytensor da una implementación en el código fuente (copiado directamente desde aquí ):

 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) 

Miré y no pude encontrar nada incorporado. Sin embargo, según esto:

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

La inicialización de Xavier es solo muestrear una distribución (generalmente gaussiana) donde la varianza es una función del número de neuronas. tf.random_normal puede hacer eso por usted, solo necesita calcular el stddev (es decir, la cantidad de neuronas representadas por la matriz de peso que está intentando inicializar).

En Tensorflow 2.0 y, además, tanto tf.contrib.* tf.get_variable() están en desuso. Para hacer la inicialización de Xavier ahora tienes que cambiar a:

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

Glorot uniform y Xavier uniform son dos nombres diferentes del mismo tipo de inicialización. Si desea saber más sobre cómo usar las inicializaciones en TF2.0 con o sin Keras, consulte la documentación .

A través del parámetro kernel_initializer a tf.layers.conv2d, tf.layers.conv2d_transpose, tf.layers.Dense etc.

p.ej

 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

En caso de que quiera usar una línea como lo hace con:

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

Tu puedes hacer:

 W = tf.Variable(tf.contrib.layers.xavier_initializer()((n_prev, n)))