Я пытаюсь понять оптимизатор SGD на keras для реализации накопительной версии этого оптимизатора. Я застрял в точке, где я не могу по-настоящему следовать рассуждениям команд после определенной точки.
Фактическая функция такова:
def get_updates(self, loss, params):
grads = self.get_gradients(loss, params)
self.updates = [K.update_add(self.iterations, 1)]
lr = self.learning_rate
if self.initial_decay > 0:
lr = lr * (1. / (1. + self.decay * K.cast(self.iterations,
K.dtype(self.decay))))
# momentum
shapes = [K.int_shape(p) for p in params]
moments = [K.zeros(shape, name='moment_' + str(i)) for (i, shape) in enumerate(shapes)]
self.weights = [self.iterations] + moments
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
# Apply constraints.
if getattr(p, 'constraint', None) is not None:
new_p = p.constraint(new_p)
self.updates.append(K.update(p, new_p))
return self.updates
, которая, если я не ошибаюсь,вызывается на каждой итерации. (Поскольку по разным причинам у меня возникают проблемы с отладкой реальной функции, я предполагаю, что это реальное поведение).
Строка moments = [K.zeros(shape, name='moment_' + str(i)) for (i, shape) in enumerate(shapes)]
создает пустой тензор для сохранения моментов, пока я его получаю. Но когда я вычисляю вручную, я не получаю результаты, которые ожидаю от теоретической формулы.
Например, для двух итераций мы имеем (предполагая self.momentum = 0.9
и не применяя Нестерова для простоты):
Iter # 1:
grads = self.get_gradients(loss, params)
: вычисляет градиент, назовем их grad1
.
...
Внутри for p, g, m in zip(params, grads, moments)
цикла:
v1 = self.momentum * m - lr * g = 0.9*0 - lr * grad1 = - lr * grad1
.
Обновление m
-> v1
и p
-> new_p = p + v1 = - lr * grad1
.
Iter # 2:
grads = self.get_gradients(loss, params)
: рассчитывает градиент, назовем их grad2
.
...
Внутри for p, g, m in zip(params, grads, moments)
цикл:
(m
инициализируется на каждой итерации в 0
Я думаю. Исправьте меня, если я ошибаюсь)
v2 = self.momentum * m - lr * g = 0.9*0 - lr * grad2 = - lr * grad2
Обновление m
-> v and
p -> new_p = p + v = v1 + v2 = - lr * grad1 - lr * grad2`.
Я ожидал бы что-то вроде: - 0.9*lr * grad1 - lr * grad2
подойдет сюда. Кроме того, судя по моим вычислениям m
(моменты), похоже, не используется, поэтому я, вероятно, как-то ошибаюсь в своих расчетах. Может кто-нибудь объяснить менталитет SGD в кератах?
Кроме того, у меня есть некоторые проблемы с пониманием того, что повторяет for
, что могло бы дать мне подсказку, что я здесь упускаю.