天天看點

《python深度學習》筆記第二章 神經網絡數學基礎第三章 神經網絡入門第四章 機器學習的通用工作流程第六章 深度學習用于文本和序列第八章 生成式深度學習

Python深度學習(Keras)

第二章 神經網絡數學基礎

對于張量運算所操作的張量,其元素可以被解釋為某種幾何空間内點的坐标.

神經網絡完全由一系列張量運算組成,而這些張量運算都隻是輸入資料的幾何變換。

是以,你可以将神經網絡解釋為高維空間中非常複雜的幾何變換,這種變換可以通過許多簡單的步驟來實作。

訓練循環過程:

(1) 抽取訓練樣本x 和對應目标y 組成的資料批量。

(2) 在x 上運作網絡[這一步叫作前向傳播(forward pass)],得到預測值y_pred。

(3) 計算網絡在這批資料上的損失,用于衡量y_pred 和y 之間的距離。

(4) 更新網絡的所有權重,使網絡在這批資料上的損失略微下降。

最終得到的網絡在訓練資料上的損失非常小,即預測值y_pred 和預期目标y 之間的距離非常小。網絡“學會”将輸入映射到正确的目标。

梯度(gradient)是張量運算的導數。

小批量随機梯度下降算法步驟

(1) 抽取訓練樣本x 和對應目标y 組成的資料批量。

(2) 在x 上運作網絡,得到預測值y_pred。

(3) 計算網絡在這批資料上的損失,用于衡量y_pred 和y 之間的距離。

(4) 計算損失相對于網絡參數的梯度[一次反向傳播(backward pass)]。

(5) 将參數沿着梯度的反方向移動一點,比如W -= step * gradient,進而使這批資料上的損失減小一點。

術語随機(stochastic)是指每批資料都是随機抽取的。

注意,小批量SGD 算法的一個變體是每次疊代時隻抽取一個樣本和目标,而不是抽取一批資料。這叫作真SGD(有别于小批量SGD)。還有另一種極端,每一次疊代都在所有資料上運作,這叫作批量SGD。這樣做的話,每次更新都更加準确,但計算代價也高得多。這兩個極端之間的有效折中則是選擇合理的批量大小。

SGD 還有多種變體,其差別在于計算下一次權重更新時還要考慮上一次權重更新,而不是僅僅考慮目前梯度值,比如帶動量的SGD、Adagrad、RMSProp 等變體。這些變體被稱為優化方法(optimization method)或優化器(optimizer)。其中動量的概念尤其值得關注,它在許多變體中都有應用。動量解決了SGD 的兩個問題:收斂速度和局部極小點。

在某個參數值附近,有一個局部極小點(local minimum):在這個點附近,向左移動和向右移動都會導緻損失值增大。如果使用國小習率的SGD 進行優化,那麼優化過程可能會陷入局部極小點,導緻無法找到全局最小點。

使用動量方法可以避免這樣的問題,這一方法的靈感來源于實體學。有一種有用的思維圖像,就是将優化過程想象成一個小球從損失函數曲線上滾下來。如果小球的動量足夠大,那麼它不會卡在峽谷裡,最終會到達全局最小點。動量方法的實作過程是每一步都移動小球,不僅要考慮目前的斜率值(目前的加速度),還要考慮目前的速度(來自于之前的加速度)。這在實踐中的是指,更新參數w 不僅要考慮目前的梯度值,還要考慮上一次的參數更新

鍊式求導:反向傳播算法

将鍊式法則應用于神經網絡梯度值的計算,得到的算法叫作反向傳播(backpropagation,有時也叫反式微分,reverse-mode differentiation)。反向傳播從最終損失值開始,從最頂層反向作用至最底層,利用鍊式法則計算每個參數對損失值的貢獻大小。現在以及未來數年,人們将使用能夠進行符号微分(symbolic differentiation)的現代架構來實作神經網絡,比如TensorFlow。也就是說,給定一個運算鍊,并且已知每個運算的導數,這些架構就可以利用鍊式法則來計算這個運算鍊的梯度函數,将網絡參數值映射為梯度值。對于這樣的函數,反向傳播就簡化為調用這個梯度函數。由于符号微分的出現,你無須手動實作反向傳播算法。是以,我們不會在本節浪費你的時間和精力來推導反向傳播的具體公式。你隻需充分了解基于梯度的優化方法的工作原理。

第二章小結

(1)學習是指找到一組模型參數,使得在給定的訓練資料樣本和對應目标值上的損失函數最小化。

(2) 學習的過程:随機選取包含資料樣本及其目标值的批量,并計算批量損失相對于網絡參數的梯度。随後将網絡參數沿着梯度的反方向稍稍移動(移動距離由學習率指定)。

(3) 整個學習過程之是以能夠實作,是因為神經網絡是一系列可微分的張量運算,是以可以利用求導的鍊式法則來得到梯度函數,這個函數将目前參數和目前資料批量映射為一個梯度值。

(4) 後續幾章你會經常遇到兩個關鍵的概念:損失和優化器。将資料輸入網絡之前,你需要先定義這二者。

(5) 損失是在訓練過程中需要最小化的量,是以,它應該能夠衡量目前任務是否已成功解決。

(6) 優化器是使用損失梯度更新參數的具體方式,比如 RMSProp 優化器、帶動量的随機梯度下降(SGD)等。

第三章 神經網絡入門

3.1 神經網絡剖析

前面幾章介紹過,訓練神經網絡主要圍繞以下四個方面。

1、層,多個層組合成網絡(或模型)。

2、輸入資料和相應的目标。

3、 損失函數,即用于學習的回報信号。

4、 優化器,決定學習過程如何進行。

四者的關系如下:多個層連結在一起組成了網絡,将輸入資料映射為預測值。然後損失函數将這些預測值與目标進行比較,得到損失值,用于衡量網絡預測值與預期結果的比對程度。優化器使用這個損失值來更新網絡的權重。

3.1.1 層:深度學習的基礎元件

神經網絡的基本資料結構是層。層是一個資料處理子產品,将一個或多個輸入張量轉換為一個或多個輸出張量。有些層是無狀态的,但大多數的層是有狀态的,即層的權重。權重是利用随機梯度下降學到的一個或多個張量,其中包含網絡的知識。不同的張量格式與不同的資料處理類型需要用到不同的層。例如,簡單的向量資料儲存在形狀為 的2D 張量中,通常用密集連接配接層[也叫全連接配接層或密集層,對應于Keras的Dense類]來處理。

序列資料儲存在形狀為的3D 張量中,通常用循環層(比如Keras 的LSTM 層)來處理。圖像資料儲存在4D 張量中,通常用二維卷積層(Keras 的Conv2D)來處理。你可以将層看作深度學習的樂高積木,Keras等架構則将這種比喻具體化。

在Keras 中,建構深度學習模型就是将互相相容的多個層拼接在一起,以建立有用的資料變換流程。這裡層相容性具體指的是每一層隻接受特定形狀的輸入張量,并傳回特定形狀的輸出張量。

3.1.2 模型:層構成的網絡

深度學習模型是層構成的有向無環圖。最常見的例子就是層的線性堆疊,将單一輸入映射為單一輸出。但随着深入學習,你會接觸到更多類型的網絡拓撲結構。一些常見的網絡拓撲結構如下。

1 雙分支網絡

2 多頭網絡

3 Inception子產品

網絡的拓撲結構定義了一個假設空間。標明了網絡拓撲結構,意味着将可能性空間(假設空間)限定為一系列特定的張量運算,将輸入資料映射為輸出資料。然後,你需要為這些張量運算的權重張量找到一組合适的值。選擇正确的網絡架構更像是一門藝術而不是科學。

3.1.3 損失函數與優化器:配置學習過程的關鍵

一旦确定了網絡架構,你還需要選擇以下兩個參數。

1 損失函數(也就是目标函數)——在訓練過程中需要将其最小化。它能夠衡量目前任務是否已成功完成。

2 優化器——決定如何基于損失函數對網絡進行更新。它執行的是随機梯度下降(SGD)的某個變體。具有多個輸出的神經網絡可能具有多個損失函數(每個輸出對應一個損失函數)。

但是,梯度下降過程必須基于單個标量損失值。是以,對于具有多個損失函數的網絡,需要将所有損失函數取平均,變為一個标量值。

選擇正确的目标函數對解決問題是非常重要的。網絡的目的是使損失盡可能最小化,是以,如果目标函數與成功完成目前任務不完全相關,那麼網絡最終得到的結果可能會不符合你的預期。一定要明智地選擇目标函數,否則你将會遇到意想不到的副作用。

幸運的是,對于分類、回歸、序列預測等常見問題,你可以遵循一些簡單的指導原則來選擇正确的損失函數。例如,對于二分類問題,你可以使用二進制交叉熵損失函數;對于多分類問題,可以用分類交叉熵損失函數;對于回歸問題,可以用均方誤差損失函數;對于序列學習問題,可以用聯結主義時序分類損失函數。隻有在面對真正全新的研究問題時,你才需要自主開發目标函數。

Keras 具有以下重要特性。

1、相同的代碼可以在 CPU或 GPU 上無縫切換運作。

2、具有使用者友好的 API,便于快速開發深度學習模型的原型。

3、内置支援卷積網絡(用于計算機視覺)、循環網絡(用于序列處理)以及二者的任意組合。

4、支援任意網絡架構:多輸入或多輸出模型、層共享、模型共享等。這也就是說,Keras能夠建構任意深度學習模型,無論是生成式對抗網絡還是神經圖靈機。

Keras 是一個模型級的庫,為開發深度學習模型提供了高層次的構模組化塊。

它不處理張量操作、求微分等低層次的運算。相反,它依賴于一個專門的、高度優化的張量庫來完成這些運算,這個張量庫就是Keras 的後端引擎。Keras 沒有選擇單個張量庫并将Keras 實作與這個庫綁定,而是以子產品化的方式處理這個問題。是以,幾個不同的後端引擎都可以無縫嵌入到Keras中。目前,Keras 有三個後端實作:TensorFlow 後端、Theano 後端和微軟認知工具包(CNTK)後端。

TensorFlow、CNTK 和Theano 是當今深度學習的幾個主要平台。

你用Keras 寫的每一段代碼都可以在這三個後端上運作,無須任何修改。也就是說,你在開發過程中可以在兩個後端之間無縫切換,這通常是很有用的。通過TensorFlow(或Theano、CNTK),Keras 可以在CPU 和GPU 上無縫運作。在CPU 上運作時,TensorFlow 本身封裝了一個低層次的張量運算庫,叫作Eigen;在GPU 上運作時,TensorFlow封裝了一個高度優化的深度學習運算庫,叫作NVIDIA CUDA 深度神經網絡庫(cuDNN)。

Keras開發流程

(1) 定義訓練資料:輸入張量和目标張量。

(2) 定義層組成的網絡(或模型),将輸入映射到目标。

(3) 配置學習過程:選擇損失函數、優化器和需要監控的名額。

(4) 調用模型的fit 方法在訓練資料上進行疊代。

