TensorFlow學習(四):梯度帶(GradientTape),優化器(Optimizer)和損失函數(losses)

更新時間:

2017.5.9 簡化了很多不需要的內容,關注重點。
2019.4.17 更新到tensorflow 2.x,添加自動求導和新版本的optimizer
因爲tensorflow 2.x相對於tensorflow 1.x的變動,API變更和思路也變化了,這節重點介紹的爲梯度帶(GradientTape)和優化器(Optimizer)
因爲大多數機器學習任務就是最小化損失,在損失定義的情況下,後面的工作就交給優化器啦。因爲深度學習常見的是對於梯度的優化,也就是說,優化器最後其實就是各種對於梯度下降算法的優化。

一.梯度帶tf.GradientTape
梯度帶是新版本tensorflow非常常用的一個特性了,因爲一旦涉及到計算梯度的問題就離不開這個新的API,下面通過幾個例子來介紹一下這個API。首先說明,下面的幾個例子比較偏底層一點,需要非常少量和簡單的一元和多元微分的知識。
例一:一元和二元求導

import tensorflow as tf

def gradient_test():
    #-------------------一元梯度案例---------------------------
    print("一元梯度")
    x=tf.constant(value=3.0)
    with tf.GradientTape(persistent=True,watch_accessed_variables=True) as tape:
        tape.watch(x)
        y1=2*x
        y2=x*x+2
        y3=x*x+2*x
    #一階導數
    dy1_dx=tape.gradient(target=y1,sources=x)
    dy2_dx = tape.gradient(target=y2, sources=x)
    dy3_dx = tape.gradient(target=y3, sources=x)
    print("dy1_dx:",dy1_dx)
    print("dy2_dx:", dy2_dx)
    print("dy3_dx:", dy3_dx)


    # # -------------------二元梯度案例---------------------------
    print("二元梯度")
    x = tf.constant(value=3.0)
    y = tf.constant(value=2.0)
    with tf.GradientTape(persistent=True,watch_accessed_variables=True) as tape:
        tape.watch([x,y])
        z1=x*x*y+x*y
    # 一階導數
    dz1_dx=tape.gradient(target=z1,sources=x)
    dz1_dy = tape.gradient(target=z1, sources=y)
    dz1_d=tape.gradient(target=z1,sources=[x,y])
    print("dz1_dx:", dz1_dx)
    print("dz1_dy:", dz1_dy)
    print("dz1_d:",dz1_d)
    print("type of dz1_d:",type(dz1_d))


if __name__=="__main__":
    gradient_test()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
結果:

一元梯度
dy1_dx: tf.Tensor(2.0, shape=(), dtype=float32)
dy2_dx: tf.Tensor(6.0, shape=(), dtype=float32)
dy3_dx: tf.Tensor(8.0, shape=(), dtype=float32)
二元梯度
dz1_dx: tf.Tensor(14.0, shape=(), dtype=float32)
dz1_dy: tf.Tensor(12.0, shape=(), dtype=float32)
dz1_d: [<tf.Tensor: id=55, shape=(), dtype=float32, numpy=14.0>, <tf.Tensor: id=56, shape=(), dtype=float32, numpy=12.0>]
type of dz1_d: <class 'list'>
1
2
3
4
5
6
7
8
9
根據這個例子說一下tf.GradientTape這個類的常見的屬性和函數,更多的可以去官方文檔來看。

__init__(persistent=False,watch_accessed_variables=True)
作用:創建一個新的GradientTape
參數:

persistent: 布爾值,用來指定新創建的gradient tape是否是可持續性的。默認是False,意味着只能夠調用一次gradient()函數。
watch_accessed_variables: 布爾值,表明這個gradien tap是不是會自動追蹤任何能被訓練(trainable)的變量。默認是True。要是爲False的話,意味着你需要手動去指定你想追蹤的那些變量。
比如在上面的例子裏面,新創建的gradient tape設定persistent爲True,便可以在這個上面反覆調用gradient()函數。

watch(tensor)
作用:確保某個tensor被tape追蹤

參數:

tensor: 一個Tensor或者一個Tensor列表
gradient(target,sources,output_gradients=None,unconnected_gradients=tf.UnconnectedGradients.NONE)
作用:根據tape上面的上下文來計算某個或者某些tensor的梯度
參數:

