RNN-LSTM
1.RNN
RNN-Recurrent Neural Network-循环神经网络
RNN用来处理序列数据。多层感知机MLP层间节点全联接,层内节点并无链接。 RNN层内节点的之间存在连接关系,用来反映上一层隐层状态作为下一层的输入,将直接输给中间隐藏层。
RNN网络模块图如下所示:
其中:
x
t
x_t
xt 网络t时刻输入,
h
t
h_t
ht 网络t时刻的输出。 如果将RNN按时间序列展开,可以得到以下链式结构:
用简单的权重矩阵建模rnn, 输入-状态-输出之间存在以下的关系:[
o
t
o_t
ot即上文的
h
t
h_t
ht]
s
t
=
f
(
U
⋅
x
t
+
W
⋅
s
t
−
1
)
s_{t} = f(U\cdot x_t + W\cdot s_{t-1})
st=f(U⋅xt+W⋅st−1)
o
t
=
g
(
V
⋅
s
t
)
o_t = g(V\cdot s_t)
ot=g(V⋅st)
s t − 1 s_{t-1} st−1能够建模历史信息对当前输出的影响。原始RNN随着时间的推移,历史状态对当前输出的影响减弱。但是很多任务需要长时依赖关系。LSTM营运而生。
2.LSTM
LSTM-Long Short-Term Memory 可以学习长时依赖信息,LSTM网络模块图如下所示:
状态传递机制决定了上一时刻状态信息的保留量,以及新输入信息的增量。LSTM包含三个关键的门用于实现这一传递机制。
**遗忘门:**上一时刻输出和这一个时刻输入决定上一时刻的状态保留百分比
f
t
f_t
ft。【sigmoid输出0-1 之间的一个数】
输入门:
C
~
t
\tilde{C}_t
C~t为新信息候选向量,
i
t
i_t
it 决定了多少新信息候选向量能够通过。随后更新状态信息:
输出门: 当前状态
C
t
C_t
Ct 和
h
t
−
1
h_{t-1}
ht−1 以及
x
t
x_t
xt 共同决定当前时刻输出信息
h
t
h_t
ht
参考资料:https://colah.github.io/posts/2015-08-Understanding-LSTMs/
3. tensorflow 中的RNN-LSTM
RNNCell是TensorFlow中实现RNN的基本单元,每个RNNCell都有一个call方法,使用方式是:(output, next_state) = call(input, state)。RNNCell是一个抽象类,实际使用时候,用它的两个子类BasicRNNCell [RNN的基础类] 和BasicLSTMCell [LSTM的基础类]。
3.1 tf.nn.rnn_cell.BasicRNNCell()
RNNCell,具有两个比较重要类属性:state_size–决定隐层的大小,output_size决定输出大小
例如将(batch_size, input_size)数据输入RNN,得到的隐层状态就是(batch_size, state_size),输出是(batch_size, output_size)。
import tensorflow as tf
import numpy as np
cell = tf.nn.rnn_cell.BasicRNNCell(num_units=128) # state_size = 128
print(cell.state_size) # 128
inputs = tf.placeholder(np.float32, shape=(32, 100)) # batch_size=32
h0 = cell.zero_state(32, np.float32) # 全零状态(batch_size, state_size)
output, h1 = cell.call(inputs, h0)
print(h1.shape) # (32, 128)
、
3.2 tf.nn.rnn_cell.BasicLSTMCell()
tf.nn.rnn_cell.BasicLSTMCell(
num_units, # int类型,隐层输出大小
forget_bias=1.0, # float类型, 遗忘门偏置
state_is_tuple=True, # 回的状态是h_t和c_t的2元tuple LSTM可以看做有两个隐状态h和c
activation=None, # 内部状态的激活函数。默认为tanh
reuse=None,
name=None,
dtype=None
)
3.3 tf.nn.dynamic_rnn()–多步执行循环神经网络
基础的RNNCell使用它的call函数进行运算时,只是在序列时间上前进了一步。例如使用(x1,h0)得到h1,(x2, h1)得到h2等。如果序列长度为10,需调用10次call函数,比较麻烦。
TensorFlow提供了一个tf.nn.dynamic_rnn函数,该函数可实现n次调用call函数。即通过{h0,x1, x2, …., xn}得{h1,h2…,hn}。
输入数据格式为(batch_size, time_steps, input_size),其中time_steps表示序列长度,input_size表示单个序列元素的特征长度。
tf.nn.dynamic_rnn(
cell, inputs, sequence_length=None, initial_state=None, dtype=None,
parallel_iterations=None, swap_memory=False, time_major=False, scope=None
)
对于一个定义的的cell ,多次执行该cell 的demo 为:
outputs, state = tf.nn.dynamic_rnn(cell, inputs, initial_state=initial_state)
# outputs就是time_steps步里所有的输出-(batch_size, time_steps, cell.output_size)。state是最后一步的隐状态,它的形状为(batch_size, cell.state_size)。
动态调整sequence_length tf.nn.dynamic_rnn 详解