一小時神經網路從入門到精通(放棄)
本文主要是學習BP神經網路的一個總結,其本身也是機器學習中比較基礎、適合入門的模型。
目前本人對於機器學習也還只是入門狀態,對於很多名詞仍然是一知半解(感覺機器學習中的很多術語本身也是模稜兩可的),對於很多公式也是不求甚解,因此這篇文章是嘗試用自己的語言和理解來複述所學習到的知識,如果有錯誤之處還望大牛們不吝斧正。
霍金說過每多一個數學公式,就會少一半的讀者,因此這裡也會盡量少用公式,要用也只用簡單易懂的公式。而且個人覺得神經網路中的很多公式是可以感性地去認識的,能完全明白推導過程自然最好,但在不求甚解的狀態下能達到感性的認知也未必不是一個快速掌握的好方法。
另外本文中用到了不少矩陣相關的知識,忘記了的同學可以看附錄中的整理。
神經元與激勵函式
神經元
神經元是神經網路的基本組成,如果把它畫出來,大概就長成下面這樣:
圖中神經元左邊的x表示對神經元的多個輸入,w表示每個輸入對應的權重,神經元右邊的箭頭表示它僅有一個輸出。
當然神經元也有很多種,下面介紹兩種比較基礎的。
神經元1:感知器
神經網路技術起源於上世紀五、六十年代,當時叫感知機(perceptron),其中的單個神經元我們可以叫作感知器。感知器的特點具有濃厚的時代氣息:其輸入輸出都是二進位制形式的(據說由於計算技術的落後,當時感知器傳輸函式是用線拉動變阻器改變電阻的方法機械實現的)。
如上圖所示,感知器有多個二進位制輸入(值只能是0或1)X1、X2..Xn,每個輸入有對應的權值W1、W2..Wn(圖中沒畫出來),將每個輸入值乘以對應的權值再求和( ∑XjWj ),然後與一個閾值(threshold) 比較,大於閾值則輸出1、小於閾值則輸出0。 寫成公式的話如下:
如果把公式寫成矩陣形式,再用b來表示負數的閾值(即b=-threshold),那就得到了如下公式:
舉個例子
例如你所在的城市將有一個你的偶像的演唱會,你正決定是否觀看,你可能會通過以下三個方面來權衡你的決定:
天氣好嗎?
你的好基友是否願意陪你去?
是否這個活動距離公共交通很近?(你自己沒車)
我們將這三個因素用對應的二進位制變數x1,x2和x3表示。比如,當天氣還不錯時,我們有x1=1,天氣不好時x1=0;相似的,如果好基友願意去,x2=1,否則x2=0;對於公共交通x3同理賦值。
然後根據你的意願,比如讓天氣權重 w1=6,其他條件權重分別為w2=2,w3=2。權重w1值越大表示天氣影響最大,比起好基友加入或者交通距離的影響都大。最後,假設你選擇5做為感知器閾值(即b為-5),按照這種選擇,這個感知器就能實現這個決策模型:當天氣好時候輸出1,天氣不好時候輸出0,無論你的好基友是否願意去,或者交通是否比較近。
神經元2:Sigmoid神經元
先來認識一個函式:Sigmoid函式,這個單詞在某些工具上直譯是“乙狀結腸”、也還真有某些資料把Sigmoid神經元叫作乙狀結腸神經元的。 其實它是一個常用的“S”型函式,可以把變數對映到(0,1)區間內,其公式如下:
它的函式影像是如下圖如示的“S”型:
那麼Sigmoid神經元是什麼呢?與感知器有什麼區別?
首先,在Sigmoid神經元中,輸入的值不再是二進位制,而是0到1之間的任意值。即Xi取值是0到1之間的任意實數。
其次,而Sigmoid神經元的輸出也不再是0或1,而是 σ(wx+b)。 注意"wx+b"是簡寫(矩陣)形式,請對照上面的感知器的公式。
因此我們可以得出Sigmoid神經元的公式:
可以發現當z=w?x+b是一個大的正數時,那麼σ(z)≈1,而當z=w?x+b是一個很小的負數(“絕對值很大的負數”比較好理解)時,σ(z)≈0。處於這兩種情況時,Sigmoid神經元的輸出跟感知器是很接近的。只有當w?x+b在一個適度的值,sigmoid神經元和感知器偏差才較大。
激勵函式
神經元的輸入和輸出之間具有函式關係,這個函式就稱為激勵函式。所以上面提到的Sigmoid函式就是激勵函式的一種,感知器的那個函式也可以稱為閾值(或階躍)激勵函式。
激勵函式也叫點火規則,這使它與人腦的工作聯絡起來。當一個神經元的輸入足夠大時,就會點火,也就是從它的軸突(輸出連線)傳送電訊號。同樣,在人工神經網路中,只要輸入超過一定標準時才會產生輸出,這就是點火規則的思想。
神經網路的結構
神經網路簡單地說就是將多個神經元連線起來、組成一個網路。 本文介紹的是最簡單、歷史悠久的一種:“多層感知機”(但我們講的這個它裡面的神經元並不是感知器、而是Sigmoid神經元,名詞混亂+1),或稱之為“多層向前神經網路(Multilayer Feed-Forward Neural Network)”,它的特點是有多層(廢話),且神經元之間是全連線的,即後一層的神經元會連線到前一層的每個神經元(這裡定義下從輸入層到輸出層為從“後”向“前”)。
一個多層感知機的示意圖如下,網路的最左邊一層被稱為輸入層,其中的神經元被稱為輸入神經元。最右邊及輸出層包含輸出神經元,在這個例子中,只有一個單一的輸出神經元,但一般情況下輸出層也會有多個神經元。中間層被稱為隱含層,因為裡面的神經元既不是輸入也不是輸出。
訓練神經網路的意義
現在神經元有了,神經網路的結構也有了,現在回到核心的問題上來:我們拿神經網路幹什麼? 要怎樣使它做到?
訓練的目標
按照常識、用人話來說,神經網路的作用就是我們預先給它大量的資料(包含輸入和輸出)來進行訓練,訓練完成後,我們希望它對於將來的真實環境的輸入也能給出一個令我們滿意的輸出。
損失函式/代價函式(Loss函式)
那麼怎樣用數學的方式來表示一個輸出有多麼令我們滿意呢? 這裡我們引入損失函式(或稱代價函式、Loss函式)的概念。
現假設有n組包含了輸入和真實結果(或稱期望結果、期望輸出)的樣本資料,對於每組輸入,我們的神經網路輸出的結果記為fi,真實結果(期望結果)記為yi。
使用數學工具中的MAE(Mean Absolute Error,平均絕對誤差),可以非常直觀地表達出輸出結果和真實結果的偏差,因此我們可以用MAE來寫出一個下面這樣的Loss函式,Loss值越大、說明神經網路的輸出結果越遠離我們的期望。
也可以用MSE(Mean Squared Error,均方誤差)作為損失函式,MSE能更好地評價資料的變化程度,簡單地說因為平方了一下、偏差是會被放大的。
將Sigmoid神經元的表示式f(x)=σ(wx+b)代入上面的損失函式中,可以發現x(輸入)是固定的,yi(期望結果)也是固定的,讓我們感性地想象一下:實際上影響Loss的只有w和b,而最重要的任務也就是尋找w和b使得Loss最小。
再具象一點,其實對神經網路進行訓練的目的就是為每個神經元找到最適合它的w和b的值,從而使得整個神經網路的輸出最接近我們的期望(說“最”其實有點違反廣告法,神經網路最終達到的很難說是問題的最優解)。
注:下面將真正用到的損失函式
在實際中,為了方便求導,一般使用如下的Loss函式:
梯度下降
根據上面的結論,可以把損失(Loss)記作C,而C又只與w和b有關,那麼可以看成C是一個關於w和b的函式,如下圖所示。注意由於神經網路中其實有大量的“w”和“b”(回憶一下、每個神經元都有多個權重和一個閾值),因此這裡也需要感性的認知。
如果把圖畫出來,它可能是下面這樣的:
我們的目標是找到w和b使C最小,當然上面這張圖很容易看出來合適的w和b在哪,但當面對更復雜的情況時、比如下圖這樣的,應該如何快速地找到C最小的點呢?
這裡我們引入梯度下降演算法,原理很簡單:把上圖看作是一個丘陵地帶,想象我們有一個球放在某個位置,讓它“自然地向低處滾”,滾得越低,C就越小,我們就越高興。
那麼怎樣使得它往低處滾呢? (注意這裡要搬出全文中第一個比較燒腦的概念了) 微分法則告訴我們,當w移動Δw、b移動Δb時,有:
由於C表示的是損失,我們想讓球往低處滾,當然是希望C不斷變小,那ΔC應該恆為負,那麼Δw、Δb應該如何取值呢? 梯度下降法是這麼設計的:
可以看出如此取值可以使ΔC恆為負,其中的η稱為學習率。
那麼現在問題變成了?C/?w、?C/?b,即 C對w 和 C對b 的偏導,這兩個鬼東西要怎麼求?
反向傳播
反向傳播(back propagation)是在這種場景下快速求解?C/?w、?C/?b的演算法,用了這個演算法的多層感知機--也就是這篇文章講的神經網路--也就叫作BP神經網路(名詞混亂+1)。
這一章包含了比較複雜的公式推導過程,個人認為不瞭解其細節也沒有關係、可以跳過這一章(只看“正向傳播”一節就行),只要知道有個經典的反向傳播演算法可以快速求解?C/?w、?C/?b,從而算出Δw和Δb,使得ΔC恆為負、即使得Loss越來越小即可。
正向傳播
正向傳播也可以叫作前饋(所以又有個前饋神經網路的詞...),正向傳播就是指給神經網路的輸入,然後一層一層向前計算輸出,最終得到一個輸出,這就是正向傳播了。
推導前的基本定義
w、a、b的定義
我們使用 wljk 表示從 (l?1)th 層的 kth 個神經元到 (l)th 層的 jth 個神經元的連結上的權重。例如,下圖給出了第二隱藏層的第四個神經元到第三隱藏層的第二個神經元的連結上的權重:
我們使用 blj 表示在 lth 層 jth 個神經元的偏差,使用 alj 表示 lth 層 jth 個神經元的啟用值。下面的圖清楚地解釋了這樣表示的含義:
基於上面的定義,可以寫出關於單個神經元啟用值alj的公式,其中sum(l-1)表示(l?1)th 層的神經元數量:
上面w的表示方法或許很奇怪,但我們把它寫成矩陣形式或許就能發現它的妙處了。用wl矩陣來表示第(l)th 層的w的值,用j作為行,k行為列,那麼上面的神經網路中的w3就可以寫成:
那麼也可以用al矩陣來表示第(l)th 層的a的值,用j作為行,但只有一列,那麼al其實是一個列向量。那麼上面的a2可以寫成下面非常形象的列向量形式:
同理,b3可以也可以寫成一個列向量:
那麼由上面的單個神經元啟用值alj的公式,可以得出al矩陣的公式:
單個神經元的帶權輸入zlj
從上面的公式中可以提取出一箇中間量zlj:
當然也可以簡寫成矩陣形式:
zlj其實就是第 l 層第 j 個神經元的啟用函式帶權輸入。
單組資料的損失
前面介紹了損失函式,那麼對於某一組輸入,其損失(大寫的“L”表示輸出層)可以寫作如下公式(這裡比上面的Loss公式少了個n,因為這裡只考慮一組輸入,而上面的Loss設定是考慮n組資料)。
這個公式同樣可以寫成矩陣的形式,這裡用到了矩陣的模(可以看附錄),模的平方即為向量各元素的平方和。
單個神經元的誤差δlj測試
定義 l 層的第 jth 個神經元上的誤差 δlj 為:
然後可以再推演兩步:
推導
輸出層的誤差矩陣
由上面的單個神經元誤差公式,可以得出輸出層誤差矩陣公式(注意這裡使用大寫的“L”表示輸出層,圓圈表示的Hadamard乘積可以看附錄):
而由於我們採用的損失函式非常容易求出C對aL的導,所以公式可以進一步簡化成:
某一層的誤差矩陣
首先推導下單個神經元誤差δlj與下一層(l+1層)的關係:
上面推導中比較難理解的可能是累加k的由來,這是因為第lth層第jth個神經元會影響到第(l+1)th層的所有神經元,所以在反向計算偏導時需要考慮第(l+1)th層的所有神經元。
然後可以得出第lth層的誤差矩陣(向量)δl的公式:
這次變換出現了矩陣轉置,可能也比較難以理解其由來。仔細觀察上面wkj會發現其中的j與k的順序與w的原始定義中的順序發生了對調,這可以理解成轉置的原因。自己拿一個示例演算一下也能發現從單個神經元誤差到某層神經元的誤差矩陣變換時的規律。
誤差與權重w的關係
在得到了單個神經元的誤差之後,再來看看誤差與w的關係:
和上節的推演一樣,若寫成矩陣,則是如下形式:
誤差與偏差b的關係
與上面w的推導過程一致,容易得到誤差與b的關係:
這個的矩陣形式就很簡單了:
總結
通過上面慘無人道的推導,可以發現在經過一次正向傳播之後,可以通過輸出層的誤差、快速求解出C對每個w和b的偏導,即?C/?w、?C/?b,再對每個w和b加上Δw、Δb,從而使得“球往下滾”,C、即Loss越來越小,神經網路在朝著我們期望的方向進行調整。
BP神經網路的訓練流程
基於上面的知識,我們現在可以總結出訓練一個神經網路的全流程:
初始化神經網路,對每個神經元的w和b賦予隨機值;
輸入訓練樣本集合,對於每個樣本,將輸入給到神經網路的輸入層,進行一次正向傳播得到輸出層各個神經元的輸出值;
求出輸出層的誤差,再通過反向傳播演算法,向後求出每一層(的每個神經元)的誤差;
通過誤差可以得出每個神經元的?C/?w、?C/?b,再乘上負的學習率(-η),就得到了Δw、Δb,將每個神經元的w和b更新為 w+Δw、b+Δb;
完成訓練之後,一般情況下我們都能得到一個損失比較小的神經網路。
附錄
矩陣
矩陣加法、減法
要求兩個矩陣大小(行數、列數)相同,然後相同位置的元素相加/相減。
矩陣乘法
這個應該都還記得,即左邊矩陣的一行乘上右邊矩陣的一列,因此矩陣相乘要求左邊矩陣的列數等於右邊矩陣的行數。
轉置
把矩陣A的行和列互相交換所產生的矩陣稱為A的轉置矩陣(即第m行第n列元素轉為第n行第m列元素),用符號T表示:
向量
只有一行的矩陣稱為行向量,只有一列的矩陣稱為列向量。行向量例如:
列向量例如:
PS:向量只是一種特殊的矩陣,矩陣乘法和轉置都是可以用在向量上的。
Hadamard乘積:?
假設S和T是兩個同樣維度的向量,使用S?T來表示按元素的乘積。所以 S?T 的元素就是(S?T)j=SjTj。
向量的模(長度或大小)
線上性代數中,向量的大小用向量兩邊加雙豎線表示,向量的大小就是向量各分量平方和的平方根。如有向量S:
則其模為:
參考資料
知乎:CNN(卷積神經網路)、RNN(迴圈神經網路)、DNN(深度神經網路)的內部網路結構有什麼區別?
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31077337/viewspace-2156393/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- 機器學習從入門到放棄:卷積神經網路CNN(二)機器學習卷積神經網路CNN
- Git 從入門到放棄Git
- XXE從入門到放棄
- Vue 從入門到放棄Vue
- Nginx從入門到放棄Nginx
- GraphQL從入門到放棄
- deepspeed從入門到放棄
- NumPy從入門到放棄
- webpack從入門到放棄Web
- openstack從入門到放棄
- HTTP從入門到放棄HTTP
- swoole——從入門到放棄(一)
- swoole——從入門到放棄(三)
- 快取從入門到放棄快取
- Spark從入門到放棄---RDDSpark
- webpack 從入門到放棄(一)Web
- 從入門到放棄 - 事件溯源事件
- HTTP快取從入門到放棄HTTP快取
- Flink從入門到放棄-大綱
- Taro 小程式 從入門到放棄!
- Python 從入門到放棄——Python科普!Python
- Scikit-learn從入門到放棄
- t-SNE 從入門到放棄
- NodeJs 入門到放棄 — 網路伺服器(三)NodeJS伺服器
- 網路篇 - http協議從入門到精通HTTP協議
- Docker 從入門到精通(三)一 網路配置Docker
- webpack -> vue Component 從入門到放棄(四)WebVue
- Realm資料庫 從入門到“放棄”資料庫
- 分散式訓練從入門到放棄分散式
- AOP埋點從入門到放棄(二)
- AOP埋點從入門到放棄(三)
- 從入門到放棄之promise用法(上)Promise
- Elasticsearch從入門到放棄:瞎說MappingElasticsearchAPP
- Elasticsearch從入門到放棄:再聊搜尋Elasticsearch
- 從入門到放棄,我用了五年
- Redis從入門到放棄系列(十) ClusterRedis
- 從入門到放棄之大資料Hive大資料Hive
- Spark從入門到放棄——初始Spark(一)Spark