如何在TensorFlow中定义各个层的重量衰减?

时间:2016-04-12 10:42:46

标签: tensorflow

在CUDA ConvNet中,我们可以为每一层写出这样的内容(source):

[conv32]
epsW=0.001
epsB=0.002
momW=0.9
momB=0.9
wc=0

其中wc=0指的是L2权重衰减。

如何在TensorFlow中实现同样的目标?

3 个答案:

答案 0 :(得分:15)

您可以将要添加重量衰减的所有变量添加到集合名称'变量'然后计算整个集合的L2范数权重衰减。

  # Create your variables
  weights = tf.get_variable('weights', collections=['variables'])

  with tf.variable_scope('weights_norm') as scope:
    weights_norm = tf.reduce_sum(
      input_tensor = WEIGHT_DECAY_FACTOR*tf.pack(
          [tf.nn.l2_loss(i) for i in tf.get_collection('weights')]
      ),
      name='weights_norm'
  )

  # Add the weight decay loss to another collection called losses
  tf.add_to_collection('losses', weights_norm)

  # Add the other loss components to the collection losses     
  # ...

  # To calculate your total loss
  tf.add_n(tf.get_collection('losses'), name='total_loss')

答案 1 :(得分:6)

get_variable(
name,
shape=None,
dtype=None,
initializer=None,
regularizer=None,
trainable=True,
collections=None,
caching_device=None,
partitioner=None,
validate_shape=True,
use_resource=None,
custom_getter=None)

这是tensorflow函数get_variable的用法。您可以轻松指定正规化器来进行重量衰减。

以下是一个例子:

weight_decay = tf.constant(0.0005, dtype=tf.float32) # your weight decay rate, must be a scalar tensor.
W = tf.get_variable(name='weight', shape=[4, 4, 256, 512], regularizer=tf.contrib.layers.l2_regularizer(weight_decay))

答案 2 :(得分:0)

目前的答案都是错误的,因为他们没有像cuda-convnet那样给你“减重”#34;而是L2正则化,这是不同的。

当使用纯SGD(没有动量)作为优化器时,权重衰减与向损失添加L2正则化项是一回事。 使用任何其他优化器时,情况并非如此。

体重衰减(不知道如何在这里使用TeX,请原谅我的伪符号):

w[t+1] = w[t] - learning_rate * dw - weight_decay * w

L2-正规化:

loss = actual_loss + lambda * 1/2 sum(||w||_2 for w in network_params)

计算L2正则化中额外项的梯度得到lambda * w,从而将其插入SGD更新方程

dloss_dw = dactual_loss_dw + lambda * w
w[t+1] = w[t] - learning_rate * dw

与重量衰减相同,但将lambdalearning_rate混合。任何其他优化器,即使是具有动量的SGD,也会为L2正则化提供不同的权重衰减更新规则!有关详细信息,请参阅文章Fixing weight decay in Adam。 (编辑:AFAIK,this 1987 Hinton paper介绍"体重衰减",字面意思为"每次更新权重时,其数量也会减少0.4%"在第10页)

话虽如此,似乎并没有支持"正确的" TensorFlow中的重量衰减了。讨论它有一些问题,特别是因为上面的论文。

实现它的一种可能方法是编写一个op,在每个优化器步骤之后手动执行衰减步骤。另一种方式,就是我目前正在做的,就是使用额外的SGD优化器来减轻重量,并且"附加"它到你的train_op。不过,这些都只是粗略的解决方案。我目前的代码:

# In the network definition:
with arg_scope([layers.conv2d, layers.dense],
               weights_regularizer=layers.l2_regularizer(weight_decay)):
    # define the network.

loss = # compute the actual loss of your problem.
train_op = optimizer.minimize(loss, global_step=global_step)
if args.weight_decay not in (None, 0):
    with tf.control_dependencies([train_op]):
        sgd = tf.train.GradientDescentOptimizer(learning_rate=1.0)
        train_op = sgd.minimize(tf.add_n(tf.get_collection(tf.GraphKeys.REGULARIZATION_LOSSES)))

这有点使用TensorFlow提供的簿记。请注意,arg_scope负责将每个图层的L2正则化项附加到REGULARIZATION_LOSSES图表键,然后我使用SGD对其进行求和并进行优化,如上所示,对应于实际重衰变。

希望有所帮助,如果有人为此获得更好的代码片段,或者TensorFlow更好地实现它(即在优化器中),请分享。

编辑:另请参阅刚刚合并到TF的this PR