优化RNN

3.4 优化RNN


RNN擅长处理序列数据,尤其当后面数据与前面数据有依赖关系时。不过,如果这种依赖涉及长依赖的话,使用RNN的效果将受到较大影响,因长依赖就意味着时间步就要大,而根据梯度的关联规则,会发现累乘会导致激活函数导数的累乘,如果取tanh或sigmoid函数作为激活函数的话,那么必然是一堆小数在做乘法,结果就是越乘越小。随着时间序列的不断深入,小数的累乘就会导致梯度越来越小直到接近于0,这就是“梯度消失“现象。实际使用中,会优先选择tanh函数,原因是tanh函数相对于sigmoid函数来说梯度较大,收敛速度更快且引起梯度消失更慢。通常减缓梯度消失的几种方法:
1、选取更好的激活函数,如Relu激活函数。ReLU函数的左侧导数为0,右侧导数恒为1,这就避免了“梯度消失“的发生。但大于1的导数容易导致“梯度爆炸“,但设定合适的阈值可以解决这个问题。
2、加入BN层,其优点包括可加速收敛、控制过拟合,可以少用或不用Dropout和正则、降低网络对初始化权重不敏感,且能允许使用较大的学习率等。
3、改变传播结构,LSTM结构可以有效解决这个问题。接下来我们将介绍LSTM相关内容。
这些方法中,LSTM比其他几种方法效果要好,LSTM的核心思想就是增加一条记忆以往信息的传送带,这条传送带通过各种更新信息相加,而从有效避免梯度消失问题。
LSTM成功用于许多应用(如语言建模,手势预测,用户建模)。 LSTM基于记忆的序列建模架构非常有影响力——它启发了许多最新的改进方法,例如Transformers。

3.4.1 LSTMCell

1.RNN与LSTM的关系图

 

图1-14 RNN与LSTM的关系
从图1-14 可知,RNN对应LSTM中方框部分,方框部分的信息就是当前状态信息,该信息将通过输入门之后加入到传送带C中。

