详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」

详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」上一节我们说了详细展示RNN的网络结构以及前向传播,在了解RNN的结构之后,如何训练RNN就是一个重要问题,训练模型就是更新模型的参数,也就是如何进行反向传播,也就意味着如何对参数进行求导。本篇内容就是详细介绍RNN的反向传播算法,即BPTT。首先让我们来用动图来表示RNN的损失是如何产生的,以及如何进行反向传播,如下图所示。上面两幅图片,已经很详细的展示了损失是如何产生的,以及…

大家好,又见面了,我是你们的朋友全栈君。

上一节我们说了详细展示RNN的网络结构以及前向传播,在了解RNN的结构之后,如何训练RNN就是一个重要问题,训练模型就是更新模型的参数,也就是如何进行反向传播,也就意味着如何对参数进行求导。本篇内容就是详细介绍RNN的反向传播算法,即BPTT。


首先让我们来用动图来表示RNN的损失是如何产生的,以及如何进行反向传播,如下图所示。

详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」

详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」

上面两幅图片,已经很详细的展示了损失是如何产生的, 以及如何来对参数求导,这是忽略细节的RNN反向传播流程,我相信已经描述的非常清晰了。下图(来自trask)描述RNN详细结构中反向传播的过程。

详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」

有了清晰的反向传播的过程,我们接下来就需要进行理论的推到,由于符号较多,为了不至于混淆,根据下图,现标记符号如表格所示:

详细阐述基于时间的反向传播算法(Back-Propagation Through Time,BPTT)「建议收藏」

公式符号表
符号 含义

K

输入向量的大小(one-hot长度,也是词典大小)

T

输入的每一个序列的长度

H

隐藏层神经元的个数

X=\left \{ x_{1},x_{2},x_{3}....,x_{T} \right \}

样本集合

x_{t}\epsilon \mathbb{R}^{K\times 1}

t时刻的输入

y_{t}\epsilon \mathbb{R}^{K\times 1}

t时刻经过Softmax层的输出。

\hat{y}_{t}\epsilon \mathbb{R}^{K\times 1}

t时刻输入样本的真实标签

L_{t}

t时刻的损失函数,使用交叉熵函数,

L_t=-\hat{y}_t^Tlog(y_t)

L

序列对应的损失函数:

L=\sum\limits_t^T L_t

RNN的反向传播是每处理完一个样本就需要对参数进行更新,因此当执行完一个序列之后,总的损失函数就是各个时刻所得的损失之和。

s_{t}\epsilon \mathbb{R}^{H\times 1}

t个时刻RNN隐藏层的输入。

h_{t}\epsilon \mathbb{R}^{H\times 1}

第t个时刻RNN隐藏层的输出。

z_{t}\epsilon \mathbb{R}^{H\times 1}

输出层的输入,即Softmax函数的输入

W\epsilon \mathbb{R}^{H\times K}

输入层与隐藏层之间的权重。

U\epsilon \mathbb{R}^{H\times H}

上一个时刻的隐藏层 与 当前时刻隐藏层之间的权值。

V\epsilon \mathbb{R}^{K\times H}

隐藏层与输出层之间的权重。

                                                                     \begin{matrix} \: \: \: \: \: \: \: \: \; \; \; \; \; \; \; \; \; \; \; \; \; s_t=Uh_{t-1}+Wx_t+b\\ \\ h_t=\sigma(s_t)\\ \\ \; \; \; \; z_t=Vh_t+c\\ \\ \; \; \; \; \; \; \; \; \; \; y_t=\mathrm{softmax}(z_t) \end{matrix}

