天天看點

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

第四章 深層神經網絡

4.1 深度學習與深層神經網絡

維基百科對深度學習的精确定義為:一類通過多層非線性變換對高複雜性資料模組化算法的集合,可見,深度學習有兩個重要的特性——多層和非線性。

深度學習具體定義可以參照維基百科:https://en.wikipedia.org/wiki/Deep_learning。

4.1.1 線性模型的局限性

線上性模型中,模型的輸出為輸入的權重和,假設一個模型的輸出y和輸入xi滿足以下關系,那麼這個模型就是一個線性模型。

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

其中wi,b為模型的參數,被稱之為線性模型是因為當模型的輸入隻有一個的時候,,x和y形成了二維坐标系上的一條直線。類似的,當模型有n個輸入時,x和y形成了n+1維空間中的一個平面。而一個線性模型中通過輸入得到輸出的函數被稱之為一個線性變換。

線性模型的最大特點是任意線性模型的組合仍然還是線性模型,以下的前向傳播算法實作的就是一個線性模型。

前向傳播算法的公式為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

其中x為輸入,W為參數,整理一下上面的公式可以得到整個模型的輸出為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

根據矩陣乘法的結合律得:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡
《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

這樣輸入輸出的關系就變為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

雖然這個神經網絡有兩層(不算輸入層),但是它和單層的神經網絡并沒有差別。以此類推,隻通過線性變換,任意層的全連接配接神經網絡和單層神經網絡模型的表達能力沒有任何差別,而且它們都是線性模型。然而線性模型能夠解決的問題是有限的。這就是線性模型最大的局限性,也是為什麼深度學習要強調非線性。

線性可分問題是指線性模型就可以解決的問題,而所謂深度學習中的複雜問題,至少是無法通過直線或高維空間的平面劃分的。然而在現實世界中,大多數問題都是無法線性分割的。

4.1.2 激活函數實作去線性化

如果将每一個神經元(也就是神經網絡中的節點)的輸出通過一個非線性函數,那麼整個神經網絡的模型也就不再是線性的了,這個非線性函數就是激活函數。

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

在3.4.2中前向傳播算法的基礎上添加偏置項和激活函數:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

其中激活函數的作用是去線性化,而偏置項允許激活函數向左或向右移位。

目前TensorFlow提供了7種不同的非線性激活函數,tf.nn.relu,tf.sigmoid,tf.tanh是其中比較常用的幾個,而且TensorFlow也支援使用自己定義的激活函數。

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

4.1.3 多層網絡解決異或運算

感覺機可以簡單地了解為單層的神經網絡,4.1.2中加入偏置項和激活函數的神經元結構就是感覺機的網絡結構,感覺機被證明是無法模拟異或運算的,但深度學習的多層變換特性可以解決這個問題,在我的了解中,多層神經網絡将每一層神經元對特征的處理能力進行堆疊,使模型的特征提取能力更加強大。

4.2 損失函數定義

神經網絡模型的效果以及優化的目标是通過損失函數(loss function)來定義的。對于相同的神經網絡,不同的損失函數會對訓練得到的模型産生重要影響。

4.2.1 經典損失函數

分類問題和回歸問題是監督學習的兩大種類,分類問題希望解決的是将不同的樣本分到事先定義好的類别中,回歸問題希望解決的是對具體數值的預測。

4.2.1.1 分類問題的經典損失函數

通過神經網絡解決多分類問題最常用的方法是設定n個輸出節點,其中n為類别的個數。對于每一個樣例,神經網絡可以得到的一個n維向量作為輸出結果,向量中的每一個次元(也就是每一個輸出節點)對應一個類别,在理想情況下,如果一個樣本屬于類别k,那麼這個類别所對應的輸出節點的輸出值應該為1,而其他節點的輸出都為0。

為了描述一個輸出向量和期望向量的接近程度,我們使用一種叫交叉熵(cross entropy)的損失函數,它能刻畫兩個機率分布之間的距離,是分類問題中使用比較廣的一種損失函數。