2.LSTMCell整体架构图
LSTM 通过精心设计的称作为“门”的结构来去除或者增加信息到传送带C状态的能力。门是一种让信息选择式通过的方法。他们通过含激活 sigmoid 神经网络层形成门(如图1-15中等信息进行过滤。

图1-15 LSTM架构图
LSTM三个门的主要功能:

输入门对当前信息C ̃_t进行过滤,其表示式为:

2.LSTMCell的详细结构

图1-16 LSTM的详细内部结构图
为简明起见,图1-16中假设输入为3个元素的向量,隐藏状态及传送信息都是2个元素的向量。隐藏状态与输入拼接成5个元素的向量。实际应用中输入、状态一般加上批量等维度,如[batch,input_size],如果在LSTM模块中还需加上序列长度,形如[batch,seg_len,input_size]。multiplication是指哈达玛积,S表示Softmoid,T表示Tanh。

3.4.2 LSTMCell

LSTMCell这是LSTM的一个单元,如图1-15所示。该单元可以用PyTorch的 nn.LSTMCell模块来实现,该模块构建LSTM中的一个Cell,同一层会共享这一个Cell,但要手动处理每个时刻的迭代计算过程。如果要建立多层的LSTM,就要建立多个nn.LSTMCell。
1 .构造方法
构造方法和nn.RNNcell类似,依次传入feature_len和hidden_len,因为这只是一个计算单元,所以不涉及层数。
2. forward方法
回顾一下nn.RNNCell的forward方法,它是:
ht=nn.rnncell(x,ht-1)
即上一时刻的输出ht−1经nn.RNNCell前向计算得到这一时刻的ht。
对于nn.LSTMCell也是类似,但因为LSTM计算单元中还涉及对上一时刻的记忆Ct−1的使用,所以是
ht,ct=lstmcell(xt,(ht-1,ct-1))
因为输入xt只是t时刻的输入,不涉及seq_len,所以其shape是[batch,feature_len]
而ht和Ct在这里只是t时刻本层的隐藏单元和记忆单元,不涉及num_layers,所以其shape是 [batch,hidden_len]

3.4.3 一层的例子

每个时刻传入新的输入xt和上一时刻的隐藏单元ht−1和记忆单元Ct−1,并把这两个单元更新。

3.4.4 两层的例子

在最底下一层l0层和上面的例子一样,上层还需要接受下层的输出ht作为当前输入,然后同样是依赖本层上一时刻的h和C更新本层的h和C。注意LSTM单元的输入输出结构,向上层传递的是h而不是C。

3.4.5 PyTorch的LSTM模块

https://zhuanlan.zhihu.com/p/139617364
1、多层LSTM的网络架构

图1-17 多层LSTM架构图
2、LSTM模块

3、输入
input(seq_len, batch, input_size)
参数有:
seq_len:序列长度,在NLP中就是句子长度,一般都会用pad_sequence补齐长度
batch:每次喂给网络的数据条数,在NLP中就是一次喂给网络多少个句子
input_size:特征维度,和前面定义网络结构的input_size一致

图1-18 LSTM的输入格式
如果LSTM的参数 batch_first=True,则要求输入的格式是:input(batch, seq_len, input_size)
4、隐含层
LSTM有两个输入是 h0 和 c0,可以理解成网络的初始化参数,用随机数生成即可。

参数:
num_layers:隐藏层数
num_directions:如果是单向循环网络,则num_directions=1,双向则num_directions=2
batch:输入数据的batch
hidden_size:隐藏层神经元个数
注意,如果我们定义的input格式是:
input(batch, seq_len, input_size)
则H和C的格式也是要变的:

5、输出
LSTM的输出是一个tuple,如下:
output,(ht, ct) = net(input)
output: 最后一个状态的隐藏层的神经元输出
ht:最后一个状态的隐含层的状态值
ct:最后一个状态的隐含层的遗忘门值
output的默认维度是:

和input的情况类似,如果我们前面定义的input格式是:
input(batch, seq_len, input_size)
则ht和ct的格式也是要变的:

3.5 LSTM实现文本生实例

本实例使用2014人民日报上的一些新闻,使用PyTorch提供的nn.LSTM模型,根据提示字符串预测给定长度的语句。整个处理与3.3小节基本相同,构建模型时稍有不同,LSTM有两个变量h和c,RNN只要一个h。

3.6 GRU结构

https://blog.csdn.net/Jerr__y/article/details/58598296
LSTM门比较多,状态有C和H,其中C就相当于中间变量一样,输出只有H。有关LSTM的改进方案比较多,其中比较著名的变种 GRU(Gated Recurrent Unit ),这是由 Cho, et al. (2014) 提出。在 GRU 中,如 下图所示,只有两个门:重置门(reset gate)和更新门(update gate)。同时在这个结构中,把细胞状态和隐藏状态进行了合并。最后模型比标准的 LSTM 结构要简单,而且这个结构后来也非常流行。

图1-19 GRU模型结构图
其中,r_t 表示重置门,z_t表示更新门。重置门决定是否将之前的状态(h_(t-1))忘记。当r_t趋于 0 的时候,前一个时刻的状态信息 h_(t-1)将被忘掉,隐藏状态 h_t会被重置为当前输入的信息。更新门决定是否要将隐藏状态更新为新的状态 h ̃_t (更新门的作用相当于合并了 LSTM 中的遗忘门和输入门)。
和 LSTM 比较一下:
(1) GRU 少一个门,同时少了传送带状态 C_t。
(2) 在 LSTM 中,通过遗忘门和输入门控制信息的保留和传入;GRU 则通过重置门来控制是否要保留原来隐藏状态的信息,但是不再限制当前信息的传入。
(3) 在 LSTM 中,虽然得到了新的传送带状态 C_t,但是它仅仅作为一个中间变量,不直接输出,而是需要经过一个过滤的处理:
h_t=O_t 〖⊗tanh⁡(C〗_t)
同样,在 GRU 中, 虽然 (2) 中也得到了新的隐藏状态h_t, 但是还不能直接输出,而是通过更新门来控制最后的输出:
h_t=(1-z_t )⊗h_(t-1)+z_t⊗h ̃_t
保留以往隐藏状态(h_(t-1))和保留当前隐藏状态(h ̃_t)之间是一种互斥关系,这点从上面这个公式也可说明。如果z_t 越接近1,则(1-z_t )就越接近于0;反之,也成立。

3.7 biRNN结构

1.biRNN的网络架构
图1-20 为biRNN的网络架构图,从图中还可以看出,对于一个序列,一次向前遍历得到左LSTM,向后遍历得到右LSTM。隐层矢量直接通过拼接(concat)得到,最终损失函数直接相加,具体如下图。

图1-20 biRNN模型结构图
2、biRNN的不足
(1)biRNN模型的前向和后向LSTM模型是分开训练的,故它不是真正双向学习的模型,即biRNN无法同时向前和向后学习。
(2)biRNN如果层数多了,将出现自己看到自己的情况。下图中第2行第2列中的A|CD,此结果是第一层Bi LSTM的B位置输出内容,包括正向A和反向CD,然后直接拼接就得到A| CD。下图中第3行第2列中的ABCD, 此结果为正向BCD和反向AB | D拼接而成,当前位置需要预测的是B,但B已经在这里ABCD出现了。所以对于Bi LSTM,只要层数增加,会有一个“看到你自己”的问题。

 

图1-21 多层biRNN将自己看到自己示意图

发表评论