wake-up-neo.com

Wie kann man die schichtweise Lernrate in Tensorflow einstellen?

Ich frage mich, ob es eine Möglichkeit gibt, unterschiedliche Lernraten für verschiedene Ebenen zu verwenden, wie in Caffe. Ich versuche, ein bereits trainiertes Modell zu modifizieren und für andere Aufgaben zu verwenden. Ich möchte das Training für neue hinzugefügte Layer beschleunigen und die trainierten Layer auf einer niedrigen Lernrate halten, damit sie nicht verzerrt werden. Ich habe zum Beispiel ein vorgebildetes Modell mit 5 Konvektionsschichten. Jetzt füge ich eine neue Conv-Ebene hinzu und feineinstellen. Die ersten 5 Schichten hätten eine Lernrate von 0,00001 und die letzte Schicht hätte 0,001. Hast du eine Idee, wie du das erreichen kannst?

42
Tong Shen

Mit zwei Optimierern ist dies problemlos möglich:

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)

Ein Nachteil dieser Implementierung besteht darin, dass sie innerhalb des Optimierers zweimal zwei Gradienten (.) Berechnet und daher hinsichtlich der Ausführungsgeschwindigkeit möglicherweise nicht optimal ist. Dies kann gemildert werden, indem explizit tf.gradients (.) Aufgerufen wird, die Liste in 2 aufgeteilt wird und entsprechende Gradienten an beide Optimierer übergeben werden.

Zugehörige Frage: Variablen während des Optimierers konstant halten

EDIT: Effizientere, aber längere Implementierung hinzugefügt:

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)

Sie können tf.trainable_variables() verwenden, um alle Trainingsvariablen abzurufen und sich für die Auswahl zu entscheiden. __ Der Unterschied besteht darin, dass tf.gradients(.) in der ersten Implementierung in den Optimierern zweimal aufgerufen wird. Dies kann dazu führen, dass einige redundante Operationen ausgeführt werden (beispielsweise können Gradienten auf der ersten Schicht einige Berechnungen für die Gradienten der folgenden Schichten wiederverwenden).

73

Update 22. Januar : Das untenstehende Rezept ist nur eine gute Idee für GradientDescentOptimizer. Andere Optimierer, die einen laufenden Durchschnitt beibehalten, wenden vor dem Parameter-Update die Lernrate an, sodass das untenstehende Rezept diesen Teil der Gleichung nicht beeinflusst

Zusätzlich zum Ansatz von Rafal können Sie die compute_gradients-, apply_gradients-Schnittstelle von Optimizer verwenden. Zum Beispiel hier ein Spielzeugnetzwerk, bei dem ich die Lernrate für den zweiten Parameter zweimal verwende

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

Das solltest du sehen

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

Tensorflow 1.7 hat tf.custom_gradient eingeführt, der die Einstellung von Multiplikatoren für die Lernrate erheblich vereinfacht, und ist jetzt mit jedem Optimierer kompatibel, einschließlich derjenigen, die Gradientenstatistiken sammeln. Zum Beispiel,

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]))
6
P-Gn

Sammeln Sie Multiplikatoren für Lernraten für jede Variable wie:

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

und wenden Sie sie dann an, bevor Sie die Farbverläufe anwenden:

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)

Das ganze Beispiel finden Sie hier .

4
Sergey Demyanov

Die ersten 5 Schichten hätten eine Lernrate von 0,00001 und die letzte Schicht hätte 0,001. Hast du eine Idee, wie du das erreichen kannst?

Es gibt einen einfachen Weg, dies mit tf.stop_gradient ..__ zu tun. Hier ist ein Beispiel mit 3 Ebenen:

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

Sie können Ihren Farbverlauf in den ersten beiden Ebenen im Verhältnis 1/100 verkleinern:

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

Auf der Schicht2 ist der "Fluss" in zwei Zweige aufgeteilt: Einer, der einen Beitrag von 1/100 hat, berechnet seinen Gradienten regelmäßig, aber mit einer um 1/100 verkleinerten Gradientengröße, der andere Zweig liefert den verbleibenden "Fluss" ohne mit dem tf.stop_gradient-Operator zum Verlauf beizutragen. Wenn Sie für Ihr Modelloptimierungsprogramm eine Lernrate von 0,001 verwenden, weisen die ersten beiden Ebenen praktisch eine Lernrate von 0,00001 auf.

0

Eine kleine Variante der Antwort von Sergey Demyanov, bei der Sie lediglich die Lernraten angeben müssen, die Sie ändern möchten

from collections import defaultdict

self.learning_rates = defaultdict(lambda: 1.0)
...
x = tf.layers.Dense(3)(x)
self.learning_rates[x.op.name] = 2.0
...
optimizer = tf.train.MomentumOptimizer(learning_rate=1e-3, momentum=0.9)
grads_and_vars = optimizer.compute_gradients(loss)
grads_and_vars_mult = []
for grad, var in grads_and_vars:
    grad *= self.learning_rates[var.op.name]
    grads_and_vars_mult.append((grad, var))
train_op = optimizer.apply_gradients(grads_and_vars_mult, tf.train.get_global_step())
0
Lewis Smith