Tip:
我们选取分母布局,都是基于分母的维度
主要是行向量为主,列向量须另外讨论,方法一样。
标量对向量的链式求导法则
假设$z$ 为标量,
标量对多个矩阵求导法则
当$A,X,B,Y$ 为矩阵时,
直接给出结论,
向量对向量求导法则
均由定义证明,取分母布局。
假设,$Z_{1,m}=a_{1,n}W_{n,m}+b_{1,m}$ ,我们$(\frac{\part Z}{\part a})_{m,n}=W^T$
用定义法求解即可。
假设,$Z_{1,m}=\sigma(a_{1,n})W_{n,m}+b_{1,m}$ ,我们$(\frac{\part Z}{\part a}){m,n}=[W^T]{m,n} [diag(\sigma^{'}(a))]_{n,n}$
反向传播
损失函数: $$ J(W,b,x,y)=\frac{1}{2}||a^L-y||_{2}^2 $$ 其中$a^L,y$ 分别为维度为$n_out$ 的向量
我们用梯度下降计算每层的$W,b$ .
假设输出层为$L$ 层:
让
于是
下面有: $$ \frac{\part J(W,b,x,y)}{\part W^L} =\frac{\part OO^T}{\part W^L}=(a^{L-1})^T\frac{\part OO^T}{\part z^l} $$ 之前为标量对矩阵求导,通过化简,变为标量对向量求导。 $$ \frac{\part J(W,b,x,y)}{\part z^l} =\frac{\part O^TO}{\part O}(\frac{\part O}{\part a^L} \frac{\part a^L}{\part z^L} ) $$
其中
综上所述:
$$
\frac{\part J(W,b,x,y)}{\part W^L}= (a^{L-1})^TO diag(\sigma^{'}(z^L))=[(a^{L-1})^TO]\odot\sigma^{'}(z^L)
$$
对于第l层的未激活输出$z^l$, 他的梯度可以为:
tip: 此时,$z^l$为向量,则可以这样链式求导 $$ \delta^l=\frac{\part J(W,b,x,y)}{\part z^l}=\frac{\part J(W,b,x,y)}{\part z^{l+1}}(\frac{\part z^{l+1}}{\part z^l})=\delta^{l+1}\frac{\part z^{l+1}}{\part z^l} $$ 那么:
tip:此时,$W^l$ 为矩阵,则不能链式求导,只能用结论:当$A,X,B,Y$ 为矩阵时,
其中:$J$ 可以看作
另外:
def affine_backward(dout, cache):
x, w, b = cache
dx, dw, db = None, None, None
x_copy = np.reshape(x, (x.shape[0], -1))
dw = x_copy.T @ dout
dx = dout @ w.T
dx = np.reshape(dx, x.shape)
db = np.sum(dout, axis=0)
return dx, dw, db
反向传播
假设,$y,z$ 为行向量,$J(x,w,b,y)=-[\ln(softmax(z))]y^T=-\ln{\frac{e^z}{e^z 1^T}}y^T=-zy^T+1\ln(e^z1^T)y^T$
那么,我们可以得到: $$ \frac{\part J}{\part z}=-y+\frac{\part 1\ln(e^z1^T)y^T}{\part e^z1^T}\frac{\part e^z1^T}{\part e^z}\frac{\part e^z}{\part z}=-y+(1\frac{1}{e^z1^T}y^T)1(diag(e^z))=-y+\frac{e^z}{e^z 1^T}=-y+a $$
其中$1$ 为全部为1的行向量,$z$ 为未经过激活函数的输出行向量,$a$ 为经过激活函数的行向量。
前向传播
序列号为
反向传播误差
对与 RNN 而言,在每个位置都会有损失函数。
于是最终的损失函数为$L=\sum\limits_{t=1}^TL_t$
其中$V,C$ 的梯度计算较为简单
在反向传播时,在某一序列位置t的梯度损失由当前位置的输出对应的梯度损失和序列索引位置$t+1$时的梯度损失两部分共同决定。
我们定义: $$ \delta_t=\frac{\part L}{\part h_t} $$
tip:
def rnn_step_backward(dnext_h, cache):
dx, dprev_h, dWx, dWh, db = None, None, None, None, None
x, Wx, Wh, prev_h, next_h, b = cache
# dO = dnext_h * (1 - next_h ** 2)
# prev_h 为 h_{t-1}, next_h = h_t
dWh = prev_h.T @ (dnext_h * (1- next_h ** 2))
dWx = x.T @ (dnext_h * (1 - next_h ** 2))
db = np.sum(dnext_h * (1 - next_h ** 2), axis=0)
dx = (dnext_h * (1 - next_h ** 2)) @ Wh.T
return dx, dprev_h, dWx, dWh, db
门控机制
遗忘上一层隐藏细胞的状态。
控制当前序列位置的输入量
前向传播算法
1)更新遗忘门:
- 更新输入门两部分输出:
3)更新细胞状态:
4)更新输出门输出:
- 更新当前学列输出预测:
反向传播算法
我们定义:
$$
\begin{align}
&\delta_h^t=\frac{\part L}{\part h^t}
\&\delta_C^t=\frac{\part L}{\part C^t}
\end{align}
$$
对于末尾序列的那个位置的$\delta_h $ 与
\end{align} $$ 先来分析: $$ \frac{\part h^{t+1}}{\part C^{t+1}}=diag(o^t\odot \tanh^{'}(C^{t+1})) $$
下面我们来分析 $$ \frac{\part C^{t+1}}{\part f^{t+1}}\frac{\part f^{t+1}}{\part h^t} + \frac{\part C^{t+1}}{\part a^{t+1}}\frac{\part a^{t+1}}{\part h^t}+\frac{\part C^{t+1}}{\part i^{t+1}}\frac{\part i^{t+1}}{\part h^t} $$
再来分析 $$ \frac{\part h^{t+1}}{\part o^{t+1}} \frac{\part o^{t+1}}{\part h^t}=diag(o^{t+1}\odot \tanh(C^{t+1})\odot \sigma^{'})W_o^T $$ 综上所述: $$ \begin{align} \delta_h^t & =(\widehat{y}^t-y^t)V^T+\delta^{t+1}\frac{\part h^{t+1}}{\part C^{t+1}}[diag(C^t\odot f^{t+1} \odot \sigma^{'})W_f^T+diag(a^{t+1}\odot i^{t+1} \odot \tanh^{'})W_a^T \& +diag(a^{t+1}\odot i^{t+1} \odot \sigma^{'})W_i^T]+\delta^{t+1}diag(o^{t+1}\odot \tanh(C^{t+1})\odot \sigma^{'})W_o^T \end{align} $$
下面,我们来分析$\delta_C^t$
而
我们仅求一个,其他的以此类推。 $$ \begin{align} \frac{\part L}{\part W_f} & =\sum\limits_{i=1}^\tau((h^{t-1})^T\frac{\part L}{\part C_t}\frac{\part C^t}{\part f_t}\frac{\part f_t}{\part h^{t-1}W_f+x^{t}U_f+b_f})\ & =\sum\limits_{i=1}^\tau((h^{t-1})^T\delta_C^t diag(C^{t-1})diag(\sigma^{'}) \ & = \sum\limits_{i=1}^\tau((h^{t-1})^T\delta_C^t \odot C^{t-1} \odot \sigma^{'}) \end{align} $$
tip 对$softmax$ 函数求导 : $$ \frac{\part \frac{e^z}{e^z 1^T}}{\part z} = \frac{1}{e^z 1^T}\frac{\part e^z}{\part z} +\frac{\part \frac{1}{e^z 1^T} e^z}{\part z} =\frac{1}{e^z 1^T}diag(e^z)-(\frac{\part \frac{1}{e^z 1^T} }{\part z})^T e^z=\frac{1}{e^z 1^T}diag(e^z)- \frac{1}{(e^z 1^T)^2}(e^z)^Te^z $$
SoftMax更新梯度
BP算法