Я смотрел пример кода для обработки градиентов, который есть в TensorFlow:
# Create an optimizer.
opt = GradientDescentOptimizer(learning_rate=0.1)
# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(loss, <list of variables>)
# grads_and_vars is a list of tuples (gradient, variable). Do whatever you
# need to the 'gradient' part, for example cap them, etc.
capped_grads_and_vars = [(MyCapper(gv[0]), gv[1]) for gv in grads_and_vars]
# Ask the optimizer to apply the capped gradients.
opt.apply_gradients(capped_grads_and_vars)
однако я заметил, что функция apply_gradients
была получена из GradientDescentOptimizer
. Означает ли это, что, используя приведенный выше пример кода, можно реализовать только градиент, например правила спуска (обратите внимание, что мы можем изменить opt = GradientDescentOptimizer
или Adam
или любой из других оптимизаторов)? В частности, что делает apply_gradients
? Я окончательно проверяю код на странице tf github но это была связка Python, не имевшая ничего общего с математическими выражениями, поэтому было трудно сказать, что она делает и как она изменилась от оптимизатора к оптимизатору.
Например, если бы я хотел реализовать свой собственный оптимизатор, который мог бы использовать градиенты (или не мог, например, просто изменять веса напрямую с помощью некоторого правила, может быть, более биологически правдоподобного правила), это невозможно с приведенным выше примером кода?
В частности, я хотел реализовать версию градиентного спуска, которая искусственно ограничена в компактной области. В частности, я хотел реализовать следующее уравнение:
w := (w - mu*grad + eps) mod B
в TensorFlow. Я понял, что верно следующее:
w := w mod B - mu*grad mod B + eps mod B
поэтому я подумал, что могу просто реализовать это, выполнив:
def Process_grads(g,mu_noise,stddev_noise,B):
return (g+tf.random_normal(tf.shape(g),mean=mu_noise,stddev=stddev_noise) ) % B
а затем просто имея:
processed_grads_and_vars = [(Process_grads(gv[0]), gv[1]) for gv in grads_and_vars]
# Ask the optimizer to apply the processed gradients.
opt.apply_gradients(processed_grads_and_vars)
однако я понял, что этого недостаточно, потому что на самом деле у меня нет доступа к w
, поэтому я не могу реализовать:
w mod B
по крайней мере, не так, как я пытался. Есть ли способ сделать это? т.е. непосредственно изменить правило обновления? По крайней мере так, как я пробовал?
Я знаю, что это своего рода хитрое правило обновления, но я хочу больше изменить уравнение обновления, чем на самом деле уделять много внимания этому правилу обновления (так что не зацикливайтесь на нем, если это немного странно).
Я придумал супер-хакерское решение:
def manual_update_GDL(arg,learning_rate,g,mu_noise,stddev_noise):
with tf.variable_scope(arg.mdl_scope_name,reuse=True):
W_var = tf.get_variable(name='W')
eps = tf.random_normal(tf.shape(g),mean=mu_noise,stddev=stddev_noise)
#
W_new = tf.mod( W_var - learning_rate*g + eps , 20)
sess.run( W_var.assign(W_new) )
def manual_GDL(arg,loss,learning_rate,mu_noise,stddev_noise,compact,B):
# Compute the gradients for a list of variables.
grads_and_vars = opt.compute_gradients(loss)
# process gradients
processed_grads_and_vars = [(manual_update_GDL(arg,learning_rate,g,mu_noise,stddev_noise), v) for g,v in grads_and_vars]
не уверен, что это работает, но что-то вроде этого должно работать в целом. Идея состоит в том, чтобы просто записать уравнение, которое вы хотите использовать (в TensorFlow) для скорости обучения, а затем обновить веса вручную с помощью сеанса.
К сожалению, такое решение означает, что мы должны позаботиться об отжиге (снижение скорости обучения вручную, что кажется раздражающим). У этого решения, вероятно, есть много других проблем, не стесняйтесь указывать на них (и предлагать решения, если можете).
Я понял, что для этой очень простой проблемы можно просто выполнить обычное правило обновления оптимизатора, а затем просто взять модификацию весов и переназначить им их значение:
sess.run(fetches=train_step)
if arg.compact:
# apply w := ( w - mu*g + eps ) mod B
W_val = W_var.eval()
W_new = tf.mod(W_var,arg.B).eval()
W_var.assign(W_new).eval()
но в данном случае это совпадение, что такое простое решение существует (к сожалению, обходит весь смысл моего вопроса).
На самом деле эти решения сильно замедляют код. На данный момент это лучшее, что у меня есть.
В качестве справки я видел этот вопрос: Как создать оптимизатор в Tensorflow, но не нашел прямого ответа на мой вопрос.
grad = w - (w mod B - mu*grad mod B + eps mod B)
и получите скорость обучения1.0
сtf.train.GradientDescentOptimizer
? Это должно применить градиенты какw -= grad
, то естьw = w mod B - mu*grad mod B + eps mod B
. - person Olivier Moindrot   schedule 22.03.2017