Я переношу свою мережу Caffe на TensorFlow, але, схоже, вона не має ініціалізації xavier. Я використовую, truncated_normal
але, здається, це значно ускладнює тренування.
Відповіді:
У Tensorflow 2.0 і далі обидва tf.contrib.*
і tf.get_variable()
застаріли. Для того, щоб виконати ініціалізацію Xavier, тепер потрібно перейти на:
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))
Уніформа Глоро та форма Ксав'є - це дві різні назви одного типу ініціалізації. Якщо ви хочете дізнатися більше про те, як використовувати ініціалізації в TF2.0 з Keras або без, зверніться до документації .
З версії 0.8 існує ініціалізатор Xavier, дивіться тут документи .
Ви можете використовувати щось подібне:
W = tf.get_variable("W", shape=[784, 256],
initializer=tf.contrib.layers.xavier_initializer())
get_variable
а замість цього надаючи її ініціалізатору? Раніше я мав tf.truncated_normal(shape=[dims[l-1],dims[l]], mean=mu[l], stddev=std[l], dtype=tf.float64)
і вказував там форму, але тепер ваша пропозиція як би закручує мій код. Чи є у вас пропозиції?
tf.Variable(...)
і використовуєtf.get_variable(...)
Просто щоб додати ще один приклад того, як визначити tf.Variable
ініціалізоване за допомогою методу Ксав'є та Йошуа :
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))
...
Це заважало мені мати nan
значення для моєї функції втрат через чисельні нестабільності при використанні декількох шарів з RELU.
@ Aleph7, ініціалізація Xavier / Glorot залежить від кількості вхідних з'єднань (fan_in), кількості вихідних з'єднань (fan_out) та виду функції активації (сигмовидної або тангової) нейрона. Див. Це: http://jmlr.org/proceedings/papers/v9/glorot10a/glorot10a.pdf
Отже, до вашого запитання. Ось як би я це зробив у 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))
Зверніть увагу, що ми повинні брати вибірки з рівномірного розподілу, а не з нормального розподілу, як пропонується в іншій відповіді.
До речі, я вчора написав допис про щось інше, використовуючи TensorFlow, яке також використовує ініціалізацію Xavier. Якщо вам цікаво, є також блокнот python із наскрізним прикладом: https://github.com/delip/blog-stuff/blob/master/tensorflow_ufp.ipynb
Гарна обгортка навколо tensorflow
викликає prettytensor
реалізацію у вихідному коді (скопійованому безпосередньо звідси ):
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-внесок має xavier_initializer
. Ось приклад використання:
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)
На додаток до цього, у tensorflow є інші ініціалізатори:
Я подивився і не міг знайти нічого вбудованого. Однак відповідно до цього:
http://andyljones.tumblr.com/post/110998971763/an-explanation-of-xavier-initialization
Ініціалізація Ксав'є - це просто вибірка розподілу (як правило, Гауса), де дисперсія є функцією кількості нейронів. tf.random_normal
може зробити це за вас, вам просто потрібно обчислити stddev (тобто кількість нейронів, представлених ваговою матрицею, яку ви намагаєтесь ініціалізувати).
Через kernel_initializer
параметр і tf.layers.conv2d, tf.layers.conv2d_transpose, tf.layers.Dense
т.д.
напр
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
Про всяк випадок, якщо ви хочете використовувати один рядок, як це робите з:
W = tf.Variable(tf.truncated_normal((n_prev, n), stddev=0.1))
Ви можете зробити:
W = tf.Variable(tf.contrib.layers.xavier_initializer()((n_prev, n)))