我們先來了解一下機率分布是什麼,機率分布刻畫了不同僚件發生的機率,當事件總數是有限的情況下,機率分布函數p(X = x)滿足:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

也就是說,任意事件發生的機率都在0和1之間,且總有某一個事件發生(機率的和為1),如果将分類問題中“一個樣例屬于某一個類别”看成一個機率事件,那麼訓練資料的正确答案就符合一個機率分布,因為事件“一個樣例屬于不正确的類别”的機率為0,而“一個樣例屬于正确的類别”的機率為1。

我們再來看一下交叉熵的公式,給定兩個機率分布p和q,通過q來表示p的交叉熵為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

注意,交叉熵刻畫的是兩個機率分布之間的距離,然而神經網絡的輸出卻不一定是一個機率分布。

為了解決這個問題,我們使用Softmax回歸,它可以将神經網絡前向傳播得到的結果變成機率分布,Softmax回歸本身可以作為一個學習算法來優化分類結果,但在TensorFlow中,Softmax回歸的參數被去掉了,它隻是一層額外的處理層,可以将神經網絡的輸出變成一個機率分布。

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

假設原始的神經網絡輸出為y1,y2,……,yn,那麼結果Softmax回歸處理後的輸出為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

從以上公式中可以看出,原始神經網絡的輸出被用作置信度來生成新的輸出,而新的輸出滿足機率分布的所有要求。這個新的輸岀可以了解為經過神經網絡的推導,一個樣例為不同類别的機率分别是多大。這樣就把神經網絡的輸出也變成了一個機率分布,進而可以通過交叉熵來計算預測的機率分布和真實答案的機率分布之間的距離了。

我們重新來看一下交叉熵的公式,我們可以發現交叉熵函數不是對稱的(H(p,q)不等于H(q,p)),它刻畫的是通過機率分布q來表達機率分布p的困難程度,因為真實值是希望得到的結果,是以當交叉嫡作為神經網絡的損失函數時,p代表的是真實值,q代表的是預測值。

交叉熵刻畫的是兩個機率分布的距離,也就是說交叉熵值越小,兩個機率分布越接近。

現在我們看一下交叉熵在TensorFlow中的代碼實作并對它進行解讀:

①y_代表n個樣例的真實值,y代表n個樣例的最終神經網絡輸出的預測值,它們都是n*m的矩陣,其中n為一個batch中樣例的數量,m為分類的類别數量;

②通過tf.clip_by_value(y, 1e-10, 1.0)函數可以将張量y中的的數值限制在一個範圍[1e-10, 1.0]之内,小于1e-10的會被轉換為1e-10,大于1.0的會被轉換為1.0,這樣可以避免一些運算錯誤(比如log0是無效的);

③tf.log函數可以完成對張量中所有元素依次求對數的功能;

④這裡的“*”乘法運算并不是矩陣乘法,而是矩陣元素之間直接相乘,矩陣乘法需要使用tf.matmul函數來完成;

⑤通過上面這三個運算,得到的結果是一個n*m的二維矩陣,根據交叉熵的公式,應該将每行中的m個結果相加得到所有樣例的交叉嫡,然後再對這n行取平均得到一個batch的平均交叉熵,但因為分類問題的類别數量是不變的,是以我們可以直接使用tf.reduce_mean函數對整個矩陣做平均而并不改變計算結果的意義,這樣的方式可以使整個程式更加簡潔。

因為交叉熵一般會與Softmax回歸一起使用,是以TensorFlow對這兩個功能進行了統一封裝,并提供了 tf.nn.softmax_cross_entropy_with_logits函數:

需要注意的是,這裡的y_仍然是真實值,但是y卻是原始神經網絡的輸出值。

對交叉熵的了解請參照:

https://blog.csdn.net/qq_36931982/article/details/82998081,

https://blog.csdn.net/shwan_ma/article/details/88795940。

4.2.1.2 回歸問題的經典損失函數

回歸問題需要預測的不是一個事先定義好的類别,而是一個任意實數,解決回歸問題的神經網絡一般隻有一個輸出節點,這個節點的輸出值就是預測值。對于回歸問題,最常用的損失函數是均方誤差(MSE, mean squared error),它的定義如下:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

