Learning Objectives
- 說明一個神經元怎麼計算:加權和、偏差項、活化函數
- 用 numpy 寫出感知器的學習規則,訓練 AND、OR
- 用「一條線能不能分開」解釋 XOR 為什麼學不起來
- 比較階梯、sigmoid、tanh、ReLU 的斜率,說明為什麼梯度下降不能用階梯函數
神經網路的最小單位
神經網路聽起來很複雜,拆開來看,每個單位只做三件事,這個單位叫神經元(neuron):
- 把每個輸入乘上權重(weight)再加總;
- 加上偏差項(bias),決定門檻在哪裡;
- 把結果送進活化函數(activation function),決定輸出。
z = w1·x1 + w2·x2 + … + b
輸出 = 活化函數(z)
如果活化函數用 sigmoid,這就是你學過的羅吉斯迴歸。把活化函數換成「z 大於等於 0 就輸出 1,否則輸出 0」的階梯函數,就是 感知器(perceptron):Frank Rosenblatt 在 1958 年發表於 Psychological Review 的模型。
這一課用 numpy 寫一個感知器,看它能學會什麼、學不會什麼。下一課的多層網路,就是為了解決它學不會的問題。
逐步看:權重相同,偏差項不同,就是不同的邏輯閘
輸入是兩個 0 或 1,共四種組合。權重固定是 1 和 1,先用偏差項 −1.5,再用 −0.5。看輸出區每一行的三個值:輸入、z、輸出。
感知器怎麼自己學到權重
上面的權重是我們自己寫的。感知器的學習規則讓它從資料學:一筆一筆看,答對就不動,答錯才調整。
誤差 = 正確答案 − 預測 (只會是 0、1 或 −1)
w = w + 學習率 × 誤差 × x
b = b + 學習率 × 誤差
直覺是:該輸出 1 卻輸出 0(誤差是 1)時,把權重往 x 的方向加,下次同樣的輸入 z 會變大,比較容易過門檻;反過來就減。
全部資料看過一次叫一輪(epoch)。
逐步看:訓練 AND
權重從 0 開始。注意右邊的 w 與 b 什麼時候改變:只有答錯的那幾步才會動。看輸出區最後一欄「答錯」的次數。
一條線分不開的問題
感知器的判斷條件是 w1·x1 + w2·x2 + b >= 0,在平面上這就是一條直線:線的一邊輸出 1,另一邊輸出 0。
所以它只學得會線性可分(linearly separable)的資料,也就是能用一條直線(或高維度時的一個平面)把兩類完全分開的資料。可分的時候,上面的規則保證在有限次更新內停下來,AND、OR 都是這樣。
XOR(互斥或)不行:兩個輸入不同時答案才是 1。
| x1 | x2 | XOR |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
答案 1 的兩點在對角線上,答案 0 的兩點在另一條對角線上。不管線怎麼畫,總有一點在錯的那一邊。 Minsky 與 Papert 在 1969 年的著作 Perceptrons 分析了這類單層模型能力的限制。下面用同一段程式跑 XOR,只換答案。
逐步看:同樣的程式跑 XOR
和上一個範例只差一行:y 換成 XOR 的答案。看輸出區每一輪的權重與答錯次數,最後看圖。
階梯函數的問題:斜率是 0
感知器只能用「答錯就調整」這條專屬規則,不能直接接到多層網路上。多層網路要靠梯度下降:看損失對權重的斜率,往損失變小的方向走。
但階梯函數除了跳躍的那一點之外,到處都是平的,斜率是 0。把權重動一點點,輸出完全不變,也就不知道該往哪裡走。
所以實際的神經網路用平滑的活化函數:
| 名稱 | 公式 | 輸出範圍 | 常見用法 |
|---|---|---|---|
| sigmoid | 1 / (1 + e^(−z)) |
0 到 1 | 二元分類的輸出層(可解讀成機率) |
| tanh | (e^z − e^(−z)) / (e^z + e^(−z)) |
−1 到 1 | 隱藏層 |
| ReLU | max(0, z) |
0 以上 | 隱藏層,MLPClassifier 的預設 |
下面實際算一次斜率。
逐步看:四個活化函數的斜率
slope 把 z 往左右各動一點點,用「輸出的變化 ÷ z 的變化」估計斜率,這叫數值微分(第 22 課會再用到)。
實作:寫一個 train_perceptron 函數
完成 train_perceptron(X, y, epochs, lr):權重從 0 開始,跑 epochs 輪,每輪逐筆預測、用感知器規則更新,最後回傳 w 和 b。程式會拿它訓練 OR 和 XOR,看四筆裡答對幾筆。
小測驗:感知器
下面程式會印出什麼?
import numpy as np
w = np.array([2.0, -1.0])
b = -1.5
x = np.array([1, 1])
z = w @ x + b
print(1 if z >= 0 else 0)
下面這一步更新之後會印出什麼?學習率 0.5,這筆答案是 0,目前預測是 1。
import numpy as np
w = np.array([0.0, 0.0])
b = 0.0
x = np.array([1, 1])
target, pred = 0, 1
w = w + 0.5 * (target - pred) * x
b = b + 0.5 * (target - pred)
print(w.tolist(), b)
單一個感知器學不會 XOR,根本的原因是?
梯度下降為什麼不能搭配階梯函數?
把活化函數換成 sigmoid、損失換成交叉熵,再用梯度下降訓練這一個神經元,會得到什麼模型?
重點整理
- 神經元:加權和+偏差項+活化函數。權重決定每個輸入的重要程度,偏差項決定門檻。
- 感知器用階梯函數,規則是答錯才調整:
w = w + 學習率 × (答案 − 預測) × x。 - 它的決策邊界是一條直線,資料線性可分時學得會(AND、OR),XOR 學不會,權重會一直繞圈。
- 階梯函數的斜率幾乎到處是 0,不能配梯度下降,所以實際上用 sigmoid、tanh、ReLU;sigmoid、tanh 兩端會飽和,ReLU 在 z 小於 0 時斜率是 0。
- 下一課把神經元疊成多層:用隱藏層解 XOR,並看清楚每一層矩陣的形狀。