In [ ]:
import numpy as np
In [ ]:
%run magic.ipynb
我們的輸入 $x=\begin{pmatrix} x_0 \\ x_1 \\ x_2 \\ x_3 \end{pmatrix} $ 是一個向量,我們看成 column vector 好了
而 Weight: $W = \begin{pmatrix} W_0 \\ W_1 \\ W_2 \end{pmatrix} = \begin{pmatrix} W_{0,0} & W_{0,1} & W_{0,2} & W_{0,3}\\ W_{1,0} & W_{1,1} & W_{1,2} & W_{1,3} \\ W_{2,0} & W_{2,1} & W_{2,2} & W_{2,3} \end{pmatrix} $
Bias: $b=\begin{pmatrix} b_0 \\ b_1 \\ b_2 \end{pmatrix} $
我們先計算"線性輸出" $ c = \begin{pmatrix} c_0 \\ c_1 \\ c_2 \end{pmatrix} = Wx+b = \begin{pmatrix} W_0 x + b_0 \\ W_1 x + b_1 \\ W_2 x + b_2 \end{pmatrix} $, 然後再取 $exp$ (逐項取)。 最後得到一個向量。
$d = \begin{pmatrix} d_0 \\ d_1 \\ d_2 \end{pmatrix} = e^{W x + b} = \begin{pmatrix} e^{c_0} \\ e^{c_1} \\ e^{c_2} \end{pmatrix}$
將這些數值除以他們的總和。 給定輸入 x, 我們希望算出來的數字 q_i 會符合 x 的類別是 i 的機率。
先隨便算一個 $\mathbb{R}^2 \rightarrow \mathbb{R}^3$ 的網路
In [ ]:
# Weight
W = Matrix([1,2],[3,4], [5,6])
W
In [ ]:
# Bias
b = Vector(1,0,-1)
b
In [ ]:
# 輸入
x = Vector(2,-1)
x
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案
#%load solutions/softmax_compute_q.py
In [ ]:
%run -i solutions/softmax_compute_q.py
# 顯示 q
q
In [ ]:
# Hint 下面產生數字 i 的 2 進位向量
i = 13
x = Vector(i%2, (i>>1)%2, (i>>2)%2, (i>>3)%2)
x
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案
#%load solutions/softmax_mod4.py
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案
#%load solutions/softmax_mod3.py
我們用一種被稱作是 gradient descent 的方式來改善我們的誤差。
因為我們知道 gradient 是讓函數上升最快的方向。所以我們如果朝 gradient 的反方向走一點點(也就是下降最快的方向),那麼得到的函數值應該會小一點。
記得我們的變數是 $W$ 和 $b$ (裡面有一堆 W_i,j b_i 這些變數),所以我們要把 $loss$ 對 $W$ 和 $b$ 裡面的每一個參數來偏微分。
還好這個偏微分是可以用手算出他的形式,而最後偏微分的式子也不會很複雜。
$loss$ 展開後可以寫成
= \log(\sum_j e^{W_j x + b_j}) - W_i x - b_i$
注意 $d_j = e^{W_j x + b_j}$ 只有變數 $b_j, W_j$
對 $k \neq i$ 時, $loss$ 對 $b_k$ 的偏微分是 $$ \frac{e^{W_k x + b_k}}{\sum_j e^{W_j x + b_j}} = q_k$$ 對 $k = i$ 時, $loss$ 對 $b_k$ 的偏微分是 $$ q_k - 1$$
對 $W$ 的偏微分也不難
對 $k \neq i$ 時, $loss$ 對 $W_{k,t}$ 的偏微分是 $$ \frac{e^{W_k x + b_k} x_t}{\sum_j e^{W_j x + b_j}} = q_k x_t$$ 對 $k = i$ 時, $loss$ 對 $W_{k,t}$ 的偏微分是 $$ q_k x_t - x_t$$
In [ ]:
# 先產生隨機的 W 和 b
W = Matrix(np.random.normal(size=(3,4)))
b = Vector(np.random.normal(size=(3,)))
In [ ]:
W
In [ ]:
b
In [ ]:
i = 14
x = Vector(i%2, (i>>1)%2, (i>>2)%2, (i>>3)%2)
y = i%3
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案(跟前面一樣)¶
#%load solutions/softmax_compute_q.py
%run -i solutions/softmax_compute_q.py
#顯示 q
q
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案(跟前面一樣)
%run -i solutions/softmax_compute_loss1.py
#顯示 loss
loss
In [ ]:
# 請在這裡計算 grad_b
In [ ]:
#參考答案
%run -i solutions/softmax_compute_grad_b.py
grad_b
In [ ]:
# 請在這裡計算
In [ ]:
#參考答案
%run -i solutions/softmax_compute_grad_W.py
grad_W
In [ ]:
# 請在這裡計算
In [ ]:
# 參考答案
%run -i solutions/softmax_update_Wb.py
In [ ]:
# 原先的 q
q
In [ ]:
# 原先的 loss
loss
In [ ]:
# 現在的 loss
%run -i solutions/softmax_compute_q.py
%run -i solutions/softmax_compute_loss1.py
loss
In [ ]:
q
In [ ]:
X = np.array([Vector(i%2, (i>>1)%2, (i>>2)%2, (i>>3)%2) for i in range(16)])
for i in range(4):
print("i=", i)
display(X[i])
In [ ]:
X
In [ ]:
# 對應的組別
y = np.array([i%3 for i in range(16)])
y
In [ ]:
# 請在這裡計算
# 參考解答如後
對照
d = np.exp(W @ x + b)
q = d/d.sum()
q
In [ ]:
d = np.exp(W @ X + b)
q = d/d.sum(axis=(1,2), keepdims=True)
q
對照
loss = -np.log(q[y])
loss
In [ ]:
loss = -np.log(q[range(len(y)), y])
loss
In [ ]:
# 用平均當成我們真正的 loss
loss.mean()
對照
grad_b = q - np.eye(3)[y][:, None]
In [ ]:
# fancy indexing :p
one_y = np.eye(3)[y][..., None]
grad_b_all = q - one_y
grad_b = grad_b_all.mean(axis=0)
grad_b
對照
grad_W = grad_b @ x.T
In [ ]:
grad_W_all = grad_b_all @ X.swapaxes(1,2)
grad_W = grad_W_all.mean(axis=0)
grad_W
In [ ]:
W -= 0.5 * grad_W
b -= 0.5 * grad_b
In [ ]:
# 之前的 loss
loss.mean()
In [ ]:
d = np.exp(W @ X + b)
q = d/d.sum(axis=(1,2), keepdims=True)
loss = -np.log(q[range(len(y)), y])
loss.mean()
In [ ]:
# 在這裡計算
In [ ]:
# 參考答案
%run -i solutions/softmax_train.py
In [ ]:
# 畫出 loss 的曲線
%matplotlib inline
import matplotlib.pyplot as plt
plt.plot(loss_history);
In [ ]:
# 對答案
display((W @ X + b).argmax(axis=1).ravel())
display(y)
In [ ]: