深度神經網路學習筆記

第一節

這篇文章是深度神經網路的學習筆記,首先拋出下面一個問題。

人工智慧、機器學習和深度學習之間的關係?

從圖中可以看出人工智慧概念的範圍更廣,機器學習是其中的一個子集,而深度學習又是機器學習中的一個子集。

深度學習的應用領域在計算機視覺、語音識別、自然語言處理和人機博弈方面比基於數理統計的機器學習會有更高的準確度。這裡主要是做深度學習方面的學習筆記。

深度學習的發展歷程

以下部分圖片摘自《TensorFlow 實戰Google深度學習框架》

深度發學習是深度神經網路的代名詞,其起源於上世紀,只是在這幾年開始火起來。

早期的神經網路模型類似於放生機器學習,由人類大腦的神經元演化出的神經元模型,見下圖:

後面出現了感知機模型、分散式知識表達和神經網路反向傳播演算法,再到後來的卷積神經網路、循環神經網路和 LSTM 模型。

在神經網路發展的同時,傳統機器學習演算法的研究也在不斷發展,上世紀 90 年代末逐步超越了神經網路,在當時相比之下傳統機器學習演算法有更好的識別準確率,而神經網路由於數據量和計算能力的限制發展比較困難。到了最近幾年,由於雲計算、GPU、大數據等的出現,為神經網路的發展做好了鋪墊,AI 開始了一個新的時代。

下面一張圖表是對比主流深度學習開源工具

目前我聽說的比較多的兩個開源工具是 Caffe 和 TensorFlow,然後去看了下 Github 關注量,前者 20.1k 後者 69.3k,TensorFlow 應該是目前最火的一個深度學習框架了吧。這篇文章包括後面的文章都會去記錄 TensorFlow 的學習過程,下面的內容是介紹 TensorFlow 的基礎概念,介紹中我盡量避免加入代碼,因為目前 TensorFlow 更新比較快,發現好多寫法在新的版本中不再被支持。

TensorFlow 學起來

TensorFlow 有兩個重要概念 Tensor (張量)和 Flow(流),Tensor 表名的是數據結構,Flow 提現的是計算模型。

PS:以下將 TensorFlow 簡稱為 tf

tf 計算模型 — 計算圖

tf 通過計算圖來表述計算的編程系統,其中的每個節點表示一個計算,不同點之間的連接表達依賴關係。下面幾行代碼表達一下:

import tensorflow as tfna = tf.constant([1.0, 2.0], name=a)nb = tf.constant([2.0, 3.0], name=b)nresult = a + bn

上面的代碼在計算圖中會有 a、b、a + b三個節點。tf 默認會有一個全局的計算圖,也可以生成新的計算圖,不同計算圖之間不會共享張量和運算

計算圖中可以通過集合的方式管理不同的資源,這些資源可以是張量、變數或者隊列資源等。

tf 數據模型 — 張量

張量是 tf 管理和表示數據的形式,可以簡單理解為多維數組。零階張量表示標量,就是一個數;一階張量是一個一維數組;n 階張量是一個 n 維數組。 tf.add(a, b, name=add) 這行代碼在運行時並不會得到結果,而是一個結果的引用,是一個張量的結構,包含三個屬性 name、shape、dtype,name 僅僅是一個節點的名稱;shape 是張量的維度,這個是一維的,長度為 2,這個屬性比較重要;dtype 是數據類型,每個張量有唯一的數據類型,不同張量之間的計算需要保證類型統一。

上面的例子就是對兩個常量做加法,然後生成計算結果的引用。

tf 運行模型 — 會話

tf 的會話用來執行定義好的運算,會話用來管理運行過程中的所有資源,計算完成後會幫助回收資源,通過 with tf.Session() as sess: 這種方式會在 with 結束時自動關閉回收資源。

通過 tf.ConfigProto 可以配置類似並行線程數、GPU分配策略、運算超時時間等參數,將配置添加到 tf.Session 中創建會話。

向前傳播演算法

通過全連接網路結構介紹,一個神經元有多個輸入和一個輸出,輸出是不同輸入的加權和,不同的輸入權重就是神經網路的參數,神經網路的優化就是優化參數取值的過程。全連接網路結構是指相鄰兩層之間任意兩個節點之間都有連接。

向前傳播演算法需要的三部分信息:

  • 第一部分從實體中取出特徵向量作為輸入。
  • 第二部分是神經網路的連接結構,不同神經元之間的輸入輸出的連接關係。
  • 第三部分是每個神經元中的參數。

在 tf 中通過變數(tf.Variable)來保存和更新神經網路中的參數。

import tensorflow as tfn# w1 是第一層,通過隨機數生成一個 (2,3) 的矩陣nw1 = tf.Variable(tf.random_normal([2, 3], stddev=1, seed=1))n# w2 是第二層,通過隨機石生成一個 (3,1) 的矩陣nw2 = tf.Variable(tf.random_normal([3, 1], stddev=1, seed=1))n# x 是輸入層,為一個 (1,2) 的矩陣nx = tf.placeholder(tf.float32, shape=(1, 2), name=input)n# 通過 tensorflow 提供的矩陣相乘演算法計算na = tf.matmul(x, w1)ny = tf.matmul(a, w2)nwith tf.Session() as sess:n # 這裡初始化所有變數n sess.run(tf.global_variables_initializer())n # 通過 輸入值 x 與 第一層的參數進行矩陣相乘,再與 第二層的參數進行矩陣相乘,實現神經網路的向前傳播演算法。n print sess.run(y, feed_dict={x: [[0.7, 0.9]]})n

