Recurrent Neural Network

Recurrent Neural Network

RNN:处理前后数据有关联的序列数据

rnn_unfolding

  • 左侧:为折叠的神经网络,右侧:按时序展开后的网络
  • $h$:循环隐层,其中神经元之间有权连接,随序列输入上一期 隐层会影响下一期
  • $o$、$y$:输出预测值、实际值
  • $L$:损失函数,随着时间累加
  • 序列往往长短不一,难以拆分为独立样本通过普通DNN训练

结构

rnn_structures

  • 普通的DNN:固定大小输入得到固定输出
  • 单个输入、序列输出:输入图片,得到描述文字序列
  • 序列输入、单个输出:情感分析
  • 异步序列输入、输出:机器翻译
  • 同步序列输入、输出:视频帧分类

权值连接

  • 循环隐层内神经元之间也建立权连接,即循环

    • 基础神经网络只在层与层之间建立权值连接是RNN同普通DNN 最大不同之处
  • 循环隐层中神经元只会和其当前层中神经元建立权值连接

    • 即不受上期非同层神经元影响
    • 循环隐层中神经元$t$期状态$h^{(t)}$由当期输入、 $h^{(t-1)}$共同决定
  • Gated Feedback RNN:循环隐层会对下期其他隐层产生影响 rnn_gated_feedback

逻辑结构

  • RNN网络实际结构是线性、折叠的,逻辑结构则是展开的结构, 考虑RNN性质应该在展开的逻辑结构中考虑
  • 序列输入

    • 实际结构:依次输入
    • 逻辑结构:里是整体作为一次输入、才是一个样本,损失、 反向传播都应该以完整序列为间隔
  • 权值共享

    • 实际结构:不同期的权值实际是同一组
    • 逻辑结构:称为权值共享
  • 重复模块链

    • 实际结构:同一个模块
    • 逻辑结构:不同期模块之间信息流动形成链式形式

信息传递

  • RNN循环层中信息只能由上一期直接传递给下一期
  • 输入、输出相关信息间隔较近时,普通RNN可以胜任

    rnn_short_dependencies

  • 当间隔很长,RNN理论上虽然能够处理,但由于梯度消失问题, 实际上长期依赖会消失,需要LSTM网络

    rnn_long_dependencies

Forward Propogation

  • $h^{(t)} = \sigma(z^{(t)}) = \sigma(Ux^{(t)} + Wh^{(t-1)} +b )$

    • $\sigma$:RNN激活函数,一般为$tanh$
    • $b$:循环隐层偏置
  • $o^{(t)} = Vh^{(t)} + c$

    • $c$:输出层偏置
  • $\hat{y}^{(t)} = \sigma(o^{(t)})$

    • $\sigma$:RNN激活函数,分类时一般时$softmax$

Back-Propogation Through Time

BPTT:训练RNN的常用方法

  • 本质仍然是BP算法,但是RNN处理序列数据,损失随期数累加, 即计算梯度时使用最终损失$L = \sum_{t=1}^\tau L^{(t)}$

  • 对循环层中参数,梯度沿着期数反向传播,第t期反向传播时, 需要逐级求导

  • 序列整体作为一次输入,进行一次反向传播
  • 理论上可以漂亮的解决序列数据的训练,但是和DNN一样有梯度 消失的问题,尤其是序列很长时,所以一般不能直接应用

非循环层

  • $\frac{\partial L}{\partial c}$

    • $L^{(t)} = \frac 1 2 (\hat{y}^{(t)} - y^{(t)})^2$: 使用平方损失
  • $\frac{\partial L}{\partial V}$

循环层

  • 为方便定义: $\delta^{(t)} = \frac {\partial L} {\partial h^{(t)}}$
  • $\delta^{(t)}$

    • $\frac{\partial h^{(t+1)}}{\partial h^{(t)}} = diag(1-h^{(t+1)})^2)$ :$tanh(x)$梯度性质
    • $h^{(t)}(t<\tau)$梯度:被后一期影响(反向传播),需递推
  • $\delta^{(\tau)}$

    • $\tau$期后没有其他序列,可以直接求出
  • $\frac{\partial L}{\partial W}$

    • 需要由$\sigma^{(t)}$累加得到
  • $\frac{\partial L}{\partial b}$

  • $\frac{\partial L}{\partial U}$

}$$

RNN

RNN

1
2
3
4
5
6
7
8
keras.layers.RNN(
cell,
return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
unroll=False
)

