为什么压缩权重改善张量流神经网络性能



i使用tanh作为激活函数,在Tensorflow中具有2层非横向务网络。我知道应使用截断的正态分布除以sqrt(nInputs),例如:

初始化权重。
weightsLayer1 = tf.Variable(tf.div(tf.truncated_normal([nInputUnits, nUnitsHiddenLayer1),math.sqrt(nInputUnits))))

在NN和Tensorflow中有点笨拙,我错误地将其实现为2行,只是使其更可读:

weightsLayer1 = tf.Variable(tf.truncated_normal([nInputUnits, nUnitsHiddenLayer1])
weightsLayer1 = tf.div(weightsLayer1, math.sqrt(nInputUnits))

我现在知道这是错误的,第二行会导致每个学习步骤重新计算权重。但是,令我惊讶的是,在火车和测试/评估数据集中,"不正确"的实现始终可以产生更好的性能。我认为不正确的2线实现应该是火车残骸,因为它正在重新计算(压制)权重,而不是优化器选择的价值,我期望这会在优化过程中造成严重破坏,但实际上会改善它。有人对此有任何解释吗?我正在使用TensorFlow Adam Optimizer。

更新2016.6.22 - 更新了上面的第二代码块。

您在每个步骤执行weightsLayer1 = tf.div(weightsLayer1, math.sqrt(nInputUnits))是正确的。但这并不意味着重量变量中的值在每个步骤中都由sqrt(nInputUnits)缩放。该行不是影响变量中存储的值的现场操作。它计算一个新的张量,将值保存在变量除以sqrt(nInputUnits)中,我假设该张量然后进入计算图的其余部分。这不会干扰优化器。您仍在定义一个有效的计算图,仅具有一些任意的权重缩放。优化器仍然可以计算相对于此变量的梯度(它将通过您的除法操作进行后退)并创建相应的更新操作。

根据您定义的模型,这两个版本是完全等效的。对于原始模型中的任何一组weightsLayer1值(在您不做部门)中,您可以通过sqrt(nInputUnits)进行扩展,然后使用第二个模型获得相同的结果。如果愿意,这两个代表完全相同的模型类。

为什么一个人比另一个更好?你的猜测和我一样好。如果您对所有变量都进行了相同的部门,则有效地将学习率除以sqrt(nInputUnits)。这个较小的学习率可能对当前的问题有益。

编辑:我认为您将相同名称与变量和新创建的张量引起混乱的事实。当你做

A = tf.Variable(1.0)
A = tf.mul(A, 2.0)
# Do something with A

然后,第二行会创建一个新的张量(如上所述),然后将名称(并且只是名称) A重新绑定到该新张量。对于被定义的图表,命名绝对无关。以下代码定义了相同的图:

A = tf.Variable(1.0)
B = tf.mul(A, 2.0)
# Do something with B

也许如果执行以下代码:

A = tf.Variable(1.0)
print A
B = A
A = tf.mul(A, 2.0)
print A
print B

输出为

<tensorflow.python.ops.variables.Variable object at 0x7ff025c02bd0>
Tensor("Mul:0", shape=(), dtype=float32)
<tensorflow.python.ops.variables.Variable object at 0x7ff025c02bd0>

您第一次print A告诉您A是一个变量对象。在执行A = tf.mul(A, 2.0)并再次打印A之后,您可以看到名称A现在已绑定到tf.Tensor对象。但是,该变量仍然存在,可以通过查看名称B的对象。

这是代码单行所做的:

t = tf.truncated_normal( [ nInputUnits, nUnitsHiddenLayer1 ] )

创建一个具有形状[ninpununits,nunitshiddenlayer1]的Tensor,以1.0初始化为截断正态分布的标准偏差。(1.0是标准的stddev值)

t1 = tf.div( t, math.sqrt( nInputUnits ) )

将t中的所有值与Math.sqrt(ninputunits)

划分

您的两行代码做完全相同的事情。在第一行和第二行上,所有值均由Math.sqrt(ninputunits)分开。

至于您的语句:

我现在知道这是错误的,第二行会在每个学习步骤中重新计算重量。

编辑我的错误

的确,您是对的,它们在每个执行时都被Math.sqrt(ninputunits)划分,但并非重新初始化!重要的重点是您放置tf.variable()

这里仅初始化两行:

weightsLayer1 = tf.truncated_normal( [ nInputUnits, nUnitsHiddenLayer1 ] )
weightsLayer1 = tf.Variable( tf.div( weightsLayer1, math.sqrt( nInputUnits ) ) )

在这里,第二行是在每个步骤中都预先形成的:

weightsLayer1 = tf.Variable( tf.truncated_normal( [ nInputUnits, nUnitsHiddenLayer1 ] )
weightsLayer1 = tf.div( weightsLayer1, math.sqrt( nInputUnits ) )

为什么第二个产生更好的结果?看起来对我来说是某种归一化,但是有人更有知识的人应该验证这一点。

ps。您可以像这样更可读性地写下它:

weightsLayer1 = tf.Variable( tf.truncated_normal( [ nInputUnits, nUnitsHiddenLayer1 ] , stddev = 1. / math.sqrt( nInputUnits ) ) 

最新更新