2016-01-22 5 views
29

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

ответ

53

Это может быть достигнуто довольно легко с 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) 

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

Связанный вопрос: Holding variables constant during optimizer

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(.) вызывается дважды внутри оптимизаторов. Это может привести к выполнению некоторых избыточных операций (например, градиенты на первом уровне могут повторно использовать некоторые вычисления для градиентов следующих слоев).

+0

Спасибо за ваш ответ Рафал. Я все еще немного удивляюсь, когда вы сказали о недостатке этого с точки зрения скорости, насколько это повлияло бы на производительность. Если я тренирую большую сеть, если это большая нагрузка, это не будет хорошим вариантом. Кроме того, не могли бы вы уточнить свой второй метод? Как явно вызвать tf.gradients()? Извините, я все еще новичок. –

+0

Отредактирован ответ. –

+0

thx man, является второй последней строкой, которая должна быть «train_op2 = opt2.apply_gradients (.)»? если я это правильно понимаю. –

6

Update 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] 
+1

Это хорошо при использовании SGD, но не уверен, оптимально ли это для более привлекательных оптимизаторов, которые вычисляют статистику по значениям прошлых градиентов ... Вероятно, это не имеет значения, если вы не хотите изменять эту скорость обучения во время обучения. –

+0

хорошая точка, обновленный ответ –

+0

Спасибо, человек, кажется, блестящий. –

3

Collect обучения мультипликаторы скорости для каждой переменной, как:

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) 

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

0

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

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

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) 

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

Смежные вопросы