隨時間反向傳播 (BackPropagation Through Time,BPTT)
符號注解:
- \(K\):詞匯表的大小
- \(T\):句子的長度
- \(H\):隱藏層單元數
- \(E_t\):第t個時刻(第t個word)的損失函數,定義為交叉熵誤差\(E_t=-y_t^Tlog(\hat{y}_t)\)
- \(E\):一個句子的損失函數,由各個時刻(即每個word)的損失函數組成,\(E=\sum\limits_t^T E_t\)。
注: 由於我們要推倒的是SGD算法, 更新梯度是相對於一個訓練樣例而言的, 因此我們一次只考慮一個句子的誤差,而不是整個訓練集的誤差(對應BGD算法) - \(x_t\in\mathbb{R}^{K\times 1}\):第t個時刻RNN的輸入,為one-hot vector,1表示一個單詞的出現,0表示不出現
- \(s_t\in\mathbb{R}^{H\times 1}\):第t個時刻RNN隱藏層的輸入
- \(h_t\in\mathbb{R}^{H\times 1}\):第t個時刻RNN隱藏層的輸出
- \(z_t\in\mathbb{R}^{K\times 1}\):輸出層的匯集輸入
- \(\hat{y}_t\in\mathbb{R}^{K\times 1}\):輸出層的輸出,激活函數為softmax
- \(y_t\in\mathbb{R}^{K\times 1}\):第t個時刻的監督信息,為一個one-hot vector
- \(r_t=\hat{y}_t-y_t\):殘差向量
- \(W\in\mathbb{R}^{H\times K}\):從輸入層到隱藏層的權值
- \(U\in\mathbb{R}^{H\times H}\):隱藏層上一個時刻到當前時刻的權值
- \(V\in\mathbb{R}^{K\times H}\):隱藏層到輸出層的權值
他們之間的關系:
其中,\(\sigma(\cdot)\)是sigmoid函數。由於\(x_t\)是one-hot向量,假設第\(j\)個詞出現,則\(Wx_t\)相當於把\(W\)的第\(j\)列選出來,因此這一步是不用進行任何矩陣運算的,直接做下標操作即可,在matlab里就是\(W(:,x_t)\)。
BPTT與BP類似,是在時間上反傳的梯度下降算法。RNN中,我們的目的是求得\(\frac{\partial E}{\partial U},\frac{\partial E}{\partial W},\frac{\partial E}{\partial V}\),根據這三個變化率來優化三個參數\(U,V,W\)
注意到\(\frac{\partial E}{\partial U}=\sum\limits_t \frac{\partial E_t}{\partial U}\),因此我們只要對每個時刻的損失函數求偏導數再加起來即可。
1.計算\(\frac{\partial E_t}{\partial V}\)
注:推導中用到了之前推導用到的結論。其中\(r_t^{(i)}=(\hat{y}_t-y_t)^{(i)}\)表示殘差向量第i個分量,\(h_t^{(j)}\)表示\(h_t\)的第j個分量。
上述結果可以改寫為:
其中\(\otimes\)表示向量外積。
2.計算\(\frac{\partial E_t}{\partial U}\)
由於U是各個時刻共享的,所以t之前每個時刻U的變化都對\(E_t\)有貢獻,反過來求偏導時,也要考慮之前每個時刻U對E的影響。我們以\(s_k\)為中間變量,應用鏈式法則:
但由於\(\frac{\partial s_k}{\partial U}\)(分子向量,分母矩陣)以目前的數學發展水平是沒辦法求的,因此我們要求這個偏導,可以拆解為\(E_t\)對\(U_{ij}\)的偏導數:
其中,\(\delta_k=\frac{\partial E_t}{\partial s_k}\),遵循
的傳遞關系,應用鏈式法則有:
其中,\(\odot\)表示向量點乘。於是,我們得到了關於\(\delta\) 的遞推關系式。由\(\delta_t\)出發,我們可以往前推出每一個\(\delta\),現在計算\(\delta_t\):
\begin{equation}\delta_t=\frac{\partial E_t}{\partial s_t}=\frac{\partial h_t}{\partial s_t}\frac{\partial z_t}{\partial h_t}\frac{\partial E_t}{\partial z_t}=diag(1-h_t\odot h_t)\cdot V^T\cdot(\hat{y}_t-y_t)=(V^T(\hat{y}t-y_t))\odot (1-h_t\odot h_t)\end{equation}
將\(\delta_0,...,\delta_t\)代入$ \frac{\partial E_t}{\partial U{ij}} $有:
將上式寫成矩陣形式:
不失嚴謹性,定義\(h_{-1}\)為全0的向量。
3.計算\(\frac{\partial E_t}{\partial W}\)
按照上述思路,我們可以得到
由於\(x_k\)是個one-hot vector,假設其第\(m\)個位置為1,那么我們在更新\(W\)時只需要更新\(W\)的第\(m\)列即可,計算\(\frac{\partial{E_t}}{\partial{W}}\)的偽代碼如下:
delta_t = V.T.dot(residual[T]) * (1-h[T]**2)
for t from T to 0
dEdW[ :,x[t] ] += delta_t
#delta_t = W.T.dot(delta_t) * (1 - h[t-1]**2)
delta_t = U.T.dot(delta_t) * (1 - h[t-1]**2)