详细阐述基于时间的反向传播算法(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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • Math.abs( x )

    Math.abs( x )

    2021年10月18日
    67
  • [转] Vue生命周期

    [转] Vue生命周期

    2022年3月2日
    42
  • delphi数组排序_sql排序函数

    delphi数组排序_sql排序函数var  m_bSort:  boolean=false;  //控制正反排序的变量     //ListView排序的回调函数,默认的是快速排序法,也可以自己在这里做算法  function  CustomSortProc(Item1,  Item2:  TListItem;  ParamSort:  integer):  integer;  stdcall

    2022年10月4日
    3
  • 页式虚拟存储管理_页式虚拟存储管理的主要特点

    页式虚拟存储管理_页式虚拟存储管理的主要特点页式存储的基本原理    将程序的逻辑地址空间划分为固定大小的页(page),而物理内存划分为同样大小的页框(pageframe)。程序加载时,可将任意一页放人内存中任意一个页框,这些页框不必连续,从而实现了离散分配。也就是把内存等分成N份,存放运行的程序时,按分成的快放置即可。但放置时要考虑主存里哪些块已经被占用,这个用主存分配表(位示图)来表示。     分页式存储器的逻辑

    2022年9月26日
    6
  • Java集合分类以及各自特点

    Java集合分类以及各自特点Java分类以及各自的特点,对集合中的自定义类元素排序,比较器集合分为Map和Collection两大类常用的就是ArrayList,LinkedList,HashSet,LinkedHashSet,TreeSet,HashMap,LinkedHashMap,TreeMap;

    2022年5月27日
    38
  • C#的继承_继承关系中的被继承人

    C#的继承_继承关系中的被继承人继承详解:一.继承的概念:二.基类和派生类:三.继承的作用:四.继承的特点:五.举例说明:六.继承注意事项:一.继承的概念:继承:是面向对象程序设计中最重要的概念之一。继承允许我们根据一个类来定义另一个类,这使得创建和维护应用程序变得更容易。同时也有利于重用代码和节省开发时间。当创建一个类时,不需要完全重新编写新的数据成员和成员函数,只需要设计一个新的类,继承了已有的类的成员即可。这个已有的类被称为的基类/父类,这个新的类被称为派生类/子类。二.基类和派生类:基类/父类:也可以理解成生活中的父亲

    2025年10月15日
    3

发表回复

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

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