定義模型有兩種方法:一種是使用Sequential 類(僅用于層的線性堆疊,這是目前最常見的網絡架構),另一種是函數式API(functional API,用于層組成的有向無環圖,讓你可以建構任意形式的架構)。一旦定義好了模型架構,使用Sequential 模型還是函數式API 就不重要了。接下來的步驟都是相同的。配置學習過程是在編譯這一步,你需要指定模型使用的優化器和損失函數,以及訓練過程中想要監控的名額。

最後,學習過程就是通過fit() 方法将輸入資料的Numpy 數組(和對應的目标資料)傳入模型,這一做法與Scikit-Learn 及其他機器學習庫類似。

不能将整數序列直接輸入神經網絡。你需要将清單轉換為張量。轉換方法有以下兩種。第一種為填充清單,使其具有相同的長度,再将清單轉換成形狀為 (samples, word_indices)的整數張量,然後網絡第一層使用能處理這種整數張量的層(即Embedding 層)。第二種對清單進行one-hot 編碼,将其轉換為 0 和 1 組成的向量。

對于這種Dense 層的堆疊,你需要确定以下兩個關鍵架構:

1、網絡有多少層;

2、每層有多少個隐藏單元。

relu(整流線性單元)函數将所有負值歸零。

而sigmoid 函數則将任意值“壓縮”到[0,1] 區間内,其輸出值可以看作機率值。

什麼是激活函數?為什麼要使用激活函數?

如果沒有relu 等激活函數(也叫非線性),Dense 層将隻包含兩個線性運算——點積和加法。這樣Dense 層就隻能學習輸入資料的線性變換(仿射變換):該層的假設空間是從輸入資料到16 位空間所有可能的線性變換集合。這種假設空間非常有限,無法利用多個表示層的優勢,因為多個線性層堆疊實作的仍是線性運算,添加層數并不會擴充假設空間。為了得到更豐富的假設空間,進而充分利用多層表示的優勢,你需要添加非線性或激活函數。relu 是深度學習中最常用的激活函數,但還有許多其他函數可選,它們都有類似的奇怪名稱,比如prelu、elu 等。

注意:

1、通常需要對原始資料進行大量預處理,以便将其轉換為張量輸入到神經網絡中。單詞序列可以編碼為二進制向量,但也有其他編碼方式。

2、帶有relu激活的 Dense 層堆疊,可以解決很多種問題(包括情感分類),你可能會經常用到這種模型。

3、對于二分類問題(兩個輸出類别),網絡的最後一層應該是隻有一個單元并使用sigmoid激活的Dense 層,網絡輸出應該是0~1 範圍内的标量,表示機率值。

4、對于二分類問題的 sigmoid标量輸出,你應該使用binary_crossentropy損失函數。

5、無論你的問題是什麼,rmsprop優化器通常都是足夠好的選擇。這一點你無須擔心。

6、随着神經網絡在訓練資料上的表現越來越好,模型最終會過拟合,并在前所未見的資料上得到越來越差的結果。一定要一直監控模型在訓練集之外的資料上的性能。

選擇損失函數和優化器時:由于你面對的是一個二分類問題,網絡輸出是一個機率值(網絡最後一層使用sigmoid 激活函數,僅包含一個單元),那麼最好使用binary_crossentropy(二進制交叉熵)損失。這并不是唯一可行的選擇,比如你還可以使用mean_squared_error(均方誤差)。但對于輸出機率值的模型,交叉熵(crossentropy)往往是最好的選擇。交叉熵是來自于資訊論領域的概念,用于衡量機率分布之間的距離,在這個例子中就是真實分布與預測值之間的距離。

将标簽向量化有兩種方法:你可以将标簽清單轉換為整數張量,或者使用one-hot 編碼。one-hot 編碼是分類資料廣泛使用的一種格式,也叫分類編碼。另一種編碼标簽的方法,就是将其轉換為整數張量,對于整數标簽,你應該使用sparse_categorical_crossentropy。

Dense 層的堆疊,每層隻能通路上一層輸出的資訊。如果某一層丢失了與分類問題相關的一些資訊,那麼這些資訊無法被後面的層找回,也就是說,每一層都可能成為資訊瓶頸。

注意:

1、對于多分類問題,最好的損失函數是categorical_crossentropy(分類交叉熵)。它用于衡量兩個機率分布之間的距離,這裡兩個機率分布分别是網絡輸出的機率分布和标簽的真實分布。通過将這兩個分布的距離最小化,訓練網絡可使輸出結果盡可能接近真實标簽。

2、如果要對 N個類别的資料點進行分類,網絡的最後一層應該是大小為N的Dense層。

3、對于單标簽、多分類問題,網絡的最後一層應該使用softmax 激活,這樣可以輸出在N個輸出類别上的機率分布。

4、這種問題的損失函數幾乎總是應該使用分類交叉熵。它将網絡輸出的機率分布與目标的真實分布之間的距離最小化。

5、處理多分類問題的标簽有兩種方法。

通過分類編碼(也叫 one-hot 編碼)對标簽進行編碼,然後使用 categorical_crossentropy 作為損失函數。 将标簽編碼為整數,然後使用 sparse_categorical_crossentropy損失函數。

6、如果你需要将資料劃分到許多類别中,應該避免使用太小的中間層,以免在網絡中造成資訊瓶頸。将取值範圍差異很大的資料輸入到神經網絡中,這是有問題的。網絡可能會自動适應這種取值範圍不同的資料,但學習肯定變得更加困難。對于這種資料,普遍采用的最佳實踐是對每個特征做标準化,即對于輸入資料的每個特征(輸入資料矩陣中的列),減去特征平均值,再除以标準差,這樣得到的特征平均值為0,标準差為1。用Numpy 可以很容易實作标準化。

注意,用于測試資料标準化的均值和标準差都是在訓練資料上計算得到的。在工作流程中,你不能使用在測試資料上計算得到的任何結果,即使是像資料标準化這麼簡單的事情也不行。一般來說,訓練資料越少,過拟合會越嚴重,而較小的網絡可以降低過拟合。網絡的最後一層隻有一個單元,沒有激活,是一個線性層。這是标量回歸(标量回歸是預測單一連續值的回歸)的典型設定。添加激活函數将會限制輸出範圍。例如,如果向最後一層添加sigmoid 激活函數,網絡隻能學會預測0~1 範圍内的值。這裡最後一層是純線性的,是以網絡可以學會預測任意範圍内的值。

注意,編譯網絡用的是mse 損失函數,即均方誤差(MSE),預測值與目标值之差的平方。這是回歸問題常用的損失函數。在訓練過程中還監控一個新名額:平均絕對誤差(MAE)。它是預測值與目标值之差的絕對值。

為了在調節網絡參數(比如訓練的輪數)的同時對網絡進行評估,你可以将資料劃分為訓練集和驗證集,正如前面例子中所做的那樣。但由于資料點很少,驗證集會非常小(比如大約100個樣本)。是以,驗證分數可能會有很大波動,這取決于你所選擇的驗證集和訓練集。也就是說,驗證集的劃分方式可能會造成驗證分數上有很大的方差,這樣就無法對模型進行可靠的評估。在這種情況下,最佳做法是使用K 折交叉驗證。這種方法将可用資料劃分為K個分區(K通常取4或5),執行個體化K個相同的模型,将每個模型在K-1 個分區上訓練,并在剩下的一個分區上進行評估。模型的驗證分數等于K 個驗證分數的平均值。

注意:

1、回歸問題使用的損失函數與分類問題不同。回歸常用的損失函數是均方誤差(MSE)。

2、同樣,回歸問題使用的評估名額也與分類問題不同。顯而易見,精度的概念不适用于回歸問題。常見的回歸名額是平均絕對誤差(MAE)。

3、如果輸入資料的特征具有不同的取值範圍,應該先進行預處理,對每個特征單獨進行縮放。

4、如果可用的資料很少,使用K折驗證可以可靠地評估模型。

5、如果可用的訓練資料很少,最好使用隐藏層較少(通常隻有一到兩個)的小型網絡,以避免嚴重的過拟合。

自監督學習是監督學習的一個特例,它與衆不同,值得單獨歸為一類。自監督學習是沒有人工标注的标簽的監督學習,你可以将它看作沒有人類參與的監督學習。标簽仍然存在(因為總要有什麼東西來監督學習過程),但它們是從輸入資料中生成的,通常是使用啟發式算法生成的。

舉個例子,自編碼器是有名的自監督學習的例子,其生成的目标就是未經修改的輸入。同樣,給定視訊中過去的幀來預測下一幀,或者給定文本中前面的詞來預測下一個詞,都是自監督學習的例子[這兩個例子也屬于時序監督學習,即用未來的輸入資料作為監督]。

注意,監督學習、自監督學習和無監督學習之間的差別有時很模糊,這三個類别更像是沒有明确界限的連續體。自監督學習可以被重新解釋為監督學習或無監督學習,這取決于你關注的是學習機制還是應用場景。

在強化學習中,智能體(agent)接收有關其環境的資訊,并學會選擇使某種獎勵最大化的行動。例如,神經網絡會“觀察”視訊遊戲的螢幕并輸出遊戲操作,目的是盡可能得高分,這種神經網絡可以通過強化學習來訓練。

術語:

多分類:一種分類任務,每個輸入樣本都應被劃分到兩個以上的類别中,比如手寫數字分類。

多标簽分類:一種分類任務,每個輸入樣本都可以配置設定多個标簽。

舉個例子,如果一幅圖像裡可能既有貓又有狗,那麼應該同時标注“貓”标簽和“狗”标簽。每幅圖像的标簽個數通常是可變的。

标量回歸(scalar regression):目标是連續标量值的任務。預測房價就是一個很好的

例子,不同的目标價格形成一個連續的空間。

向量回歸(vector regression):目标是一組連續值(比如一個連續向量)的任務。如果對多個值(比如圖像邊界框的坐标)進行回歸,那就是向量回歸。

小批量(mini-batch)或批量(batch):模型同時處理的一小部分樣本(樣本數通常為8~128)。樣本數通常取2 的幂,這樣便于GPU 上的記憶體配置設定。訓練時,小批量用來為模型權重計算一次梯度下降更新。

為什麼在訓練集/測試集之外還需要驗證集?

原因在于開發模型時總是需要調節模型配置,比如選擇層數或每層大小[這叫作模型的超參數,以便與模型參數(即權重)區分開]。這個調節過程需要使用模型在驗證資料上的性能作為回報信号。這個調節過程本質上就是一種學習:在某個參數空間中尋找良好的模型配置。是以,如果基于模型在驗證集上的性能來調節模型配置,會很快導緻模型在驗證集上過拟合,即使你并沒有在驗證集上直接訓練模型也會如此。

造成這一現象的關鍵在于資訊洩露。每次基于模型在驗證集上的性能來調節模型超參數,都會有一些關于驗證資料的資訊洩露到模型中。如果對每個參數隻調節一次,那麼洩露的資訊很少,驗證集仍然可以可靠地評估模型。但如果你多次重複這一過程(運作一次實驗,在驗證集上評估,然後據此修改模型),那麼将會有越來越多的關于驗證集的資訊洩露到模型中。

