是否只能使用TensorFlow中处理渐变的代码示例来实现梯度下降(如优化器)?

Pin*_*hio 7 python machine-learning neural-network conv-neural-network tensorflow

我正在查看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)
Run Code Online (Sandbox Code Playgroud)

但是,我注意到这个apply_gradients功能来源于GradientDescentOptimizer.这是否意味着,使用示例代码从上面,只能实现梯度下降一样的规则(注意我们可以改变opt = GradientDescentOptimizerAdam或任何其他优化的)?特别是,做apply_gradients什么?我明确地检查了tf github页面中的代码,但它是一堆与数学表达式无关的python,因此很难分辨出它在做什么以及它如何从优化器更改为优化器.

例如,如果我想实现我自己的可能使用渐变的自定义优化器(或者可能不会直接使用某些规则更改权重,可能是更生物学上合理的规则),那么上述示例代码是不可能的?


特别是我想实现一个在紧凑域中人为限制的梯度下降版本.特别是我想实现以下等式:

w := (w - mu*grad + eps) mod B
Run Code Online (Sandbox Code Playgroud)

在TensorFlow中.我意识到以下情况属实:

w := w mod B - mu*grad mod B + eps mod B
Run Code Online (Sandbox Code Playgroud)

所以我认为我可以通过这样做来实现它:

def Process_grads(g,mu_noise,stddev_noise,B):
    return (g+tf.random_normal(tf.shape(g),mean=mu_noise,stddev=stddev_noise) ) % B
Run Code Online (Sandbox Code Playgroud)

然后只是:

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)
Run Code Online (Sandbox Code Playgroud)

但是,我意识到这不够好,因为我实际上没有访问权,w所以我无法实现:

w mod B
Run Code Online (Sandbox Code Playgroud)

至少不是我尝试的方式.有没有办法做到这一点?即实际直接更改更新规则?至少我试过的方式?

我知道它是一种hacky更新规则,但我的观点更多的是更改更新等式,而不是实际关注更新规则(所以如果它有点奇怪,不要挂断它).


我提出了超级hacky解决方案:

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]
Run Code Online (Sandbox Code Playgroud)

不知道它是否有效,但这样的事情应该是一般的.我们的想法是只记下想要使用的等式(在TensorFlow中)以获得学习率,然后使用会话手动更新权重.

不幸的是,这样的解决方案意味着我们必须处理退火(手动衰减学习率,这看起来很烦人).这个解决方案可能还有许多其他问题,请随意指出(如果可以的话,给出解决方案).


对于这个非常简单的问题,我意识到可以执行常规优化器更新规则,然后只需获取权重的mod并将它们重新分配给它们的值:

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()
Run Code Online (Sandbox Code Playgroud)

但在这种情况下,存在这样一个简单的解决方案的巧合(不幸的是,绕过了我的问题的全部要点).

实际上,这个解决方案会大大减慢代码的速度.目前是我所拥有的最好的.


作为参考,我看到了这个问题:如何在Tensorflow中创建优化器,但没有发现它直接回答了我的问题.

pat*_*_ai 3

事实上,你受到了一定的限制,什么也做不了。但是,您想要做的事情可以通过创建张量流类的子类来轻松完成Optimizer

您需要做的就是_apply_dense为您的类编写一个方法。该_apply_dense方法将gradw作为参数,因此您可以对这些变量执行任何您想要执行的操作。

看看这里的例子: https: //github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/adam.py 这是Adam在tensorflow中的实现,你需要做的就是更改第_apply_dense131行以及_prepare_finish方法。

例如:

def _apply_dense(self, grad, var):
    B = math_ops.cast(self.B, var.dtype.base_dtype)
    eps = math_ops.cast(self.eps, var.dtype.base_dtype)
    mu = math_ops.cast(self.mu, var.dtype.base_dtype)


    var_update = state_ops.assign(var, tf.floormod(var - mu*grad + eps,B),
                           use_locking=self._use_locking)

    return var_update
Run Code Online (Sandbox Code Playgroud)