手刻 Deep Learning -第壹章 -PyTorch教學-激勵函數與感知機入門(上)

激勵函數不會幫忙你喊加油!加油!加油!,但是可以幫你解決非線性問題

Seachaos
Published in
9 min readNov 15, 2021

--

前言

本文接續前篇教學 Pytorch 與線性迴歸 ,本文著重在 Activation Function ( 中文稱 激勵函數 ),我們會介紹激勵函數 (也有人稱 激活函數? 激發函數? )為什麽會有用,還有透過範例來探討/實作(本文介紹常用的 ReLU, Tanh, Sigmoid, Softmax )

閱讀本文需要有矩陣計算的知識,還有知道線性迴歸的原理
另外我們也使用 Pytorch

本文希望透過生活中的範例,白話文的精神,讓各位了解 Deep Learning/Machine Learning 中的激勵函數 ( Activation Function )
了解激勵函數,其實就是往 Deep Learning 更邁進了一步

激勵函數(Activation Function) 為什麽會有用

網路上大家應該看過什麼激勵函數解決線性,非線性問題,這些都是抽象的老生常談,不是數學領域的人應該很難理解,但其實他的概念很簡單:

我相信寫過程式的人,一定都有用過 if 這個語法
而激勵函數的精神,其實就是用數學的形式來表達 if else 語法

核心概念就是這麼簡單
我們透過大量的 if else 去編織(矩陣計算)出結果,這就是為什麽需要激勵函數,用這種方法配合微分就可以解決問題

激勵函數 — 生活中的概念範例

我們來看一個簡單的問題:傳統電鍋 / 電熱水壺

電鍋示意圖,非當事電鍋

傳統電鍋/熱水壺是溫度達到一個程度後就會跳開 ( 燒開水 ),這就是激勵函數的概念
例如:
- 溫度 130 度 以下保持加熱 ( switch = 0 )
- 超過 130 度的時候跳停 (switch = 1 )

溫度在 130 度的時候跳停 ( switch 1 )

我們來看看程式怎麼寫

def check(t):
if t > 130:
return 1
return 0

看到我們使用 if 來解決問題了嗎?

激勵函數之 Sigmoid

數學上,我們可以透過函數達到這種效果,我們來看 sigmoid 這個範例;關於 Sigmoid 的計算公式有興趣可以看看 wiki ,我們這邊主要說明他的概念為什麽有效

簡單的說,Sigmoid 是透過計算讓他的範圍維持在於 0 到 1 之間

先看 Pytorch 程式碼繪製的 sigmoid activation function

x = torch.arange(-10., 10., step=0.01)
plt.plot(x, torch.sigmoid(x))
sigmoid 激勵函數

解說:

  • torch.arange 是產生一個 -10 … 10 的 array ( tensor )
  • torch.sigmoid 就是 torch 的 sigmoid 函數
  • 我們把它繪製成圖表來看

可以看到在不同的 X 範圍,最多輸出 ( y ) 就是 0~1 之間,就算是 -100000 到 100000 也是 ( 如下圖 )

sigmoid 激勵函數,不管 x 範圍多少,就是輸出 0–1 之間

看起來是不是和電鍋跳停的圖片有八成像?
那麼問題來了,怎麼套用在我們的電鍋問題上?

激勵函數與線性迴歸組合

我們這邊,假設 x 是溫度,是不是只要有辦法讓 sigmoid(x) 在 x 大於 130的時候輸出 1 就好 ?

回到線性迴歸公式, y = ax + b
所以我們要改寫成 y = sigmoid(ax + b)
( a 和 b 是我們的變數 )
我們寫成 Pytorch 程式碼來看,套用之前文章講到的自動微分
( 後面有完整可執行範例,以下是片段程式碼 )

a = torch.rand(1, requires_grad=True)
b = torch.rand(1, requires_grad=True)
def forward(t):
return torch.sigmoid( a * t + b )
  • 這邊我們要使用 自動導數 ( Auto grad ) 來找出正確的 a, b ,所以 requires_grad=True
  • 我們這邊 forward(t) 使用 t ,避免變數名稱與 x 混淆

先看我們沒有訓練前的結果

# 溫度範圍 0 ~ 200 度
x = torch.arange(0, 200, step=0.1)
# y_p 是 y predict, 我們預測的 y
y_p = forward(x).detach().numpy() # .detach().numpy() 是轉換成 numpy
# 繪圖
plt.plot(x, y_p)
未經訓練的輸出結果

還沒訓練以前,看起來一點也不像是有用的東西
現在我們開始訓練,這之前,先準備一下正確答案 ( y 為正確答案)