最後,你得到的模型在驗證集上的性能非常好(人為造成的),因為這正是你優化的目的。你關心的是模型在全新資料上的性能,而不是在驗證資料上的性能,是以你需要使用一個完全不同的、前所未見的資料集來評估模型,它就是測試集。你的模型一定不能讀取與測試集有關的任何資訊,既使間接讀取也不行。如果基于測試集性能來調節模型,那麼對泛化能力的衡量是不準确的。

資料量較少的時候訓練集/測試集/驗證集的劃分的三種經典的評估方法:

1、簡單的留出驗證

缺點:如果可用的資料很少,那麼可能驗證集和測試集包含的樣本就太少,進而無法在統計學上代表資料。

2、K 折驗證

3、帶有打亂資料的重複K 折驗證。

具體做法是多次使用K 折驗證,在每次将資料劃分為K 個分區之前都先将資料打亂。最終分數是每次K 折驗證分數的平均值。注意,這種方法一共要訓練和評估P×K 個模型(P是重複次數),計算代價很大。

評估模型的注意事項

選擇模型評估方法時,需要注意以下幾點。

資料代表性 :你希望訓練集和測試集都能夠代表目前資料。

例如,你想要對數字圖像進行分類,而圖像樣本是按類别排序的,如果你将前80% 作為訓練集,剩餘20% 作為測試集,那麼會導緻訓練集中隻包含類别0~7,而測試集中隻包含類别8~9。這個錯誤看起來很可笑,卻很常見。是以,在将資料劃分為訓練集和測試集之前,通常應該随機打亂資料。

時間箭頭:如果想要根據過去預測未來(比如明天的天氣、股票走勢等),那麼在劃分資料前你不應該随機打亂資料,因為這麼做會造成時間洩露,你的模型将在未來資料上得到有效訓練。在這種情況下,你應該始終確定測試集中所有資料的時間都晚于訓練集資料。

資料備援:如果資料中的某些資料點出現了兩次(這在現實中的資料裡十分常見),那麼打亂資料并劃分成訓練集和驗證集會導緻訓練集和驗證集之間的資料備援。從效果上來看,你是在部分訓練資料上評估模型,這是極其糟糕的!一定要確定訓練集和驗證集之間沒有交集。

資料預處理的目的是使原始資料更适于用神經網絡處理,包括向量化、标準化、處理缺失值和特征提取神經網絡的所有輸入和目标都必須是浮點數張量(在特定情況下可以是整數張量)。無論處理什麼資料(聲音、圖像還是文本),都必須首先将其轉換為張量,這一步叫作資料向量化。

一般來說,将取值相對較大的資料(比如多位整數,比網絡權重的初始值大很多)或異質資料(比如資料的一個特征在0~1 範圍内,另一個特征在100~200 範圍内)輸入到神經網絡中是不安全的。這麼做可能導緻較大的梯度更新,進而導緻網絡無法收斂。為了讓網絡的學習變得更容易,輸入資料應該具有以下特征。

1、取值較小:大部分值都應該在 0~1 範圍内。

2、同質性:所有特征的取值都應該在大緻相同的範圍内。

此外,下面這種更嚴格的标準化方法也很常見,而且很有用,雖然不一定總是必需的(例如,對于數字分類問題就不需要這麼做)。

1、将每個特征分别标準化,使其平均值為 0。

2、将每個特征分别标準化,使其标準差為 1。

一般來說,對于神經網絡,将缺失值設定為0 是安全的,隻要0 不是一個有意義的值。網絡能夠從資料中學到0 意味着缺失資料,并且會忽略這個值。

注意,如果測試資料中可能有缺失值,而網絡是在沒有缺失值的資料上訓練的,那麼網絡不可能學會忽略缺失值。在這種情況下,你應該人為生成一些有缺失項的訓練樣本:多次複制一些訓練樣本,然後删除測試資料中可能缺失的某些特征。

特征工程是指将資料輸入模型之前,利用你自己關于資料和機器學習算法(這裡指神經網絡)的知識對資料進行寫死的變換(不是模型學到的),以改善模型的效果。多數情況下,一個機器學習模型無法從完全任意的資料中進行學習。呈現給模型的資料應該便于模型進行學習。

,對于現代深度學習,大部分特征工程都是不需要的,因為神經網絡能夠從原始資料中自動提取有用的特征。這是否意味着,隻要使用深度神經網絡,就無須擔心特征工程呢?

并不是這樣,原因有兩點。

1、良好的特征仍然可以讓你用更少的資源更優雅地解決問題。例如,使用卷積神經網絡來讀取鐘面上的時間是非常可笑的。

2、良好的特征可以讓你用更少的資料解決問題。深度學習模型自主學習特征的能力依賴于大量的訓練資料。如果隻有很少的樣本,那麼特征的資訊價值就變得非常重要。

訓練資料上的損失越小,測試資料上的損失也越小。這時的模型是欠拟合的。

為了防止模型從訓練資料中學到錯誤或無關緊要的模式,最優解決方法是擷取更多的訓練資料。模型的訓練資料越多,泛化能力自然也越好。如果無法擷取更多資料,次優解決方法是調節模型允許存儲的資訊量,或對模型允許存儲的資訊加以限制。如果一個網絡隻能記住幾個模式,那麼優化過程會迫使模型集中學習最重要的模式,這樣更可能得到良好的泛化。這種降低過拟合的方法叫作正則化。

幾種最常見的正則化方法

1、減小網絡大小

防止過拟合的最簡單的方法就是減小模型大小,即減少模型中可學習參數的個數。在深度學習中,模型中可學習參數的個數通常被稱為模型的容量。直覺上來看,參數更多的模型擁有更大的記憶容量,是以能夠在訓練樣本和目标之間輕松地學會完美的字典式映射,這種映射沒有任何泛化能力。與此相反,如果網絡的記憶資源有限,則無法輕松學會這種映射。是以,為了讓損失最小化,網絡必須學會對目标具有很強預測能力的壓縮表示,這也正是我們感興趣的資料表示。同時請記住,你使用的模型應該具有足夠多的參數,以防欠拟合,即模型應避免記憶資源不足。在容量過大與容量不足之間要找到一個折中。

要找到合适的模型大小,一般的工作流程是開始時選擇相對較少的層和參數,然後逐漸增加層的大小或增加新層,直到這種增加對驗證損失的影響變得很小。

更大網絡的訓練損失很快就接近于零,網絡的容量越大,它拟合訓練資料(即得到很小的訓練損失)的速度就越快,但也更容易過拟合(導緻訓練損失和驗證損失有很大差異)。

簡單模型是指參數值分布的熵更小的模型(或參數更少的模型)。是以,一種常見的降低過拟合的方法就是強制讓模型權重隻能取較小的值,進而限制模型的複雜度,這使得權重值的分布更加規則。這種方法叫作權重正則化,其實作方法是向網絡損失函數中添加與較大權重值相關的成本(cost)。

這個成本有兩種形式。

1、L1 正則化(L1 regularization):添加的成本與權重系數的絕對值[權重的 L1 範數(norm)]成正比。

2、L2 正則化(L2 regularization):添加的成本與權重系數的平方(權重的L2 範數)成正比。神經網絡的L2 正則化也叫權重衰減(weight decay)。不要被不同的名稱搞混,權重衰減與L2 正則化在數學上是完全相同的。在Keras 中,添權重重正則化的方法是向層傳遞權重正則化項執行個體(weight regularizerinstance)作為關鍵字參數。

由于這個懲罰項隻在訓練時添加,是以這個網絡的訓練損失會比測試損失大很多。

dropout 是神經網絡最有效也最常用的正則化方法之一對某一層使用dropout,就是在訓練過程中随機将該層的一些輸出特征舍棄(設定為0)。dropout 比率(dropout rate)是被設為0 的特征所占的比例,通常在0.2~0.5範圍内。測試時沒有單元被舍棄,而該層的輸出值需要按dropout 比率縮小,因為這時比訓練時有更多的單元被激活,需要加以平衡。

dropout正則化的核心思想是在層的輸出值中引入噪聲,打破不顯著的偶然模式。

防止神經網絡過拟合的常用方法包括:

1、擷取更多的訓練資料

2、減小網絡容量

3、添權重重正則化

4、添加 dropout

卷積運算

密集連接配接層和卷積層的根本差別在于,Dense 層從輸入特征空間中學到的是全局模式(比如對于MNIST 數字,全局模式就是涉及所有像素的模式),而卷積層學到的是局部模式這個重要特性使卷積神經網絡具有以下兩個有趣的性質。

1、卷積神經網絡學到的模式具有平移不變性(translation invariant)。卷積神經網絡在圖像右下角學到某個模式之後,它可以在任何地方識别這個模式,比如左上角。對于密集連接配接網絡來說,如果模式出現在新的位置,它隻能重新學習這個模式。這使得卷積神經網絡在處理圖像時可以高效利用資料(因為視覺世界從根本上具有平移不變性),它隻需要更少的訓練樣本就可以學到具有泛化能力的資料表示。

2、卷積神經網絡可以學到模式的空間層次結構(spatial hierarchies of patterns)。

第一個卷積層将學習較小的局部模式(比如邊緣),第二個卷積層将學習由第一層特征組成的更大的模式,以此類推。這使得卷積神經網絡可以有效地學習越來越複雜、越來越抽象的視覺概念(因為視覺世界從根本上具有空間層次結構)。

對于包含兩個空間軸(高度和寬度)和一個深度軸(也叫通道軸)的3D 張量,其卷積也叫特征圖(feature map)。對于RGB 圖像,深度軸的次元大小等于3,因為圖像有3 個顔色通道:紅色、綠色和藍色。對于黑白圖像(比如MNIST 數字圖像),深度等于1(表示灰階等級)。卷積運算從輸入特征圖中提取圖塊,并對所有這些圖塊應用相同的變換,生成輸出特征圖(output feature map)。該輸出特征圖仍是一個3D 張量,具有寬度和高度,其深度可以任意取值,因為輸出深度是層的參數,深度軸的不同通道不再像RGB 輸入那樣代表特定顔色,而是代表過濾器(filter)。過濾器對輸入資料的某一方面進行編碼,比如,單個過濾器可以從更高層次編碼這樣一個概念:“輸入中包含一張臉。”

卷積由以下兩個關鍵參數所定義。

1、從輸入中提取的圖塊尺寸:這些圖塊的大小通常是 3×3 或 5×5。本例中為 3×3,這是很常見的選擇。

2、輸出特征圖的深度:卷積所計算的過濾器的數量。本例第一層的深度為32,最後一層的深度是64。

輸出的寬度和高度可能與輸入的寬度和高度不同。不同的原因可能有兩點。

1、邊界效應,可以通過對輸入特征圖進行填充來抵消。

2、使用了步幅(stride),稍後會給出其定義。

如果你希望輸出特征圖的空間次元與輸入相同,那麼可以使用填充(padding)。填充是在輸入特征圖的每一邊添加适當數目的行和列,使得每個輸入方塊都能作為卷積視窗的中心。

