為什么在 NLP 分類任務中選擇 CNN 呢? 它的主要好處是高效率。在許多方面,由于池化層和卷積核大小所造成的限制 (雖然可以將卷積核設置得更大),會導致丟棄大量的信息,但這并不意味著它們不是有用的模型。大家已經看到,利用 CNN 能夠有效地對相對較大的數據集進行檢測和預測情感,即使依賴 Word2vec 詞嵌入,CNN 也可以在不映射整個語言的條件下,通過較少的詞嵌入表示來運行。(本文節選自《自然語言處理實戰》一書,我們將在文末抽取五位幸運用戶,每人送出一本該書)
語言的真正力量不在于文字本身,而在于文字的間隔、順序以及詞的各種組合。有時候,語言的意義隱藏在文字的背后,蘊含在形成詞的特定組合的意圖和情感中。無論是人類還是機器,理解隱藏在文字背后的意圖,對于同理心強、情商高的傾聽者或自然語言的閱讀者而言,都是一項重要的技能。就像在思想和觀念中,正是詞之間的聯系創造了語言的深度、信息度和復雜度。除了理解單個詞的含義,詞之間還有各種各樣巧妙的組合方式,有沒有一些比 n-gram 匹配更靈活的方法,可以用來衡量這些組合詞的意義呢? 我們如何從一個詞序列中得到語義和情感——隱性語義信息,從而利用它來做一些事情呢? 更進一步地說,我們如何才能將這種隱藏的語義傳達給冰冷的計算機來生成文本呢?
“機器生成的文本”這個短語甚至讓人聯想到由空洞的金屬聲音發出的一個個詞塊。機器也許能讓人明白它表達的意思,但僅此而已。其中缺少的是什么呢? 是交流過程中人們變化的語調、流利度以及即使是在非常短暫的交談中,人們也期待表露出來的個性特點,這些微妙之處存在于字里行間以及詞的構建模式中。人們在交流時,會在他們的文字和演講中蘊含各種語言模式。偉大的作家和演講家會積極運用這些模式來制造非常好的效果。人們天生具有識別這些模式的能力,這種識別甚至是在無意識的狀態下進行的,而這也正是機器生成的文本聽起來很糟糕的原因,因為它們不具備這些模式。不過大家可以從人類生成的文本中挖掘這些模式,并將其賦給機器。
在過去的幾年里,圍繞神經網絡的研究迅速開展起來,同時出現了大量可用的開源工具,神經網絡在大型數據集中發現模式的能力得到大幅提升,并使 NLP 領域發生了巨大的轉變。感知 機迅速轉變為前饋網絡 (一個多層感知機),并由此衍生出各種變體: 卷積神經網絡和循環神經網絡,并發展出各種應用于大型數據集上模式挖掘的更為有效和準確的工具。
正如大家看到的 Word2Vec 那樣,神經網絡給 NLP 領域帶來了一個全新的方法。雖然設計神經網絡最初的目的是作為一個學習量化輸入的機器,這個領域已經從只能處理分類、回歸問題 (主題分析、情緒分析) 發展到能夠基于以前未見過的輸入來生成新文本: 將短語翻譯為另一種語言,對未見過的問題生成回復 (聊天機器人),甚至能夠生成基于特定作者風格的新文本。
完全理解神經網絡的數學原理對于使用本章介紹的工具并不重要,不過這確實有助于加強我們對神經網絡內部如何運作的認識。另外,還可以簡化神經網絡結構 (層數或者神經元數量) 來改進效果,這也有助于大家了解神經網絡如何賦予聊天機器人深度。神經網絡讓聊天機器人成為一個很好的、從表面上看不怎么健談的傾聽者。
7.1 語義理解
詞的性質和奧妙與詞之間的關系密切相關。這種關系至少有兩種表達方式。
(1) 詞序——下面兩個句子含義完全不一樣:
The dog chased the cat.
The cat chased the dog.
(2) 詞的鄰近度 (proximity)——下面句子的“shone”指的是句子另一端的“hull”:
The ship's hull, despite years at sea, millions of tons of cargo, and two mid-sea
collisions, shone like new.
這些關系的模式 (以及詞本身存在的模式) 可以從兩個方面來表示: 空間和時間。兩者的區 別主要是: 對于前者,要像在書頁上的句子那樣來處理——在文字的位置上尋找關系 ; 對于后者, 要像說話那樣來處理——詞和字母變成了時間序列數據。這兩者是密切相關的,但是它們標志著 神經網絡處理方式的一個關鍵區別。空間數據通常通過固定寬度的窗口來查看,而時間序列則可 以對于未知的時間無限延展。
基本的前饋網絡 (多層感知機) 能夠從數據中提取模式,這些模式來自與權重相關的輸入片段, 但它無法捕獲到詞條在空間或時間上的關系。不過前饋神經網絡只是神經網絡結構的開端部分,目前,自然語言處理領域中兩個最重要的模型是卷積神經網絡和循環神經網絡,以及它們的各種變體。
在圖 7-1 中,對神經網絡輸入層傳入 3 個詞條。每個輸入層神經元都與隱藏層神經元全連接,并各自具有不同的權重。
提示:怎樣將詞條傳入網絡呢? 本章使用的兩種主要方法是前面章節中使用的獨熱編碼和詞向 量。大家可以對輸入進行獨熱編碼——在向量中我們考慮的所有可能的詞位置上都標記為 0,對正在編碼的詞的位置標記為 1。或者,也可以使用第 6 章中訓練好的詞向量。總之,需要將詞表示為數字以便進行數學運算。
圖 7-1 全連接神經網絡
如果將這些詞條的順序從“See Jim run”改為“run See Jim”并將其傳入網絡中,不出所料, 會得到一個不同的結果。因此請記住,每個輸入位置與每個隱藏層神經元都有一個特定的對應權 重 (x1 與 w1 相連,x2 與 w2 相連,以此類推)。
因為詞條同時出現在一個樣本中的不同位置,所以前饋網絡可以學習詞條之間的一些特定關系,但是大家可以很容易看出,對于 5 個、10 個或 50 個詞條的長句子 (每個位置上都包含所有 可能的詞對、三元組等),這會成為一個棘手的問題。幸運的是,我們還有其他可選方案。
7.2 工具包
Python 是神經網絡工具包最豐富的語言之一。雖然很多主要的參與者 (如谷歌和 Facebook) 已經轉移到較低級別的語言以便于密集計算的實現,不過依然留下了用 Python 在早期模型上投 入大量資源進行開發的痕記。兩個主要的神經網絡架構分別是 Theano 和 TensorFlow。這兩者的 底層計算深度依賴 C 語言,不過它們都提供了強大的 Python API。Facebook 基于 Lua 語言開發 了 Torch,它在 Python 里面也有一個對應的 API 是 PyTorch。這些框架都是高度抽象的工具集, 適用于從頭構建模型。Python 社區開發了一些第三方庫來簡化這些底層架構的使用。Lasagne(Theano) 和 Skflow(TensorFlow) 很受歡迎,我們選擇使用 Keras,它在 API 的友好性和功能性 方面比較均衡。Keras 可以使用 TensorFlow 或 Theano 作為后端,這兩者各有利弊,我們將使用 TensorFlow 后端來做演示,另外我們還需要 h5py 包來保存已訓練模型的內部狀態。
Keras 默認以 TensorFlow 作為后端,運行時第一行輸出就會提醒大家目前使用的是哪個后端。大家可以通過在環境變量或腳本中修改配置文件來更換后端。Keras 的說明文檔非常清晰完整,我們強 烈建議大家在上面多花點兒時間。不過我們在這里也提供一個快速概述:Sequential() 是一個神經網絡的抽象類,用于訪問 Keras 的基本 API,compile 方法主要用于構建底層權重及它們之間的 相互關系,而 fit 方法計算訓練過程中產生的誤差并實施最重要的應用反向傳播過程。epochs、 batch_size 和 optimizer 是需要調優的超參數,從某種意義上來說,調參也是一門藝術。
遺憾的是,對于神經網絡的設計和調優,沒有一個放之四海而皆準的方法。對于特定的應用應選擇哪種適合的框架,需要大家根據自己的經驗和直覺來判斷。不過如果能找到和當前的應用 相似的實現案例,那么完全可以使用這個框架并對實現進行調整來滿足大家的需求。神經網絡框 架或者所有這些花哨的東西并沒有什么可怕的。現在我們把話題轉回到基于圖像處理的自然語言 處理。為什么還有圖像? 稍微耐心學習一下就會明白了。
7.3 卷積神經網絡
卷積神經網絡 (convolutional neural net,CNN) 得名于在數據樣本上用滑動窗口 (或卷積) 的概念。
卷積在數學中應用很廣泛,通常與時間序列數據相關。在本章中,可以不用關注其中的高階概念,只需要知道它是用一個可視化盒子在一個區域內滑動 (如圖 7-2 所示)。大家將從圖像上的滑動窗口概念入手,然后擴展到文本上的滑動窗口。總體來說,就是在較大的數據塊上設置一個滑動窗口,每次滑動時只能看到窗口范圍內的數據。
圖 7-2 卷積窗口函數
7.3.1 構建塊
卷積神經網絡最早出現在圖像處理和圖像識別領域,它能夠捕捉每個樣本中數據點之間的空間關系,也就能識別出圖像中的是貓還是狗在駕駛推土機。
卷積網絡 (convolutional net),也稱為 convnet(這個多出來的 n 很難發音), 不像傳統的前饋網絡那樣對每個元素 (圖像中的每個像素) 分配權重,而是定義了一組在圖像上移動的過濾器 (filter,也稱為卷積核、濾波器或者特征檢測器)。這就是卷積!
在圖像識別中,每個數據點的元素可以是黑白圖像中的每個像素點,取值是 1(on) 或 0(off)。
圖 7-3 電線桿圖像
也可以是灰度圖像中每個像素的強度 (如圖 7-3 和圖 7-4 所示),或者彩色圖像中每個像素的每個顏色通道的強度。
圖 7-4 電線桿圖像的像素值
卷積核會在輸入樣本中 (在這個例子中,就是圖像的像素值) 進行卷積或滑動。我們先暫 停一下,講講滑動是什么意思。在窗口“移動”的時候我們不會做任何事情,大家可以把它看作是一系列的快照,數據通過這個窗口的時候,會做一些處理,窗口向下滑動一點,就再做一 次處理。
提示:正是這個滑動 / 快照使卷積神經網絡具有高度的并行性。對給定數據樣本的每個快照都可以獨 立于其他數據樣本進行計算,后面的快照也不需要等待上一個快照。
我們談論的這些卷積核有多大呢? 卷積核窗口大小的參數由模型構建器選擇,并且高度依賴數據內容。不過其中還是有一些共性的。在圖像數據中,大家通常會看到窗口大小為 3 × 3(3, 3) 像素。在本章后面回到 NLP 上時我們會更詳細地講解窗口大小的選擇。
7.3.2 步長
注意,在滑動階段,移動的距離是一個參數,一般不會超過卷積核寬度,每個快照通常都與相鄰快照有重疊的部分。
每個卷積“走”的距離稱為步長,通常設置為 1。只移動一個像素 (或其他小于卷積核寬度 的距離) 將使進入卷積核的不同輸入在一個位置和下一個位置之間出現重疊。如果由于步長太大 而使卷積核之間沒有重疊,就會失去像素 (在 NLP 中是詞條) 與相鄰像素之間的“模糊”效果。
這種重疊有一些有趣的特性,特別是在查看卷積核如何隨時間變化的時候,這些特性非常明顯。
7.3.3 卷積核的組成
到目前為止,我們已經描述了數據上的滑動窗口,以及通過這個窗口來觀察數據,但還沒有介紹如何處理觀察到的數據。
卷積核由兩部分組成:
- 一組權重 (就像第 5 章中給神經元分配的權重);
- 一個激活函數。
如前所述,卷積核通常是 3 × 3(也有其他大小和形狀)。
提示:卷積核神經元與普通的隱藏層神經元十分相似,但是在掃描輸入樣本的整個過程中,每個卷 積核的權重是固定的,在整個圖像中所有卷積核的權重都一樣。卷積神經網絡中的每個卷積核都是 獨一無二的,但是在圖像快照中每個卷積核的元素都是固定的。
當卷積核在圖像上滑動時,每次前進一個步長,得到當前覆蓋像素的快照,然后將這些像素 的值與卷積核中對應位置的權重相乘。
假設大家用的是 3 × 3 卷積核,從左上角開始,第一個像素 (0, 0) 乘以卷積核第一個位置 (0, 0) 上的權重,第二個像素 (0, 1) 乘以位置 (0, 1) 上的權重,以此類推。
然后對像素和權重 (對應位置) 的乘積求和,并傳遞到激活函數中 (如圖 7-5 所示),通常選擇 ReLU 函數 (線性修正單元)——我們待會再討論這個問題。
在圖 7-5 和圖 7-6 中,xi 是位置 i 上的像素值,z0 是 ReLU 激活函數的輸出 z_0 = max(sum(x * w), 0) 或 z0 = max(xi × wj)), 0)。該激活函數的輸出將被記錄在輸出圖像中的一個位置上。卷積核 滑動一個步長,處理下一個快照,并將輸出值放在上一個輸出值的旁邊 (如圖 7-6 所示)。
在一個層中有多個這樣的卷積核,當它們在整個圖像上進行卷積時,會各自創建一個新的“圖像”——一個被“過濾”后的圖像。假設有 n 個卷積核,在經過這個處理之后,將得到 n 個經過 過濾的新圖像。
我們一會兒再來看看對這 n 個新圖像的處理。
圖 7-5 卷積神經網絡步驟
圖 7-6 卷積
7.3.4 填充
然而,在圖像的邊緣會發生一些有趣的事情。如果大家從輸入圖像的左上角開始一個 3 × 3 的卷積核,每次移動一個像素,當卷積核的最右側邊緣到達輸入圖像的最右側邊緣時停止,那么 輸出的“圖像”將比原圖像窄兩個像素。
Keras 提供了處理這個問題的工具。第一個策略是忽略輸出維度變小的問題。在 Keras 中,可以設置參數 padding = 'valid'。使用這種方法時,需要注意下一層輸入的維度。這種策 略的缺點是重疊位置上的內部數據點被多次傳遞到每個卷積核上,原始輸入的邊緣數據將被欠采 樣。在比較大的圖像上,這可能不是問題,但是如果把這個概念應用到 Twitter 數據上,例如, 在一個 10 個單詞的數據集上進行欠采樣,則可能會極大地改變輸出結果。
另一個策略稱為填充 (padding),即向輸入數據的外部邊緣添加足夠多的數據,使邊緣上的第一個數據點可以被視為內部數據點進行處理。這種策略的缺點是向輸入數據中添加了可能不相 關的內容,導致偏離了輸出結果。大家不需要專門去尋找生成虛假數據的模式,可以用幾種不同 的方法進行填充以盡量減少不良影響。具體做法參見代碼清單 7-1。
代碼清單 7-1 Keras 中一個卷積層的神經網絡
稍后將詳細介紹實現細節。需要對這些數據位多加注意,大家使用的工具中已經對這些問題進行了很好的處理。
還有一些策略,例如在預處理過程中通過模擬已存在的邊緣數據點來預測要填充位置上的值。不過這種策略危險性較大,NLP 應用中一般不會使用。
卷積流水線
現在有 n 個卷積核和 n 個新圖像,接下來怎么處理呢? 和大多數神經網絡應用一樣,我們從一個已標注的數據集開始,任務目標也類似: 預測一個給定新圖像的標簽。最簡單的方法是將每 個過濾后的圖像串起來并輸入到前饋層。
提示:大家可以將這些經過過濾的圖像傳遞到第二個卷積層,它也有一組卷積核。在實踐中,這是最常見的架構,稍后我們會再詳細介紹。多層卷積網絡對抽象層的學習路徑一般是: 首先是邊緣, 然后是形狀 / 顏色,最后是含義。
不管大家在網絡中添加了多少層 (卷積層或其他層),一旦得到一個最終輸出,就可以計算出誤差并通過網絡進行反向傳播該誤差。
因為激活函數是可微的,所以可以像之前一樣反向傳播并更新各個卷積核的權重。然后網絡會學習到需要什么樣的卷積核才能為給定的輸入獲得正確的輸出。
大家可以將此過程視為神經網絡在學習檢測和提取信息,以便讓后面的層能更容易地進行處理。
7.3.5 學習
就像所有神經網絡一樣,卷積核本身會以初始化為接近零的隨機值的權重開始。那么輸出的“圖像”怎樣才不會是噪聲呢? 在最初的幾輪迭代訓練中,它確實只是噪聲。
但是大家構建的分類器會根據各個輸入數據,從期望標簽中獲得一定的誤差值,并通過激活函數將輸入數據反向傳播給卷積核。對于誤差值的反向傳播,我們還需要計算誤差對輸入權重的導數。
當卷積層剛出現時,它用的是上層梯度對輸入權重的導數。這個計算和正常的反向傳播類似,對于給定訓練樣本,卷積核權重會在多個位置上輸出對應的結果。
梯度對卷積核權重的導數的具體計算超出了本書的范圍,不過可以簡單介紹一下,對于一個給定卷積核的權重,梯度是前向傳播過程中卷積的每個位置上梯度的和。這是一個相當復雜的公式,兩個求和及多個疊加式如下:
公式 7-1 卷積核權值的梯度之和
這一概念與常規的前饋網絡基本相同,即計算出每個特定權重對系統總體誤差的貢獻,然后再來決定如何更好地調整權重,使其能夠在后面的訓練樣本上盡量減小誤差。這些細節對于理解卷積神經網絡在自然語言處理中的應用并不是特別重要,但還是希望大家對如何調整神經網絡結構有直觀的認識,在本書后面的內容中會構建這些示例。
小結
- 卷積是在一個大的數據集上滑動窗口 (使關注點保持在整體的一個子集上)。
- 神經網絡可以像處理圖像一樣處理文本并“理解”它們。
- 用 dropout 來阻礙學習過程實際上是有幫助的。
- 情感不僅存在于詞中,還存在于使用的語言模式中。
- 神經網絡有很多可調參數。
附:機器學習常見工具與技術
許多自然語言處理都涉及機器學習,所以理解機器學習的一些基本工具和技術是有益處的。有些工具已經討論過,有些還沒有,但這里我們會討論所有這些工具。
D.1 數據選擇和避免偏見
數據選擇和特征工程會帶來偏見的風險 (用人類的話來說)。一旦我們把自己的偏見融入算法中,通過選擇一組特定的特征,模型就會適應這些偏見并產生帶有偏差的結果。如果我們足夠幸運能在投入生產之前發現這種偏見,那么也需要投入大量的工作來消除這種偏見。例如,必須重新構建和重新訓練整個流水線,以便能夠充分利用分詞器的新詞匯表。我們必須重新開始。
一個例子是著名的 Word2vec 模型的數據和特征選擇。Word2vec 是針對大量的新聞報道進行訓練的,從這個語料庫中選擇了大約 100 萬個 n-gram 作為這個模型的詞匯表 (特征)。它產生了一個使數據科學家和語言學家興奮的模型,后者能夠對詞向量 (如“king ? man + woman = queen”) 進行數學運算。但隨著研究的深入,在模型中也出現了更多有問題的關系。
例如,對于“醫生 ? 父親 + 母親 = 護士”這個表達式,“護士”的答案并不是人們希望的無偏見和合乎邏輯的結果。性別偏見在不經意間被訓練到模型中。類似的種族、宗教甚至地理區域偏見在原始的 Word2vec 模型中普遍存在。谷歌公司的研究人員無意制造這些偏見,偏見存在于數據中,即他們訓練 Word2vec 使用的谷歌新聞語料庫中詞使用統計的數據。
許多新聞報道只是帶有文化偏見,因為它們是由記者撰寫的,目的是讓讀者開心。這些記者描寫的是一個存在制度偏見和現實生活中人們對待事件的偏見的世界。谷歌新聞中的詞使用統計數據僅僅反映的是,在母親當中當護士的數目要比當醫生的多得多,同時在父親當中當醫 生的數目比當護士的多得多。Word2vec 模型只是為我們提供了一個窗口,讓我們了解我們創建的世界。
幸運的是,像 Word2vec 這樣的模型不需要標記訓練數據。因此,我們可以自由選擇任何喜歡的文本來訓練模型。我們可以選擇一個更平衡的、更能代表大家希望模型做出的信念和推理的數據集。當其他人躲在算法背后說他們只是按照模型做事時,我們可以與他們分享自己的數據集,這些數據集更公平地代表了一個社會,在這個社會里,我們渴望為每個人提供平等的機會。
當訓練和測試模型時,大家可以依靠自己天生的公正感來幫助決定一個模型何時可以做出影響用戶生活的預測。如果得到的模型以我們希望的方式對待所有用戶,那么我們可以在晚上睡個好覺。它還可以幫助密切關注那些與大家不同的用戶的需求,特別是那些通常處于社會不利地位的用戶。如果需要更正式的理由來證明自己的行為,大家還可以學習更多關于統計學、哲學、倫理學、心理學、行為經濟學和人類學的知識,來增強大家在本書中學到的計算機科學技能。
作為一名自然語言處理實踐者和機器學習工程師,大家有機會訓練出比人類做得更好的機器。老板和同事不會告訴大家應該在訓練集中添加或刪除哪些文本,大家自己有能力影響塑造整體社區和社會的機器的行為。
我們已經為大家提供了一些關于如何組裝一個帶有更少偏見和更公平的數據集的想法。現在,我們將展示如何使得到的模型與無偏見數據相擬合,以便它們在現實世界中精確和有用。
D.2 模型擬合程度
對于所有機器學習模型,一個主要的挑戰是克服模型過度優異的表現。什么是“過度優異” 呢? 在處理所有模型中的樣本數據時,給定的算法都可以很好地在給定數據集中找到模式。但是考慮到我們已經知道訓練集中所有給定樣本的標簽 (如果不知道其標簽表明它不在訓練集中), 因此算法在訓練樣本的上述預測結果不會特別有用。我們真正的目的是利用這些訓練樣本來構建一個有泛化能力的模型,能夠為一個新樣本打上正確標簽。盡管該樣本與訓練集的樣本類似,但是它是訓練集以外的樣本。在訓練集之外新樣本上的預測性能就是我們想優化的目標。
我們稱能夠完美描述 (并預測) 訓練樣本的模型“過擬合”(overfit)(如圖 D-1 所示)。這樣的模型將很難或沒有能力描述新數據。它不是一個通用的模型,當給出一個不在訓練集中的樣本時,很難相信它會做得很好。
圖 D-1 訓練樣本上的過擬合現象
相反,如果我們的模型在訓練樣本上做出了許多錯誤的預測,并且在新樣本上也做得很差,則稱它“欠擬合”(underfit)(如圖 D-2 所示)。在現實世界中,這兩種模型都對預測作用不大。因此,下面看看哪些技術能夠檢測出上述兩種擬合問題,更重要的是,我們還會給出一些避免上述問題的方法。
圖 D-2 訓練樣本上的欠擬合現象
D.3 數據集劃分
在機器學習實踐中,如果數據是黃金,那么標注數據就是 raritanium(某游戲里的一種珍貴 資源)。我們的第一直覺可能是獲取帶標注數據并把它們全部傳遞給模型。更多的訓練數據會產生更有彈性的模型,對吧? 但這使我們沒有辦法測試這個模型,只能心中希望它在現實世界中能產生好的結果。這顯然是不切實際的。解決方案是將帶標注的數據拆分為兩個數據集,有時是 3 個數據集: 一個訓練集、一個驗證集,在某些情況下還有一個測試集。
訓練集是顯而易見的。在一輪訓練中,驗證集是我們保留的對模型隱藏的一小部分帶標注數據。在驗證集上獲得良好性能是驗證經過訓練的模型在訓練集之外的新數據上表現良好的第一步。大家經常會看到將一個給定的標注數據集按照訓練與驗證比 80%/20% 或 70%/30% 進行劃分。測試集類似于驗證集,也是帶標注訓練數據的子集,用于測試模型并度量性能。但是這個測試集與驗證集有什么不同呢? 在組成上,它們其實沒有任何不同,區別在于使用它們的方法。
在訓練集上對模型進行訓練時,會有若干次迭代,迭代過程中會有不同的超參數。我們選擇的最終模型將是在驗證集上執行得最好的模型。但是這里有一個問題,我們如何知道自己沒有 優化一個僅僅是高度擬合驗證集的模型? 我們沒有辦法驗證該模型在其他數據上的性能是否 良好。這就是我們的老板或論文的讀者最感興趣的地方——該模型在他們的數據上的效果到底 如何?
因此,如果有足夠的數據,需要將標注數據集的第三部分作為測試集。這將使我們的讀者 (或老板) 更有信心,確信模型在訓練和調優過程中在從未看到的數據上也可以獲得很好的效果。一旦根據驗證集性能選擇了經過訓練的模型,并且不再訓練或調整模型,那么就可以對測試集中的每個樣本進行預測 (推理)。假如模型在第三部分數據上表現良好,那么它就有不錯的泛化性。為了得到這種具有高可信度的模型驗證,大家經常會看到數據集按照 60%/20%/20% 的訓練 / 驗證 / 測試比進行劃分的情形。
提示:在對數據集進行訓練集、驗證集和測試集的劃分之前,對數據集進行重新排序是非常重要的。我們希望每個數據子集都是能代表“真實世界”的樣本,并且它們需要與期望看到的每個標簽的比大致相同。如果訓練集有 25% 的正向樣本和 75% 的負向樣本,那么同樣也希望測試集和驗證集也有 25% 的正向樣本和 75% 的負向樣本。如果原始數據集的前面都是負向樣本,并且在將數據集劃分為 50%/50% 比的訓練集 / 測試集前沒有打亂數據,那么在訓練集中將得到 100% 的負向樣本,而在測試集中將得到 50% 的負向樣本。這種情況下,模型永遠不能從數據集中的正向樣本中學習。
D.4 交叉擬合訓練
另一個劃分訓練集 / 測試集的方法是交叉驗證或者 k 折交叉驗證 (如圖 D-3 所示)。交叉驗證背后的概念和我們剛討論過的數據劃分非常相似,但是它允許使用所有的帶標記數據集進行訓練。這個過程將訓練集劃分為 k 等分,或者說 k 折。然后通過將 k ? 1 份數據作為訓練集訓練模 型并在第 k 份數據上進行驗證。之后將第一次嘗試中用作訓練的 k ? 1 份數據中的一份數據作為驗證集,剩下的 k ? 1 份數據成為新訓練集,進行重新訓練。
圖 D-3 k 折交叉驗證
該技術對于分析模型的結構和尋找對各個驗證數據性能表現良好的超參數具有重要價值。一旦選擇了超參數,還需要選擇表現最好的經過訓練的模型,因此很容易受到上一節所表述的偏見的影響,因此,在此過程中仍然建議保留一份測試集。
這種方法還提供了關于模型可靠性的一些新信息。我們可以計算一個 P 值,表示模型發現的輸入特征和輸出預測之間的關系的可能性在統計上是顯著的,而不是隨機選擇的結果。如果訓練集確實是真實世界的代表性樣本,那么這將是一個非常重要的新信息。
這種對模型有額外信心的代價是,需要 k 倍的訓練時間來進行 k 折的交叉驗證。所以,如果 想要得到關于問題的 90% 的答案,通常可以簡單地做 1 折交叉驗證。這個驗證方法與我們之前做的訓練集 / 驗證集劃分方法完全相同。我們不會對模型這個對真實世界的動態描述的可靠性有 100% 的信心,但是如果它在測試集中表現良好,也可以非常自信地認為它是預測目標變量的有用模型。所以通過這種實用方法得到的機器學習模型對大多數商業應用來說都是有意義的。
D.5 抑制模型
在 model.fit() 中,梯度下降過分熱衷于追求降低模型中可能出現的誤差。這可能導致過擬合,即學到的模型在訓練集上效果很好,但是在新的未見樣本集 (測試集) 上卻效果很差。因此,我們可能希望“保留”對模型的控制。以下是 3 種方法:
- 正則化 ;
- 隨機 dropout;
- 批歸一化。
D.5.1 正則化
在所有機器學習模型中,最終都會出現過擬合。幸運的是,有幾種工具可以解決這個問題。第一個是正則化,它是對每個訓練步驟的學習參數的懲罰。它通常但不總是參數本身的一個因子。其中,L1 范數和 L2 范數是最常見的做法。
L1 正則化:
L1 是所有參數 (權重) 的絕對值與某個 λ(超參數) 乘積的和,通常是 0 到 1 之間的一個小浮點數。這個和應用于權重的更新——其思想是,較大的權重會產生較大的懲罰,因此鼓勵模型 使用更多的、均勻的權重......
L2 正則化:
類似地,L2 是一種權重懲罰,但定義略有不同。這種情況下,它是權重的平方與某個 λ 乘 積的和,這個 λ 值是一個要在訓練前選擇的單獨超參數。
D.5.2 dropout
在神經網絡中,dropout 是另一個解決過擬合的辦法——乍一看似乎很神奇。dropout 的概念是,在神經網絡的任何一層,我們都會在訓練的時候,按一定比例關閉通過這一層的信號。注意,這只發生在訓練期間,而不是推理期間。在所有訓練過程中,網絡層中一部分神經元子集都會被 “忽略”,這些輸出值被顯式地設置為零。因為它們對預測結果沒有輸入,所以在反向傳播步驟中不會進行權重更新。在下一個訓練步驟中,將選擇層中不同權重的子集,并將其他權重歸零。
一個在任何時間都有 20% 處于關閉狀態的大腦的網絡該如何學習呢? 其思想是,沒有一個特 定的權重路徑可以完全定義數據的特定屬性。該模型必須泛化其內部結構,以便該模型通過神經元的多條路徑都能夠處理數據。
被關閉的信號的百分比被定義為超參數,因為它是一個介于 0 和 1 之間的浮點數。在實踐中,從 0.1 到 0.5 的 dropout 通常是最優的,當然,這是依賴模型的。在推理過程中,dropout 會被忽 略,從而充分利用訓練后的權值對新數據進行處理。
Keras 提供了一種非常簡單的實現方法,可以在本書的示例和代碼清單 D-1 中看到。
D.5.3 批歸一化
神經網絡中一個稱為批歸一化的新概念可以幫助對模型進行標準化和泛化。批歸一化的思想 是,與輸入數據非常相似,每個網絡層的輸出應該歸一化為 0 到 1 之間的值。關于如何、為什么、 什么時候這樣做是有益的,以及在什么條件下應該使用它,仍然存在一些爭議。我們希望大家自 己去對這個研究方向進行探索。
但是 Keras 的 BatchNormalization 層提供了一個簡單的實現方法,如代碼清單 D-2 所示。
D.6 非均衡訓練集
機器學習模型的好壞取決于提供給它們的數據。只有當樣本中涵蓋了希望在預測階段的所有 情況時,擁有大量的數據才有幫助,并且數據集涵蓋每種情況僅僅一次是不夠的。想象一下我們 正試圖預測一副圖像到底是一只狗還是一只貓。這時我們手里有一個訓練集,里面包含 20 000 張貓的照片,但是狗的照片只有 200 張。如果要在這個數據集中訓練一個模型,那么這個模型很 可能只是簡單地學會將任何給定的圖像都預測為一只貓,而不管輸入是什么。從模型的角度來說, 這個結果還可以接受,對不對? 我的意思是,對 99% 的訓練樣本的預測結果都是正確的。當然, 這個觀點實際完全站不住腳,這個模型毫無價值。但是,完全超出了特定模型的范圍之外,造成 這種失敗的最可能原因是非均衡訓練集。
模型可能會非常關注訓練集,其原因很簡單,來自標記數據中過采樣類的信號會壓倒來自欠 采樣類的信號。權重將更經常地由主類信號的誤差進行更新,而來自小類的信號將被忽視。獲得 每個類的絕對均勻表示并不重要,因為模型自己能夠克服一些噪聲。這里的目標只是讓類的比例 達到均衡水平。
與任何機器學習任務一樣,第一步是長時間、仔細地查看數據,了解一些細節,并對數據實 際表示的內容進行一些粗略的統計。不僅要知道有多少數據,還要知道有多少種類的數據。
那么,如果事情從一開始就沒有特別之處,大家會怎么做呢? 如果目標是使類的表示均勻 (確 實如此),則有 3 個主要方法可供選擇: 過采樣、欠采樣和數據增強。
D.6.1 過采樣
過采樣是一種重復采樣來自一個或多個欠表示類的樣本的技術。我們以先前的狗 / 貓分類示 例為例 (只有 200 只狗,有 20 000 只貓)。我們可以簡單地重復 100 次已有的 200 張狗的圖像, 最終得到 40 000 個樣本,其中一半是狗,一半是貓。
這是一個極端的例子,因此會導致自身固有的問題。這個網絡很可能會很好地識別出這 200 只特定的狗,而不能很好地推廣到其他不在訓練集中的狗。但是,在不那么極端不平衡的情況下, 過采樣技術肯定有助于平衡訓練集。
D.6.2 欠采樣
欠采樣是同一枚硬幣的反面。在這里,就是從過度表示的類中刪除部分樣本。在上面的貓 / 狗示例中,我們將隨機刪除 19 800 張貓的圖片,這樣就會剩下 400 個樣本,其中一半是狗,一 半是貓。當然,這樣做本身也有一個突出的問題,就是我們拋棄了絕大多數的數據,而只在一個 不那么寬泛的數據基礎上進行研究。上述例子中這樣的極端做法并不理想,但是如果欠表示類本 身包含大量的樣本,那么上述極端做法可能是一個很好的解決方案。當然,擁有這么多數據絕對 是太奢侈了。
D.6.3 數據增強
數據增強有點兒棘手,但在適當的情況下它可以給我們帶來幫助。增強的意思是生成新的數 據,或者從現有數據的擾動中生成,或者重新生成。AffNIST 就是這樣一個例子。著名的 MNIST 數據集由一組手寫的 0~9 數字組成 (如圖 D-4 所示)。AffNIST 在保留原始標簽的同時,以各種 方式對每個數字進行傾斜、旋轉和縮放。
圖 D-4 最左側列中的條目是原始 MNIST 中的樣本,其他列都是經仿射 轉換后包含在 affNIST 中的數據 (圖片經“affNIST”授權)
這種特別的做法的目的并不是平衡訓練集,而是使像卷積神經網絡一樣的網絡對以其他方式 編寫的新數據更具彈性,但這里數據增強的概念仍然適用。
不過,大家必須小心,添加不能真正代表待建模型數據的數據有可能弊大于利。假設數據集 是之前的 200 只狗和 20 000 只貓組成的圖片集。我們進一步假設這些圖像都是在理想條件下拍 攝的高分辨率彩色圖像。現在,給 19 000 名幼兒園教師一盒蠟筆并不一定能得到想要的增強數 據。因此,考慮一下增強的數據會對模型產生什么樣的影響。答案并不是在任何時候都清晰無比, 所以如果一定要沿著這條路徑走下去的話,在驗證模型時請記住模型的影響這一點,并努力圍繞 其邊緣進行測試,以確保沒有無意中引入意外的行為。
最后,再說一件可能價值最小的事情,但這的確是事實: 如果數據集“不完整”,那么首先 應該考慮回到原來的數據源中尋找額外的數據。這種做法并不總是可行,但至少應該把它當作一 種選擇。
D.7 性能指標
任何機器學習流水線中最重要的部分都是性能指標。如果不知道學到的機器學習模型運行得 有多好,就無法讓它變得更好。當啟動機器學習流水線時,要做的第一件事是在任何 sklearn 機 器學習模型上設置一個性能度量方法,例如“.score()”。然后我們構建一個完全隨機的分類 / 回歸 流水線,并在最后計算性能分數。這使我們能夠對流水線進行增量式改進,從而逐步提高分數, 以便更接近最終的目標。這也是讓老板和同事確信大家走在正確的軌道上的好方法。
D.7.1 分類的衡量指標
對分類器而言,我們希望它做對兩件事: 一是用類標簽標記真正屬于該類的對象,二是不用 這個標簽去標記不屬于此類的對象。這兩件事對應得到的正確計數值分別稱為真陽 (true positive) 和真陰 (true negative)。如果有一個 numpy 數組包含模型分類或預測的所有結果,那么就可以計 算出正確的預測結果,如代碼清單 D-3 所示。
通常而言,對模型預測錯誤的計數也很重要,如代碼清單 D-4 所示。
有時,這 4 個數合并成一個 4 × 4 矩陣,稱為誤差矩陣或混淆矩陣。代碼清單 D-5 給出了混 淆矩陣中預測值和真實值的樣子。
在混淆矩陣中,我們希望對角線 (左上角和右下角) 上的數字較大,希望對角線外的數字 (左 上角和左下角) 較小。然而,正向類和負向類的順序是任意的,所以有時可能會看到這個表的數 字被調換了位置。請始終標記好混淆矩陣的列和下標。有時可能會聽到統計學家把這個矩陣稱為 分類器列聯表,但如果堅持使用“混淆矩陣”這個名字的話,就可以避免混淆。
對于機器學習分類問題,有兩種有用的方法可以將這 4 種計數值中的一些指標組合成一個性 能指標: 正確率 (precision) 和召回率 (recall)。信息檢索 (搜索引擎) 和語義搜索就是此分類 問題的例子,因為那里的目標是將文檔分為 (和輸入查詢) 匹配或不匹配兩類。第 2 章中,我們 學習過詞干還原和詞形歸并如何能夠提高召回率,但同時降低了正確率。
正確率度量的是模型在檢測所感興趣類的所有對象 (稱為正向類) 的能力,因此它也被稱為 正向預測值 (positive predictive value)。由于真陽是預測正確的正向類樣本數目,而假陽是錯誤地 標記為正向類的負向類樣本數目,因此可以按照代碼清單 D-6 所示來計算正確率。
上述例子中的混淆矩陣給出了約 57% 的正確率,因為在所有預測為正向類的樣本中有約 57% 是正確的。
召回率和正確率類似,它也被稱為靈敏度、真陽率或查全率。因為數據集中的樣本總數是真 陽 (true positive) 和假陰 (false negative) 的和,所以可以計算召回率,即檢測到的預測正確的 正向類樣本占所有樣本的百分比,代碼如代碼清單 D-7 所示。
這就是說上面例子中得到的模型檢測到了數據集中 80% 的正向類樣本。
D.7.2 回歸的衡量指標
用于機器學習回歸問題的兩個最常見的性能評價指標是均方根誤差 (RMSE) 和皮爾遜相關系數 (R2)。事實證明,分類問題背后實際上是回歸問題。因此,如果類標簽已經轉換為數字 (就像我們在上一節中所做的那樣),就可以在其上使用回歸度量方法。下面的代碼示例將復用上一節的那些預測值和真實值。RMSE 對于大多數問題是最有用的,因為它給出的是預測值與真實值可能的相差程度。RMSE 給出的是誤差的標準偏差,如代碼清單 D-8 所示。
皮爾遜相關系數是回歸函數的另一個常見性能指標。sklearn 模塊默認將其作為.score() 函數附加到大多數模型上。如果大家不清楚這些指標如何計算的話,那么應該手動計算一下找找感覺。相關系數的計算參見代碼清單 D-9。
由此可見我們的樣本預測值與真實值的相關度只有 28%。
D.8 專業技巧
一旦掌握了基本知識,那么下面這些簡單的技巧將有助于更快地建立良好的模型:
- 使用數據集中的一個小的隨機樣本子集來發現流水線的可能缺陷 ;
- 當準備將模型部署到生產環境中時,請使用所有的數據來訓練模型 ;
- 首先應該嘗試自己最了解的方法,這個技巧也適用于特征提取和模型本身 ;
- 在低維特征和目標上使用散點圖和散點矩陣,以確保沒有遺漏一些明顯的模式 ;
- 繪制高維數據作為原始圖像,以發現特征的轉移 1;
- 當希望最大化向量對之間的差異時,可以嘗試對高維數據使用 PCA(對 NLP 數據使用 LSA);
- 當希望在低維空間中進行回歸或者尋找匹配的向量對時,可以使用非線性降維,如 t-SNE;
- 構建一個 sklearn.Pipeline 對象,以提高模型和特性提取器的可維護性和可復用性 ;
- 使超參數的調優實現自動化,這樣模型就可以了解數據,大家就可以花時間學習機器學習。
超參數調優: 超參數是所有那些確定流水線性能的值,包括模型類型及其配置方式等。超參數還可 以是神經網絡中包含的神經元數和層數,或者是 sklearn.linear_model.Ridge 嶺回歸模型中 的 alpha 值。超參數還包括控制所有預處理步驟的值,例如分詞類型、所有忽略的詞列表、TF-IDF 詞匯表的最小和最大文檔頻率、是否使用詞形歸并、TF-IDF 歸一化方法等。
超參數調優可能是一個十分緩慢的過程,因為每個實驗都需要訓練和驗證一個新模型。因此,在搜索范圍廣泛的超參數時,我們需要將數據集減小到具有代表性的最小樣本集。當搜索接近滿足需求的最終模型時,可以增加數據集的大小,以使用盡可能多的所需數據。
優化流水線的超參數是提高模型性能的方法。實現超參數調優自動化可以節省更多的時間來閱讀本書這樣的書籍,或者可視化和分析最后的結果。當然大家仍然可以通過直覺設置要嘗試的超參數范圍來指導調優。
提示:超參數調優最有效的算法是 (從最好到最差):
(1) 貝葉斯搜索 ;
(2) 遺傳算法 ;
(3) 隨機搜索 ;
(4) 多分辨率網格搜索 ;
(5) 網格搜索。
但是無論如何,在大家進入夢鄉時工作的所有計算機搜索算法,都比手動猜測一個個新參數好。
本文轉自 公眾號:AI前線 ,節選自《自然語言處理實戰》,點擊閱讀原文
審核編輯:符乾江
-
人工智能
+關注
關注
1806文章
49007瀏覽量
249274 -
機器學習
+關注
關注
66文章
8501瀏覽量
134572
發布評論請先 登錄
評論