之前的文章分別介紹了TensorFlow中張量的一些基本知識:
tf2.0學習(一)——基礎(chǔ)知識
tf2.0學習(二)——進階知識
現(xiàn)在介紹一下TensorFlow中關(guān)于神經(jīng)網(wǎng)絡(luò)的操作。
3.1 全連接層
全連接是有感知機發(fā)展起來的,由于感知機模型使用的是介躍激活函數(shù),他是不連續(xù)不可導的,這嚴重制約了該模型的潛力。如果把激活函數(shù)換成平滑連續(xù)可到的函數(shù),并堆疊多個網(wǎng)絡(luò)層來增強網(wǎng)絡(luò)的表達能力,就形成了我們接下來要介紹的全連接網(wǎng)絡(luò)。
3.1.1 張量方式實現(xiàn)
TensorFlow中提供了很好的矩陣運算和反向傳播算法,可以利用這一特性方便的用張量來實現(xiàn)全連接網(wǎng)絡(luò)。
x = tf.random.uniform([2, 784]) # x為模擬的輸入數(shù)據(jù)
# w1為隨機初始化的參數(shù)w1
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
# b1為0初始化的bias
b1 = tf.Variable(tf.zeros([256]))
# 矩陣相乘 在加bias,即全連接過程
o1 = tf.matmul(x, w1) + b1
# relu激活函數(shù)
o1 = tf.nn.relu(o1)
o1.shape
TensorShape([2, 256])
3.1.2 層的方式實現(xiàn)
全連接作為很常用的網(wǎng)絡(luò)成知識,TensorFlow提供了更高層、更方便的實現(xiàn)方式:tf.keras.layers.Dense(units, activation)。其中unis為輸出的節(jié)點數(shù),activation為激活函數(shù)。
# 輸入數(shù)據(jù)
x = tf.random.normal([4, 28 * 28])
fc = tf.keras.layers.Dense(512, activation=tf.nn.relu)
h1 = fc(x)
h1.shape
TensorShape([4, 512])
如上所示可以很方便的構(gòu)建全連接網(wǎng)絡(luò)層。通過 fc.kernel 和 fc.bias 可以獲取權(quán)重張量W和偏置張量b。
在進行參數(shù)優(yōu)化時,可以用 fc.trainable_variables 獲取待優(yōu)化的參數(shù)。
3.2 神經(jīng)網(wǎng)絡(luò)
通過對神經(jīng)層(例如全連接層)的層層堆疊,并且保證前一層的輸出節(jié)點數(shù)與當前層的輸入節(jié)點數(shù)匹配,即可以構(gòu)建出任意層的神經(jīng)網(wǎng)絡(luò)。
3.2.1 張量的方式
x = tf.random.normal([4, 784])
w1 = tf.Variable(tf.random.truncated_normal([784, 256], stddev=0.1))
b1 = tf.Variable(tf.zeros([256]))
w2 = tf.Variable(tf.random.truncated_normal([256, 184], stddev=0.1))
b2 = tf.Variable(tf.zeros([184]))
w3 = tf.Variable(tf.random.truncated_normal([184, 10], stddev=0.1))
b3 = tf.Variable(tf.zeros([10]))
with tf.GradientTape() as tape:
h1 = x @ w1 + b1
h1 = tf.nn.relu(h1)
h2 = h1 @ w2 + b2
h2 = tf.nn.relu(h2)
h3 = h2 @ w3 + b3
其中h3可以直接作為輸出,也可以加個激活函數(shù)之后再作為輸出,需要視情況而定。
如果希望TensorFlow對一個過程自動求導的話,需要把這個過程的前向傳播放到tf.GradientTape()環(huán)境中,gradient()方法自動求解參數(shù)的梯 度,并利用 optimizers 對象更新參數(shù)。
3.2.2 層的方式
層的方式可以更加簡潔高效的實現(xiàn)神經(jīng)網(wǎng)絡(luò)。
fc1 = tf.keras.layers.Dense(256, activation=tf.nn.relu)
fc2 = tf.keras.layers.Dense(184, activation=tf.nn.relu)
fc3 = tf.keras.layers.Dense(10)
x = tf.random.normal([4, 784])
h1 = fc1(x)
h2 = fc2(h1)
h3 = fc3(h2)
我們同樣可以引入容器Sequential將多個神經(jīng)層封裝成一個大的類,可以更加簡介:
model = tf.keras.Sequential([
tf.keras.layers.Dense(256, activation=tf.nn.relu),
tf.keras.layers.Dense(184, activation=tf.nn.relu),
tf.keras.layers.Dense(10)
])
out = model(x)
前向計算只需要調(diào)用一次網(wǎng)絡(luò)大類對象,就可以按順序計算完所有層。
3.3.3 優(yōu)化目標
我們把神經(jīng)網(wǎng)絡(luò)從輸入到輸出的過程叫做前向傳播。前向傳播的過程也是數(shù)據(jù)從輸入層經(jīng)過第一層,第二層。。。直到輸出層的過程。
前向傳播的最后一步就是完成誤差計算。
其中代表了利用
參數(shù)化的神經(jīng)網(wǎng)絡(luò)模型,g稱為誤差函數(shù),用來表述當前網(wǎng)絡(luò)的與測試
和真實值y之間的差距的度量。我們希望通過訓練集的數(shù)據(jù)
上學習到一組參數(shù)
使得訓練的誤差L最小。
從另一個角度理解神經(jīng)網(wǎng)絡(luò),他完成的是特征的維度變換的過程。比如 4 層的 MNIST 手寫數(shù)字圖片識別的全連接網(wǎng)絡(luò),它依次完成了784 → 256 → 128 → 64 → 10的特 征降維過程。
3.4 激活函數(shù)
激活函數(shù)實現(xiàn)了神經(jīng)網(wǎng)絡(luò)的非線性變換,但和階越函數(shù)和符號函數(shù)等不同,激活函數(shù)一般是平滑可導的,更適合梯度下降算法。
3.4.1 Sigmoid
Sigmoid函數(shù)也叫Logistic函數(shù),定義如下:
他的一個優(yōu)良特性就是能把的輸入壓縮到
的區(qū)間內(nèi)。這個區(qū)間的數(shù)值常被用來表示一下意義:
- 概率分布
- 信號強度
# x為(-6,6)的10個數(shù)
x = tf.linspace(-6, 6, 10)
tf.nn.sigmoid(x)
<tf.Tensor: shape=(10,), dtype=float64, numpy=
array([0.00247262, 0.00931596, 0.0344452 , 0.11920292, 0.33924363,
0.66075637, 0.88079708, 0.9655548 , 0.99068404, 0.99752738])>
x中元素的范圍是[-6, 6],映射到(0,1)區(qū)間。
3.4.2 ReLU
ReLU(REctified Linear Unit,修正線性單元)激活函數(shù)提出前,Sigmoid是最常用的神經(jīng)網(wǎng)絡(luò)激活函數(shù)。但Sigmoid函數(shù)在輸入值較大或較小時,容易出現(xiàn)梯度值接近0的現(xiàn)象,梯度為0會是網(wǎng)絡(luò)參數(shù)得不到有效的更新,導致訓練不收斂。
x = tf.linspace(-6, 6, 10)
tf.nn.relu(x)
<tf.Tensor: shape=(10,), dtype=float64, numpy=
array([0. , 0. , 0. , 0. , 0. ,
0.66666667, 2. , 3.33333333, 4.66666667, 6. ])>
3.4.3 LeakyReLU
ReLU激活函數(shù)的問題在于,當x<0時,其梯度為0,同樣回導致梯度消失的問題,LeakyReLU就是為解決這一問題而提出的。
其中p為用戶設(shè)定的極小的超參數(shù),如0.02等。
x = tf.linspace(-6, 6, 10)
tf.nn.leaky_relu(x, alpha=0.01)
<tf.Tensor: shape=(10,), dtype=float64, numpy=
array([-0.06 , -0.04666667, -0.03333333, -0.02 , -0.00666667,
0.66666667, 2. , 3.33333333, 4.66666667, 6. ])>
3.4.4 Tanh
Tanh函數(shù)能夠?qū)?img class="math-inline" src="https://math.jianshu.com/math?formula=x%5Cin%20R" alt="x\in R" mathimg="1">的輸入壓縮到的區(qū)間內(nèi)。
x = tf.linspace(-6, 6, 10)
tf.nn.tanh(x)
<tf.Tensor: shape=(10,), dtype=float64, numpy=
array([-0.99998771, -0.99982316, -0.99745797, -0.96402758, -0.58278295,
0.58278295, 0.96402758, 0.99745797, 0.99982316, 0.99998771])>
3.5 輸出層設(shè)計
最有一層作為神經(jīng)網(wǎng)絡(luò)的輸出層,要根據(jù)具體的任務(wù)、場景來判斷是否使用激活函數(shù),以及使用什么樣的激活函數(shù)。
- 普通實數(shù)空間
這種輸出比較普遍,譬如房價預(yù)測、年齡預(yù)測、股票預(yù)測,都屬于整個或部分連續(xù)的實數(shù)空間,輸出層可以不加激活函數(shù)(或用relu)。 - [0, 1] 區(qū)間
二分類問題,常用Sigmoid作為激活函數(shù)。 - [0, 1]區(qū)間,且和為1
多分類問題,常用Softmax作為激活函數(shù)。
3.6 誤差計算
在搭建完模型結(jié)構(gòu)之后,下一步就是選擇合適的誤差函數(shù)來計算誤差了。常見的誤差函數(shù)有mse,mae,hinge loss,cross entrpy等,其中均方誤差和交叉熵在深度學習中比較常見。
3.6.1 均方誤差
tensorflow中:
o = tf.random.normal([2, 10])
y = tf.constant([1, 3])
y = tf.one_hot(y, depth=10)
loss = tf.keras.losses.MSE(y, o)
tf.reduce_sum(loss)
需要注意的是,tf.keras.losses.MSE()返回的是每個樣本的均方誤差,計算當前batch的均方誤差時,需要tf.reduce_mean(loss)
也可以通過層的方式計算:
mse = tf.keras.losses.MeanSquaredError()
mse(y, o)
3.6.2 交叉熵
信息學中有個重要的概念叫熵。
熵用來衡量信息的不確定度。熵越大代表不確定性越大,信息量也就越大。
通過熵,引出交叉熵的定義:
通過變換,交叉熵可以分解為p的熵和p,q的KL散度的和:
其中KL散度為:
KL散度是用來衡量兩個分布之間的距離的指標。當p與q之間的距離越大,KL散度也就越大。
最小化交叉熵損失函數(shù)的過程也是最大化正確類別的預(yù)測概率的過程。從這個角 度去理解交叉熵損失函數(shù),非常地直觀易懂。
3.7 神經(jīng)網(wǎng)絡(luò)的類型
全連接是最基本的網(wǎng)絡(luò)類型,對后續(xù)其他神經(jīng)網(wǎng)絡(luò)的研究有巨大貢獻。在學習過程中,全連接的前向傳播和反向傳播都比較容易理解。但由于全連接沒有參數(shù)共享機制,當特征比較多時,會產(chǎn)生大量的參數(shù),訓練過程十分消耗資源。隨著神經(jīng)網(wǎng)絡(luò)在計算機視覺、自然語言處理中廣泛研究,產(chǎn)生了很多其他的神經(jīng)網(wǎng)絡(luò)。
3.7.1 卷積神經(jīng)網(wǎng)絡(luò)(CNN)
計算機視覺領(lǐng)域的核心問題,是如何識別、理解圖片。由于圖片的維度較高,特征較多,如果用傳統(tǒng)的全連接網(wǎng)絡(luò),會產(chǎn)生巨大的參數(shù)量,從而使訓練十分困難。通過利用局部相關(guān)性和權(quán)值共享的思想,CNN應(yīng)運而生。CNN在計算機視覺領(lǐng)域的表現(xiàn)大大超過了其他算法,逐漸統(tǒng)治該領(lǐng)域。
其中CNN的平移不變性起著關(guān)鍵作用,圖片中的目標不管被如何平移,都能得到相同的結(jié)果。卷積+最大池化對平移不變性起了關(guān)鍵作用。
3.7.2 循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)
除了具有空間結(jié)構(gòu)的圖片外,具有序列信息的文本、信號等也是一種十分常見的數(shù)據(jù)形式。CNN由于沒有Memory機制,很難形成長程依賴,這對序列信息不太友好。RNN就是一種有一定Memory機制,一定程度上能解決長程依賴問題的神經(jīng)網(wǎng)絡(luò)。之后作為RNN的變種,LSTM、GRU等相對更具有長期記憶的模型提出來。
3.7.3 注意力機制(Attention)
RNN并不是NLP的終局,近年來隨著注意力機制的提出,克服了RNN不靈活,難以并行等缺點。2017年google提出了純注意力機制的網(wǎng)絡(luò)Transformer,后邊又出現(xiàn)了各種變種模型,Bert,GPT等。
3.7.4 圖卷機網(wǎng)絡(luò)
圖片、文本等數(shù)據(jù)具有規(guī)則的空間、時間結(jié)構(gòu),這種數(shù)據(jù)我們稱為歐幾里得數(shù)據(jù)。CNN和RNN都十分擅長處理這些數(shù)據(jù)。但還有一種數(shù)據(jù),如社交網(wǎng)絡(luò)、交通網(wǎng)絡(luò)、蛋白質(zhì)分子等,是一種不規(guī)則的拓撲結(jié)構(gòu)的數(shù)據(jù)。GCN隨之被提出來處理這類數(shù)據(jù)。