Как установить уровень обучения в Tensorflow?

Мне интересно, есть ли способ, которым я могу использовать разную скорость обучения для разных слоев, например, что есть в Caffe. Я пытаюсь изменить предварительно подготовленную модель и использовать ее для других задач. Я хочу ускорить обучение новым добавленным слоям и поддерживать обученные слои с низкой скоростью обучения, чтобы они не искажались. например, у меня есть предварительно подготовленная модель с 5 уровнями. Теперь я добавляю новый слой conv и настраиваю его. Первые 5 слоев будут иметь скорость обучения 0,00001, а последняя - 0,001. Любая идея, как достичь этого?

Ответ 1

Это можно легко добиться двумя оптимизаторами:

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)

Одним из недостатков этой реализации является то, что она дважды вычисляет tf.gradients(.) внутри оптимизаторов и, следовательно, может быть не оптимальной с точки зрения скорости выполнения. Это можно смягчить, явно называя tf.gradients(.), Разбивая список на 2 и передавая соответствующие градиенты обоим оптимизаторам.

Связанный с этим вопрос: Сохранение переменных во время оптимизации

EDIT: добавлена ​​более эффективная, но более длинная реализация:

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)

Вы можете использовать tf.trainable_variables() для получения всех переменных обучения и выбрать их выбор. Разница в том, что в первой реализации tf.gradients(.) вызывается дважды внутри оптимизаторов. Это может привести к выполнению некоторых избыточных операций (например, градиенты на первом уровне могут повторно использовать некоторые вычисления для градиентов следующих слоев).

Ответ 2

Обновление 22 января. Рецепт ниже - это только хорошая идея для GradientDescentOptimizer, другие оптимизаторы, которые сохраняют среднее значение, будут применять скорость обучения до обновления параметра, поэтому рецепт ниже не повлияет на это часть уравнения

В дополнение к подходу Rafal вы можете использовать интерфейс compute_gradients, apply_gradients Optimizer. Например, здесь есть игрушечная сеть, в которой я использую 2x скорость обучения для второго параметра

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])

Вы должны увидеть

[0.80000001, 0.40000001]
[0.72000003, 0.56]
[0.68800002, 0.62400001]
[0.67520005, 0.64960003]
[0.67008007, 0.65984005]

Ответ 3

Собирайте коэффициенты скорости обучения для каждой переменной, например:

self.lr_multipliers[var.op.name] = lr_mult

а затем примените их перед применением градиентов, например:

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)

Здесь вы можете найти весь пример .

Ответ 4

Первые 5 слоев будут иметь скорость обучения 0,00001, а последняя - 0,001. Любая идея, как достичь этого?

Существует простой способ сделать это с помощью tf.stop_gradient. Вот пример с тремя слоями:

x = layer1(input)
x = layer2(x)
output = layer3(x)

Вы можете сжать свой градиент в первых двух слоях соотношением 1/100:

x = layer1(input)
x = layer2(x)
x = 1/100*x + (1-1/100)*tf.stop_gradient(x)
output = layer3(x)

На слое2 "поток" разделяется на две ветки: одна, которая имеет вклад 1/100, регулярно выполняет свой градиент, но с градиентной величиной, уменьшенной на долю 1/100, другая ветвь обеспечивает оставшуюся "поток", не внося вклад в градиент из-за оператора tf.stop_gradient. В результате, если вы используете скорость обучения 0,001 для вашего оптимизатора модели, первые два уровня будут иметь скорость обучения 0,00001.