Como fazer a inicialização do Xavier no TensorFlow

86

Estou transferindo minha rede Caffe para o TensorFlow, mas não parece ter inicialização xavier. Estou usando, truncated_normalmas parece que está dificultando muito o treino.

Alejandro
fonte
2
Xavier é a inicialização padrão. Consulte stackoverflow.com/questions/37350131/…
Thomas Ahle

Respostas:

12

No Tensorflow 2.0 e posteriores, ambos tf.contrib.*e tf.get_variable()estão obsoletos. Para fazer a inicialização do Xavier, você agora deve alternar para:

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

Uniforme Glorot e Uniforme Xavier são dois nomes diferentes do mesmo tipo de inicialização. Se você quiser saber mais sobre como usar inicializações no TF2.0 com ou sem Keras, consulte a documentação .

y.selivonchyk
fonte
Usei o código acima e recebo um erro como abaixo; _init_xavier = tf.Variable (init (shape = shape)) NameError: o nome 'forma' não está definido
Chiranga
119

Desde a versão 0.8 existe um inicializador Xavier, veja aqui os documentos .

Você pode usar algo assim:

W = tf.get_variable("W", shape=[784, 256],
           initializer=tf.contrib.layers.xavier_initializer())
Sung Kim
fonte
3
você sabe fazer isso sem dar a forma a, get_variablemas em vez disso dando ao inicializador? Eu costumava ter tf.truncated_normal(shape=[dims[l-1],dims[l]], mean=mu[l], stddev=std[l], dtype=tf.float64)e especificava a forma lá, mas agora sua sugestão meio que bagunçou meu código. Você tem alguma sugestão?
Pinóquio
1
@Pinocchio, você pode simplesmente escrever um invólucro que tenha a mesma assinatura tf.Variable(...)e usetf.get_variable(...)
jns
2
Link "Atual" sem versão: tensorflow.org/api_docs/python/tf/contrib/layers/…
scipilot
28

Apenas para adicionar outro exemplo de como definir um tf.Variableinicializado usando o método de Xavier e 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))
    ...

Isso me impediu de ter nanvalores na minha função de perda devido a instabilidades numéricas ao usar várias camadas com RELUs.

Saullo GP Castro
fonte
2
Este formato se ajustou melhor ao meu código - e me permitiu retornar minha taxa de aprendizado para 0,5 (eu tive que diminuí-la para 0,06 ao adicionar outra camada recarregada). Depois de aplicar esse inicializador a TODAS as camadas ocultas, estou obtendo taxas de validação incrivelmente altas desde as primeiras centenas de épocas. Eu não posso acreditar a diferença que fez!
scipilot
12

@ Aleph7, a inicialização do Xavier / Glorot depende do número de conexões de entrada (fan_in), do número de conexões de saída (fan_out) e do tipo de função de ativação (sigmóide ou tanh) do neurônio. Veja isto: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf

Então, agora, à sua pergunta. É assim que eu faria no 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))

Observe que devemos obter uma amostra de uma distribuição uniforme, e não da distribuição normal, como sugerido na outra resposta.

A propósito, escrevi um post ontem sobre algo diferente usando o TensorFlow que também usa a inicialização do Xavier. Se você estiver interessado, há também um bloco de notas Python com um exemplo de ponta a ponta: https://github.com/delip/blog-stuff/blob/master/tensorflow_ufp.ipynb

Delip
fonte
1
Como podemos usá-lo com a função de ativação relu.
gautam840
Esse artigo estuda o comportamento dos gradientes de peso sob diferentes funções de ativação com a inicialização comumente usada. Em seguida, eles propõem uma inicialização universal, independentemente de qualquer função de ativação. Além disso, seu método também não depende da função de ativação, então é melhor usar a inicialização Xavier integrada no Tensorflow.
Vahid Mirjalili
8

Um bom wrapper tensorflowchamado prettytensorfornece uma implementação no código-fonte (copiado diretamente daqui ):

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)
Fisgado
fonte
8

TF-contrib tem xavier_initializer. Aqui está um exemplo de como usá-lo:

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)

Além disso, o tensorflow tem outros inicializadores:

Salvador Dalí
fonte
obrigado, senhor, isso foi muito útil, gostaria de perguntar se posso inicializar o bias usando xavier_initializer
Sakhri Houssem
4

Procurei e não encontrei nada embutido. Porém, de acordo com isto:

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

A inicialização de Xavier é apenas uma amostra de uma distribuição (geralmente gaussiana) onde a variância é uma função do número de neurônios. tf.random_normalpode fazer isso para você, você só precisa calcular o stddev (ou seja, o número de neurônios sendo representado pela matriz de peso que você está tentando inicializar).

Vince Gatto
fonte
Vince você deve estar amostrando de uma distribuição uniforme.
Delip
4

Por meio do kernel_initializerparâmetro para tf.layers.conv2d, tf.layers.conv2d_transpose, tf.layers.Dense etc

por exemplo

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
fonte
3

Apenas no caso de você querer usar uma linha como faz com:

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

Você pode fazer:

W = tf.Variable(tf.contrib.layers.xavier_initializer()((n_prev, n)))
Tony Power
fonte
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
fonte