web-dev-qa-db-fra.com

Comment définir le taux d'apprentissage par couche dans Tensorflow?

Je me demande s’il est possible d’utiliser un taux d’apprentissage différent pour différentes couches, comme dans Caffe. J'essaie de modifier un modèle pré-formé et de l'utiliser pour d'autres tâches. Ce que je veux, c'est accélérer la formation pour les nouvelles couches ajoutées et garder les couches formées à un taux d'apprentissage faible afin d'éviter qu'elles ne soient déformées. Par exemple, j'ai un modèle pré-formé de 5 couches de conv. Maintenant, j'ajoute un nouveau calque de conv et je l'affine. Les 5 premières couches auraient un taux d’apprentissage de 0,00001 et la dernière, de 0,001. Une idée comment y parvenir?

42
Tong Shen

Cela peut être réalisé assez facilement avec 2 optimiseurs:

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)

Un inconvénient de cette implémentation est qu’elle calcule tf.gradients (.) Deux fois dans les optimiseurs et qu’elle risque donc de ne pas être optimale en termes de vitesse d’exécution. Cela peut être atténué en appelant explicitement tf.gradients (.), En scindant la liste en 2 et en transmettant les dégradés correspondants aux deux optimiseurs.

Question associée: Maintien constant des variables pendant l'optimiseur

EDIT: Ajout d'une implémentation plus efficace mais plus longue:

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)

Vous pouvez utiliser tf.trainable_variables() pour obtenir toutes les variables d’apprentissage et décider de les sélectionner .. La différence est que, dans la première implémentation, tf.gradients(.) est appelé deux fois dans les optimiseurs. Cela peut entraîner l'exécution d'opérations redondantes (par exemple, les gradients de la première couche peuvent réutiliser certains calculs pour les gradients des couches suivantes).

73
Rafał Józefowicz

Mise à jour du 22 janv. : La recette ci-dessous n’est qu’une bonne idée pour GradientDescentOptimizer, d’autres optimiseurs conservant une moyenne mobile appliqueront la vitesse d’apprentissage avant la mise à jour du paramètre.

En plus de l'approche de Rafal, vous pouvez utiliser compute_gradients, apply_gradients interface de Optimizer. Par exemple, voici un réseau de jouets où j'utilise 2x le taux d'apprentissage pour le deuxième paramètre

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

Tu devrais voir

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

Tensorflow 1.7 a introduit le tf.custom_gradient qui simplifie grandement le réglage des multiplicateurs de vitesse d’apprentissage, d’une manière désormais compatible avec tout optimiseur, y compris ceux qui accumulent des statistiques de gradient. Par exemple,

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

Recueillez des multiplicateurs de taux d’apprentissage pour chaque variable, par exemple:

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

puis appliquez-les pendant avant d'appliquer les dégradés comme:

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)

Vous pouvez trouver l'exemple complet ici .

4
Sergey Demyanov

Les 5 premières couches auraient un taux d’apprentissage de 0,00001 et la dernière, de 0,001. Une idée comment y parvenir?

Il existe un moyen simple de faire cela en utilisant tf.stop_gradient . Voici un exemple avec 3 couches:

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

Vous pouvez réduire votre dégradé dans les deux premières couches selon un rapport de 1/100:

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

Sur la couche 2, le "flux" est divisé en deux branches: l’une qui a une contribution de 1/100 calcule sa pente régulièrement mais avec une magnitude de gradient réduite de 1/100, l’autre branche fournit le "flux" restant. sans contribuer au gradient en raison de l'opérateur tf.stop_gradient. Par conséquent, si vous utilisez un taux d'apprentissage de 0,001 sur votre optimiseur de modèle, les deux premières couches auront un taux d'apprentissage de 0,00001.

0
Nicolas Pinchaud

Une légère variation de la réponse de Sergey Demyanov, où il vous suffit de spécifier les taux d’apprentissage que vous souhaitez modifier.

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