歡迎光臨
每天分享高質量文章

從頭構建惡性腫瘤檢測網路 | 100行Python程式碼理解深度學習關鍵概念

作者 | Javier Ideami

譯文來源 | 雲棲社群(譯者: Mags,審校:袁虎)

在構建乳腺癌預測神經網路過程中,我們主要分為3大部分:

 

1.用Python從零開始建立一個神經網路,並使用梯度下降演演算法訓練模型。

 

2.在該神經網路中使用威斯康星乳腺癌資料集,根據9種不同的特徵,預測腫瘤是良性還是惡性的。

 

3.探索反向傳播和梯度下降演演算法的工作原理。

 

在這個領域中,有很多大牛都透過影片和博文分享了自己掌握的專業知識,如fast.ai的Jeremy Howard、吳恩達、Andrej Karpathy、Yann Lecun等等。

 

他們一致認為,深度學習的關鍵之一就是,儘快親自動手編寫一個深度學習的模型。當前,深度學習領域中有很多強大的庫可供我們使用,如Tensorflow、 PyTorch、 Fast.ai、 Keras、 Mxnett、Nctk、DL4J 等。如果僅僅直接使用這些強大的庫,我們可能會錯過很多關鍵的東西,因此,我們需要進一步思考這些行程中最重要的那部分。

 

如果能自己親自動手編碼建立一個神經網路,我們就不得不面對建立過程中出現的一些問題和障礙,挖掘深度學習背後隱藏的那些令人驚嘆的知識。

 

當前,深度學習領域中有各種各樣的架構和開發:摺積神經網路、迴圈神經網路和生成對抗網路等等。在這些不同種類的網路背後,都包含了兩個相同的演演算法:反向傳播演演算法和梯度下降演演算法。

 

探索神秘的函式

 

宇宙中的很多事物都可以用函式表示。本質上來說,函式是一種數學結構,接受一個輸入並產生一個輸出,表示因果關係、輸入輸出關係。

 

當我們審視周圍的世界時,會接收到很多資訊,我們將這些資訊轉化為資料,就可以從這些資料中學到很多知識。在利用這些資料進行學習的時候,會有很多不同的種類。通常來說,深度學習中有三種最常見的型別:

 

1.監督學習:從一組有標簽(已分類)的訓練資料中學習函式,輸入和輸出是成對的資料集。

2.非監督學習:從沒有任何標簽或分類的資料中學習到函式。

3.強化學習:代理人會在特定環境中做出相應的動作,透過最大化代理人得到的獎勵得到函式。

 

監督學習

 

本文中,我們主要關註監督學習。現在,我們有一個資料集,包含輸入及對應的輸出。下麵,我們想瞭解這些輸入和輸出是如何透過一個神秘的函式聯絡起來的。

 

當資料集達到一定的複雜度時,尋找這個函式的難度就相當大。因此,我們就需要使用神經網路和深度學習,來探索這個神秘的函式。

 

本質上來說,神經網路透過一系列的中間“權重”連線我們的輸入和期望輸出資料。這些權重實際上就是一些數字。

 

當我們使用正確的架構和引數,透過神經網路的結構和最佳化演演算法,我們可將神經網路近似成一個通用函式近似器,將輸入和輸出資料聯絡起來。

 

建立一個神經網路

 

一般來說,簡單的神經網路包括兩層(輸入不計入層數):

 

1.輸入:神經網路的輸入包含了我們的源資料。並且,神經元的數量與源資料的特徵數量相匹配。下圖中有4個輸入,當我們使用威斯康星乳腺癌資料集建立神經網路的時候,就會使用9個輸入。

 

2.第一層:隱藏層,包含一些隱藏層神經元,這些神經元將會與周圍層中的所有單元相連線。

 

3.第二層:有一個單元,為神經網路的輸出。

 

在實際的神經網路構建過程中,我們可以使用更多的層,比如10個或20個層的網路。為了簡單起見,在這裡,我們使用2個層。千萬不要小看這2個層,它能夠實現很多功能。

 

神經網路如何進行學習

 

問題來了:在這個神經網路中,學習將在哪個部分進行?

 

我們來回顧一下,我們在神經網路的輸入層放置了一些資料,並向網路展示某個輸入應該對應什麼輸出,也就是說,神經網路的輸出(第2層)應該是什麼結果。

 

在神經網路中,每個神經元都有一個相關的權重以及一個偏差。這些權重只是神經網路在開始學習時候初始化的一些隨機數字。

 

神經網路根據輸入資料和這些權重值進行計算,透過神經網路傳播,直到輸出產生最終的結果。

 

這些計算的結果就是一個將輸入對映到輸出的函式。

 

我們需要的就是,這些神經網路能夠計算出一個最佳權重值。因為網路透過計算,不同的權重和不同的層結合起來,會近似出不同型別的函式。

 

現在,我們來進一步探索正在探尋的函式。為了方便閱讀,我們需要解釋下這些變數的名稱:

 

1.X表示輸入層,即提供給網路的資料集。

 

2.Y表示與輸入x對應的標的輸出,由輸入經過網路進行一系列的計算得到的輸出。

 

3.Yh(y hat)表示預測函式,即我們像網路提供輸入資料集x後,經過神經網路一系列的計算產生的輸出。因此,Y是理想的輸出,Yh是神經網路接收到輸入資料後產生的實際輸出。

 

4.W表示網路各層的權重。

 

我們首先看第一層——隱藏層,它執行了一個運算W*X(即W和X的乘積)。

 

 

然後進行一個加權和:

 

1.這一層中的每個單元都和前一層中的每個單元相連線。

 

2.權重值存在於每個連線中。

 

3.該層中每個單元的值都是由前一個層中每個單元的值*權重的總和,而該權重則是1中所得到的權重。

 

從某種程度上來說,權重表示連線的強度,即:不同層之間單元連線的強度。

 

現在,我們要在這個架構中新增一個額外的量——偏差:W*X+b。

 

這個偏差能夠給神經網路帶來更多的靈活性,偏差允許網路“移動”單位的線性計算,加強網路學習這些函式的能力。

 

b代表單位偏差項。

 

我們看到,W*X+b就是一個線性方程,透過乘積與和運算表示輸入和輸出的線性關係。

 

現在,我們的神經網路只有2層,但是請記住,一個神經網路可以有很多層,比如20個甚至200個。因此,我們用數字表述這些變數屬於哪一層。這樣一來,定義隱藏層(第1層)的線性方程則為:W1*X+b1,併為其輸出命名為Z,表示某一層計算的輸出。因此,我們得到如下方程:

 

Z1=W1*X+b1

 

註意,這個計算應該針對每個層的每個單元進行。當我們為神經網路編寫程式碼的時候,我們將使用向量化程式設計,也就是說,利用矩陣將某一層的所有計算放在一個單一的數學運算中。

 

上面所講述的是隻有一個層的神經網路。現在,我們考慮一個有很多層的神經網路,每個層執都執行一個類似上面的線性運算,當所有的線性運算連線在一起時,這個神經網路就能夠計算複雜的函式了。

 

啟用函式

 

然而,現在就有一個問題:線性函式——太簡單了吧。

 

這個世界是複雜的,因此,線性函式遠遠滿足不了實際需求。一般來說,複雜的函式往往都是非線性的。而且,如果神經網路的架構僅僅由線性函式計算,那麼就很難計算非線性行為。這就是為什麼我們要在神經網路的每一層末尾加上一個額外的量:啟用函式。現在,我們介紹4個最典型的例子。

 

為了方便我們後續對啟用函式進行深入探索,首先需要介紹梯度這一概念。一個函式在某一點上的梯度也稱為函式的導數,表示該函式在該點輸出值的變化率。

 

我們來思考這樣一個問題:當特定輸入發生變化時,函式的輸出會發生怎樣的變化?

 

當梯度(導數)非常小,即函式的輸出變化非常平坦時,我們稱之為梯度消失。在後邊的反向傳播演演算法中,我們可以透過梯度瞭解網路中每個引數將會如何影響網路的輸出,從而就能夠決定如何調整網路的權值,也就是說瞭解這個引數的變化將會使網路的輸出增加還是減少?

 

梯度消失是我們所面臨的一個問題,因為如果某一點的梯度變化很小或趨於0,我們就很難確定該神經網路在該點的輸出方向。

 

當然,我們也會遇到相反的情況——梯度爆炸。當梯度值非常大時,神經網路可能就會變得非常不穩定。

 

不同的啟用函式有各自的優點,但是都會面臨梯度消失和梯度爆炸這兩大問題。

 

左上:Sigmoid啟用函式;右上:Tanh啟用函式;