我们对参数V,c求导比较方便,只有每一时刻的输出对应的损失与V,c相关,可以直接进行求导,即:

                                                  \frac{\partial L}{\partial V} =\sum\limits_{t=1}^{T}\frac{\partial L_{t}}{\partial V} = \sum\limits_{t=1}^{T}\frac{\partial L_{t}}{\partial z_{t}} \frac{\partial z_{t}}{\partial V} = \sum\limits_{t=1}^{\tau}(\hat{ y}_{t}-y_{t}) (h_{t})^T

                                                 \frac{\partial L}{\partial c} = \sum\limits_{t=1}^{T}\frac{\partial L_{t}}{\partial c} = \sum\limits_{t=1}^{T}\frac{\partial L_{t}}{\partial z_{t}} \frac{\partial z_{t}}{\partial c} = \sum\limits_{t=1}^{T}y_{t} - \hat{y}_{t}

要对参数W,U,b进行更新,就不那么容易了,因为参数W,U,b虽是共享的,但是他们不只是对第t刻的输出做出了贡献,同样对t+1时刻隐藏层的输入s_{t+1}做出了贡献,因此在对W,U,b参数求导的时候,需要从后向前一步一步求导。

假设我们在对t时刻的参数W,U,b求导,我们利用链式法则可得出:

                                                                   \frac{\partial L}{\partial W}=\frac{\partial L}{\partial h_{t}}\frac{\partial h_{t}}{\partial s_{t}}\frac{\partial s_{t}}{\partial W}

                                                                    \frac{\partial L}{\partial U}=\frac{\partial L}{\partial h_{t}}\frac{\partial h_{t}}{\partial s_{t}}\frac{\partial s_{t}}{\partial U}

                                                                    \frac{\partial L}{\partial b}=\frac{\partial L}{\partial h_{t}}\frac{\partial h_{t}}{\partial s_{t}}\frac{\partial s_{t}}{\partial b}

我们发现对W,U,b进行求导的时候,都需要先求出\frac{\partial L}{\partial h_{t}},因此我们设:

                                                                         \delta ^{t}=\frac{\partial L}{\partial h_{t}}=\frac{\partial L}{\partial z_{t}}\frac{\partial z_{t}}{\partial h_{t}}+\frac{\partial L}{\partial h_{t+1}}\frac{\partial h_{t+1}}{\partial h_{t}}

那么我们现在需要先求出\delta ^{t},则:

                                                                        \frac{\partial L}{\partial z_{t}}\frac{\partial z_{t}}{\partial h_{t}}=V^{T}(y_{t}-\hat{y}_{t})

                                                                   \begin{matrix} \frac{\partial L}{\partial h_{t+1}}\frac{\partial h_{t+1}}{\partial h_{t}}=U^{T}\delta ^{t+1}\odot \sigma ^{'}(z_{t+1})\\ \\ =U^{T}diag(\delta ^{t+1}) \sigma ^{'}(z_{t+1})\\ \\ =U^{T}diag(\sigma ^{'}(z_{t+1}))\delta ^{t+1} \\ \\ =U^{T}diag(1-h_{t+1}^{2})\delta ^{t+1} \end{matrix}

注:在求解激活函数导数时,是将已知的部分求导之后,然后将它和激活函数导数部分进行哈达马乘积。激活函数的导数一般是和前面的进行哈达马乘积,这里的激活函数是双曲正切,用矩阵中对角线元素表示向量中各个值的导数,可以去掉哈达马乘积,转化为矩阵乘法。

则:

                                                                \begin{matrix} \delta ^{t}=\frac{\partial L}{\partial h_{t}}=\frac{\partial L}{\partial z_{t}}\frac{\partial z_{t}}{\partial h_{t}}+\frac{\partial L}{\partial h_{t+1}}\frac{\partial h_{t+1}}{\partial h_{t}}\\ \\\: \; \; \; \; \; \; \; \; \; \; \; \; \; \; =V^{T}(y_{t}-\hat{y}_{t})+U^{T}\delta ^{t+1}\odot \sigma ^{'}(z_{t+1})\\ \\ \: \: \: \: \: \: \: \: \: \: \: \: \: \: \: \; =V^{T}(y_{t}-\hat{y}_{t})+U^{T}\delta ^{t+1} (1-h_{t+1}^{2}) \end{matrix}

我们求得\delta ^{t},之后,便可以回到最初对参数的求导,因此有:

                                                           \frac{\partial L}{\partial W} = \sum\limits_{t=1}^{T}\frac{\partial L}{\partial h_{t}} \frac{\partial h_{t}}{\partial W} = \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}(x_{t})^T

                                                            \frac{\partial L}{\partial b}= \sum\limits_{t=1}^{T}\frac{\partial L}{\partial h_{t}} \frac{\partial h_{t}}{\partial b} = \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}

                                                           \frac{\partial L}{\partial U} = \sum\limits_{t=1}^{T}\frac{\partial L}{\partial h_{t}} \frac{\partial h_{t}}{\partial U} = \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}(h_{t-1})^T