對于Conv2D 層,可以通過padding 參數來設定填充,這個參數有兩個取值:"valid" 表示不使用填充(隻使用有效的視窗位置);"same" 表示“填充後輸出的寬度和高度與輸入相同”。

padding 參數的預設值為"valid"。

兩個連續視窗的距離是卷積的一個參數,叫作步幅,預設值為1。也可以使用步進卷積(strided convolution),即步幅大于1 的卷積。

為了對特征圖進行下采樣,我們不用步幅,而是通常使用最大池化(max-pooling)運算.最大池化的作用:對特征圖進行下采樣.

最大池化是從輸入特征圖中提取視窗,并輸出每個通道的最大值。它的概念與卷積類似,但是最大池化使用寫死的max 張量運算對局部圖塊進行變換,而不是使用學到的線性變換(卷積核)。最大池化與卷積的最大不同之處在于,最大池化通常使用2×2 的視窗和步幅2,其目的是将特征圖下采樣2 倍。與此相對的是,卷積通常使用3×3 視窗和步幅1。

使用下采樣的原因,一是減少需要處理的特征圖的元素個數,二是通過讓連續

卷積層的觀察視窗越來越大(即視窗覆寫原始輸入的比例越來越大),進而引入空間過濾器的層級結構。

注意,最大池化不是實作這種下采樣的唯一方法。你已經知道,還可以在前一個卷積層中使用步幅來實作。此外,你還可以使用平均池化來代替最大池化,其方法是将每個局部輸入圖塊變換為取該圖塊各通道的平均值,而不是最大值。但最大池化的效果往往比這些替代方法更好。

簡而言之,原因在于特征中往往編碼了某種模式或概念在特征圖的不同位置是否存在(是以得名特征圖),而觀察不同特征的最大值而不是平均值能夠給出更多的資訊。是以,最合理的子采樣政策是首先生成密集的特征圖(通過無步進的卷積),然後觀察特征每個小圖塊上的最大激活,而不是檢視輸入的稀疏視窗(通過步進卷積)或對輸入圖塊取平均,因為後兩種方法可能導緻錯過或淡化特征是否存在的資訊。

資料增強(data augmentation),它在計算機視覺領域是一種非常強大的降低過拟合的技術。将深度學習應用于小型資料集的另外兩個重要技巧:用預訓練的網絡做特征提取,對預訓練的網絡進行微調。

由于卷積神經網絡學到的是局部的、平移不變的特征,它對于感覺問題可以高效地利用資料。雖然資料相對較少,但在非常小的圖像資料集上從頭開始訓練一個卷積神經網絡,仍然可以得到不錯的結果,而且無須任何自定義的特征工程。

此外,深度學習模型本質上具有高度的可複用性,比如,已有一個在大規模資料集上訓練的圖像分類模型或語音轉文本模型,你隻需做很小的修改就能将其複用于完全不同的問題。特别是在計算機視覺領域,許多預訓練的模型(通常都是在ImageNet 資料集上訓練得到的)現在都可以公開下載下傳,并可以用于在資料很少的情況下建構強大的視覺模型。

資料預處理

你現在已經知道,将資料輸入神經網絡之前,應該将資料格式化為經過預處理的浮點數張量。現在,資料以JPEG 檔案的形式儲存在硬碟中,是以資料預處理步驟大緻如下。

(1) 讀取圖像檔案。

(2) 将JPEG 檔案解碼為RGB 像素網格。

(3) 将這些像素網格轉換為浮點數張量。

(4) 将像素值(0~255 範圍内)縮放到[0, 1] 區間(正如你所知,神經網絡喜歡處理較小的輸入值)。

Keras有一個圖像處理輔助工具的子產品,位于keras.preprocessing.image。特别地,它包含ImageDataGenerator 類,可以快速建立Python 生成器,能夠将硬碟上的圖像檔案自動轉換為預處理好的張量批量。

資料增強是從現有的訓練樣本中生成更多的訓練資料,其方法是利用多種能夠生成可信圖像的随機變換來增加(augment)樣本。其目标是,模型在訓練時不會兩次檢視完全相同的圖像。這讓模型能夠觀察到資料的更多内容,進而具有更好的泛化能力。

想要将深度學習應用于小型圖像資料集,一種常用且非常高效的方法是使用預訓練網絡。預訓練網絡(pretrained network)是一個儲存好的網絡,之前已在大型資料集(通常是大規模圖像分類任務)上訓練好。如果這個原始資料集足夠大且足夠通用,那麼預訓練網絡學到的特征的空間層次結構可以有效地作為視覺世界的通用模型,是以這些特征可用于各種不同的計算機視覺問題,即使這些新問題涉及的類别和原始任務完全不同。舉個例子,你在ImageNet 上訓練了一個網絡(其類别主要是動物和日常用品),然後将這個訓練好的網絡應用于某個不相幹的任務,比如在圖像中識别家具。這種學到的特征在不同問題之間的可移植性,是深度學習與許多早期淺層學習方法相比的重要優勢,它使得深度學習對小資料問題非常有效。

使用預訓練網絡有兩種方法:特征提取(feature extraction)和微調模型(fine-tuning)。

特征提取是使用之前網絡學到的表示來從新樣本中提取出有趣的特征。然後将這些特征輸入一個新的分類器,從頭開始訓練。用于圖像分類的卷積神經網絡包含兩部分:首先是一系列池化層和卷積層,最後是一個密集連接配接分類器。第一部分叫作模型的卷積基(convolutional base)。對于卷積神經網絡而言,特征提取就是取出之前訓練好的網絡的卷積基,在上面運作新資料,然後在輸出上面訓練一個新的分類器。

為什麼僅重複使用卷積基?我們能否也重複使用密集連接配接分類器?一般來說,應該避免這麼做。原因在于卷積基學到的表示可能更加通用,是以更适合重複使用。卷積神經網絡的特征圖表示通用概念在圖像中是否存在,無論面對什麼樣的計算機視覺問題,這種特征圖都可能很有用。但是,分類器學到的表示必然是針對于模型訓練的類别,其中僅包含某個類别出現在整張圖像中的機率資訊。此外,密集連接配接層的表示不再包含物體在輸入圖像中的位置資訊。密集連接配接層舍棄了空間的概念,而物體位置資訊仍然由卷積特征圖所描述。如果物體位置對于問題很重要,那麼密集連接配接層的特征在很大程度上是無用的。

注意,某個卷積層提取的表示的通用性(以及可複用性)取決于該層在模型中的深度。模型中更靠近底部的層提取的是局部的、高度通用的特征圖(比如視覺邊緣、顔色和紋理),而更靠近頂部的層提取的是更加抽象的概念(比如“貓耳朵”或“狗眼睛”)。是以,如果你的新資料集與原始模型訓練的資料集有很大差異,那麼最好隻使用模型的前幾層來做特征提取,而不是使用整個卷積基。

卷積基的使用有兩種方法可供選擇。

1、在你的資料集上運作卷積基,将輸出儲存成硬碟中的Numpy 數組,然後用這個資料作為輸入,輸入到獨立的密集連接配接分類器中(與本書第一部分介紹的分類器類似)。這種方法速度快,計算代價低,因為對于每個輸入圖像隻需運作一次卷積基,而卷積基是目前流程中計算代價最高的。但出于同樣的原因,這種方法不允許你使用資料增強。

2、在頂部添加 Dense 層來擴充已有模型(即 conv_base),并在輸入資料上端到端地運作整個模型。這樣你可以使用資料增強,因為每個輸入圖像進入模型時都會經過卷積基。但出于同樣的原因,這種方法的計算代價比第一種要高很多。

特征提取的第二種方法,它的速度更慢,計算代價更高,但在訓練期間可以使用資料增強。這種方法就是:擴充conv_base 模型,然後在輸入資料上端到端地運作模型。模型的行為和層類似,是以你可以向Sequential 模型中添加一個模型(比如conv_base),就像添加一個層一樣。

(卷積基參數很多是以)在編譯和訓練模型之前,一定要“當機”卷積基。當機(freeze)一個或多個層是指在訓練過程中保持其權重不變。如果不這麼做,那麼卷積基之前學到的表示将會在訓練過程中被修改。因為其上添加的Dense 層是随機初始化的,是以非常大的權重更新将會在網絡中傳播,對之前學到的表示造成很大破壞。在Keras 中,當機網絡的方法是将其trainable 屬性設為False(conv_base.trainable = False)。

注意,為了讓這些修改生效,你必須先編譯模型。如果在編譯之後修改了權重的trainable 屬性,那麼應該重新編譯模型,否則這些修改将被忽略。

另一種廣泛使用的模型複用方法是模型微調(fine-tuning),與特征提取互為補充。對于用于特征提取的當機的模型基,微調是指将其頂部的幾層“解凍”,并将這解凍的幾層和新增加的部分(本例中是全連接配接分類器)聯合訓練。之是以叫作微調,是因為它隻是略微調整了所複用模型中更加抽象的表示,以便讓這些表示與手頭的問題更加相關。

當機VGG16 的卷積基是為了能夠在上面訓練一個随機初始化的分類器。同理,隻有上面的分類器已經訓練好了,才能微調卷積基的頂部幾層。如果分類器沒有訓練好,那麼訓練期間通過網絡傳播的誤差信号會特别大,微調的幾層之前學到的表示都會被破壞。是以,微調網絡的步驟如下。

(1) 在已經訓練好的基網絡(base network)上添加自定義網絡。

(2) 當機基網絡。

(3) 訓練所添加的部分。

(4) 解凍基網絡的一些層。

(5) 聯合訓練解凍的這些層和添加的部分。

為什麼不微調更多層?為什麼不微調整個卷積基?你當然可以這麼做,但需要考慮以下幾點。

. 卷積基中更靠底部的層編碼的是更加通用的可複用特征,而更靠頂部的層編碼的是更專業化的特征。微調這些更專業化的特征更加有用,因為它們需要在你的新問題上改變用途。微調更靠底部的層,得到的回報會更少。

. 訓練的參數越多,過拟合的風險越大。卷積基有 1500 萬個參數,是以在你的小型資料集上訓練這麼多參數是有風險的。是以,在這種情況下,一個好政策是僅微調卷積基最後的兩三層。

微調網絡時我們将使用學習率非常小的RMSProp 優化器來實作。之是以讓學習率很小,是因為對于微調的三層表示,我們希望其變化範圍不要太大。太大的權重更新可能會破壞這些表示。

注意,從損失曲線上看不出與之前相比有任何真正的提高(實際上還在變差)。你可能感到奇怪,如果損失沒有降低,那麼精度怎麼能保持穩定或提高呢?答案很簡單:圖中展示的是逐點(pointwise)損失值的平均值,但影響精度的是損失值的分布,而不是平均值,因為精度是模型預測的類别機率的二進制門檻值。

下面是你應該從以上兩節的練習中學到的要點。

卷積神經網絡是用于計算機視覺任務的最佳機器學習模型。即使在非常小的資料集上也可以從頭開始訓練一個卷積神經網絡,而且得到的結果還不錯。

在小型資料集上的主要問題是過拟合。在處理圖像資料時,資料增強是一種降低過拟合的強大方法。

