Estou transferindo minha rede Caffe para o TensorFlow, mas não parece ter inicialização xavier. Estou usando, truncated_normal
mas parece que está dificultando muito o treino.
Respostas:
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 .
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())
get_variable
mas 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?
tf.Variable(...)
e usetf.get_variable(...)
Apenas para adicionar outro exemplo de como definir um tf.Variable
inicializado 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 nan
valores na minha função de perda devido a instabilidades numéricas ao usar várias camadas com RELUs.
@ 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
Um bom wrapper tensorflow
chamado prettytensor
fornece 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)
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:
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_normal
pode 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).
Por meio do kernel_initializer
parâ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
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)))