其中yi為一個batch中第i個樣例的真實值,而yi’為神經網絡給出的預測值。

我們來看一下均方誤差在TensorFlow中的代碼實作并對它進行解讀:

①其中y代表了神經網絡的預測值,y_代表了真實值

②tf.square函數對張量中的值依次進行平方;

③“-”是矩陣對應元素的減法;

④tf.reduce_mean函數進行平均求值。

4.2.2 自定義損失函數

TensorFlow不僅支援經典的損失函數,還可以優化任意的自定義損失函數。

自定義損失函數在TensorFlow中的具體執行個體請參照:初步了解TensorFlow如何實作自定義損失函數。

4.3 神經網絡優化算法

神經網絡通過反向傳播算法(backpropagation)和梯度下降算法(gradient decent)調整參數的取值。

梯度下降算法主要用于優化單個參數的取值,而反向傳播算法給出了一個高效的方式在所有參數上使用梯度下降算法,進而使神經網絡模型在訓練資料上的損失函數盡可能小。

反向傳播算法是訓練神經網絡的核心算法,它可以根據定義好的損失函數優化神經網絡中參數的取值,進而使神經網絡模型在訓練資料集上的損失函數達到一個較小值,神經網絡模型中參數的優化過程直接決定了模型的品質。

神經網絡的優化過程可以分為兩個階段:

第一個階段,通過前向傳播算法計算得到預測值,并将預測值和真實值做對比得出兩者之間的差距;

第二個階段,通過反向傳播算法計算損失函數對每一個參數的梯度,再根據梯度和學習率使用梯度下降算法更新每一個參數。

需要注意的是,梯度下降算法存在兩個問題:

①梯度下降算法并不能保證被優化的函數達到全局最優解,在訓練神經網絡時,參數的初始值會很大程度影響最後得到的結果,隻有當損失函數為凸函數時,梯度下降算法才能保證達到全局最優解。

②梯度下降算法計算時間太長,因為要在全部訓練資料上最小化損失,這樣在每一輪疊代中都需要計算在全部訓練資料上的損失函數。在海量訓練資料下,要計算所有訓練資料的損失函數是非常消耗時間的。為了加速訓練過程,可以使用随機梯度下降算法(stochastic gradient descent)。這個算法優化的不是在全部訓練資料上的損失函數,而是在每一輪疊代中,随機優化某一條訓練資料上的損失函數。這樣每一輪參數更新的速度就大大加快了。因為随機梯度下降算法每次優化的隻是某一條資料上的損失函數,是以它的問題也非常明顯:在某一條資料上損失函數更小并不代表在全部資料上損失函數更小,于是使用随機梯度下降優化得到的神經網絡甚至可能無法達到局部最優。

為了綜合梯度下降算法和随機梯度下降算法的優缺點,在實際應用中一般釆用這兩個算法的折中——每次計算一小部分訓練資料的損失函數,這一小部分資料被稱之為一個batch,通過矩陣運算,每次在一個batch上優化神經網絡的參數并不會比單個資料慢太多,另一方面,每次使用一個batch可以大大減小收斂所需要的疊代次數,同時可以使收斂到的結果更加接近梯度下降的效果。

4.4 神經網絡進一步優化

4.4.1 學習率的設定

在訓練神經網絡時,需要設定學習率(leaming rate)來控制參數更新的速度,學習率決定了參數每次更新的幅度,如果幅度過大,那麼可能導緻參數在極優值的兩側來回移動,如果幅度過小,雖然能保證收斂性,但是這會大大降低優化速度。

為了解決設定學習率的問題,TensorFlow提供了一種更加靈活的學習率設定方法——指數衰減法,通過指數衰減的學習率既可以讓模型在訓練的前期快速接近較優解,又可以保證模型在訓練後期不會有太大的波動,進而更加接近局部最優。

指數衰減學習率在TensorFlow中的具體應用請參照:初步了解TensorFlow如何實作指數衰減學習率。

