自動求梯度

自動求梯度

import tensorflow as tf
print(tf.__version__)
2.1.0

自動求梯度

在深度學習中,我們經常需要對函數求梯度(gradient)。本節將介紹如何使用tensorflow2.0提供的GradientTape來自動求梯度。

2.3.1 一個簡單的例子

我們先看一個簡單例子:對函數 y=2xxy = 2\boldsymbol{x}^{\top}\boldsymbol{x} 求關於列向量 x\boldsymbol{x} 的梯度。我們先創建變量x,並賦初值。

x = tf.reshape(tf.Variable(range(4), dtype=tf.float32),(4,1))
x
<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[0.],
       [1.],
       [2.],
       [3.]], dtype=float32)>

函數 y=2xxy = 2\boldsymbol{x}^{\top}\boldsymbol{x} 關於x\boldsymbol{x} 的梯度應爲4x4\boldsymbol{x}。現在我們來驗證一下求出來的梯度是正確的。

with tf.GradientTape() as t:
    t.watch(x)
    y = 2 * tf.matmul(tf.transpose(x), x)
    
dy_dx = t.gradient(y, x)
dy_dx
<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[ 0.],
       [ 4.],
       [ 8.],
       [12.]], dtype=float32)>

2.3.2 訓練模式和預測模式

import warnings
warnings.filterwarnings('ignore')
x*x
<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
array([[0.],
       [1.],
       [4.],
       [9.]], dtype=float32)>
with tf.GradientTape(persistent=True) as g:
    g.watch(x)
    y = x * x
    z = y * y
    dz_dx = g.gradient(z, x)  # 108.0 (4*x^3 at x = 3)
    dy_dx = g.gradient(y, x)  # 6.0
dz_dx,dy_dx
WARNING:tensorflow:Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.
WARNING:tensorflow:Calling GradientTape.gradient on a persistent tape inside its context is significantly less efficient than calling it outside the context (it causes the gradient ops to be recorded on the tape, leading to increased CPU and memory usage). Only call GradientTape.gradient inside the context if you actually want to trace the gradient in order to compute higher order derivatives.





(<tf.Tensor: shape=(4, 1), dtype=float32, numpy=
 array([[  0.],
        [  4.],
        [ 32.],
        [108.]], dtype=float32)>,
 <tf.Tensor: shape=(4, 1), dtype=float32, numpy=
 array([[0.],
        [2.],
        [4.],
        [6.]], dtype=float32)>)

2.3.3 對python控制流求梯度

即使函數的計算圖包含了Python的控制流(如條件和循環控制),我們也有可能對變量求梯度。

考慮下面程序,其中包含Python的條件和循環控制。需要強調的是,這裏循環(while循環)迭代的次數和條件判斷(if語句)的執行都取決於輸入a的值。

def f(a):
    b = a * 2
    while tf.norm(b) < 1000:
        b = b * 2
    if tf.reduce_sum(b) > 0:
        c = b
    else:
        c = 100 * b
    return c

我們來分析一下上面定義的f函數。事實上,給定任意輸入a,其輸出必然是 f(a) = x * a的形式,其中標量係數x的值取決於輸入a。由於c = f(a)有關a的梯度爲x,且值爲c / a,我們可以像下面這樣驗證對本例中控制流求梯度的結果的正確性。

a = tf.random.normal((1,1),dtype=tf.float32)
with tf.GradientTape() as t:
    t.watch(a)
    c = f(a)
t.gradient(c,a) == c/a
<tf.Tensor: shape=(1, 1), dtype=bool, numpy=array([[ True]])>

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章