循环神经网络层基类:抽象类、无法实例化对象

  • 参数

    • cell:RNN单元实例、列表,为RNN单元列表时,单元 堆叠放置,实现高效堆叠RNN

    • return_sequences:返回输出序列最后值/全部序列

    • return_state:是否返回最后一个状态

    • go_backwards:是否向后处理输入序列并返回相反的序列。

    • stateful:批次中索引i处的每个样品的最后状态将 用作下一批次中索引i样品的初始状态

    • unroll:是否将网络展开(否则将使用符号循环)

      • 展开可以加速 RNN,但它往往会占用更多的内存
      • 展开只适用于短序列
    • input_dim:输入的维度(整数)

      • 将此层用作模型中的第一层时,此参数是必需的 (或者关键字参数 input_shape
    • input_length: 输入序列的长度,在恒定时指定

      • 如果你要在上游连接 FlattenDense 层,则 需要此参数(没有它,无法计算全连接输出的尺寸)
      • 如果循环神经网络层不是模型中的第一层,则需要在 第一层的层级指定输入长度 (或通过关键字参数input_shape
  • 输入:(batch_size, timesteps, input_dim)3D张量

  • 输出

    • return_state=True:则返回张量列表,第一个张量为 输出、剩余的张量为最后的状态,每个张量的尺寸为 (batch_size, units)
    • return_state=False(batch_size, units)2D张量

说明

  • 屏蔽覆盖:支持以可变数量的时间步长对输入数据进行屏蔽覆盖

  • 使用状态:可以将 RNN 层设置为 stateful(有状态的)

    • 这意味着针对一批中的样本计算的状态将被重新用作下一批 样品的初始状态
    • 这假定在不同连续批次的样品之间有一对一的映射。

    • 为了使状态有效:

      • 在层构造器中指定 stateful=True
      • 为模型指定一个固定的批次大小
        • 顺序模型:为模型的第一层传递一个 batch_input_shape=(...) 参数
        • 带有Input层的函数式模型,为的模型的所有i 第一层传递一个batch_shape=(...),这是输入 预期尺寸,包括批量维度
      • 在调用 fit() 是指定 shuffle=False
    • 要重置模型的状态,请在特定图层或整个模型上调用 .reset_states()

  • 初始状态

    • 通过使用关键字参数initial_state调用它们来符号化地 指定 RNN 层的初始状态(值应该是表示RNN层初始状态的 张量或张量列表)
    • 通过调用带有关键字参数statesreset_states方法 来数字化地指定 RNN 层的初始状态(值应该是一个代表RNN 层初始状态的NDA/[NDA])
  • RNN单元对象需要具有

    • call(input_at_t, states_at_t)方法,它返回 (output_at_t, states_at_t_plus_1),单元的调用 方法也可以采用可选参数 constants
    • state_size属性
      • 单个整数(单个状态):在这种情况下,它是循环层 状态大小(应该与单元输出的大小相同)
      • 整数的列表/元组(每个状态一个大小):第一项应该 与单元输出的大小相同
  • 传递外部常量

    • 使用RNN.call以及RNN.callconstants关键字 参数将外部常量传递给单元
    • 要求cell.call方法接受相同的关键字参数constants, 这些常数可用于调节附加静态输入(不随时间变化)上的 单元转换,也可用于注意力机制

例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class MinimalRNNCell(keras.layers.Layer):
# 定义RNN细胞单元(网络层子类)
def init(self, units, **kwargs):
self.units = units
self.state_size = units
super(MinimalRNNCell, self).init(**kwargs)

def build(self, input_shape):
self.kernel = self.add_weight(
shape=(input_shape[-1], self.units),
initializer="uniform",
name="kernel"
)
self.recurrent_kernel = self.add_weight(
shape=(self.units, self.units),
initializer="uniform",
name="recurrent_kernel")
self.built = True

def call(self, inputs, states):
prev_output = states[0]
h = K.dot(inputs, self.kernel)
output = h + K.dot(prev_output, self.recurrent_kernel)
return output, [output]

cell = MinimalRNNCell(32)
# 在RNN层使用这个单元:
x = keras.Input((None, 5))
layer = RNN(cell)
y = layer(x)


cells = [MinimalRNNCell(32), MinimalRNNCell(64)]
# 用单元格构建堆叠的RNN的方法:
x = keras.Input((None, 5))
layer = RNN(cells)
y = layer(x)

SimpleRNN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
keras.layers.SimpleRNN(
units,
activation="tanh",
use_bias=True,
kernel_initializer="glorot_uniform",
recurrent_initializer="orthogonal",
bias_initializer="zeros",
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
unroll=False
)

完全连接的RNN,其输出将被反馈到输入。

  • 参数

    • units:正整数,输出空间的维度。

    • activation:要使用的激活函数

      • tanh:默认
      • None:则不使用激活函数,即线性激活:a(x) = x
    • use_bias:布尔值,该层是否使用偏置向量。

    • kernel_initializerkernel权值矩阵的初始化器

    • recurrent_initializerrecurrent_kernel权值矩阵

    • bias_initializer:偏置向量的初始化器

    • kernel_regularizer:运用到kernel权值矩阵的正则化 函数

    • recurrent_regularizer:运用到 recurrent_kernel 权值 矩阵的正则化函数

    • bias_regularizer:运用到偏置向量的正则化函数

    • activity_regularizer:运用到层输出(它的激活值)的 正则化函数

    • kernel_constraint:运用到kernel权值矩阵的约束函数

    • recurrent_constraint:运用到recurrent_kernel权值矩阵 的约束函数

    • bias_constraint: 运用到偏置向量的约束函数

    • dropout:单元的丢弃比例,用于输入的线性转换

      • 0-1之间的浮点数
    • recurrent_dropout:单元的丢弃比例,用于循环层状态线性 转换

    • return_sequences:返回输出序列中的全部序列

      • 默认:返回最后最后一个输出
    • return_state:除输出之外是否返回最后一个状态

    • go_backwards:向后处理输入序列并返回相反的序列

    • stateful:批次中索引 i 处的每个样品的最后状态,将用作 下一批次中索引 i 样品的初始状态

    • unroll:展开网络

GRU

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
keras.layers.GRU(
units,
activation="tanh",
recurrent_activation="hard_sigmoid",
use_bias=True,
kernel_initializer="glorot_uniform",
recurrent_initializer="orthogonal",
bias_initializer="zeros",
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
implementation=1,
return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
unroll=False,
reset_after=False
)

门限循环单元网络

LSTM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
keras.layers.LSTM(
units,
activation="tanh",
recurrent_activation="hard_sigmoid",
use_bias=True,
kernel_initializer="glorot_uniform",
recurrent_initializer="orthogonal",
bias_initializer="zeros",
unit_forget_bias=True,
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
implementation=1,
return_sequences=False,
return_state=False,
go_backwards=False,
stateful=False,
unroll=False
)

长短期记忆网络层(Hochreiter 1997)

ConvLSTM2D

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
keras.layers.ConvLSTM2D(
filters(int),
kernel_size(tuple(int, int)),
strides=(1, 1),
padding='valid',
data_format=None,
dilation_rate=(1, 1),
activation='tanh',
recurrent_activation='hard_sigmoid',
use_bias=True,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
unit_forget_bias=True,
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
return_sequences=False,
go_backwards=False,
stateful=False,
dropout=0.0,
recurrent_dropout=0.0
)

卷积LSTM:它类似于LSTM层,但输入变换和循环变换都是卷积的

  • 说明

    • 当前的实现不包括单元输出的反馈回路
  • 参数

    • dilation_rate:用于膨胀卷积的膨胀率
      • stride!=1dilation_rate!=1两者不兼容。
  • 输入尺寸

    • data_format="channels_first":尺寸为 (batch, time, channels, rows, cols)
    • data_format="channels_last":尺寸为 (batch, time, rows, cols, channels)
  • 输出尺寸

    • return_sequences=True

      • data_format="channels_first":返回尺寸为 (batch, time, filters, output_row, output_col)

      • data_format="channels_last":返回尺寸为 (batch, time, output_row, output_col, filters)

    • return_seqences=False

      • data_format ="channels_first":返回尺寸为 (batch, filters, output_row, output_col)

      • data_format="channels_last":返回尺寸为 (batch, output_row, output_col, filters)

  • 参考文献

SimpleRNNCell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
keras.layers.SimpleRNNCell(
units,
activation='tanh',
use_bias=True,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0
)

SimpleRNN的单元类

GRUCell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
keras.layers.GRUCell(
units,
activation='tanh',
recurrent_activation='hard_sigmoid',
use_bias=True,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
implementation=1
)

GRU层的单元类

LSTMCell

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
keras.layers.LSTMCell(
units,
activation='tanh',
recurrent_activation='hard_sigmoid',
use_bias=True,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
unit_forget_bias=True,
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
dropout=0.0,
recurrent_dropout=0.0,
implementation=1
)

LSTM层的单元类

StackedRNNCells

1
keras.layers.StackedRNNCells(cells)

将一堆RNN单元表现为一个单元的封装器

  • 说明

    • 用于实现高效堆叠的 RNN。
  • 参数

    • cells:RNN 单元实例的列表

例子

1
2
3
4
5
6
7
8
cells = [
keras.layers.LSTMCell(output_dim),
keras.layers.LSTMCell(output_dim),
keras.layers.LSTMCell(output_dim),
]

inputs = keras.Input((timesteps, input_dim))
x = keras.layers.RNN(cells)(inputs)

CuDNNGRU

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
keras.layers.CuDNNGRU(
units,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
return_sequences=False,
return_state=False,
stateful=False
)

CuDNN 支持的快速GRU实现

  • 说明

    • 只能以TensorFlow后端运行在GPU

CuDNNLSTM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
keras.layers.CuDNNLSTM(
units,
kernel_initializer='glorot_uniform',
recurrent_initializer='orthogonal',
bias_initializer='zeros',
unit_forget_bias=True,
kernel_regularizer=None,
recurrent_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
recurrent_constraint=None,
bias_constraint=None,
return_sequences=False,
return_state=False,
stateful=False
)

CuDNN 支持的快速LSTM实现

  • 说明

    • 只能以TensorFlow后端运行在GPU