4.4.2 過拟合問題

實際上,在現實應用中我們想要的并不是讓模型盡量模拟訓練資料的行為,而是希望通過訓練出來的模型對未知的資料給出判斷,模型在訓練資料上的表現并不一定代表了它在未知資料上的表現。

所謂過拟合,指的是當一個模型過為複雜之後,它可以很好地“記憶”每一個訓練資料中随機噪音的部分而忘記了要去“學習”訓練資料中通用的趨勢,過度拟合訓練資料中的随機噪音雖然可以得到非常小的損失函數,但是對于未知資料可能無法做出可靠的判斷。

為了避免過拟合問題,一個非常常用的方法是正則化(regularization),正則化的思想就是在損失函數中加入刻畫模型複雜程度的名額。

假設用于刻畫模型在訓練資料上表現的損失函數為J(θ),那麼在優化時不是直接優化J(θ),而是優化J(θ) + λR(w),其中R(w)刻畫的是模型的複雜程度,而λ表示模型複雜損失在總損失中的比例,需要注意的是,這裡的θ表示的是一個神經網絡中所有的參數,它包括邊上的權重w和偏置項b,但一般來說模型複雜度隻由權重w決定。

常用的刻畫模型複雜度的函數R(w)有兩種,一種是L1正則化,計算公式是:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

另一種是L2正則化,計算公式是:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

無論是哪一種正則化方式,基本的思想都是希望通過限制權重的大小,使得模型不能任意拟合訓練資料中的随機噪音,但這兩種正則化的方法也有很大的差別:

①L1正則化會讓參數變得更稀疏,而L2正則化不會,所謂參數變得更稀疏是指會有更多的參數變為0,這樣可以達到類似特征選取的功能,之是以L2正則化不會讓參數變得稀疏的原因是當參數很小時,比如0.001,這個參數的平方基本上就可以忽略了,于是模型不會進一步将這個參數調整為0;

②L1正則化的計算公式不可導,而L2正則化公式可導,因為在優化時需要計算損失函數的偏導數,是以對含有L2正則化損失函數的優化要更加簡潔,優化含有L1正則化的損失函數要更加複雜,而且優化方法也有很多種。

在實踐中,也可以将L1正則化和L2正則化同時使用:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

L1正則化和L2正則化在TensorFlow中的具體實作請參照:初步了解TensorFlow如何實作正則化。

4.4.3 滑動平均模型

為了使模型在測試資料上更健壯(robust),我們使用一種特殊的方法——滑動平均模型,在釆用随機梯度下降算法訓練神經網絡時,使用滑動平均模型在很多應用中都可以在一定程度提高最終模型在測試資料上的表現。

在TensorFlow中提供了tf.train.ExponentialMovingAverage函數來實作滑動平均模型,在初始化ExponentialMovingAverage時,需要提供一個衰減率(decay),這個衰減率将用于控制模型更新的速度,ExponentialMovingAverage對每一個變量會維護一個影子變量(shadow variable),這個影子變量的初始值就是相應變量的初始值,而每次運作變量更新時,影子變量的值會更新為:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

其中shadow variable為影子變量,variable為相應的變量,decay為衰減率。

從公式中可以看到,decay決定了模型更新的速度,decay越大模型越趨于穩定,在實際應用中,decay 一般會設成非常接近1的數(比如0.999或0.9999),為了使得模型在訓練前期可以更新得更快,ExponentialMovingAverage還提供了num_updates參數來動态設定decay的大小,如果在ExponentialMovingAverage初始化時提供了num_updates參數,那麼每次使用的衰減率将是:

《Tensorflow 實戰Google深度學習架構》學習筆記(三)第四章 深層神經網絡

滑動平均模型的了解與使用請參照:

https://blog.csdn.net/Dongjiuqing/article/details/88049882,

https://blog.csdn.net/m0_38106113/article/details/81542863。

4.5 學習資源

該書樣例代碼網址:https://github.com/caicloud/tensorflow-tutorial

繼續閱讀