第1节 循环神经网络简介
循环神经网络 (Recurrent Neural Network) 或 RNN 是一类用于处理 序列数据 的神经网络
卷积神经网络是专门用于处理网格化数据 \Imℑ 的神经网络,循环神经网络是专门用于处理序列 x_i = \lbrace\vec{x}^{(1)}_i, \vec{x}^{(2)}_i, \vec{x}^{(3)}_i, \dots, \vec{x}^{(\tau)}_i\rbracexi={xi(1),xi(2),xi(3),…,xi(τ)} 的神经网络
卷积神经网络可以很容易扩展到处理具有很大宽度和高度,以及大小可变的图像,循环神经网络可以扩展到更长的序列,大多数也具备处理可变长度序列的能力
1.1 历史发展
1982 年,美国加州理工学院物理学家 John hopfield 发明了一种单层反馈神经网络 Hopfield Network,用来解决组合优化问题, 这是最早 RNN 的雏形。1986 年,Michael I. Jordan 定义了 Recurrent 概念,提出 Jordan Network
1990 年,美国认知科学家 Jeffrey L. Elman 对 Jordan Network 进行了简化, 并采用 Back Propagation 算法进行训练,便有了如今最简单的包含单个自连接节点的 RNN 模型。但此时由于 梯度消失 (Gradient Vanishing) 及 梯度爆炸 (Gradient Exploding) 的问题,训练非常困难,应用非常受限
1997 年,人工智能研究所主任 Jurgen Schmidhuber 提出 长短期记忆(LSTM),使用门控单元及记忆机制大大缓解了早期 RNN训练的问题。同年 Mike Schuster 提出 双向 RNN (Bidirectional RNN), 这两种模型大大改进了早期 RNN 结构,拓宽了 RNN 的应用范围,为后续序列建模的发展奠定了基础。此时 RNN 虽然在一些序列建模任务上取得了不错的效果,但由于计算资源消耗大,后续几年一直没有太大的进展
2010 年,Tomas Mikolov 对 Bengio 提出的 Feedforward Neural Network Language Model (NNLM) 进行了改进,提出了基于 RNN 语言模型(RNN LM),并将其用在语音识别任务中,大幅提升了识别精度。在此基础上 Tomas Mikolov 于 2013 年提出了大名鼎鼎的 word2vec,与 NNLM 及 RNNLM 不同,word2vec 目标不再专注于建模语言模型,而是如何利用语言模型学习每个单词的语义化向量(Distributed Tepresentation),其中 Distributed Representation概念最早要来源于 Hinton 1986 年的工作。Word2vec 引发了深度学习在 自然语言处理 领域的浪潮,除此之外还启发了 Knowledge Representation,Network Representation 等新的表示学习领域
2014 年,Bengio 团队与 Google 同时提出了 seq2seq 架构,将 RNN 用于机器翻译。没过多久,Bengio 团队又提出 Attention 机制,对 seq2seq 架构进行改进。自此机器翻译全面进入到神经机器翻译(NMT)的时代,NMT 不仅过程简单,而且效果要远超统计机器翻译的效果。目前主流的机器翻译系统几乎都采用了神经机器翻译的技术。除此之外,Attention 机制也被广泛用于基于深度学习的各种任务中
2017 年,Facebook 人工智能实验室提出基于卷积神经网络的 seq2seq 架构,将 RNN 替换为带有 GRU 的 CNN,提升效果的同时大幅加快了模型训练速度,此后不久,G
oogle 提出 Transformer 架构,使用 Self-Attention 代替原有 RNN 及 CNN,更进一步降低了模型复杂度
1.2 模型特性
- 从多层神经网络出发到循环神经网络,需要利用 20 世纪 80 年代机器学习和统计模型早期思想的优点:参数共享 即在模型的不同部分共享权重与偏置值
参数共享使得模型能够扩张到不同形式的样本并进行泛化,当信息的特定部分在序列内多个位置出现时,这样的共享尤为重要
传统的 全连接前馈网络 (FNN or MLP) 会给每个输入特征分配一个单独的参数,所以需要分别学习序列数据中每个位置的权重与偏置值
相比之下,循环神经网络在几个时间步内共享相同的权重,不需要分别学习每个位置的权重与偏置值
- 循环神经网络用于处理序列数据 x_i = \lbrace\vec{x}^{(1)}_i, \vec{x}^{(2)}_i, \vec{x}^{(3)}_i, \dots, \vec{x}^{(\tau)}_i\rbracexi={xi(1),xi(2),xi(3),…,xi(τ)} 的神经网络,其中 x_ixi 表示第 ii 个样本, x_ixi 是一个序列,序列的长度可以是固定的,也可以是变化的
固定的序列长度:对每个样本 x_ixi,其序列长度都是常数 \tau_i = \tauτi=τ
可变的序列长度:样本 x_ixi 的序列长度 \tau_iτi 可能不等于样本 x_jxj 的序列长度 \tau_j, i \ne jτj,i=j
-
循环网络中使用参数共享的前提是相同参数可以用于不同的时间步, 即前一个时间步和后一个时间步之间的关系与时刻 tt 无关
-
几乎所有函数都可以被认为是前馈神经网络,几乎任何涉及循环的函数都可以被认为是循环神经网络
第2节 循环神经网络设计理念
2.1 RNN 计算图
计算图 (Computational Graph) 是形式化一组计算结构的方式,如那些设计将输入和参数映射到输出和损失的计算
- 图中的每一个节点来表示一个变量,可以是标量、向量、矩阵、张量或者甚至是另一类型的变量
- 为了形式化图形,还需引入 操作 (Operation) 这一概念,指一个或多个变量的简单函数,可以通过多个操作符合在一起来描述更为负责的函数
展开 (Unfolding) 循环计算得到的重复结构进行解释,这些重复结构通常对应于一个事件链,展开这个计算图将导致深度网络结构中的参数共享
- 考虑动态系统的经典形式 s^{(t)} = f(s^{(t-1)};\theta)s(t)=f(s(t−1);θ), 其中 s^{(t)}s(t) 称为系统的状态
ss 在时刻 tt 的定义需要参考时刻 t-1t−1 时同样的定义,因此原式是自循环的
对有限时间步 \tau, \tau -1τ,τ−1 次应用此项定义可以进行计算图展开,例如 \tau = 3τ=3, 可以得到s^{(3)} = f(s^{(2)};\theta)s(3)=f(s(2);θ)
\quad\enspace=f(f(s^{(1)};\theta);\theta)=f(f(s(1);θ);θ)
以这种方式重复应用定义,展开等式,就能得到不涉及循环的表达
- 考虑由外部信号 x^{(t)}x(t) 驱动的动态系统 s^{(t)} = f(s^{(t-1)}, x^{(t)};\theta)s(t)=f(s(t−1),x(t);θ)
RNN 可以通过许多不同的方式建立,就像几乎所有函数都可以被认为是前馈网络,本质上任何涉及循环的函数都可以视为一个循环神经网络
很多 RNN 使用原式定义隐藏单元的值,为了表明状态时网络的隐藏单元,使用变量 \mathcal{h}h 代表状态重写式\mathcal{h}^{(t)} = f(\mathcal{h}^{(t-1)}, x^{(t)};\theta)h(t)=f(h(t−1),x(t);θ)
令函数 g^{(t)}g(t) 代表经 tt 步展开后的循环
\mathcal{h}^{(t)} = f(\mathcal{h}^{(t-1)}, x^{(t)};\theta)h(t)=f(h(t−1),x(t);θ)
\quad\enspace\, = g^{(t)}(x^{(t)},x^{(t-1)},x^{(t-2)},\dots,x^{(2)},x^{(1)})=g(t)(x(t),x(t−1),x(t−2),…,x(2),x(1))
函数 g^{(t)}g(t) 将全部的过去序列 \lbrace x^{(t)},x^{(t-1)},x^{(t-2)},\dots,x^{(2)},x^{(1)}\rbrace{x(t),x(t−1),x(t−2),…,x(2),x(1)} 作为输入来生成当前状态,但是展开的循环架构允许将 g^{(t)}g(t) 分解为函数 ff 的重复应用,因此
- 无论序列的长度,生成的模型始终具有相同的输入大小,因为指定的是从一种状态到另一种状态的迁移,而不是在可变长度的历史状态上操作
- 每个时间步使用相同参数的 相同 转移函数 ff
学习在所有时间步和所有序列长度上操作单一模型 ff 是可能的,而不需要在所有可能时间步学习独立的模型 g^{(t)}g(t)
学习单一的共享模型允许泛化到没有见过的序列长度
估计模型所需的训练样本远远少于不带参数共享的模型
2.2 RNN 设计模式
基于图展开和参数共享的思想,可以设计不同模式的循环神经网络,RNN 重要设计模式包括
- 每个时间步都有输出,并且隐藏单元之间有循环连接的循环网络
- 每个时间步都产生一个输出,只有当前时刻的输出到下个时刻的隐藏单元之间有循环连接的循环网络
- 隐藏单元之间存在循环连接,但读取整个序列后产生单个输出的循环网络
基于输入序列的长度,RNN 网络模式可以划分为输入序列长度为 00、输入序列长度为 11、 输入序列长度为 \tauτ
- 设样本集合为 \mathbb{X} = \lbrace x_1,x_2,\dots,x_N \rbraceX={x1,x2,…,xN},其中每个样本为
对于输入序列长度 =1=1 的样本 \mathrm{x}_i = \vec{x}_ixi=xi
对于输入序列长度 >1>1 的样本 \mathrm{x}_i = \lbrace \vec{x}_i^{(1)},\vec{x}_i^{(2)},\dots,\vec{x}_i^{(\tau_i)}\rbracexi={xi(1),xi(2),…,xi(τi)},其中 \tau_iτi 为第 ii 个样本的序列长度
- 设样本对应的真实标记集合为 \mathbb{Y} = \lbrace y_1,y_2,\dots,y_N \rbraceY={y1,y2,…,yN},其中每个样本的标记为
对于输出序列长度 =1=1 的样本 \mathrm{y}_i = y_iyi=yi, 对应的网络输出为 o_i = \vec{o}_ioi=oi
对于输出序列长度 >1>1 的样本 \mathrm{y}_i = \lbrace y_i^{(1)},y_i^{(2)},\dots,y_i^{(\tau_i)}\rbraceyi={yi(1),yi(2),…,yi(τi)}, 其中 \tau_iτi 为第 ii 个样本的序列长度
对应的网络输出为 o_i = \lbrace \vec{o}_i^{(1)},\vec{o}_i^{(2)},\dots,\vec{o}_i^{(\tau_i)}\rbraceoi={oi(1),oi(2),…,oi(τi)}
第3节 循环神经网络模型结构
3.1 零长度输入序列
- 零长度输入序列 RNN 网络中,输入序列长度为 00,即此时网络没有外部输入,网络将当前时刻的输出作为下一个时刻的输入,意味着模型需要提供一个初始的输出 y^{(0)}y(0)
如文本生成算法中首先给定 y^{(0)}y(0) 作为种子,然后通过 tt 时刻为止的单词序列来预测 t+1t+1 时刻的单词;如果遇到某个输出为停止符,或者句子长度达到给定阈值则停止生成
在这个任务中,任何早期输出的单词都会对它后面的单词产生影响
- 零长度输入序列 RNN 网络中,过去的输出序列 \lbrace y^{(1)}, y^{(2)}, \dots, y^{(t-1)}\rbrace{y(1),y(2),…,y(t−1)} 通过影响 \vec{h}^{(t)}h(t) 来影响当前的输出 y^{(t)}y(t),从而 解耦 y^{(i)}, i = 1,2,\dots,t-1y(i),i=1,2,…,t−1 和 y^{(t)}y(t)
该模型的数学表示为
o^{(t)}_k = p(y^{(t)} = k | y^{(0)}, y^{(1)},\dots, y^{(t-1)}), k = 1,2,\dots, Kok(t)=p(y(t)=k∣y(0),y(1),…,y(t−1)),k=1,2,…,K
其中 y^{(t)}_kyk(t) 表示模型第 tt 步输出 \vec{y}^{(t)}_iyi(t) 的第 kk 个分量, 单个样本的损失为
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)} + \mathbf{U}\vec{\mathbf{y}}^{(t-1)}a(t)=b+Wh(t−1)+Uy(t−1)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
其中输出到隐状态的权重为 \mathbf{U}U,隐状态到输出的权重为 \mathbf{V}V,隐状态到隐状态的权重为 \mathbf{W}W,\vec{\mathbf{b}},\vec{\mathbf{c}}b,c 为输入偏置向量和输出偏置向量
3.2 单长度输入序列
单长度输入序列 RNN 网络中,输入序列长度为 1,即模型包含单个 \vec{\mathbf{x}}x 作为输入, 共有三种输入方式
- 输入 \vec{\mathbf{x}}x 作为 初始状态 \vec{\mathbf{h}}^{(0)}h(0)
该模型的数学表示为
o^{(t)}_k = p(y^{(t)} = k | y^{(0)}, y^{(1)},\dots, y^{(t-1)}), k = 1,2,\dots, Kok(t)=p(y(t)=k∣y(0),y(1),…,y(t−1)),k=1,2,…,K
单个样本的损失为
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)} + \mathbf{U}\vec{\mathbf{y}}^{(t-1)}a(t)=b+Wh(t−1)+Uy(t−1)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
- 输入 \vec{\mathbf{x}}x 作为每个 时间步 的输入
该模型的数学表示为
o^{(t)}_k = p(y^{(t)} = k | y^{(0)}, y^{(1)},\dots, y^{(t-1)},\vec{\mathbf{x}}), k = 1,2,\dots, Kok(t)=p(y(t)=k∣y(0),y(1),…,y(t−1),x),k=1,2,…,K
单个样本的损失为
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)} + \mathbf{U}\vec{\mathbf{y}}^{(t-1)} + \mathbf{R}\vec{\mathbf{x}}a(t)=b+Wh(t−1)+Uy(t−1)+Rx
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
其中输入到隐状态的权重为 \mathbf{R}R, 输出到隐状态的权重为 \mathbf{U}U,隐状态到输出的权重为 \mathbf{V}V,隐状态到隐状态的权重为 \mathbf{W}W,\vec{\mathbf{b}},\vec{\mathbf{c}}b,c 为输入偏置向量和输出偏置向量
- 两种方式的结合
输入 \vec{\mathbf{x}}x 作为初始状态 \vec{\mathbf{h}}^{(0)}h(0) 时,每个时间步也没有额外的输入
输出 y^{(t)}y(t) 用作 t+1t+1 时刻的输入来预测 y^{(t+1)}y(t+1),也用于 tt 时刻计算损失函数 L^{(t)}L(t)
零输入 RNN 的初始输出 y^{(0)}y(0) 是需要给定的,而这里的初始状态 \vec{\mathbf{h}}^{(0)}h(0) 是给定的
3.3 多长度输入序列
多长度输入序列 RNN 包含了 多输出 & 隐-隐连接、多输出 & 输出-隐连接、单输出 & 隐-隐连接 等网络类型
- 每个时间步都有输出,并且隐单元之间有循环连接
- 将一个输入序列映射到相同长度的输出序列
该模型的数学表示为
o^{(t)}_k = p(y^{(t)} = k | x^{(1)}, x^{(2)},\dots, x^{(t)}), k = 1,2,\dots, Kok(t)=p(y(t)=k∣x(1),x(2),…,x(t)),k=1,2,…,K
单个样本的损失为
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)} + \mathbf{U}\vec{\mathbf{x}}^{(t)}a(t)=b+Wh(t−1)+Ux(t)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
其中输入到隐状态的权重为 \mathbf{R}R, 输出到隐状态的权重为 \mathbf{U}U,隐状态到输出的权重为 \mathbf{V}V,隐状态到隐状态的权重为 \mathbf{W}W,\vec{\mathbf{b}},\vec{\mathbf{c}}b,c 为输入偏置向量和输出偏置向量
- 每个时间步都有输出,只有当前时刻的输出和下个时刻的隐单元之间有循环连接
- 将一个输入序列映射到相同长度的输出序列
该模型的数学表示为
o^{(t)}_k = p(y^{(t)} = k | x^{(1)}, x^{(2)},\dots, x^{(t)}), k = 1,2,\dots, Kok(t)=p(y(t)=k∣x(1),x(2),…,x(t)),k=1,2,…,K
单个样本的损失为
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{o}}^{(t-1)} + \mathbf{U}\vec{\mathbf{x}}^{(t)}a(t)=b+Wo(t−1)+Ux(t)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
其中输入到隐状态的权重为 \mathbf{R}R, 输出到隐状态的权重为 \mathbf{U}U,隐状态到输出的权重为 \mathbf{V}V,隐状态到隐状态的权重为 \mathbf{W}W,\vec{\mathbf{b}},\vec{\mathbf{c}}b,c 为输入偏置向量和输出偏置向量
- 隐单元之间存在循环连接,但是读取整个序列之后产生单个输出
- 将一个输入序列映射到单个输出
该模型的数学表示为
o^{(\tau)}_k = p(y^{(\tau)} = k | x^{(1)}, x^{(2)},\dots, x^{(\tau)}), k = 1,2,\dots, Kok(τ)=p(y(τ)=k∣x(1),x(2),…,x(τ)),k=1,2,…,K
单个样本的损失为
L = - \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(\tau)}} \log \hat{\mathbf{y}}_k^{(\tau)}L=−k=1∑KIk=y(τ)logy^k(τ)
更新方程
\vec{\mathbf{a}}^{(t)} = \vec{\mathbf{b}} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)} + \mathbf{U}\vec{\mathbf{x}}^{(t)}a(t)=b+Wh(t−1)+Ux(t)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
其中输入到隐状态的权重为 \mathbf{R}R, 输出到隐状态的权重为 \mathbf{U}U,隐状态到输出的权重为 \mathbf{V}V,隐状态到隐状态的权重为 \mathbf{W}W,\vec{\mathbf{b}},\vec{\mathbf{c}}b,c 为输入偏置向量和输出偏置向量
第4节 循环神经网络 BPTT 算法
4.1 RNN 前向传播
基于 3.3.1 节 多输出 & 隐-隐 连接
RNN 模型为例,RNN 时间序列下进行前向传播的权重更新公式为
\vec{\mathbf{a}}^{(t)} = \color{brown}{\vec{\mathbf{b}}} + \color{blue} {\mathbf{U}\vec{\mathbf{x}}^{(t)}} + \color{red}{\mathbf{W}\vec{\mathbf{h}}^{(t-1)}}a(t)=b+Ux(t)+Wh(t−1)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \color{brown}{\vec{\mathbf{c}}} + \color{green}{\mathbf{V}\vec{\mathbf{h}}^{(t)}}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t))
-
隐藏层
- 输入
- 时序数据 \vec{\mathbf{x}}^{(t)}x(t) 与 输入到隐藏连接权重矩阵 \color{blue}{U}U
- 前次隐藏层初始状态 \vec{\mathbf{h}}^{(t-1)}h(t−1) 与 隐藏到隐藏连接权重矩阵 \color{red}{W}W
- 隐藏层偏置值 \color{brown}{\vec{\mathbf{b}}}b
- 输出
- 使用 tanhtanh 输出当前隐藏层初始状态 \vec{\mathbf{h}}^{(t)}h(t)
- 输入
-
输出层
- 输入
- 当前隐藏层初始状态 \vec{\mathbf{h}}^{(t)}h(t) 与 隐藏到输出连接权重矩阵 \color{green}{V}V
- 输出层偏置值 \color{brown}{\vec{\mathbf{c}}}c
- 输出
- 使用 softmaxsoftmax 输出输出层权重 \vec{\mathbf{o}}^{(t)}o(t)
- 使用 softmaxsoftmax 输出时,假设 \vec{\mathbf{o}}^{(t)}o(t) 是未归一化的对数概率
- 输入
-
损失值
- 衡量每个 \vec{\mathbf{o}}^{(t)}o(t) 与相应的训练目标 \hat{\mathbf{y}}^{(t)}y^(t) 的距离
- 损失 LL 内部计算 \hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}})y^(t)=softmax(o)
关于各个参数计算这个损失函数的梯度是计算成本很高的操作,梯度计算涉及执行一次前向传播,接着是由右到左的反向传播
运行时间为 \vartheta(\tau)ϑ(τ), 并且不能通过并行化来降低,因为前向传播图是固有循序的,每个时间步只能一前一后地计算
前向传播中各个状态 必须保存, 直到在反向传播中被再次使用,因此内存代价也是 \vartheta(\tau)ϑ(τ)
4.2 RNN 反向传播
时序反向传播算法 (Back-Propagation Through Time, BPTT), 通过时间反向传播算法,其算法复杂度为 \vartheta(\tau)ϑ(τ), 由 BPTT 计算得到梯度,再结合任何通用的、基于梯度的技术就可以训练 RNN
计算 RNN 的梯度是容易的,可以简单地将 BP 算法应用于展开的 RNN 计算图,而不需要特殊化的算法,如下会演示对上述公式的梯度计算步骤
-
权重更新公式
\vec{\mathbf{a}}^{(t)} = \color{brown}{\vec{\mathbf{b}}} + \color{blue} {\mathbf{U}\vec{\mathbf{x}}^{(t)}} + \color{red}{\mathbf{W}\vec{\mathbf{h}}^{(t-1)}}a(t)=b+Ux(t)+Wh(t−1)
\vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{a}}^{(t)})h(t)=tanh(a(t))
\vec{\mathbf{o}}^{(t)} = \color{brown}{\vec{\mathbf{c}}} + \color{green}{\mathbf{V}\vec{\mathbf{h}}^{(t)}}o(t)=c+Vh(t)
\hat{\mathbf{y}}^{(t)} = softmax(\vec{\mathbf{o}}^{(t)})y^(t)=softmax(o(t)) -
单个样本损失函数
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
计算图的节点包括参数 \mathbf{U},\mathbf{V},\mathbf{W},\vec{\mathbf{b}},\vec{\mathbf{c}}U,V,W,b,c,以及以 \vec{\mathbf{x}}^{(t)},\vec{\mathbf{h}}^{(t)},\vec{\mathbf{o}}^{(t)}, \mathbf{y}^{(t)}, \mathbf{L}^{(t)}x(t),h(t),o(t),y(t),L(t) 为索引的节点序列
- BPTT 算法中,对于每一个节点 \mathcal{N}N, 需要基于 \mathcal{N}N 后面的节点的梯度,递归地计算梯度 \nabla_{\mathcal{N}}L∇NL
L = \sum\limits^{\tau}_{t=1}L^{(t)} \implies \left.{\partial L} \middle/ {\partial L^{(t)}} \right. = 1L=t=1∑τL(t)⟹∂L/∂L(t)=1
-
已知 \mathbf{y}^{(t)} = softmax(\mathbf{o}^{(t)})y(t)=softmax(o(t)),则有
L = - \sum\limits^{\tau}_{t=1} \sum\limits^K_{k=1} \mathbb{I}_{k = y^{(t)}} \log \hat{\mathbf{y}}_k^{(t)}L=−t=1∑τk=1∑KIk=y(t)logy^k(t)
\enspace\;\,= - o^{(t)}_{y^{(t)}} + \log \sum\limits ^ K _ {k=1} \exp (o^{(t)}_k)=−oy(t)(t)+logk=1∑Kexp(ok(t)) -
其中 o^{(t)}_kok(t) 表示 \vec{\mathbf{o}}^{(t)}o(t) 的第 kk 个分量,则有
(\nabla_{\vec{\mathbf{o}}^{(t)}}L)_k = \frac{\partial L}{\partial \vec{\mathbf{o}}^{(t)}_k}(∇o(t)L)k=∂ok(t)∂L
\qquad\quad\enspace= \frac{\partial L}{\partial L^{(t)}} \times \frac{\partial L^{(t)}}{\partial \vec{\mathbf{o}}^{(t)}_k}=∂L(t)∂L×∂ok(t)∂L(t)
\qquad\quad\enspace= 1 \times \frac{\partial L^{(t)}}{\partial \vec{\mathbf{o}}^{(t)}_k}=1×∂ok(t)∂L(t)
\qquad\quad\enspace= -\mathbb{I}_{k=y^{(t)}} + \left.{\exp (o^{(t)}_k)}\middle/{\sum\limits^K_{k'=1}\exp (o^{(t)}_{k'})}\right.=−Ik=y(t)+exp(ok(t))/k′=1∑Kexp(ok′(t))
\qquad\quad\enspace= \hat{\mathbf{y}}^{(t)}_k - \mathbb{I}_{k=y^{(t)}}=y^k(t)−Ik=y(t) -
其中 \mathbb{I}(\cdot)I(⋅) 为 示性函数 (Characteristic Function),则输出 o^{(t)}o(t) 的梯度写成向量形式为
\color{red}{\nabla_{\vec{\mathbf{o}}^{(t)}}L = \hat{\mathbf{y}}^{(t)}_k - y^{(t)}_k}∇o(t)L=y^k(t)−yk(t)
其中 y^{(t)}_k = (0,\dots,0,1,0,\dots,0)yk(t)=(0,…,0,1,0,…,0) 为真实标签 y^{(t)}y(t) 扩充得到的概率分布 (One-Hot Shot),其真实的类别 y^{(t)}_iyi(t) 位置上的分量为 1,而其它位置上的分量为 0
-
已知 \vec{\mathbf{h}}^{(t)} = tanh(\vec{\mathbf{b}} + \mathbf{U}\vec{\mathbf{x}}^{(t)} + \mathbf{W}\vec{\mathbf{h}}^{(t-1)})h(t)=tanh(b+Ux(t)+Wh(t−1)),则有
\vec{\mathbf{h}}^{(t+1)} = tanh(\vec{\mathbf{b}} + \mathbf{U}\vec{\mathbf{x}}^{(t+1)} + \mathbf{W}\vec{\mathbf{h}}^{(t)})h(t+1)=tanh(b+Ux(t+1)+Wh(t))
\implies h^{(t+1)}_i = tanh(b_i + \sum_i W_{i,j}h^{(t)}_j + \sum_j U_{i,j}x^{(t+1)}_j)⟹hi(t+1)=tanh(bi+∑iWi,jhj(t)+∑jUi,jxj(t+1)) -
已知双曲正切函数 tanh 的导数为 d\frac{tanh(x)}{dx} = 1 - tanh^2(x)ddxtanh(x)=1−tanh2(x), 则有
\frac{\partial h^{(t+1)}_i}{\partial h^{(t)}_j} = (1-(h_i^{(t+1)})^2) W_{i,j}∂hj(t)∂hi(t+1)=(1−(hi(t+1))2)Wi,j -
设隐向量长度为 n,则有
\qquad\qquad\frac{\partial \vec{\mathbf{h}}^{(t+1)}}{\partial \vec{\mathbf{h}}^{(t)}} = \begin{bmatrix}\frac{\partial h^{(t+1)}_1}{\partial h^{(t)}_1} & \dots & \frac{\partial h^{(t+1)}_n}{\partial h^{(t)}_1}\\\vdots & \ddots & \vdots\\\frac{\partial h^{(t+1)}_1}{\partial h^{(t)}_n} & \dots &\frac{\partial h^{(t+1)}_n}{\partial h^{(t)}_n}\end{bmatrix}∂h(t)∂h(t+1)=⎣⎢⎢⎢⎢⎡∂h1(t)∂h1(t+1)⋮∂hn(t)∂h1(t+1)…⋱…∂h1(t)∂hn(t+1)⋮∂hn(t)∂hn(t+1)⎦⎥⎥⎥⎥⎤
\;diag(1-(\vec{\mathbf{h}}^{(t+1)})^2) = \begin{bmatrix}1-(h_1^{(t+1)})^2 & 0 & \dots & 0\\0 & 1-(h_2^{(t+1)})^2 & \dots & 0\\\vdots & \vdots & \ddots & \vdots\\0 & 0 & \dots & 1-(h_n^{(t+1)})^2\end{bmatrix}diag(1−(h(t+1))2)=⎣⎢⎢⎢⎢⎢⎡1−(h1(t+1))20⋮001−(h2(t+1))2⋮0……⋱…00⋮1−(hn(t+1))2⎦⎥⎥⎥⎥⎥⎤
\qquad\qquad\color{blue}{\frac{\partial \vec{\mathbf{h}}^{(t+1)}}{\partial \vec{\mathbf{h}}^{(t)}} = diag(1-(\vec{\mathbf{h}}^{(t+1)})^2)W}∂h(t)∂h(t+1)=diag(1−(h(t+1))2)W -
已知 \vec{\mathbf{o}}^{(t)} = \vec{\mathbf{c}} + \mathbf{V}\vec{\mathbf{h}}^{(t)}o(t)=c+Vh(t), 则有
\color{green}{\left.{\partial \vec{\mathbf{o}}^{(t)}} \middle/ {\partial \vec{\mathbf{h}}^{(t)}} \right.= V}∂o(t)/∂h(t)=V -
因此可以得到隐单元 \vec{h}^{(t)}h(t) 的梯度
- 当 t = \taut=τ 时,\vec{\mathbf{h}}^{(\tau)}h(τ) 只有 一个 后续结点 \vec{\mathbf{o}}^{(\tau)}o(τ), 则有
\nabla_{\vec{\mathbf{h}}^{(\tau)}}L = (\color{green}{\left.{\partial \vec{\mathbf{o}}^{(t)}} \middle/ {\partial \vec{\mathbf{h}}^{(t)}} \right.})^T \nabla_{\vec{\mathbf{o}}^{(t)}}L∇h(τ)L=(∂o(t)/∂h(t))T∇o(t)L
\qquad\enspace= \color{green}{V}^T\nabla_{\vec{\mathbf{o}}^{(\tau)}}L=VT∇o(τ)L
- 当 t < \taut<τ 时,\vec{\mathbf{h}}^{(t)}h(t) 同时具有 两个 后续节点 \vec{\mathbf{o}}^{(t)},\vec{\mathbf{h}}^{(t+1)}o(t),h(t+1),则有
\nabla_{\vec{\mathbf{h}}^{(t)}}L = (\color{green}{\left.{\partial \vec{\mathbf{o}}^{(t)}} \middle/ {\partial \vec{\mathbf{h}}^{(t)}} \right.})^T \nabla_{\vec{\mathbf{o}}^{(t)}}L + (\color{blue}{\left.{\partial \vec{\mathbf{h}}^{(t+1)}} \middle/ {\partial \vec{\mathbf{h}}^{(t)}} \right.})^T \nabla_{\vec{\mathbf{h}}^{(t+1)}} L∇h(t)L=(∂o(t)/∂h(t))T∇o(t)L+(∂h(t+1)/∂h(t))T∇h(t+1)L
\qquad\enspace= \color{green}{V}^T\nabla_{\vec{\mathbf{o}}^{(\tau)}}L + \color{blue}{diag(1-(\vec{\mathbf{h}}^{(t+1)})^2)W}^T(\nabla_{\vec{\mathbf{h}}^{(t+1)}} L)=VT∇o(τ)L+diag(1−(h(t+1))2)WT(∇h(t+1)L)
从上可知,由于 \nabla_{\vec{\mathbf{h}}^{(t)}} L∇h(t)L 依赖于 \nabla_{\vec{\mathbf{h}}^{(t+1)}} L∇h(t+1)L,因此求解隐单元的梯度时,从末尾开始 反向计算 (Bottom-Up Approach)
- 当 t = \taut=τ 时,\vec{\mathbf{h}}^{(\tau)}h(τ) 只有 一个 后续结点 \vec{\mathbf{o}}^{(\tau)}o(τ), 则有
当获取计算图内部节点的梯度后,就可以得到关于参数节点的梯度
-
已知 o^{(t)}_i = \vec{\mathbf{c}} + \mathbf{V}h_i^{(t)}oi(t)=c+Vhi(t), 则有
\nabla_{\mathbf{V}} L = \sum\limits^{}_t \sum\limits_i (\frac{\partial L}{\partial o^{(t)}_i}) \nabla_{\mathbf{V}} o_i^{(t)}∇VL=t∑i∑(∂oi(t)∂L)∇Voi(t)
\color{red}{\qquad=\sum\limits^{}_t(\nabla_{o^{(t)}} L) h^{(t)^T}}=t∑(∇o(t)L)h(t)T
-
已知 h_i^{(t)} = tanh(\vec{\mathbf{b}} + \mathbf{W}h^{(t-1)}_i + \mathbf{U}x^{(t)})hi(t)=tanh(b+Whi(t−1)+Ux(t)), 则有
\nabla_{\mathbf{W}} L = \sum\limits^{}_t \sum\limits^{}_i (\frac{\partial L}{\partial h^{(t)}_i}) \nabla_{\mathbf{W}^{(t)}}h_i^{(t)}∇WL=t∑i∑(∂hi(t)∂L)∇W(t)hi(t)
\color{red}{\qquad=\sum\limits^{}_t diag(1 - (h^{(t)})^2)(\nabla_{h^{(t)}}L)h^{(t-1)^T}}=t∑diag(1−(h(t))2)(∇h(t)L)h(t−1)T
\nabla_{\mathbf{U}} L = \sum\limits^{}_t \sum\limits^{}_i (\frac{\partial L}{\partial h^{(t)}_i}) \nabla_{\mathbf{U}^{(t)}}h_i^{(t)}∇UL=t∑i∑(∂hi(t)∂L)∇U(t)hi(t)
\color{red}{\qquad=\sum\limits^{}_t diag(1 - (h^{(t)})^2)(\nabla_{h^{(t)}}L)x^{(t)^T}}=t∑diag(1−(h(t))2)(∇h(t)L)x(t)T
-
已知 h_i^{(t)} = tanh(\vec{\mathbf{b}} + \mathbf{W}h^{(t-1)}_i + \mathbf{U}x^{(t)})hi(t)=tanh(b+Whi(t−1)+Ux(t)), 则有
\nabla_{\mathbf{b}} L = \sum\limits^{}_t (\frac{\partial h^{(t)}}{\partial b^{(t)}})^T \nabla_{\mathbf{h}^{(t)}} L∇bL=t∑(∂b(t)∂h(t))T∇h(t)L
\color{red}{\quad\quad=\sum\limits^{}_t diag(1 - (h^{(t)})^2)\nabla_{h^{(t)}} L}=t∑diag(1−(h(t))2)∇h(t)L
-
已知 o^{(t)}_i = \vec{\mathbf{c}} + \mathbf{V}h_i^{(t)}oi(t)=c+Vhi(t), 则有
\nabla_{\mathbf{V}} L = \sum\limits^{}_t (\frac{\partial o^{(t)}}{\partial c})^T \nabla o{(t)} L∇VL=t∑(∂c∂o(t))T∇o(t)L
\color{red}{\qquad=\sum\limits^{}_t \nabla_{o^{(t)}} L}=t∑∇o(t)L
因为任何参数都不是训练数据 \vec{\mathbf{x}}^{(t)}x(t) 的父节点,因此不需要计算 \nabla_{\vec{\mathbf{x}}^{(t)}}L∇x(t)L
开始实验