利用特征提取,可以很容易将現有的卷積神經網絡複用于新的資料集。對于小型圖像資料集,這是一種很有價值的方法。

作為特征提取的補充,你還可以使用微調,将現有模型之前學到的一些資料表示應用于新問題。這種方法可以進一步提高模型性能。

卷積神經網絡的可視化

可視化卷積神經網絡的中間輸出(中間激活):有助于了解卷積神經網絡連續的層如何對輸入進行變換,也有助于初步了解卷積神經網絡每個過濾器的含義。

可視化卷積神經網絡的過濾器:有助于精确了解卷積神經網絡中每個過濾器容易接受的視覺模式或視覺概念。

可視化圖像中類激活的熱力圖:有助于了解圖像的哪個部分被識别為屬于某個類别,進而可以定位圖像中的物體。

可視化中間激活,是指對于給定輸入,展示網絡中各個卷積層和池化層輸出的特征圖(層的輸出通常被稱為該層的激活,即激活函數的輸出)。這讓我們可以看到輸入如何被分解為網絡學到的不同過濾器。我們希望在三個次元對特征圖進行可視化:寬度、高度和深度(通道)。每個通道都對應相對獨立的特征,是以将這些特征圖可視化的正确方法是将每個通道的内容分别繪制成二維圖像。

為了提取想要檢視的特征圖,我們需要建立一個Keras 模型,以圖像批量作為輸入,并輸出所有卷積層和池化層的激活。為此,我們需要使用Keras 的Model 類。模型執行個體化需要兩個參數:一個輸入張量(或輸入張量的清單)和一個輸出張量(或輸出張量的清單)。得到的類是一個Keras 模型,就像你熟悉的Sequential 模型一樣,将特定輸入映射為特定輸出。Model 類允許模型有多個輸出,這一點與Sequential 模型不同

這裡需要注意:第一層是各種邊緣探測器的集合。在這一階段,激活幾乎保留了原始圖像中的所有資訊。随着層數的加深,激活變得越來越抽象,并且越來越難以直覺地了解。它們開始表示更高層次的概念,比如“貓耳朵”和“貓眼睛”。層數越深,其表示中關于圖像視覺内容的資訊就越少,而關于類别的資訊就越多。激活的稀疏度(sparsity)随着層數的加深而增大。在第一層裡,所有過濾器都被輸入圖像激活,但在後面的層裡,越來越多的過濾器是空白的。也就是說,輸入圖像中找不到這些過濾器所編碼的模式。

深度神經網絡可以有效地作為資訊蒸餾管道,輸入原始資料(本例中是RGB 圖像),反複對其進行變換,将無關資訊過濾掉(比如圖像的具體外觀),并放大和細化有用的資訊(比如圖像的類别)。

想要觀察卷積神經網絡學到的過濾器,另一種簡單的方法是顯示每個過濾器所響應的視覺模式。這可以通過在輸入空間中進行梯度上升來實作:從空白輸入圖像開始,将梯度下降應用于卷積神經網絡輸入圖像的值,其目的是讓某個過濾器的響應最大化。得到的輸入圖像是標明過濾器具有最大響應的圖像。這個過程很簡單:我們需要建構一個損失函數,其目的是讓某個卷積層的某個過濾器的值最大化;然後,我們要使用随機梯度下降來調節輸入圖像的值,以便讓這個激活值最大化。

為了實作梯度下降,我們需要得到損失相對于模型輸入的梯度。為此,我們需要使用Keras的backend子產品内置的gradients 函數

為了讓梯度下降過程順利進行,一個非顯而易見的技巧是将梯度張量除以其L2 範數(張量中所有值的平方的平均值的平方根)來标準化。這就確定了輸入圖像的更新大小始終位于相同的範圍。

第四章 機器學習的通用工作流程

本節将介紹一種可用于解決任何機器學習問題的通用模闆。這一模闆将你在本章學到的這些概念串在一起:問題定義、評估、特征工程和解決過拟合。

4.5.1 定義問題,收集資料集

首先,你必須定義所面對的問題。

你的輸入資料是什麼?你要預測什麼?隻有擁有可用的訓練資料,你才能學習預測某件事情。比如,隻有同時擁有電影評論和情感标注,你才能學習對電影評論進行情感分類。是以,資料可用性通常是這一階段的限制因素(除非你有辦法付錢讓人幫你收集資料)。 你面對的是什麼類型的問題?是二分類問題、多分類問題、标量回歸問題、向量回歸問題,還是多分類、多标簽問題?或者是其他問題,比如聚類、生成或強化學習?确定問題類型有助于你選擇模型架構、損失函數等。隻有明确了輸入、輸出以及所使用的資料,你才能進入下一階段。注意你在這一階段所做的假設。

假設輸出是可以根據輸入進行預測的。假設可用資料包含足夠多的資訊,足以學習輸入和輸出之間的關系。在開發出工作模型之前,這些隻是假設,等待驗證真假。并非所有問題都可以解決。你收集了包含輸入X 和目标Y 的很多樣例,并不意味着X 包含足夠多的資訊來預測Y。例如,如果你想根據某支股票最近的曆史價格來預測其股價走勢,那你成功的可能性不大,因為曆史價格并沒有包含很多可用于預測的資訊。

有一類無法解決的問題你應該知道,那就是非平穩問題(nonstationary problem)。假設你想要建構一個服裝推薦引擎,并在一個月(八月)的資料上訓練,然後在冬天開始生成推薦結果。一個大問題是,人們購買服裝的種類是随着季節變化的,即服裝購買在幾個月的尺度上是一個非平穩現象。你想要模組化的對象随着時間推移而改變。在這種情況下,正确的做法是不斷地利用最新資料重新訓練模型,或者在一個問題是平穩的時間尺度上收集資料。對于服裝購買這種周期性問題,幾年的資料足以捕捉到季節性變化,但一定要記住,要将一年中的時間作為模型的一個輸入。請記住,機器學習隻能用來記憶訓練資料中存在的模式。你隻能識别出曾經見過的東西。在過去的資料上訓練機器學習來預測未來,這裡存在一個假設,就是未來的規律與過去相同。

但事實往往并非如此。

4.5.2 選擇衡量成功的名額

要控制一件事物,就需要能夠觀察它。要取得成功,就必須給出成功的定義:精度?準确率(precision)和召回率(recall)?客戶保留率?衡量成功的名額将指引你選擇損失函數,即模型要優化什麼。它應該直接與你的目标(如業務成功)保持一緻。

對于平衡分類問題(每個類别的可能性相同),精度和接收者操作特征曲線下面積(area under the receiver operating characteristic curve,ROC AUC)是常用的名額。對于類别不平衡的問題,你可以使用準确率和召回率。對于排序問題或多标簽分類,你可以使用平均準确率均值(mean average precision)。自定義衡量成功的名額也很常見。要想了解各種機器學習的成功衡量名額以及這些名額與不同問題域的關系,你可以浏覽Kaggle 網站上的資料科學競賽,上面展示了各種各樣的問題和評估名額。

4.5.3 确定評估方法

一旦明确了目标,你必須确定如何衡量目前的進展。前面介紹了三種常見的評估方法。 留出驗證集。資料量很大時可以采用這種方法。K折交叉驗證。如果留出驗證的樣本量太少,無法保證可靠性,那麼應該選擇這種方法。重複的 K 折驗證。如果可用的資料很少,同時模型評估又需要非常準确,那麼應該使用這種方法。隻需選擇三者之一。大多數情況下,第一種方法足以滿足要求。

4.5.4 準備資料

一旦知道了要訓練什麼、要優化什麼以及評估方法,那麼你就幾乎已經準備好訓練模型了。但首先你應該将資料格式化,使其可以輸入到機器學習模型中(這裡假設模型為深度神經網絡)。

如前所述,應該将資料格式化為張量。

這些張量的取值通常應該縮放為較小的值,比如在 [-1, 1] 區間或 [0, 1] 區間。

如果不同的特征具有不同的取值範圍(異質資料),那麼應該做資料标準化。

你可能需要做特征工程,尤其是對于小資料問題。

準備好輸入資料和目标資料的張量後,你就可以開始訓練模型了。

4.5.5 開發比基準更好的模型

這一階段的目标是獲得統計功效(statistical power),即開發一個小型模型,它能夠打敗純随機的基準(dumb baseline)。在MNIST 數字分類的例子中,任何精度大于0.1 的模型都可以說具有統計功效;在IMDB 的例子中,任何精度大于0.5 的模型都可以說具有統計功效。注意,不一定總是能獲得統計功效。如果你嘗試了多種合理架構之後仍然無法打敗随機基準,那麼原因可能是問題的答案并不在輸入資料中。要記住你所做的兩個假設。

假設輸出是可以根據輸入進行預測的。

假設可用的資料包含足夠多的資訊,足以學習輸入和輸出之間的關系。

這些假設很可能是錯誤的,這樣的話你需要從頭重新開始。如果一切順利,你還需要選擇三個關鍵參數來建構第一個工作模型。

1、最後一層的激活。它對網絡輸出進行有效的限制。例如,IMDB 分類的例子在最後一層使用了sigmoid,回歸的例子在最後一層沒有使用激活,等等。

2、損失函數。它應該比對你要解決的問題的類型。例如,IMDB 的例子使用 binary_crossentropy、回歸的例子使用mse,等等。

3、優化配置。你要使用哪種優化器?學習率是多少?大多數情況下,使用 rmsprop 及其預設的學習率是穩妥的。

關于損失函數的選擇,需要注意,直接優化衡量問題成功的名額不一定總是可行的。有時難以将名額轉化為損失函數,要知道,損失函數需要在隻有小批量資料時即可計算(理想情況下,隻有一個資料點時,損失函數應該也是可計算的),而且還必須是可微的(否則無法用反向傳播來訓練網絡)。例如,廣泛使用的分類名額ROC AUC 就不能被直接優化。是以在分類任務中,常見的做法是優化ROC AUC 的替代名額,比如交叉熵。一般來說,你可以認為交叉熵越小,ROC AUC 越大。

表4-1 列出了常見問題類型的最後一層激活和損失函數,可以幫你進行選擇。表4-1 為模型選擇正确的最後一層激活和損失函數

問題類型 最後一層激活 損失函數
二分類問題 sigmoid binary_crossentropy
多分類、單标簽問題 softmax categorical_crossentropy
多分類、多标簽問題 sigmoid binary_crossentropy
回歸到任意值 mse
回歸到0~1、範圍内的值 sigmoid mse或binary_crossentropy

4.5.6 擴大模型規模:開發過拟合的模型

一旦得到了具有統計功效的模型,問題就變成了:模型是否足夠強大?它是否具有足夠多的層和參數來對問題進行模組化?例如,隻有單個隐藏層且隻有兩個單元的網絡,在MNIST 問題上具有統計功效,但并不足以很好地解決問題。請記住,機器學習中無處不在的對立是優化和泛化的對立,理想的模型是剛好在欠拟合和過拟合的界線上,在容量不足和容量過大的界線上。為了找到這條界線,你必須穿過它。

要搞清楚你需要多大的模型,就必須開發一個過拟合的模型,這很簡單。