target: 被微分的Tensor或者Tensor列表,你可以理解爲經過某個函數之後的值
sources: Tensors 或者Variables列表(當然可以只有一個值). 你可以理解爲函數的某個變量
output_gradients: a list of gradients, one for each element of target. Defaults to None.
unconnected_gradients: a value which can either hold ‘none’ or ‘zero’ and alters the value which will be returned if the target and sources are unconnected. The possible values and effects are detailed in ‘UnconnectedGradients’ and it defaults to ‘none’.
返回:
一個列表表示各個變量的梯度值,和source中的變量列表一一對應,表明這個變量的梯度。

上面的例子中的梯度計算部分可以更直觀的理解這個函數的用法。

二.優化器
優化器也是大家非常熟悉的東西了,tensorflow 2.x也會把優化器移動到了tf.keras.optimizers,其他的用法還是和之前一樣,這裏就不囉嗦了。同時這裏推薦一個博客,總結了這些優化器的原理以及性能,寫的挺好的:An overview of gradient descent optimazation algorithms

注意,這裏所有的優化器裏面一般會有幾個更新梯度的常用函數:

apply_gradients(grads_and_vars,name=None)
作用:把計算出來的梯度更新到變量上面去。
參數:

grads_and_vars: (gradient, variable) 對的列表.
name: 操作名
Returns:
An Operation that applies the specified gradients. If global_step was not None, that operation also increments global_step.

三.損失函數
損失函數可以根據自己的需要自己寫,也可以使用tensorflow中封裝的一些損失函數,比如均方誤差啊等等。損失函數也不用我囉嗦了,需要使用tensorflow中自帶的那些損失函數,在tf.keras.losses裏面找就行.

四.線性迴歸例子
有了上面兩個的基礎,下面就用一個線性迴歸的簡單綜合例子來把優化器和梯度帶結合起來。
要是有不知道線性迴歸的理論知識的,請到
http://blog.csdn.net/xierhacker/article/details/53257748
http://blog.csdn.net/xierhacker/article/details/53261008
熟悉的直接跳過。
直接上代碼:

import tensorflow as tf
import numpy as np
import matplotlib.pyplot as plt

TRAIN_STEPS=20

# Prepare train data
train_X = np.linspace(-1, 1, 100)
train_Y = 2 * train_X + np.random.randn(*train_X.shape) * 0.33 + 10

print(train_X.shape)

w=tf.Variable(initial_value=1.0)
b=tf.Variable(initial_value=1.0)

optimizer=tf.keras.optimizers.SGD(0.1)
mse=tf.keras.losses.MeanSquaredError()

for i in range(TRAIN_STEPS):
    print("epoch:",i)
    print("w:", w.numpy())
    print("b:", b.numpy())
    #計算和更新梯度
    with tf.GradientTape() as tape:
        logit = w * train_X + b
        loss=mse(train_Y,logit)
    gradients=tape.gradient(target=loss,sources=[w,b])  #計算梯度
    #print("gradients:",gradients)
    #print("zip:\n",list(zip(gradients,[w,b])))
    optimizer.apply_gradients(zip(gradients,[w,b]))     #更新梯度


#draw
plt.plot(train_X,train_Y,"+")
plt.plot(train_X,w * train_X + b)
plt.show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
結果:

epoch: 0
w: 1.0
b: 1.0
epoch: 1
w: 1.062283
b: 2.799747
epoch: 2
w: 1.12033
b: 4.2395444
epoch: 3
w: 1.1744289
b: 5.391382
epoch: 4
w: 1.2248484
b: 6.3128524
epoch: 5
w: 1.2718387
b: 7.050029
epoch: 6
w: 1.3156329
b: 7.6397696
epoch: 7
w: 1.3564487
b: 8.111563
epoch: 8
w: 1.3944883
b: 8.4889965
epoch: 9
w: 1.4299408
b: 8.790944
epoch: 10
w: 1.462982
b: 9.032502
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33


這裏你可以使用更多的優化器來試一下各個優化器的性能和調參情況
————————————————
版權聲明:本文爲CSDN博主「謝小小XH」的原創文章,遵循 CC 4.0 BY-SA 版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/xierhacker/article/details/53174558

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