- 用Python實現深度學習框架
- 張覺非 陳震
- 6442字
- 2021-04-19 16:09:31
第一部分 原理篇
第 1 章 機器學習與模型
在本書中,我們用Python語言實現了一個深度學習框架,它叫作MatrixSlow。我們會圍繞這個框架講解機器學習和深度學習的相關原理與技術。機器學習框架的核心功能是搭建并訓練模型。基于計算圖的深度學習框架更是擁有異常靈活的能力,允許人們搭建各種模型。我們在本書中就用MatrixSlow框架搭建并訓練了多種常見且典型的模型,并將它們用于一些實際的機器學習問題。
用理解指導建造,以建造加深理解,這是本書的主旨。理解,必須從最基本的概念開始,比如模型。這是一個所有人耳熟卻未必能詳的名詞,這個抽象的詞匯在很多不同的領域被大量使用,但它的含義卻變得模糊且混亂。比如,當人們在交流中使用“模型”一詞時,很難保證他們就其含義達成了一致。因此,我們首先要做的就是明確一些基本概念,特別是模型這個詞的確切含義。本章從基礎入手,帶領讀者了解機器學習、模型、樣本以及訓練等概念。
1.1 模型
很多領域都有模型,我們關心的是機器學習領域的模型。在機器學習領域內部,也可以按不同的標準將模型分成不同種類。本書討論的是其中一個子類別,即神經網絡。好了,現在我們已經將模型限制在一個比較狹窄的范圍中了。我們可以從外部和內部這兩種視角來看待模型:從外部來看,模型是一個黑盒子,它接受若干數值為輸入,產生若干數值為輸出,如圖1-1所示。
圖1-1 模型——黑盒子
作為輸入的數值,稱為特征,它們描述現實世界的一個事物。例如,一個模型接受3個輸入,分別是一個人的身高、體重和體脂率,比如:
身高
體重
體脂率
用這3個特征代表一個人,它們構成了一個樣本(sample)。我們有意將特征列在括號中,其意義將在后文揭曉。模型接受這3個特征后,在盒子中做某些計算,最后輸出一個數值0或1:模型輸出0,表示它判斷樣本是一位女性;模型輸出1,表示它判斷樣本是一位男性。剛剛的樣本是一位女性,如果模型輸出0,則判斷正確。再看一個男性樣本:
身高
體重
體脂率
對于這個樣本,若模型輸出1,則判斷正確。如果模型對于任意一個樣本都能以較大的可能性做出正確判斷,那它就是一個好模型。總結一下,我們構造的這個模型接受3個特征:身高、體重和體脂率。進行一番計算后產生一個輸出,即0或1,表示它對樣本所表示的人的性別做出的判斷。現在我們打開黑盒子,看看它內部是怎么運作的。我們令模型在內部做這樣的運算:
為什么要如此計算呢?因為我們認為男性的身高普遍高于女性,用權重1.0乘以身高,男性很可能會得到較大的值,女性很可能會得到較小的值。同樣,男性的體重普遍大于女性,因此也將權重1.0賦予體重。另外,女性的體脂率普遍高于男性,將權重 - 100.0賦予體脂率,女性會得到更小(絕對值更大)的負值。體脂率在量級上是身高或體重的百分之一(例如0.17對182或72),所以權重的絕對值較大(100.0),這使體脂率的作用不至于被其他特征淹沒。
將身高、體重和體脂率乘上各自的權重后相加,男性很可能得到較大的值,女性很可能得到較小的值。若模型判斷該值大于200,則輸出1,判斷為男性;若該值小于200,則輸出0,判斷為女性。為什么以200為分界點呢?因為就手頭的兩個樣本來說,男性樣本計算出來的值是237,女性樣本計算出來的值是189,以200為分界點恰好能分開這僅有的兩個樣本。現在抽象一步,用符號表示特征:
身高, 體重, 體脂率
3個權重這樣表示:
模型還有一個分界點200,這樣表示:
為什么要帶個負號,馬上就會清楚。、
、
和
稱為模型的參數:
、
、
是特征的權重(或稱權值),
是閾值(或稱偏置)。模型所做的計算就是:
挪到不等號左側后,分界點變成了0,這就是為什么令
等于200。對于一個函數,如果其輸入大于等于0時輸出1,輸入小于0時輸出0,這樣的函數稱為階躍函數(step function)。把階躍函數記為
,于是模型就可以表示為:
可以用一種圖示法表示這個模型,如圖1-2所示。特征與各自的權值相乘,再與偏置 相加,結果被送給階躍函數。這就是本書的第一個也是最簡單的模型。圖1-2這樣的圖稱為計算圖。本書涉及的模型都可以用計算圖描述。
圖1-2 模型的圖示法
1.2 參數與訓練
、
、
和
是模型的參數,式(1.1)是模型的“形式”。在形式固定的前提下,參數決定模型的行為,即對什么樣的輸入產生什么樣的輸出。將3個權值和3個特征括在括號中,是將它們看作向量(vector)。3個特征構成輸入向量
:
3個權值構成權值向量 :
每一個特征或權值就是輸入向量或權值向量的分量。輸入向量和權值向量的對應分量的乘積之和,稱為輸入向量和權值向量的內積(或點積):
這樣模型就可以表示為:
我們可以給這個模型一個名字,叫它ADALINE(Adaptive Linear Neuron,自適應線性神經元)。這個名字不是我們發明的,它誕生于1960年,是神經網絡先驅Bernard Widrow和他的研究生Ted Hoff于斯坦福大學提出的。
向量、內積與分界面
如果采用一個坐標系,比如三維坐標系,一個向量就表示坐標系中的一個點。例如向量
,它的3個分量給出點在3個坐標軸上的坐標。從原點畫一個指向該點的箭頭,該箭頭就由向量決定。箭頭既有方向也有長度,所以向量是一個既有方向也有大小(長度)的量,如圖1-3所示。
圖1-3 向量
可以證明,內積
等于向量
的長度乘以向量
的長度,再乘以它們之間夾角的余弦,如圖1-4所示。
圖1-4 內積
容易看出,向量
的長度(
)乘上夾角
的余弦就是向量
朝向量
方向上投影的長度。
等于
朝
方向上的投影長度再乘上
的長度(
)。
ADALINE首先計算輸入向量
與權值向量
的內積,再加上偏置
,根據結果是否大于0而輸出1或0,所以
就是兩種輸出之間的分界。因為
意味著
朝
方向上的投影長度等于
,所以ADALINE對朝
方向上的投影長度大于
的
輸出1,對朝
方向的投影長度小于
的
輸出0,如圖1-5所示。
圖1-5 ADALINE的分界面
這里展示的是三維的情況,更高維依此類推。假如
朝
方向上的投影長度等于
,則
,即
。
落在ADALINE的分界面上,ADALINE對
的輸出是1;
朝
方向上的投影長度大于
,即
,ADALINE對
的輸出是1;
朝
方向上的投影長度小于
,即
,ADALINE對
的輸出是0。
我們之前給權重和偏置取了一組特定的值,此時ADALINE能將僅有的男/女兩個樣本正確分類。若此時來了一位身材高挑的女士,具有這樣的特征(抽象一點,不再使用漢字了):
ADALINE對她的計算結果是13,大于0,輸出1,結果為男性,判斷錯誤。面對此錯誤,需要對模型進行修正。在不改變模型“形式”的前提下,只能調整模型的參數——權值和偏置。如何調整呢?我們發現,模型對新來的這位女士樣本的輸出過大(),我們需要減小這個值。為了達到這個目的,可以這樣做:
● 如果 大于0,則減小
(
);
● 如果 小于0,則增大
(
);
● 減小 。
于是,可以這樣調整權值和偏置:
式(1.3)利用 的符號控制
的更新(增大還是減小)。
是控制調整強度的參數。如果令
為0.0005,那么更新后的權值向量是:
更新后的偏置 是 -200.0005。用這套新參數進行計算:第一位女士是 -26.43,小于0;第一位男士是19.17,大于0;第二位女士是 -3.65,雖然有點危險但畢竟小于0。經過參數調整的模型能將最初的男士、女士以及新來的女士都正確分類。
假如此時又來了一位相對瘦小的男士,身高和體重較低,現在的ADALINE又很可能對他誤判(為免煩瑣,我們不給出具體的數值,只定性地說明),此時需要繼續調整模型參數以使它正確分類這位男士。與第二位女士的情況相反,應該增大模型對這位男士的輸出。可以將這兩種情況統一起來:
取1或0,表示樣本的真實性別(男/女)。在機器學習中,這稱作標簽(label)。對于第二位女士,最初的模型對她的輸出是
,但她的真實性別是
,于是
,式(1.4)等同于式(1.3)。對于第二位男士,假如經過第一次調整的模型對它的輸出是
,而他的真實性別是
,于是
,
變成
,即更新值多了一個負號,式(1.4)起到了增大模型對該男士性別輸出的作用。如果模型對樣本判斷正確,則
與標簽一致,即
,式(1.4)不改變參數。其實,
正是模型的判斷與真實標簽之間的差異——誤差。
現在模型對兩位男士和兩位女士都判斷正確。大功告成了么?當然沒有,這個樣本量(4)太少了。要統計兩性的身高、體重和體脂率差異,你肯定不會只測量4個人。也許你會收集含一個、幾十個乃至幾百個人的樣本集。機器學習模型也一樣,不可能只根據4個樣本就調整出一個足夠好的模型。“足夠好”是指模型能夠正確分類將來遇到的樣本。因此我們需要收集一個帶有真實性別標簽的樣本集,其中有男有女,每個樣本包含一個人的身高、體重和體脂率。這樣的樣本集就是訓練集,其中的帶標簽樣本就是訓練樣本。
依次對每個訓練樣本計算模型的輸出,根據輸出與標簽之間的誤差調整模型參數,這個過程稱作“訓練”。 是針對訓練的參數(注意不是模型參數),它是一個“超參數”。前文中,每一次參數調整后,模型對新的和舊的樣本都能正確分類,這在真實的訓練中是不一定能做到的(幾乎不能)。試想,如果超參數
設置得再小一些,調整后的模型對高挑女士可能仍然判斷錯誤。
但無論如何,參數已經朝著正確的方向前進了一點,這就是這一次調整的目的。全部訓練樣本依次送給模型,每一次都試著向正確的方向調整參數。所有樣本用完后,可以再回過頭來重復這個過程,直到模型足夠好。關于模型的訓練,這里只是勾勒個大概,開個頭。訓練背后更深刻的原理以及很多復雜的事項,本書后面會詳細展開。
ADALINE只是機器學習模型的一種,剛剛描述的訓練方法也只是眾多訓練算法中的一個。我們以一個特例引入了這些概念,現在有必要及時簡述一下它們的常規理解:模型是一個函數,它接受若干數值作為輸入,這些數值稱作特征。控制模型行為的是它的參數。訓練集是許多樣本,每個樣本包含特征和類別標簽。根據模型輸出與標簽之間的誤差調整模型參數,這個過程稱作訓練。訓練也受一些參數控制,有些模型的結構也受一些參數的影響,這類參數稱為超參數。不同于模型參數,超參數不在訓練過程中調整。以ADALINE為例,模型的訓練過程如圖1-6所示。
圖1-6 ADALINE的訓練過程
1.3 損失函數
為了更形象地理解,我們把訓練樣本的標簽(例如男和女或1和0)看作做題時的正確答案,或者學生們的教師,它們對模型的訓練起一個指引的作用。在正確答案的指引下,訓練算法根據誤差調整模型參數。我們可以看到,ADALINE用階躍函數將輸出限定為1或0,但是這樣就掩蓋了一些信息。假如模型對于一位男性樣本計算出 -21,對于另一位男性樣本計算出 -0.7,經過階躍函數后模型對他們都輸出0。雖然都判斷錯誤,但是顯然對第一位男性樣本錯誤更嚴重些。錯誤的嚴重程度應該利用起來,就好比一位同學58分,另一位同學20分,不能因為他們都不及格而等同視之。所以我們要繞開階躍函數,直接用階躍函數之前的模型輸出與標簽比較。我們可以嘗試構造一個函數,這個函數接受標簽值和(不經階躍函數的)模型輸出,能衡量模型的錯誤程度。
首先,不再使用1/0標識男/女,而用 或
標識男/女(標簽只是一個標識,可隨意安排)。如果樣本是男性,若
為正,則分類正確,為負則分類錯誤,且該負數越小錯誤越嚴重;如果樣本是女性,若
為負,則分類正確,為正則分類錯誤,且該正數越大錯誤越嚴重。我們構造的函數應該在分類正確時絕對值較小,分類錯誤時絕對值較大,且錯誤越嚴重絕對值越大。具有這樣行為的函數能衡量模型的錯誤程度,稱為損失函數(loss function)。我們構造這樣一個損失函數:
分析一下 的行為:當樣本是男性時,標簽
是1,如果
是正數,則模型分類正確,此時
大于等于0,損失值是0;如果
是負數,則模型分類錯誤,此時
小于0,損失值是
,損失值大于0且
的絕對值越大錯誤越嚴重,損失值就越大。
當樣本是女性時,標簽 是 -1,如果
是負數,則模型分類正確,此時
大于等于0,損失值是0;如果
是正數,則模型分類錯誤,此時
是負數,損失值是
,損失值大于0且
越大錯誤越嚴重,損失值就越大。
為了讓模型表現更好,需要讓模型對每一個訓練樣本的損失值盡量小。訓練時,每接受一個訓練樣本,都向著降低損失值的方向調整模型參數,使損失值減小。上面構造的 只是損失函數的一種,還有許多其他針對不同問題和模型的損失函數,本書后面會詳細展開。
1.4 計算圖的訓練
在圖1-2中,我們已經用計算圖來表示ADALINE模型了。現在擴展一下該計算圖,將損失函數也加入其中,如圖1-7所示。
圖1-7 帶損失函數的ADALINE計算圖
相比圖1-2,圖1-7新添的部分是將標簽()與模型的輸出(
)相乘,之后根據式(1.5)計算損失值
。
訓練開始前,隨機初始化參數 、
、
和
。訓練時,依次取訓練樣本,把3個特征和標簽賦給
、
、
和
,計算出損失值
,然后調整
、
、
和
以減小
。如何調整呢?請看圖1-8。
圖1-8 ADALINE的訓練(反向傳播)
圖1-8初看上去有些復雜,我們來解釋一下。當一個樣本的特征和標簽被賦給和 節點后,沿著計算圖向前依次計算各個節點。具體來說,每個節點知曉自身的計算方法,當它的各個父節點的值被計算出來后,就可以計算它自身的值了。它的各個子節點也會等待并利用其值計算它們自身的值。最終,階躍函數節點
的值和損失值節點
的值都會被計算出來。
這個前向(forward)過程結束后,每個節點都保存本輪計算中自身的值。例如,左上角的 節點,它根據父節點
和
的值(身高和身高的權重)計算并保存自身的值:
。其他節點也都一樣。
之后,開始一個反向(backward)過程,也是調整參數的過程。損失值節點 將二元組
傳給它的父節點(這里的斜杠
表示或)。二元組的第一個值是1,若其父節點的值小于0,第二個值取 -1;若父節點的值大于等于0,第二個值取0。
右上角的 節點將收到的二元組的兩個值1和 -1/0相乘,得到 -1/0。
節點把 -1/0作為第一個值,將
作為第二個值構造二元組
,傳給它的父節點(
節點)。
節點將二元組的兩個值相乘,得到
,構造二元組
,傳給它的4個父節點:3個
節點和
節點。
3個 節點的動作相同,下面以第一個節點為例來說明。它收到二元組
,相乘得到
,作為第一個值,以父節點
的值為第二個值,組成二元組
,傳給父節點
。
節點將二元組的兩個值相乘,得到
。類似地,
節點和
節點將算出
或
。
節點也收到二元組
,相乘得到
。
最后,每個參數節點用超參數 乘以得到的值,從自己的當前值中減去該值,完成本次更新,即:
太抽象了,是吧?以男性樣本為例,若右上角的 節點的值大于等于0,則模型分類正確。此時
節點向前傳的二元組的第二個值是0,一直傳到最前面,各個參數節點得到的也是0,參數值不更新。
若對于這個男性樣本,右上角的 節點的值小于0,
節點向前傳的二元組的第二個值是 -1,最前面的參數節點
的更新量是
。如果
大于0,則
變大;如果
小于0,則
變小。這兩種情況都是使
變大,將參數往分類正確的方向上修正。對
的更新也是這個效果。
再回顧一下式(1.4),樣本為男性時,若模型分類正確,則 為0,參數不更新;若模型分類錯誤,則
為 -1,參數更新量為
(對
)或
(對
)。可見,更新式(1.6)等價于更新式(1.4)。我們描述的是同一種ADALINE訓練算法,這種算法的動機和目的就是如1.2節描述的那樣。那么,為什么要大費周章呢?那些向后傳播的二元組中的數值是什么意思呢?這樣更新參數能否減小損失值
呢?請接著往下看。
1.5 小結
本章是本書的開篇,我們從一個簡單具象的例子引入了機器學習的相關概念。我們構造了一個根據身高、體重和體脂率判斷男性和女性的問題,接著描述了一個模型——ADALINE,這個模型是神經網絡的先驅。以當代視角看,ADALINE是一個以階躍函數為“激活函數”的神經元。本書后面介紹的所有模型都在神經網絡這個范疇之內,而機器學習領域還有其他類型的模型。
模型的行為受控于自身內部的參數。訓練集是一個包含許多帶類別標簽的樣本的集合。將模型對樣本的判斷結果與正確類別進行比對,根據誤差調整模型參數,盡量將模型調整到能夠正確分類訓練樣本以及未來遇到的新樣本的狀態,這就是有監督學習。所謂有監督,是指有正確類別標簽作為“教師”。有監督學習是機器學習模型訓練方法中的一種。
訓練ADALINE時,將樣本一個一個送給模型,計算出模型的輸出和損失函數值。損失函數值衡量模型對樣本分類的錯誤程度,分類正確時損失值小,分類錯誤時損失值大,且錯誤越嚴重損失值越大。根據損失值將一些信息(二元組)沿著計算圖反向傳播,參數節點根據收到的信息更新自身的值。我們發現,這種更新算法與基于模型結構和含義的更新方法是一致的。
但本章沒有說明的是:沿著計算圖反向傳播的那些信息究竟是什么,為什么這樣更新參數有助于降低模型對當前樣本的損失值。超前一點說,這種方法就是基于計算圖反向傳播的隨機梯度下降算法。本章使讀者大致認識了計算圖,在下一章中我們將詳細介紹計算圖,并講解梯度下降法和計算圖反向傳播的原理和實現。
- Clojure Programming Cookbook
- Unreal Engine Physics Essentials
- TypeScript Blueprints
- Linux C/C++服務器開發實踐
- Instant RubyMotion App Development
- Java程序設計:原理與范例
- Mastering Apache Maven 3
- Python數據結構與算法(視頻教學版)
- Corona SDK Mobile Game Development:Beginner's Guide(Second Edition)
- C++寶典
- Building Microservices with .NET Core
- Natural Language Processing with Java and LingPipe Cookbook
- Unity 2018 Augmented Reality Projects
- Emotional Intelligence for IT Professionals
- Java EE Web應用開發基礎