1. 程式人生 > 實用技巧 >TensorFlow學習筆記之--[compute_gradients和apply_gradients原理淺析]

TensorFlow學習筆記之--[compute_gradients和apply_gradients原理淺析]

I optimizer.minimize(loss, var_list)

我們都知道,TensorFlow為我們提供了豐富的優化函式,例如GradientDescentOptimizer。這個方法會自動根據loss計算對應variable的導數。示例如下:

loss = ...
opt = tf.tf.train.GradientDescentOptimizer(learning_rate=0.1)
train_op = opt.minimize(loss)
init = tf.initialize_all_variables()

with tf.Seesion() as sess:
    
for step in range(10): session.run(train_op)

首先我們看一下minimize()的原始碼(為方便說明,部分引數已刪除):

def minimize(self, loss, global_step=None, var_list=None, name=None):

    grads_and_vars = self.compute_gradients(loss, var_list=var_list)

    vars_with_grad = [v for g, v in grads_and_vars if g is not None]
    
if not vars_with_grad: raise ValueError( "No gradients provided for any variable, check your graph for ops" " that do not support gradients, between variables %s and loss %s." % ([str(v) for _, v in grads_and_vars], loss)) return self.apply_gradients(grads_and_vars, global_step=global_step, name
=name)

由原始碼可以知道minimize()實際上包含了兩個步驟,即compute_gradientsapply_gradients,前者用於計算梯度,後者用於使用計算得到的梯度來更新對應的variable。下面對這兩個函式做具體介紹。

II computer_gradients(loss, val_list)

引數含義:

  • loss: 需要被優化的Tensor
  • val_list: Optional list or tuple of tf.Variable to update to minimize loss. Defaults to the list of variables collected in the graph under the key GraphKeys.TRAINABLE_VARIABLES.

簡單說該函式就是用於計算loss對於指定val_list的導數的,最終返回的是元組列表,即[(gradient, variable),...]。

看下面的示例

x = tf.Variable(initial_value=50., dtype='float32')
w = tf.Variable(initial_value=10., dtype='float32')
y = w*x

opt = tf.train.GradientDescentOptimizer(0.1)
grad = opt.compute_gradients(y, [w,x])
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    print(sess.run(grad))

返回值如下:

>>> [(50.0, 10.0), (10.0, 50.0)]

可以看到返回了一個list,list中的元素是元組。第一個元組第一個元素是50,表示\(\frac{\partial{y}}{\partial{w}}\)的計算結果,第二個元素表示\(w\)。第二個元組同理不做贅述。

其中tf.gradients(loss, tf.variables)的作用和這個函式類似,但是它只會返回計算得到的梯度,而不會返回對應的variable。

with tf.Graph().as_default():
    x = tf.Variable(initial_value=3., dtype='float32')
    w = tf.Variable(initial_value=4., dtype='float32')
    y = w*x

    grads = tf.gradients(y, [w])
    print(grads)
    
    opt = tf.train.GradientDescentOptimizer(0.1)
    grads_vals = opt.compute_gradients(y, [w])
    print(grad_vals)

>>>
[<tf.Tensor 'gradients/mul_grad/Mul:0' shape=() dtype=float32>]
[(<tf.Tensor 'gradients_1/mul_grad/tuple/control_dependency:0' shape=() dtype=float32>, <tf.Variable 'Variable_1:0' shape=() dtype=float32_ref>)]

III apply_gradients(grads_and_vars, global_step=None, name=None)

該函式的作用是將compute_gradients()返回的值作為輸入引數對variable進行更新。

那為什麼minimize()會分開兩個步驟呢?原因是因為在某些情況下我們需要對梯度做一定的修正,例如為了防止梯度消失(gradient vanishing)或者梯度爆炸(gradient explosion),我們需要事先干預一下以免程式出現Nan的尷尬情況;有的時候也許我們需要給計算得到的梯度乘以一個權重或者其他亂七八糟的原因,所以才分開了兩個步驟。

IV Example

下面給出一個使用tf.global_norm來修正梯度的例子:

with tf.Graph().as_default():
    x = tf.Variable(initial_value=3., dtype='float32')
    w = tf.Variable(initial_value=4., dtype='float32')
    y = w*x
    
    opt = tf.train.GradientDescentOptimizer(0.1)
    grads_vals = opt.compute_gradients(y, [w])
    for i, (g, v) in enumerate(grads_vals):
        if g is not None:
            grads_vals[i] = (tf.clip_by_norm(g, 5), v)  # clip gradients
    train_op = opt.apply_gradients(grads_vals)
    with tf.Session() as sess:
        sess.run(tf.global_variables_initializer())
        print(sess.run(grads_vals))
        print(sess.run([x,w,y]))
        
>>>     
[(3.0, 4.0)]
[3.0, 4.0, 12.0]  

其他的tf.clip_by_*方法可參看TensorFlow學習筆記之--[tf.clip_by_global_norm,tf.clip_by_value,tf.clip_by_norm等的區別]

該文章轉載自:https://cloud.tencent.com/developer/article/1375874