web-dev-qa-db-ja.com

Tensorflowでレイヤーごとの学習率を設定するにはどうすればよいですか?

Caffeのように、レイヤーごとに異なる学習率を使用できる方法があるかどうか疑問に思っています。事前に訓練されたモデルを変更し、他のタスクに使用しようとしています。私が欲しいのは、新たに追加されたレイヤーのトレーニングをスピードアップし、トレーニングされたレイヤーを低学習率に保ち、レイヤーが歪まないようにすることです。たとえば、事前にトレーニングされた5 conv-layerモデルがあります。次に、新しいconvレイヤーを追加し、微調整します。最初の5つのレイヤーの学習率は0.00001で、最後の1つのレイヤーの学習率は0.001です。これを達成する方法はありますか?

46
Tong Shen

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

この実装の1つの欠点は、オプティマイザー内でtf.gradients(。)を2回計算するため、実行速度の点で最適ではない可能性があることです。これは、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)
_

tf.trainable_variables()を使用してすべてのトレーニング変数を取得し、それらから選択することができます。違いは、最初の実装ではtf.gradients(.)がオプティマイザー内で2回呼び出されることです。これにより、いくつかの冗長な操作が実行される場合があります(たとえば、最初のレイヤーのグラデーションは、後続のレイヤーのグラデーションの計算を再利用できます)。

80

1月22日更新:以下のレシピはGradientDescentOptimizerにのみ適しています。実行平均を維持する他のオプティマイザーは、パラメーター更新の前に学習率を適用するため、以下のレシピはそれに影響しません方程式の一部

Rafalのアプローチに加えて、compute_gradientsapply_gradientsOptimizerのインターフェース。たとえば、2番目のパラメーターに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])

見るべき

[0.80000001, 0.40000001]
[0.72000003, 0.56]
[0.68800002, 0.62400001]
[0.67520005, 0.64960003]
[0.67008007, 0.65984005]
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]))
7
P-Gn

次のような各変数の学習率の乗数を収集します。

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 を見つけることができます。

6
Sergey Demyanov

最初の5つのレイヤーの学習率は0.00001で、最後の1つのレイヤーの学習率は0.001です。これを達成する方法はありますか?

Tf.stop_gradientを使用して簡単に実行できます。 3つのレイヤーの例を次に示します。

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

最初の2つのレイヤーのグラデーションを1/100の比率で縮小できます。

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

レイヤー2では、「フロー」は2つのブランチに分割されます。1/ 100の寄与を持つブランチは定期的に勾配を計算しますが、勾配の大きさは1/100の割合で縮小します。 tf.stop_gradient演算子により勾配に寄与しません。その結果、モデルオプティマイザーで学習率0.001を使用すると、最初の2つのレイヤーの学習率は事実上0.00001になります。

0

セルゲイデミャノフの回答のわずかなバリエーション。変更したい学習率を指定するだけです。

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