(1) 添加更多的層。

(2) 讓每一層變得更大。

(3) 訓練更多的輪次。

要始終監控訓練損失和驗證損失,以及你所關心的名額的訓練值和驗證值。如果你發現模型在驗證資料上的性能開始下降,那麼就出現了過拟合。下一階段将開始正則化和調節模型,以便盡可能地接近理想模型,既不過拟合也不欠拟合。

4.5.7 模型正則化與調節超參數

這一步是最費時間的:你将不斷地調節模型、訓練、在驗證資料上評估(這裡不是測試資料)、再次調節模型,然後重複這一過程,直到模型達到最佳性能。

你應該嘗試以下幾項:

添加 dropout。

 嘗試不同的架構:增加或減少層數。

 添加 L1 和 / 或 L2 正則化。

 嘗試不同的超參數(比如每層的單元個數或優化器的學習率),以找到最佳配置。

反複做特征工程:添加新特征或删除沒有資訊量的特征。

請注意:每次使用驗證過程的回報來調節模型,都會将有關驗證過程的資訊洩露到模型中。如果隻重複幾次,那麼無關緊要;但如果系統性地疊代許多次,最終會導緻模型對驗證過程過拟合(即使模型并沒有直接在驗證資料上訓練)。這會降低驗證過程的可靠性。

一旦開發出令人滿意的模型配置,你就可以在所有可用資料(訓練資料+ 驗證資料)上訓

練最終的生産模型,然後在測試集上最後評估一次。如果測試集上的性能比驗證集上差很多,那麼這可能意味着你的驗證流程不可靠,或者你在調節模型參數時在驗證資料上出現了過拟合。在這種情況下,你可能需要換用更加可靠的評估方法,比如重複的K 折驗證。

第六章 深度學習用于文本和序列

用于處理序列的兩種基本的深度學習算法分别是循環神經網絡(recurrent neural network)和一維卷積神經網絡(1D convnet)。

深度學習用于自然語言處理是将模式識别應用于單詞、句子和段落,這與計算機視覺是将模式識别應用于像素大緻相同。

與其他所有神經網絡一樣,深度學習模型不會接收原始文本作為輸入,它隻能處理數值張量。文本向量化(vectorize)是指将文本轉換為數值張量的過程。它有多種實作方法:

将文本分割為單詞,并将每個單詞轉換為一個向量。

将文本分割為字元,并将每個字元轉換為一個向量。

提取單詞或字元的 n-gram,并将每個 n-gram 轉換為一個向量。n-gram 是多個連續單詞或字元的集合(n-gram 之間可重疊)。

将文本分解而成的單元(單詞、字元或n-gram)叫作标記(token),将文本分解成标記的過程叫作分詞(tokenization)。所有文本向量化過程都是應用某種分詞方案,然後将數值向量與生成的标記相關聯。這些向量組合成序列張量,被輸入到深度神經網絡中。将向量與标記相關聯的方法有很多種。本節将介紹兩種主要方法:對标記做one-hot 編碼(one-hotencoding)與标記嵌入[token embedding,通常隻用于單詞,叫作詞嵌入(word embedding)]。

n-gram 是從一個句子中提取的N 個(或更少)連續單詞的集合。這一概念中的“單詞”也可以替換為“字元”。這樣的集合分别叫作二進制文法袋(bag-of-2-grams)及三元文法袋(bag-of-3-grams)。這裡袋(bag)這一術語指的是,我們處理的是标記組成的集合,而不是一個清單或序列,即标記沒有特定的順序。這一系列分詞方法叫作詞袋(bag-of-words)。

詞袋是一種不儲存順序的分詞方法(生成的标記組成一個集合,而不是一個序列,舍棄了句子的總體結構),是以它往往被用于淺層的語言處理模型,而不是深度學習模型。提取n-gram 是一種特征工程,深度學習不需要這種死闆而又不穩定的方法,并将其替換為分層特征學習。本章後面将介紹的一維卷積神經網絡和循環神經網絡,都能夠通過觀察連續的單詞序列或字元序列來學習單詞組和字元組的資料表示,而無須明确知道這些組的存在。是以,本書不會進一步讨論n-gram。但一定要記住,在使用輕量級的淺層文本處理模型時(比如logistic 回歸和随機森林),n-gram 是一種功能強大、不可或缺的特征工程工具。

one-hot 編碼是将标記轉換為向量的最常用、最基本的方法。它将每個單詞與一個唯一的整數索引相關聯,然後将這個整數索引i 轉換為長度為N 的二進制向量(N 是詞表大小),這個向量隻有第i 個元素是1,其餘元素都為0。當然,也可以進行字元級的one-hot 編碼。

Keras 的内置函數可以對原始文本資料進行單詞級或字元級的one-hot 編碼。你應該使用這些函數,因為它們實作了許多重要的特性,比如從字元串中去除特殊字元、隻考慮資料集中前N 個最常見的單詞(這是一種常用的限制,以避免處理非常大的輸入向量空間)。one-hot 編碼的一種變體是所謂的one-hot 散列技巧(one-hot hashing trick),如果詞表中唯一标記的數量太大而無法直接處理,就可以使用這種技巧。這種方法沒有為每個單詞顯式配置設定一個索引并将這些索引儲存在一個字典中,而是将單詞散列編碼為固定長度的向量,通常用一個非常簡單的散列函數來實作。這種方法的主要優點在于,它避免了維護一個顯式的單詞索引,進而節省記憶體并允許資料的線上編碼(在讀取完所有資料之前,你就可以立刻生成标記向量)。這種方法有一個缺點,就是可能會出現散列沖突(hash collision),即兩個不同的單詞可能具有相同的散列值,随後任何機器學習模型觀察這些散列值,都無法區分它們所對應的單詞。如果散列空間的次元遠大于需要散列的唯一标記的個數,散列沖突的可能性會減小。

---------------------------------------------------------------------------

6.1 使用詞嵌入

将單詞與向量相關聯還有另一種常用的強大方法,就是使用密集的詞向量(word vector),也叫詞嵌入(word embedding)。one-hot 編碼得到的向量是二進制的、稀疏的、次元很高的(次元大小等于詞表中的單詞個數),而詞嵌入是低維的浮點數向量(即密集向量,與稀疏向量相對)。與one-hot 編碼得到的詞向量不同,詞嵌入是從資料中學習得到的。常見的詞向量次元是256、512 或1024(處理非常大的詞表時)。與此相對,onehot編碼的詞向量次元通常為20 000 或更高(對應包含20 000 個标記的詞表)。是以,詞向量可以将更多的資訊塞入更低的次元中。

one-hot 編碼或one-hot 散列得到的詞表示是稀疏的、高維的、寫死的,而詞嵌入是密集的、相對低維的,而且是從資料中學習得到的

擷取詞嵌入有兩種方法。

1、在完成主任務(比如文檔分類或情感預測)的同時學習詞嵌入。在這種情況下,一開始是随機的詞向量,然後對這些詞向量進行學習,其學習方式與學習神經網絡的權重相同。

2、在不同于待解決問題的機器學習任務上預計算好詞嵌入,然後将其加載到模型中。這些詞嵌入叫作預訓練詞嵌入(pretrained word embedding)。

合理的做法是對每個新任務都學習一個新的嵌入空間。幸運的是,反向傳播讓這種學習變得很簡單,而Keras 使其變得更簡單。我們要做的就是學習一個層的權重,這個層就是Embedding 層。最好将Embedding 層了解為一個字典,将整數索引(表示特定單詞)映射為密集向量。它接收整數作為輸入,并在内部字典中查找這些整數,然後傳回相關聯的向量。Embedding 層實際上是一種字典查找。

有時可用的訓練資料很少,以至于隻用手頭資料無法學習适合特定任務的詞嵌入。可以使用已有的預計算的詞嵌入資料庫,如Google的word2vec 算法,其次元抓住了特定的語義屬性,比如性别。另一個常用的是GloVe,由斯坦福開發。這種嵌入方法基于對詞共現統計矩陣進行因式分解。

前饋網絡指沒有記憶的神經網絡(如密集連接配接網絡和卷積神經網絡),它們單獨處理每個輸入,在輸入與輸入之間沒有儲存任何狀态。

循環神經網絡(RNN)采用同樣的原理,不過是一個極其簡化的版本:它處理序列的方式是,周遊所有序列元素,并儲存一個狀态,其中包含與已檢視内容相關的資訊。實際上,RNN 是一類具有内部環的神經網絡。在處理兩個不同的獨立序列之間,RNN 狀态會被重置,是以,你仍可以将一個序列看作單個資料點,即網絡的單個輸入。真正改變的是,資料點不再是在單個步驟中進行處理,相反,網絡内部會對序列元素進行周遊。

RNN 是一個for 循環,它重複使用循環前一次疊代的計算結果。

與Keras 中的所有循環層一樣,SimpleRNN 可以在兩種不同的模式下運作:一種是傳回每個時間步連續輸出的完整序列;另一種是隻傳回每個輸入序列的最終輸出。為了提高網絡的表示能力,将多個循環層逐個堆疊有時也是很有用的。在這種情況下,你需要讓所有中間層都傳回完整的輸出序列。

SimpleRNN 并不是Keras 中唯一可用的循環層,還有另外兩個:長短期記憶算法LSTM 和GRU。在實踐中總會用到其中之一,因為SimpleRNN 通常過于簡化,沒有實用價值。SimpleRNN 的最大問題是,在時刻t,理論上來說,它應該能夠記住許多時間步之前見過的資訊,但實際上它是不可能學到這種長期依賴的。其原因在于梯度消失問題,這一效應類似于在層數較多的非循環網絡(即前饋網絡)中觀察到的效應:随着層數的增加,網絡最終變得無法訓練。

LSTM 層是SimpleRNN 層的一種變體,它增加了一種攜帶資訊跨越多個時間步的方法。假設有一條傳送帶,其運作方向平行于你所處理的序列。序列中的資訊可以在任意位置跳上傳送帶,然後被傳送到更晚的時間步,并在需要時原封不動地跳回來。這實際上就是LSTM 的原理:它儲存資訊以便後面使用,進而防止較早期的信号在處理過程中逐漸消失。

RNN用法的三種技巧

1、循環 dropout:這是一種特殊的内置方法,在循環層中使用 dropout來降低過拟合。

2、堆疊循環層。這會提高網絡的表示能力(代價是更高的計算負荷)。

3、雙向循環層。将相同的資訊以不同的方式呈現給循環網絡,可以提高精度并緩解遺忘問題。

 一種基本的機器學習方法:在嘗試機器學習方法之前,建立一個基于常識的基準方法是很有用的;同樣,在開始研究複雜且計算代價很高的模型(比如RNN)之前,嘗試使用簡單且計算代價低的機器學習模型也是很有用的,比如小型的密集連接配接網絡。這可以保證進一步增加問題的複雜度是合理的,并且會帶來真正的好處。