輸出:

[[ 3.95757794]]n

第二節

向前傳播演算法是一種線性模型,全連接神經網路和單層神經網路模型都只能處理線性問題,這具有相當大的局限性。而深度學習要強調的是非線性。

激活函數去線性化

如下圖,如果我們將每一個神經元的輸出通過一個非線性函數,那麼這個神經網路模型就不再是線性的了,而這個非線性函數就是激活函數,也實現了我們對神經元的去線性化。

下面列舉了三個常用激活函數

  • ReLU 函數
  • sigmoid 函數
  • tanh 函數

tf 中也提供了這幾種不同的非線性激活函數。

tf.nn.relu(tf.matmul(x, w1) + biases1)n

通過對 x 的加權增加偏置項,再在外層加上激活函數,實現神經元的非線性化。

損失函數

損失函數用來衡量預測值與真實值之間的不一致程度,是一個非負實值函數,損失函數越小,證明模型預測的越準確。

交叉熵可以用來衡量兩個概率分布之間的距離,是分類問題中使用比較光的一種損失函數。對於兩個概率分布 p 和 q,表示交叉熵如下:

H(p,q)=-sum_{x}p(x)log q(x)

將神經網路向前傳播得到的結果變成概率分布使用 Softmax 回歸,它可以作為一個演算法來優化分類結果。假設神經網路的輸出值為 y1,y2,...yn,那麼 Softmax 回歸處理的輸出為:

如下圖通過 Softmax 層將神經網路的輸出變成一個概率分布。

交叉熵一般會與 Softmax 回歸一起使用,tf 對這兩個功能提供了封裝提供函數

tf.nn.softmax_cross_entropy_with_logitsn

對於回歸問題區別與分類問題,需要預測的是一個任意實數,最常使用的損失函數是均方誤差 MSE,定義如下:

反向傳播演算法

反向傳播演算法是訓練神經網路的核心演算法,它可以根據定義好的損失函數優化神經網路的參數值,是神經網路模型的損失函數達到一個較小的值。

梯度下降演算法是最常用的神經網路優化方法,假設用 θ 表示神經網路的參數, J(θ) 表示給定參數下的取值,梯度下降演算法會迭代式的更新 θ,讓迭代朝著損失最小的方向更新。梯度通過求偏導的方式計算,梯度為:

frac{?}{?θ}J(θ)

然後定義一個學習率 η。參數更新公式如下:

θ_{n+1}=θ_n-ηfrac{?}{?θ_n}J(θ_n)

優化過程分為兩步:

  1. 通過向前傳播演算法得到預測值,將預測值與真實值之間對比差距。
  2. 通過反向傳播演算法計算損失函數對每一個參數的梯度,根據梯度和學習率是梯度下降演算法更新每一個參數。

為了降低計算量和加速訓練過程,可以使用隨機梯度下降演算法,選取一部分數據進行訓練。

學習率的設置可以通過指數衰減法,逐步減小學習率,可以在開始時快速得到一個較優解,然後減小學習率,使後模型的訓練更加穩定。tf 提供了tf.train.exponential_decay 函數實現指數衰減學習率。

每一輪優化的學習率 = 初始學習率 * 衰減係數 ^ (學習步數 / 衰減速度)n

過擬合問題

通過損失函數優化模型參數的時候,並不是讓模型盡量的模擬訓練數據的行為,而是通過訓練數據對未知數據給出判斷,當一個模型能完美契合訓練數據的時候,損失函數為0,但是無法對未知數據做出可靠的判斷,這就是過擬合。

避免過擬合的常用方法是正則化,就是在損失函數中加入刻畫模型複雜度的指標,我們對模型的優化則變為:

J(θ)+λR(w)

其中 R(w) 刻畫的是模型的複雜程度,λ 表示模型複雜損失在總損失中的比例。下面是兩種正則化函數:

L1正則化:會讓參數變得稀疏,公式不可導

R(w) = |~w~Vert_1 = sum_i|w_i|

L2正則化:不會讓參數變得稀疏,公式可導

R(w) = |~w~Vert_2^2 = sum_i|w_i^2|

在實際使用中會將 L1 正則化和 L2 正則化同時使用:

R(w) = sum_iα|w_i|+(1-α)w_i^2

滑動平均模型

在採用隨機梯度下降演算法訓練神經網路時,使用平均滑動模型可以在大部分情況下提高模型在測試數據上的表現。在 tf 中提供了 tf.train.ExponentialMovingAverage 來實現這個模型,通過設置一個衰減率來初始化,在其中維護一個影子變數,可以控制模型的更新速度。

影子變數值 = 衰減率 * 影子變數值 + (1 - 衰減率) * 待更新變數n

為了讓模型前期更新比較快,還提供了 num_updates 參數,每次使用的衰減率為:

minleft{decay,frac{1+num_updates}{10+num_updates}right}

筆記結束,如有錯誤還望幫忙指正。

最後,歡迎大家關注我的專欄『知一周曝』,我會繼續給大家分享開發生涯中的學習總結和生活感悟,一起探討提高~~

我的個人學習筆記地址:『Noogels notes』,這裡會先發布我平時的學習筆記,整理後會發到我的專欄。

推薦閱讀:

M.1.2 神經網路的數學基礎-度量、運動、變換和群
S 1.1 機器學習-樸素貝葉斯與單層神經網路關係
[乾貨|實踐] Tensorflow學習 - 使用flags定義命令行參數

TAG:深度学习DeepLearning | TensorFlow | 神经网络 |