私はPyTorchでのSGD + Momentumの実装を見てきましたが、他のパッケージ(および論文)がそれを説明する方法とは少し異なることに気づきました。 とりあえず、ネステロフのバージョンではなく、(古典的な)勢いだけに焦点を当てましょう。
これを書いている時点で、実装は次のようになっています。
`` `
勢いの場合!= 0:
param_state = self.state [p]
'momentum_buffer'がparam_stateにない場合:
buf = param_state ['momentum_buffer'] = d_p.clone()
それ以外:
buf = param_state ['momentum_buffer']
buf.mul_(momentum).add_(1-減衰、d_p)
nesterovの場合:
d_p = d_p.add(momentum、buf)
それ以外:
d_p = buf
p.data.add_(-group['lr'], d_p)
Mathematically, if we denote the momentum buffer by `v` and assume that `dampening=0`, at every iteration, the buffer is updated as `v = m*v + g` and the step is `∆x = lr * v`. Notice that the learning rate `lr` hits the momentum term `v` as well as the gradient. To me, this is different from what classical momentum is, and also differs from how other packages implement SGD+M.
Let us contrast this with the Sutskever et. al. paper and other commonly used pacakges such as Lasagne, Keras, Neon, etc.
## [Sutskever et. al.](http://www.jmlr.org/proceedings/papers/v28/sutskever13.pdf)
The snippet of the relevant section is pasted below.
![Sutskever et. al.](http://i.imgur.com/QJelodE.png)
Retaining the syntax from above, the algorithm updates `v` as `v = m*v - lr * g` with the step `∆x = v`. So, the learning rate `lr` only hits the gradient. It does not (explicitly) influence the effect of the momentum term which is in contrast with PyTorch's implementation.
# [Lasagne](https://github.com/Lasagne/Lasagne/blob/master/lasagne/updates.py#L217)
Lasagne employs the same rule as suggested in Sutskever for momentum.
for param in params:
value = param.get_value(borrow=True)
velocity = theano.shared(np.zeros(value.shape, dtype=value.dtype),
broadcastable=param.broadcastable)
x = momentum * velocity + updates[param]
updates[velocity] = x - param
# [Keras](https://github.com/fchollet/keras/blob/master/keras/optimizers.py#L141)
Same for Keras:
for p, g, m in zip(params, grads, moments):
v = self.momentum * m - lr * g # velocity
self.updates.append(K.update(m, v))
if self.nesterov:
new_p = p + self.momentum * v - lr * g
else:
new_p = p + v
# [Neon](https://github.com/NervanaSystems/neon/blob/master/neon/optimizers/optimizer.py#L520)
and Neon.
velocity[:] = self.momentum_coef * velocity - lrate * grad
# Nesterov accelerated gradient (NAG) is implemented the same
# as in torch's "sgd.lua". It's a reformulation of Sutskever's
# NAG equation found in "On the importance of initialization
# and momentum in deep learning".
if self.nesterov:
param[:] = param + self.momentum_coef * velocity -\
lrate * grad
else:
param[:] = param + velocity
`` `
格差は本当ですか、それとも私は何か重要なものを見逃していますか?
2つの実装の違いは重要ではなく、特にlr
が途中で削減された場合は重要です。 私の主張が真実である場合、参照を更新するか(それが何であるかはわかりません)、SGDコードに上記のバージョンを含めることができますか(必要に応じてこれを取り上げることができます)?
学習率が固定されている場合、2つの定式化は同等です。 ステップサイズが学習率に正比例するため、トーチの定式化が選択されます。 これは、学習率を下げると、ステップサイズがすぐに減少することを意味します。これは、一般的に必要な反復回数の後ではありません。
同意します。 私の唯一の懸念は、メソッドのリファレンスがSutskeverの論文であり、違いを説明するドキュメントがないことを考えると、現在の実装は、他のフレームワークからPyTorchに移行する人々にとって潜在的な「落とし穴」になる可能性があるということでした。
@keskarnitishドキュメントにメモを追加するPRを送信する場合は、マージできてうれしいです。
最も参考になるコメント
学習率が固定されている場合、2つの定式化は同等です。 ステップサイズが学習率に正比例するため、トーチの定式化が選択されます。 これは、学習率を下げると、ステップサイズがすぐに減少することを意味します。これは、一般的に必要な反復回数の後ではありません。