我們已經學過降低過拟合的一種經典技術——dropout,即将某一層的輸入單元随機設為0,其目的是打破該層訓練資料中的偶然相關性。但在循環網絡中如何正确地使用dropout,這并不是一個簡單的問題。人們早就知道,在循環層前面應用dropout,這種正則化會妨礙學習過程,而不是有所幫助。2015 年,在關于貝葉斯深度學習的博士論文中a,Yarin Gal 确定了在循環網絡中使用dropout 的正确方法:對每個時間步應該使用相同的dropout 掩碼(dropout mask,相同模式的舍棄單元),而不是讓dropout 掩碼随着時間步的增加而随機變化。此外,為了對GRU、LSTM 等循環層得到的表示做正則化,應該将不随時間變化的dropout 掩碼應用于層的内部循環激活(叫作循環dropout 掩碼)。對每個時間步使用相同的dropout 掩碼,可以讓網絡沿着時間正确地傳播其學習誤差,而随時間随機變化的dropout 掩碼則會破壞這個誤差信号,并且不利于學習過程。

Yarin Gal 使用Keras 開展這項研究,并幫助将這種機制直接内置到Keras 循環層中。Keras的每個循環層都有兩個與dropout 相關的參數:一個是dropout,它是一個浮點數,指定該層輸入單元的dropout 比率;另一個是recurrent_dropout,指定循環單元的dropout 比率。我們向GRU 層中添加dropout 和循環dropout,看一下這麼做對過拟合的影響。因為使用dropout正則化的網絡總是需要更長的時間才能完全收斂,是以網絡訓練輪次增加為原來的2 倍。

機器學習的通用工作流程:增加網絡容量通常是一個好主意,直到過拟合變成主要的障礙(假設你已經采取基本步驟來降低過拟合,比如使用dropout)。隻要過拟合不是太嚴重,那麼很可能是容量不足的問題。增加網絡容量的通常做法是增加每層單元數或增加層數。循環層堆疊(recurrent layer stacking)是建構更加強大的循環網絡的經典方法。

在Keras 中逐個堆疊循環層,所有中間層都應該傳回完整的輸出序列(一個3D 張量),而不是隻傳回最後一個時間步的輸出。這可以通過指定return_sequences=True 來實作。

雙向RNN 是一種常見的RNN 變體,它在某些任務上的性能比普通RNN 更好。它常用于自然語言處理,可謂深度學習對自然語言處理的瑞士軍刀。

RNN 特别依賴于順序或時間,RNN 按順序處理輸入序列的時間步,而打亂時間步或反轉時間步會完全改變RNN 從序列中提取的表示。正是由于這個原因,如果順序對問題很重要,RNN的表現會很好。雙向RNN 利用了RNN 的順序敏感性:它包含兩個普通RNN,比如你已經學過的GRU 層和LSTM 層,每個RNN 分别沿一個方向對輸入序列進行處理(時間正序和時間逆序),然後将它們的表示合并在一起。通過沿這兩個方向處理序列,雙向RNN 能夠捕捉到可能被單向RNN 忽略的模式。

在Keras 中将一個雙向RNN 執行個體化,我們需要使用Bidirectional 層,它的第一個參數是一個循環層執行個體。

小結

遇到新問題時,最好首先為你選擇的名額建立一個基于常識的基準。如果沒有需要打敗的基準,那麼就無法分辨是否取得了真正的進步。

在嘗試計算代價較高的模型之前,先嘗試一些簡單的模型,以此證明增加計算代價是有意義的。有時簡單模型就是你的最佳選擇。

如果時間順序對資料很重要,那麼循環網絡是一種很适合的方法,與那些先将時間資料展平的模型相比,其性能要更好。

想要在循環網絡中使用 dropout,你應該使用一個不随時間變化的 dropout 掩碼與循環dropout 掩碼。這二者都内置于Keras 的循環層中,是以你隻需要使用循環層的dropout和recurrent_dropout 參數即可。

與單個 RNN 層相比,堆疊 RNN 的表示能力更加強大。但它的計算代價也更高,是以不一定總是需要。雖然它在機器翻譯等複雜問題上很有效,但在較小、較簡單的問題上可能不一定有用。

雙向 RNN 從兩個方向檢視一個序列,它對自然語言處理問題非常有用。但如果在序列資料中最近的資料比序列開頭包含更多的資訊,那麼這種方法的效果就不明顯。

循環注意和序列掩碼這兩個概念通常對自然語言處理特别有用。

卷積神經網絡在計算機視覺問題上表現出色,原因在于它能夠進行卷積運算,從局部輸入圖塊中提取特征,并能夠将表示子產品化,同時可以高效地利用資料。

這種一維卷積層可以識别序列中的局部模式。因為對每個序列段執行相同的輸入變換,是以在句子中某個位置學到的模式稍後可以在其他位置被識别,這使得一維卷積神經網絡具有平移不變性(對于時間平移而言)。字元級的一維卷積神經網絡能夠學會單詞構詞法。

你已經學過二維池化運算,比如二維平均池化和二維最大池化,在卷積神經網絡中用于對圖像張量進行空間下采樣。一維也可以做相同的池化運算:從輸入中提取一維序列段(即子序列),然後輸出其最大值(最大池化)或平均值(平均池化)。與二維卷積神經網絡一樣,該運算也是用于降低一維輸入的長度(子采樣)。

一維卷積神經網絡的架構與二維卷積神經網絡相同,它是Conv1D 層和MaxPooling1D層的堆疊,最後是一個全局池化層或Flatten 層,将三維輸出轉換為二維輸出,讓你可以向模型中添加一個或多個Dense 層,用于分類或回歸。

不過二者有一點不同:一維卷積神經網絡可以使用更大的卷積視窗。對于二維卷積層,3×3 的卷積視窗包含3×3=9 個特征向量;但對于一位卷積層,大小為3 的卷積視窗隻包含3個卷積向量。是以,你可以輕松使用大小等于7 或9 的一維卷積視窗。

在單詞級的情感分類任務上,一維卷積神經網絡可以替代循環網絡,并且速度更快、計算代價更低。

結合CNN 和RNN 來處理長序列

一維卷積神經網絡分别處理每個輸入序列段,是以它對時間步的順序不敏感(這裡所說順序的範圍要大于局部尺度,即大于卷積視窗的大小),這一點與RNN 不同。

要想結合卷積神經網絡的速度和輕量與RNN 的順序敏感性,一種方法是在RNN 前面使用一維卷積神經網絡作為預處理步驟。對于那些非常長,以至于RNN 無法處理的序列(比如包含上千個時間步的序列),這種方法尤其有用。卷積神經網絡可以将長的輸入序列轉換為進階特征組成的更短序列(下采樣)。然後,提取的特征組成的這些序列成為網絡中RNN 的輸入。這種方法的速度要快很多。

小結:

二維卷積神經網絡在二維空間中處理視覺模式時表現很好,與此相同,一維卷積神經網絡在處理時間模式時表現也很好。對于某些問題,特别是自然語言處理任務,它可以替代RNN,并且速度更快。

通常情況下,一維卷積神經網絡的架構與計算機視覺領域的二維卷積神經網絡很相似,它将Conv1D 層和MaxPooling1D 層堆疊在一起,最後是一個全局池化運算或展平操作。

因為 RNN 在處理非常長的序列時計算代價很大,但一維卷積神經網絡的計算代價很小,是以在RNN 之前使用一維卷積神經網絡作為預處理步驟是一個好主意,這樣可以使序列變短,并提取出有用的表示交給RNN 來處理。

Sequential模型假設網絡隻有一個輸入和一個輸出,而且網絡是層的線性堆疊。

如果你隻有中繼資料,那麼可以使用one-hot 編碼,然後用密集連接配接網絡來預測價格。如果你隻有文本描述,那麼可以使用循環神經網絡或一維卷積神經網絡。如果你隻有圖像,那麼可以使用二維卷積神經網絡。但怎麼才能同時使用這三種資料呢?一種樸素的方法是訓練三個獨立的模型,然後對三者的預測做權重平均。但這種方法可能不是最優的,因為模型提取的資訊可能存在備援。更好的方法是使用一個可以同時檢視所有可用的輸入模态的模型,進而聯合學習一個更加精确的資料模型——這個模型具有三個輸入分支。

許多最新開發的神經架構要求非線性的網絡拓撲結構,即網絡結構為有向無環圖。比如,Inception 系列網絡依賴于Inception 子產品,其輸入被多個并行的卷積分支所處理,然後将這些分支的輸出合并為單個張量。最近還有一種趨勢是向模型中添加殘差連接配接,殘差連接配接是将前面的輸出張量與後面的輸出張量相加,進而将前面的表示重新注入下遊資料流中,這有助于防止資訊處理流程中的資訊損失。

将Model 對象執行個體化隻用了一個輸入張量和一個輸出張量。Keras 會在背景檢索從input_tensor 到output_tensor 所包含的每一層,并将這些層組合成一個類圖的資料結構,即一個Model。當然,這種方法有效的原因在于,output_tensor 是通過對input_tensor 進行多次變換得到的。如果你試圖利用不相關的輸入和輸出來建構一個模型,那麼會得到RuntimeError。

函數式API 可用于建構具有多個輸入的模型。通常情況下,這種模型會在某一時刻用一個可以組合多個張量的層将不同的輸入分支合并,張量組合方式可能是相加、連接配接等。這通常利用Keras 的合并運算來實作,比如keras.layers.add、keras.layers.concatenate。

使用函數式API 來建構具有多個輸出(或多頭)的模型。訓練這種模型需要能夠對網絡的各個頭指定不同的損失函數,例如,年齡預測是标量回歸任務,而性别預測是二分類任務,二者需要不同的訓練過程。但是,梯度下降要求将一個标量最小化,是以為了能夠訓練模型,我們必須将這些損失合并為單個标量。合并不同損失最簡單的方法就是對所有損失求和。在Keras 中,你可以在編譯時使用損失組成的清單或字典來為不同輸出指定不同損失,然後将得到的損失值相加得到一個全局損失,并在訓練過程中将這個損失最小化。

注意,嚴重不平衡的損失貢獻會導緻模型表示針對單個損失值最大的任務優先進行優化,而不考慮其他任務的優化。為了解決這個問題,我們可以為每個損失值對最終損失的貢獻配置設定不同大小的重要性。如果不同的損失值具有不同的取值範圍,那麼這一方法尤其有用。比如,用于年齡回歸任務的均方誤差(MSE)損失值通常在3~5 左右,而用于性别分類任務的交叉熵損失值可能低至0.1。在這種情況下,為了平衡不同損失的貢獻,我們可以讓交叉熵損失的權重取10,而MSE 損失的權重取0.5。

層組成的有向無環圖

利用函數式API,我們不僅可以建構多輸入和多輸出的模型,而且還可以實作具有複雜的内部拓撲結構的網絡。Keras 中的神經網絡可以是層組成的任意有向無環圖(directed acyclic graph)。無環(acyclic)這個限定詞很重要,即這些圖不能有循環。張量x 不能成為生成x 的某一層的輸入。唯一允許的處理循環(即循環連接配接)是循環層的内部循環。一些常見的神經網絡元件都以圖的形式實作。兩個著名的元件是Inception 子產品和殘差連接配接。

