如何在Tensorflow中设置分层学习率?

Ton*_*hen 46 python deep-learning tensorflow

我想知道是否有一种方法可以为不同的层使用不同的学习率,就像Caffe中的那样.我正在尝试修改预先训练的模型并将其用于其他任务.我想要的是加快新增加的层的训练,并使训练好的层保持低学习率,以防止它们被扭曲.例如,我有一个5-conv层预训练模型.现在我添加一个新的转换层并对其进行微调.前5层的学习率为0.00001,最后一层的学习率为0.001.知道怎么做到这一点?

Raf*_*icz 81

使用2个优化器可以很容易地实现:

var_list1 = [variables from first 5 layers]
var_list2 = [the rest of variables]
train_op1 = GradientDescentOptimizer(0.00001).minimize(loss, var_list=var_list1)
train_op2 = GradientDescentOptimizer(0.0001).minimize(loss, var_list=var_list2)
train_op = tf.group(train_op1, train_op2)
Run Code Online (Sandbox Code Playgroud)

这种实现的一个缺点是它在优化器内部计算两次tf.gradients(.),因此在执行速度方面可能不是最佳的.这可以通过显式调用tf.gradients(.),将列表拆分为2并将相应的渐变传递给两个优化器来缓解.

相关问题:在优化器期间保持变量不变

编辑:添加更有效但更长的实现:

var_list1 = [variables from first 5 layers]
var_list2 = [the rest of variables]
opt1 = tf.train.GradientDescentOptimizer(0.00001)
opt2 = tf.train.GradientDescentOptimizer(0.0001)
grads = tf.gradients(loss, var_list1 + var_list2)
grads1 = grads[:len(var_list1)]
grads2 = grads[len(var_list1):]
tran_op1 = opt1.apply_gradients(zip(grads1, var_list1))
train_op2 = opt2.apply_gradients(zip(grads2, var_list2))
train_op = tf.group(train_op1, train_op2)
Run Code Online (Sandbox Code Playgroud)

您可以使用tf.trainable_variables()获取所有训练变量并决定从中进行选择.不同之处在于第一个实现tf.gradients(.)在优化器内部被调用两次.这可能导致执行一些冗余操作(例如,第一层上的梯度可以重用一些计算用于后续层的梯度).

  • 另外,如果我在`apply_gradients`中使用`global_step`,您会同时将其用于`opt1`和`opt2`还是只在最后一个`apply_gradients`中使用它? (2认同)

Yar*_*tov 8

1月22日更新:下面的配方只是一个好主意GradientDescentOptimizer,保持运行平均值的其他优化器将在参数更新之前应用学习速率,因此下面的配方不会影响等式的那一部分

除了Rafal的方法,你可以使用compute_gradients,apply_gradients界面Optimizer.例如,这是一个玩具网络,我使用2倍于第二个参数的学习率

x = tf.Variable(tf.ones([]))
y = tf.Variable(tf.zeros([]))
loss = tf.square(x-y)
global_step = tf.Variable(0, name="global_step", trainable=False)

opt = tf.GradientDescentOptimizer(learning_rate=0.1)
grads_and_vars = opt.compute_gradients(loss, [x, y])
ygrad, _ = grads_and_vars[1]
train_op = opt.apply_gradients([grads_and_vars[0], (ygrad*2, y)], global_step=global_step)

init_op = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init_op)
for i in range(5):
  sess.run([train_op, loss, global_step])
  print sess.run([x, y])
Run Code Online (Sandbox Code Playgroud)

你应该看到

[0.80000001, 0.40000001]
[0.72000003, 0.56]
[0.68800002, 0.62400001]
[0.67520005, 0.64960003]
[0.67008007, 0.65984005]
Run Code Online (Sandbox Code Playgroud)


P-G*_*-Gn 8

Tensorflow 1.7引入tf.custom_gradient了大大简化设置学习速率乘数的方法,现在与任何优化器兼容,包括那些累积梯度统计数据.例如,

import tensorflow as tf

def lr_mult(alpha):
  @tf.custom_gradient
  def _lr_mult(x):
    def grad(dy):
      return dy * alpha * tf.ones_like(x)
    return x, grad
  return _lr_mult

x0 = tf.Variable(1.)
x1 = tf.Variable(1.)
loss = tf.square(x0) + tf.square(lr_mult(0.1)(x1))

step = tf.train.GradientDescentOptimizer(learning_rate=0.1).minimize(loss)

sess = tf.InteractiveSession()
tf.global_variables_initializer().run()
tf.local_variables_initializer().run()

for _ in range(5):
  sess.run([step])
  print(sess.run([x0, x1, loss]))
Run Code Online (Sandbox Code Playgroud)


Ser*_*nov 6

收集每个变量的学习率乘数,例如:

self.lr_multipliers[var.op.name] = lr_mult
Run Code Online (Sandbox Code Playgroud)

然后在应用渐变之前应用它们,例如:

def _train_op(self):
  tf.scalar_summary('learning_rate', self._lr_placeholder)
  opt = tf.train.GradientDescentOptimizer(self._lr_placeholder)
  grads_and_vars = opt.compute_gradients(self._loss)
  grads_and_vars_mult = []
  for grad, var in grads_and_vars:
    grad *= self._network.lr_multipliers[var.op.name]
    grads_and_vars_mult.append((grad, var))
    tf.histogram_summary('variables/' + var.op.name, var)
    tf.histogram_summary('gradients/' + var.op.name, grad)
  return opt.apply_gradients(grads_and_vars_mult)
Run Code Online (Sandbox Code Playgroud)

您可以在此处找到整个示例。