1.3 淺層 logistic 神經網絡
視訊: 第三周 淺層神經網絡 整理: 飛龍
普通的 logistic 可看做無隐層的神經網絡。下面我們做出一個單隐層的神經網絡,它本質上是 logistic 套着 logistic,是以也叫作多層 logistic。
我們的神經網絡有三層,輸入層,一個隐層,和輸出層。輸入層的每個節點對應訓練集
X
的每個特征,節點數量就是特征數量。隐層的節點任意,這張圖裡面是四個。輸出層隻有一個節點,它就是我們的假設。
每個隐層節點,以及輸出層節點中,都要執行上一節的 logistic 運算。
上一節中,我們已經推導了向量化的公式。為了簡便起見,我們直接用向量化的公式起步。
我們引入一種的表達方式,用 Z[1]j 表示隐層第
j
個節點裡面的值。用 Z[2] 表示輸出層裡面的值,因為隻有一個節點,就不加下标了。
在每個隐層節點中,我們有:
Z[1]j=Xθ[1]jA[1]j=σ(Z[1]j)
注:
我這裡的 X 仍然是行為樣本,列為特征。如果你的 X 是我這裡的轉置,記得把其它的量也加上轉置。
然後,我們嘗試進一步使其向量化。
Θ[1]=⎡⎣⎢⎢⎢⎢⎢⎢⎢⋯|θ[1]j|⋯⎤⎦⎥⎥⎥⎥⎥⎥⎥
我們把 θ[1]j 按列堆疊,得到 Θ[1]。由于 θ[1]j 是矩陣乘法的右邊,它乘以 X 會得到按列堆疊的 Z[1]j。
Z[1]=XΘ[1]=⎡⎣⎢⎢⎢⎢⎢⎢⎢⋯|Z[1]j|⋯⎤⎦⎥⎥⎥⎥⎥⎥⎥
A[1] 就是對 Z[1] 的每個元素應用 sigmoid 函數,是以是一樣的結構。
A[1]=σ(Z[1])=⎡⎣⎢⎢⎢⎢⎢⎢⎢⋯|A[1]j|⋯⎤⎦⎥⎥⎥⎥⎥⎥⎥
在神經網絡中,sigmoid 函數叫做激活函數,A[1] 叫做激活值。每個節點的激活值提供給下一層,作為下一層的特征。
也就是說:
Z[2]=A[1]θ[2]A[2]=σ(Z[2])
A[2] 就是我們的假設,它等于樣本屬于正向分類的機率。
成本函數 J 的計算也類似。
J=−Sum(Y∗log(A[2])+(1−Y)∗log(1−(A[2]))
計算圖
由于目前為止的量有點多,我們需要畫出它們的關系圖。
X-----------Z^[1]----A^[1]-------Z^[2]----A^[2]---J
| | |
Theta^[1]---+ theta^[2]---+ Y-------+
然後我們統計一下這些量的尺寸資訊。
量 | 尺寸 |
---|---|
X | |
Θ[1] | |
Z[1]A[1] | |
θ[2] | |
Z[2]A[2] | |
這個很重要,以後有用。
反向傳播
神經網絡中的求導過程又叫做反向傳播,隻是一個新名詞,沒什麼特别的。
我們這裡待定的量變成了兩個:Θ[1] 和 θ[2]。
首先,J 和 θ[2] 的關系,類似于 logistic 裡面它和 θ 的關系。我們可以直接得出:
dJdθ[2]=A[1]T(A[2]−Y)
下面求 dJdΘ[1]。從 J 到 Θ[1] 路徑上的所有導數都需要求出來。首先我們得出:
dJdZ[2]=A[2]−Y
然後:
dZ[2]dA[1]=θ[2]T
這個導數與 A[1] 同型,隻有我們将 θ[2] 轉置過來,再廣播成
n_data x n_hidden_nodes
,它才同型。
dJdA[1]=dJdZ[2]θ[2]T
我們發現,左邊的導數是
n_data x n_hidden_nodes
的,右邊的兩個導數分别是
n_data x 1
和
1 x n_hidden_nodes
的,是以用矩陣乘法。
dA[1]dZ[1]=A[1]∗(1−A[1])dJdZ[1]=dJdA[1]∗A[1]∗(1−A[1])
n_data x n_hidden_nodes
的,右邊的兩個導數也是,是以用逐元素乘法。這個規律在反向傳播中十分重要。
最後一步和 logistic 中的情況相似,是以照搬。
dJdΘ[1]=XTdJdZ[1]
最後别忘了對兩個導數除以 ndata。
代碼
Theta_sup1 = np.random.rand(n_features, n_hidden_nodes) / 100
theta_sup2 = np.random.rand(n_hidden_nodes, 1) / 100
for _ in range(max_iter):
# 正向傳播過程
Z_sup1 = np.dot(X, Theta_sup1)
A_sup1 = sigmoid(Z_sup1)
Z_sup2 = np.dot(A_sup1, theta_sup2)
A_sup2 = sigmoid(Z_sup2)
# 反向傳播過程
dJ_dZ_sup2 = (A_sup2 - Y) / n_data
dJ_dtheta_sup2 = np.dot(A_sup1.T, dJ_dZ_sup2)
dZ_sup2_dA_sup1 = theta_sup2.T
dA_sup1_dZ_sup1 = A_sup1 * (1 - A_sup1)
dJ_dZ_sup1 = np.dot(dJ_dZ_sup2, dZ_sup2_dA_sup1) * dA_sup1_dZ_sup1
dJ_dTheta_sup1 = np.dot(X.T, dJ_dZ_sup1)
Theta_sup1 -= alpha * dJ_dTheta_sup1
theta_sup2 -= alpha * dJ_dtheta_sup2