左下:Relu啟用函式;右下:Leaky Relu啟用函式

 

(1)Sigmoid啟用函式——1/(1+e**-x)

 

1.輸出範圍:[0,1]。

 

2.非線性,輸出為兩個極端變數0和1。適用於二分類問題。

 

3.曲線變化溫和,因此,梯度(導數)比較容易控制。

 

4.該啟用函式的主要缺點為:在極端情況下,函式的輸出曲線變得非常平坦,也就是說,函式的導數(變化率)將變得非常小,在這種情況下,Sigmoid啟用函式的計算效率和速度將會非常低,甚至會完全沒效率。

 

5.當Sigmoid啟用函式出現在神經網路的最後一層時,將會特別有用,因為Sigmoid啟用函式有助於將輸出變為0或1(即二分類問題)。如果將Sigmoid啟用函式放在神經網路的其他層,就會出現梯度消失問題。

 

(2)Tanh啟用函式——(2/(1+e**-2x))-1

 

1.輸出範圍:[-1,1]。

 

2.曲線和Sigmoid啟用函式的曲線類似,是Sigmoid啟用函式曲線的縮小版。

 

3.Tanh啟用函式曲線較為陡峭,因此,該啟用函式的導數(變化率)比較大。

 

4.Tanh啟用函式的缺點與Sigmoid啟用函式類似。

 

(3)Relu啟用函式——max (0,x)

 

1.如果輸入大於0,那麼,輸出值等於輸入值;否則,輸出為0。

 

2.Relu啟用函式的範圍是[0,+∞),這就意味著輸出可能是+∞,可能會存在梯度爆炸問題。

 

3.優點:使神經網路輕量化,因為一些神經元可能輸出為0,防止所有的神經元被同時啟用。

 

4.Relu啟用函式存在一個問題,即輸入為0的時候,輸出全部為0,這將會導致梯度為0,會讓我們忽視某些神經元的一些有用的計算。

 

5.Relu啟用函式計算簡單,成本低廉。

 

6.當前,Relu啟用函式是神經網路內層最經常使用的啟用函式。

 

(4)    Leaky Relu啟用函式——e**x / Sum(e**x)

 

1.輸出範圍:[0,1]

 

2.Leaky Relu啟用函式將輸入進行標準化處理為一個機率分佈。

 

3.通常用於多分類場景中的輸出層。

 

在這裡,我們在輸出層使用Sigmoid啟用函式,在隱藏層使用Relu啟用函式。

 

好了,現在我們已經理解了啟用函式,那麼,就需要對其進行命名!

 

A:表示啟用函式的輸出。

因此,在神經網路的隱藏層中,將會進行如下計算:

A1=Relu(Z1)

Z1=W1*X+b1

 

在第二層的輸出層中,將會進行如下計算:

A2=Sigmoid(Z2)

Z2=W2*A1+b2

 

請註意,第二層(輸出層)的輸入為第一層的輸出,即A1。

 

第二層的輸出就是網路的最終輸出。將上面的計算歸納一下,就得到2層神經網路所執行的全部計算:

 

Yh = A2 = Sigmoid(W2*ReLU (W1*X+ b1) + b2 )

因此,本質上來說,神經網路是一連串的函式,有些是線性函式,有些是非線性函式,它們共同組成了一個複雜的函式,將我們的輸入資料和想要的輸出資料連線了起來。

 

現在,我們註意到,在這個方程的所有變數中,W和b是兩個未知數,這就是神經網路需要學習的地方。也就是說,神經網路必須進行不斷的學習,找到W和b的正確值,才能計算出正確的函式。

 

因此,我們訓練神經網路的目的也變得明瞭了,即尋找W1,b1,W2,b2的正確值。但是,在開始訓練神經網路之前,我們必須首先對這些值進行初始化,即用隨機函式對其進行初始化處理。

 

初始化以後,我們就可以對神經網路進行編碼,我們使用Python構建一個類,對這些主要的引數進行初始化處理。

 

我們將如何進行實戰編碼呢?請繼續閱讀我們的第二部分:用Python構建一個神經網路

 

原文地址:

https://towardsdatascience.com/the-keys-of-deep-learning-in-100-lines-of-code-907398c76504

譯文地址:

https://yq.aliyun.com/articles/694113?utm_content=g_1000047152

    已同步到看一看
    贊(0)

    分享創造快樂