有了各个参数导数之后,我们可以进行参数更新:

                                                          W^{'}=W-\theta \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}(x_{t})^T

                                                           U^{'}=U-\theta \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}(h_{t-1})^T

                                                          V^{'}=V-\theta \sum\limits_{t=1}^{T}(\hat{ y}_{t}-y_{t}) (h_{t})^T

                                                           b^{'}=b-\theta \sum\limits_{t=1}^{T}diag(1-(h_{t})^2)\delta^{t}

                                                          c^{'}=c- \theta \sum\limits_{t=1}^{T}y_{t} - \hat{y}_{t}


参考:

刘建平《循环神经网络(RNN)模型与前向反向传播算法

李弘毅老师《深度学习》

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/152338.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • vuex mapGetters「建议收藏」

    vuex mapGetters「建议收藏」1、vuex配置//vuex的配置//注意Store是大写conststore=newVuex.Store({//数据保存state:{show:false,count:…

    2022年6月8日
    26
  • excel如何打开100万行以上的csv文件

    excel如何打开100万行以上的csv文件前言正常情况下,2007版本以上的excel打开的csv文件,最多只能显示1048576行数据,如果我们恰好有一个超大csv文件行数超过这个量级,该如何解决呢,可以使用powerquery来解决。步骤1.切换到数据选项卡,依次点击新建查询->从文件->从CSV,然后选择需要导入的超大csv文件2.在出现的窗口里,点击加载->加载到3.选择仅创建连接和将此数据添加到数据模型,点击加载4.等excel加载完数据后,在窗口的右侧会出现一个工作簿查询,点击里面的文件,

    2022年7月21日
    132
  • vscode 快捷键绑定

    vscode 快捷键绑定最近迷上了vscode,用它开发.netcore程序十分方便,智能提示也很好用,插入智能提示的选项是enter键或者tab键,可惜我以前习惯使用vs写c#,习惯用空格做智能提示的选择,多方查找资料甚至准备采用开发一个vscode插件的方式解决,后来无意间查看官方文档,利用vscode的快捷键绑定功能是可以做到的。打开vscode,进入文件->首选项->键盘快捷方式查看’tab’的功能,其中就有一项:

    2022年5月18日
    39
  • cuda安装教程+cudnn安装教程

    cuda安装教程+cudnn安装教程cuda9.0+cudnn7.0安装教程 1、下载cuda9.0下载链接:https://developer.nvidia.com/cuda-toolkit-archive 2、安装cuda安装cuda时,第一次会让设置临时解压目录,第二次会让设置安装目录;临时解压路径,建议默认即可,也可以自定义。安装结束后,临时解压文件夹会自动删除;安装目录,建议默认…

    2022年6月8日
    47
  • levelDB 的版本控制[通俗易懂]

    首先本次类FileMetaData之前我们在LevelDB-总体介绍中提到一个疑问,levelDB是将磁盘文件以层的结构存在,那么哪里维护这个层结构呢,其实就是在Version类中,classVersion{public://Lookupthevalueforkey.Iffound,storeitin*valand//returnOK.Elsereturnanon-OKstatus.Fills*stats.//REQUIRES:

    2022年4月9日
    43

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号