def check(t):
if t > 130:
return 1
return 0
y = torch.tensor([check(t) for t in x]).float()

註 1: torch.tensor 是將 python array 變成 torch 的 array ( tensor ),類似於 np.array
註 2: 因為我們計算都是用 float, 所以要轉成 torch 的 float

然後準備一下 優化器 和 損失函數 ( Loss function )
( 優化器我們使用 Adam ,損失函數我們先用 BCELoss, 這部分有空再另寫文章介紹… )

# 準備變數
a = torch.rand(1, requires_grad=True)
b = torch.rand(1, requires_grad=True)
# 定義計算
def forward(t):
# y = sigmoid(ax + b)
return torch.sigmoid(a * t + b)
# 優化器
opt = torch.optim.Adam([a, b], lr=0.05)
# 損失函數
loss_func = torch.nn.BCELoss()

開始訓練的程式碼

for _ in range(10000):
y_p = forward(x) # 預測 y
loss = loss_func(y_p, y) # 計算誤差
opt.zero_grad() # 導數重置
loss.backward() # 反向傳導
opt.step() # 優化器修正

我們整理一下,完整可執行範例 :

得到的如下圖

訓練過的 sigmoid 結果比較

左邊 ( 正確答案 ) 和 右邊 ( 預測結果 ) 看起來有八成像了,用 y 約 0.5 做分界點, 落在 130 度左右的範圍

以上的範例中,我們從來沒有真正的去管 a, b 的實際數值多少,這就是 Machine Learning 厲害的地方,他會自己去找到答案
( 我們一直是用 y = ax + b 這個公式,上面範例也是一種最簡單的感知機 )

激勵函數之 Sigmoid / ReLU / Tanh / Softmax 比較

其實 relu, tanh, softmax 各有自己的應用場景,本文篇幅有限,我們無法在本篇說明實際的應用( 實際應用會於日後文章再說明)

- ReLU, Tanh 和 Sigmoid 簡介

ReLU, Tanh 和 Sigmoid 其實差別就是輸出的範圍

  • Sigmoid:上面提過,數字越大(正數),越趨近於 1,數字越小(負數),越趨近於 0,主要用在 0 / 1 的判斷場景,目前比較多的應用是放在輸出層 ( Deep Learning )
  • ReLU:數字大於 0 ,就會是那個數字,如果小於 0 就會是 0 ,用程式碼來看就是 “if x > 0 then x else 0" 又或是 max(x, 0)
    因為這個特性適合用在線性回歸的問題或是保留特徵值傳遞 ( Deep Learning )
  • Tanh :和 Sigmoid 類似,但它的輸出範圍從 0 變成 -1,所以是 -1 與 1,不少場合使用 Tanh 會有更高的效率 ( 因為他比 Sigmoid 有更大的範圍可以傳遞資訊 )

看文字敘述不清楚的話,可以看看輸出範圍圖 ( 我們都假設 x 是 -5 ~ 5)

從左至右為 Sigmoid, ReLU, Tanh

- Softmax 簡介

其中 Softmax 有些特別,他不是一個單純的計算,他適用於分類
( 例如物件辨識,手寫辨識… )

白話文的說,他是用來計算機率的,他會將輸入的數字給出對應的機率,該機率總和就是就是 1 ( 意即 100% )

例如,我們常常看到的物件辨識範例,可能會有
- 貓 70%
- 狗 25%
- 馬 5%
這個 0.70 + 0.25 + 0.05 = 1.00 就是 softmax 輸出的總和

他不管輸入的數值(x) 範圍是多少,就是會給出一個對應的 x 機率範圍
大家可以跑看看以下程式碼

x = torch.randn(30)
plt.stem(torch.softmax(x, dim=0))
print('總和:', torch.sum(torch.softmax(x, dim=0)))

類似下圖的東西 ( 因為是亂數,所以每次結果都不會相同 )
總和會是: tensor(1.0000)

Softmax 會告訴我們哪個 x 發生的機率更大
而那個 x 怎麼來的,我們可以透過 Machine Learning 找出來
所以用在影像辨識方面的輸出層很常見

小結語

本文是激勵函數的簡介上篇,以上是很常用的激勵函數 ( Activation Funcitons )

往後我們的 Deep Learning 基本上都脫離不了他們的概念,下篇我們會來看實際範例的應用 ( 下篇等本人有空再寫…. )

另外激勵函數使用需要注意的部分,有興趣的讀者可以多多研究

  • 輸出範圍與傳遞資訊問題
  • 微分問題
  • 選擇正確的輸出函數

--

--