卷積能夠在輸入張量的每一個方塊周圍提取空間圖塊,并對所有圖塊應用相同的變換。極端情況是提取的圖塊隻包含一個方塊。這時卷積運算等價于讓每個方塊向量經過一個Dense 層:它計算得到的特征能夠将輸入張量通道中的資訊混合在一起,但不會将跨空間的資訊混合在一起(因為它一次隻檢視一個方塊)。這種1×1 卷積[也叫作逐點卷積]是Inception 子產品的特色,它有助于區分開通道特征學習和空間特征學習。如果你假設每個通道在跨越空間時是高度自相關的,但不同的通道之間可能并不高度相關,那麼這種做法是很合理的。

殘差連接配接(residual connection)是一種常見的類圖網絡元件,殘差連接配接解決了困擾所有大規模深度學習模型的兩個共性問題:梯度消失和表示瓶頸。通常來說,向任何多于10 層的模型中添加殘差連接配接,都可能會有所幫助。殘差連接配接是讓前面某層的輸出作為後面某層的輸入,進而在序列網絡中有效地創造了一條捷徑。前面層的輸出沒有與後面層的激活連接配接在一起,而是與後面層的激活相加(這裡假設兩個激活的形狀相同)。如果它們的形狀不同,我們可以用一個線性變換将前面層的激活改變成目标形狀(例如,這個線性變換可以是不帶激活的Dense 層;對于卷積特征圖,可以是不帶激活1×1 卷積)。

如果特征圖的尺寸相同,在Keras 中實作殘差連接配接的方法是恒等殘差連接配接。

如果特征圖的尺寸不同,實作殘差連接配接的方法是線性殘差連接配接。

如果你對一個層執行個體調用兩次,而不是每次調用都執行個體化一個新層,那麼每次調用可以重複使用相同的權重。

這個LSTM 層的表示(即它的權重)是同時基于兩個輸入來學習的。我們将其稱為連體LSTM或共享LSTM模型。

将模型作為層:在函數式API 中,可以像使用層一樣使用模型。實際上,你可以将模型看作“更大的層”。

訓練過程中将回調函數作用于模型:回調函數(callback)是在調用fit 時傳入模型的一個對象(即實作特定方法的類執行個體),它在訓練過程中的不同時間點都會被模型調用。它可以通路關于模型狀态與性能的所有可用資料,還可以采取行動:中斷訓練、儲存模型、加載一組不同的權重或改變模型的狀态。

回調函數的一些用法示例如下所示:

1、模型檢查點:在訓練過程中的不同時間點儲存模型的目前權重。

2、提前終止:如果驗證損失不再改善,則中斷訓練(當然,同時儲存在訓練過程中得到的最佳模型)。

3、在訓練過程中動态調節某些參數值:比如優化器的學習率。

4、在訓練過程中記錄訓練名額和驗證名額,或将模型學到的表示可視化(這些表示也在不斷更新):你熟悉的Keras 進度條就是一個回調函數!

編寫你自己的回調函數:實作方式是建立keras.callbacks.Callback 類的子類。

TensorBoard,一個内置于TensorFlow 中的基于浏覽器的可視化工具。注意,隻有當Keras 使用TensorFlow 後端時,這一方法才能用于Keras 模型。

TensorBoard 的主要用途是,在訓練過程中幫助你以可視化的方法監控模型内部發生的一切。如果你監控了除模型最終損失之外的更多資訊,那麼可以更清楚地了解模型做了什麼、沒做什麼,并且能夠更快地取得進展。TensorBoard 具有下列巧妙的功能,都在浏覽器中實作:在訓練過程中以可視化的方式監控名額;将模型架構可視化;将激活和梯度的直方圖可視化;以三維的形式研究嵌入。

EMBEDDINGS(嵌入)标簽頁讓你可以檢視輸入詞表中2000 個單詞的嵌入位置和空間關系,它們都是由第一個Embedding 層學到的。因為嵌入空間是128 維的,是以TensorBoard 會使用你選擇的降維算法自動将其降至二維或三維,可選的降維算法有主成分分析(PCA)和t-分布随機近鄰嵌入(t-SNE)

殘差連接配接、标準化和深度可分離卷積,這些模式在建構高性能深度卷積神經網絡時特别重要。

标準化(normalization)是一大類方法,用于讓機器學習模型看到的不同樣本彼此之間更加相似,這有助于模型的學習與對新資料的泛化。最常見的資料标準化形式:将資料減去其平均值使其中心為0,然後将資料除以其标準差使其标準差為1。實際上,這種做法假設資料服從正态分布(也叫高斯分布),并確定讓該分布的中心為0,同時縮放到方差為1。

批标準化即使在訓練過程中均值和方差随時間發生變化,它也可以适應性地将資料标準化。批标準化的工作原理是,訓練過程中在内部儲存已讀取每批資料均值和方差的指數移動平均值。批标準化的主要效果是,它有助于梯度傳播(這一點和殘差連接配接很像),是以允許更深的網絡。對于有些特别深的網絡,隻有包含多個BatchNormalization 層時才能進行訓練。例如,BatchNormalization 廣泛用于Keras 内置的許多進階卷積神經網絡架構,比如ResNet50、Inception V3 和Xception。

BatchNormalization 層通常在卷積層或密集連接配接層之後使用。

深度可分離卷積層

深度可分離卷積層(SeparableConv2D)的作用。這個層對輸入的每個通道分别執行空間卷積,然後通過逐點卷積(1×1 卷積)将輸出通道混合,這相當于将空間特征學習和通道特征學習分開,如果你假設輸入中的空間位置高度相關,但不同的通道之間相對獨立,那麼這麼做是很有意義的。它需要的參數要少很多,計算量也更小,是以可以得到更小、更快的模型。因為它是一種執行卷積更高效的方法,是以往往能夠使用更少的資料學到更好的表示,進而得到性能更好的模型。

對于規模更大的模型,深度可分離卷積是Xception 架構的基礎,Xception 是一個高性能的卷積神經網絡,内置于Keras 中。

超參數優化

超參數優化,你需要制定一個原則,系統性地自動探索可能的決策空間。你需要搜尋架構空間,并根據經驗找到性能最佳的架構。這正是超參數自動優化領域的内容。超參數優化的過程通常如下所示。

(1) 選擇一組超參數(自動選擇)。

(2) 建構相應的模型。

(3) 将模型在訓練資料上拟合,并衡量其在驗證資料上的最終性能。

(4) 選擇要嘗試的下一組超參數(自動選擇)。

(5) 重複上述過程。

(6) 最後,衡量模型在測試資料上的性能。

這個過程的關鍵在于,給定許多組超參數,使用驗證性能的曆史來選擇下一組需要評估的超參數的算法。有多種不同的技術可供選擇:貝葉斯優化、遺傳算法、簡單随機搜尋等。訓練模型權重相對簡單:在小批量資料上計算損失函數,然後用反向傳播算法讓權重向正确的方向移動。與此相反,更新超參數則非常具有挑戰性。我們來考慮以下兩點。

計算回報信号(這組超參數在這個任務上是否得到了一個高性能的模型)的計算代價可能非常高,它需要在資料集上建立一個新模型并從頭開始訓練。

超參數空間通常由許多離散的決定組成,因而既不是連續的,也不是可微的。是以,你通常不能在超參數空間中做梯度下降。相反,你必須依賴不使用梯度的優化方法,而這些方法的效率比梯度下降要低很多。

這些挑戰非常困難,而這個領域還很年輕,是以我們目前隻能使用非常有限的工具來優化模型。通常情況下,随機搜尋(随機選擇需要評估的超參數,并重複這一過程)就是最好的解決方案,雖然這也是最簡單的解決方案。但我發現有一種工具确實比随機搜尋更好,它就是Hyperopt。它是一個用于超參數優化的Python 庫,其内部使用Parzen 估計器的樹來預測哪組超參數可能會得到好的結果。另一個叫作Hyperas 的庫将Hyperopt 與Keras 模型內建在一起。

注意 在進行大規模超參數自動優化時,有一個重要的問題需要牢記,那就是驗證集過拟合。因為你是使用驗證資料計算出一個信号,然後根據這個信号更新超參數,是以你實際上是在驗證資料上訓練超參數,很快會對驗證資料過拟合。

模型內建

模型內建是指将一系列不同模型的預測結果彙集到一起,進而得到更好的預測結果。

将分類器內建有一個更聰明的做法,即權重平均,其權重在驗證資料上學習得到。通常來說,更好的分類器被賦予更大的權重,而較差的分類器則被賦予較小的權重。為了找到一組好的內建權重,你可以使用随機搜尋或簡單的優化算法(比如Nelder-Mead 方法)。還有許多其他變體,比如你可以對預測結果先取指數再做平均。一般來說,簡單的權重平均,其權重在驗證資料上進行最優化,這是一個很強大的基準方法。想要保證內建方法有效,關鍵在于這組分類器的多樣性(diversity)。多樣性就是力量。

內建的模型應該盡可能好,同時盡可能不同。這通常意味着使用非常不同的架構,甚至使用不同類型的機器學習方法。有一件事情基本上是不值得做的,就是對相同的網絡,使用不同的随機初始化多次獨立訓練,然後內建。如果模型之間的唯一差別是随機初始化和訓練資料的讀取順序,那麼內建的多樣性很小,與單一模型相比隻會有微小的改進。

第八章 生成式深度學習

DeepDream 的過程是反向運作一個卷積神經網絡,基于網絡學到的表示來生成輸入。得到的結果是很有趣的,有些類似于通過迷幻劑擾亂視覺皮層而誘發的視覺僞影。 注意,這個過程并不局限于圖像模型,甚至并不局限于卷積神經網絡。它可以應用于語音、音樂等更多内容。

神經風格遷移

神經風格遷移是指将參考圖像的風格應用于目标圖像,同時保留目标圖像的内容。

網絡更靠底部的層激活包含關于圖像的局部資訊,而更靠近頂部的層則包含更加全局、更加抽象的資訊。卷積神經網絡不同層的激活用另一種方式提供了圖像内容在不同空間尺度上的分解。是以,圖像的内容是更加全局和抽象的,我們認為它能夠被卷積神經網絡更靠頂部的層的表示所捕捉到。

神經風格遷移可以用任何預訓練卷積神經網絡來實作,例如VGG19 網絡。VGG19 是第5 章介紹的VGG16 網絡的簡單變體,增加了三個卷積層。

神經風格遷移的一般過程如下。

(1) 建立一個網絡,它能夠同時計算風格參考圖像、目标圖像和生成圖像的VGG19 層激活。

(2) 使用這三張圖像上計算的層激活來定義之前所述的損失函數,為了實作風格遷移,需要将這個損失函數最小化。

(3) 設定梯度下降過程來将這個損失函數最小化。

風格遷移是指建立一張新圖像,保留目标圖像的内容的同時還抓住了參考圖像的風格。内容可以被卷積神經網絡更靠頂部的層激活所捕捉到。風格可以被卷積神經網絡不同層激活的内部互相關系所捕捉到。是以,深度學習可以将風格遷移表述為一個最優化過程,并用到了一個用預訓練卷積神經網絡所定義的損失。

繼續閱讀