7

我一直在寻找用于处理梯度示例代码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) 

然而,我注意到apply_gradients函数从GradientDescentOptimizer的。这是否意味着使用上面的示例代码,只能实现渐变规则(请注意,我们可以更改opt = GradientDescentOptimizerAdam或任何其他优化器)?特别是,apply_gradients是做什么的?我明确地检查了tf github page中的代码,但它是一堆与数学表达式无关的python,所以很难说出它在做什么以及它是如何从优化器转换为优化器的。例如,如果我想实现我自己的可能使用渐变的自定义优化器(或者可能不会,例如直接用一些规则更改权重,也许生物学上更合理的规则),那么使用上面的示例代码不可能实现?


我特别想要实现了在一个紧凑的域人为限制的梯度下降版本。特别是我想实现下面的等式:

w := (w - mu*grad + eps) mod B 

in 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中的)作为学习率,然后使用会话手动更新权重。

不幸的是,这样的解决方案意味着我们必须照顾退火(手动衰减学习率似乎令人讨厌)。这个解决方案可能有很多其他问题,随时指出(如果可以的话,给出解决方案)。


对于这个非常简单的问题,我意识到一个可以做正常的优化更新规则,然后只取权重的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() 

但在这种情况是一个巧合,这种简单的解决方案存在(不幸的是,绕过了我的问题的整个观点)。

其实,这种解决方案会减慢代码很多。目前是我拥有的最好的。


作为参考,我已经看到了这个问题:How to create an optimizer in Tensorflow,但没有找到它直接回答我的问题。

+2

如果你修改所有的梯度是'毕业= W - (W MOD乙 - 亩*毕业MOD B + EPS MOD B) ''和'tf.train.GradientDescentOptimizer'具有1.0的学习率?这应该将梯度应用为'w = = grad',即'w = w mod B-mu * grad mod B + eps mod B'。 –

回答

3

你的确是受到一定的限制,不能做任何事情。但是,你希望做什么可以很容易地通过使tensorflow Optimizer类的你女儿的类来完成。

所有你需要做的是写你的类的_apply_dense方法。该_apply_dense方法需要gradw作为参数,所以你要这些做的变量,你可以做任何事情。

看吧例如:https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/training/adam.py 这就是亚当的tensorflow实施,所有你需要做的是改变_apply_dense在行131还有_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 
3

您的解决方案会减慢代码,因为您在“train_step”的创作过程中使用sess.run和.eval()代码。相反,您应该只使用内部张量函数(不使用sess.run和.eval())来创建train_step图。此后,您只能评估循环中的train_step。

如果你不希望使用任何标准的优化,你可以编写自己的“应用渐变”图。下面是一个可能的解决方案:

learning_rate = tf.Variable(tf.constant(0.1)) 
mu_noise = 0. 
stddev_noise = 0.01 

#add all your W variables here when you have more than one: 
train_w_vars_list = [W] 
grad = tf.gradients(some_loss, train_w_vars_list) 

assign_list = [] 
for g, v in zip(grad, train_w_vars_list): 
    eps = tf.random_normal(tf.shape(g), mean=mu_noise, stddev=stddev_noise) 
    assign_list.append(v.assign(tf.mod(v - learning_rate*g + eps, 20))) 

#also update the learning rate here if you want to: 
assign_list.append(learning_rate.assign(learning_rate - 0.001)) 

train_step = tf.group(*assign_list) 

您也可以使用标准的优化器之一来创建grads_and_vars列表(用它来代替拉链(研究生,train_w_vars_list)的即可)。

这里是MNIST一个简单的例子,你的损失:

from __future__ import absolute_import 
from __future__ import division 
from __future__ import print_function 

from tensorflow.examples.tutorials.mnist import input_data 

import tensorflow as tf 

# Import data 
mnist = input_data.read_data_sets('PATH TO MNIST_data', one_hot=True) 

# Create the model 
x = tf.placeholder(tf.float32, [None, 784]) 
W = tf.Variable(tf.zeros([784, 10])) 
y = tf.matmul(x, W) 


# Define loss and optimizer 
y_ = tf.placeholder(tf.float32, [None, 10]) 

cross_entropy = tf.reduce_mean(
    tf.nn.softmax_cross_entropy_with_logits(labels=y_, logits=y)) 

learning_rate = tf.Variable(tf.constant(0.1)) 
mu_noise = 0. 
stddev_noise = 0.01 

#add all your W variables here when you have more than one: 
train_w_vars_list = [W] 
grad = tf.gradients(cross_entropy, train_w_vars_list) 

assign_list = [] 
for g, v in zip(grad, train_w_vars_list): 
    eps = tf.random_normal(tf.shape(g), mean=mu_noise, stddev=stddev_noise) 
    assign_list.append(v.assign(tf.mod(v - learning_rate*g + eps, 20))) 

#also update the learning rate here if you want to: 
assign_list.append(learning_rate.assign(learning_rate - 0.001)) 

train_step = tf.group(*assign_list) 


sess = tf.InteractiveSession() 
tf.global_variables_initializer().run() 


# Train 
for _ in range(1000): 
    batch_xs, batch_ys = mnist.train.next_batch(100) 
    sess.run(train_step, feed_dict={x: batch_xs, y_: batch_ys}) 


# Test trained model 
correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1)) 
accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) 
print(sess.run(accuracy, feed_dict={x: mnist.test.images, 
            y_: mnist.test.labels}))