从RNN到Sequence2Sequence(二) LSTM

前言:由于梯度消失的存在,在实际应用中,RNN很难处理长距离的依赖。RNN的一种改进版本:长短时记忆网络(Long Short Term Memory Network, LSTM)。 LSTM就是用来解决RNN中梯度消失问题的。
怎么解决的呢?
LSTM增加了一个可以相隔多个timesteps来传递信息的方法。想想有一个传送带在你处理sequences时一起运转。每个时间节点的信息都可以放到传送带上,或者从传送带上拿下来,当然你也可以更新传送带上的信息。这样就保存了很久之前的信息,防止了信息的丢失。

LSTM

一、概述

从RNN到Sequence2Sequence(二) LSTM
如果把LSTM当成黑盒子看待,可以分为以下关键变量(参考上图):

  1. 输入:(h_{t-1}) (t-1时刻的隐藏层向量)和 (x_t)(t时刻的特征向量)
  2. 输出:(h_t)(加softmax即可作为真正输出,否则作为隐藏层)
  3. 主线/记忆: (c_{t-1})(c_t)
    LSTM分为三个部分:
  • 遗忘门:决定了上一时刻的单元状态(c_{t-1})有多少保留到当前时刻(c_t)。如果之前单元状态中有主语,而输入中又有了主语,那么原来存在的主语就应该被遗忘。concatenate的输入和上一时刻的输出经过sigmoid函数后,越接近于0被遗忘的越多,越接近于1被遗忘的越少。
  • 输入门:决定了当前时刻网络的输入(x_t)有多少保存到单元状态(c_t);即哪些新的状态应该被加入。新进来的主语自然就是应该被加入到细胞状态的内容,同理也是靠sigmoid函数来决定应该记住哪些内容。
  • 输出门:控制单元状态(c_t)有多少输出到LSTM的当前输出值(h_t)。根据当前的状态和现在的输入,确定输出的比例。

从RNN到Sequence2Sequence(二) LSTM

  • (h_{t-1})(x_t)联合起来作为最终的输入数据。
  • (c_{t-1})(c_t)始终与外界隔离开来,显然是作为LSTM记忆或者主线剧情的存在。
  • (f_t)为遗忘门的输出。主线进来后,首先受到遗忘门的衰减作用。
  • (i_t)为输入门的输出。输入门控制“补给大小”,给主线补充能量生成全新的主线。
  • (o_t)为输出门的输出,其经过变换得到当前时刻的隐层向量(h_t),同时也为当前时刻的输出。

二、三个门的计算公式,在时间步t。

假设1个batch,输入为[1,length,d]。length是预定义的最大序列长度, (d)是序列中每个step的维度。隐层神经元个数为(h)

  • 遗忘门部分

[f_t = sigma(W_{if}x_t + W_{hf}h_{t-1}) qquad (遗忘门)\ k_t = c_{t-1} odot f_t qquad (主线遗忘)]

(x_t = [1,d])(h_{t-1} = [1,h]),则遗忘门权重矩阵的形状 (W_f = [d+h,h]),遗忘门的输出(f_t = [1,h])

  • 输入门部分

[i_t = sigma (W_{ii}x_t + W_{hi}h_{t-1}) qquad (输入门) \ g_t = tanh(W_{ig}x_t + W_{hg}h_{t-1}) qquad (补给来源) \ j_t = i_t odot g_t qquad (门控制补给大小) \ c_t= j_t+ k_t qquad (补给主线) \]

输入门矩阵(W_i = [d+h,h]),输入门矩阵的输出(i_t =[1,h]);
补给矩阵(W_g=[d+h,h]),补给输出(g_t=[1,h]);
补给主线(c_t=[1,h])

  • 输出门部分

[o_t = sigma (W_{io}x_t + W_{ho}h_{t-1}) qquad (输出门) \ h_t= tanh(c_t)odot o_t qquad (主线最终输出) \]

输出门矩阵(W_o = [d+h,h]),输出门输出(o_t=[1,h])
最终的输出(h_t=[1,h])

三、LSTM参数的数量

LSTM参数应该指包括embedding层的整个网络的参数的数量。
LSTM的参数计算公式:

[num(Embedding)+num(LSTM)=Word embedding dim * Vocab size +(hidden size * (hidden size + x_dim ) + hidden size) *4 ]

四、LSTM 和 RNN 结构对比

从RNN到Sequence2Sequence(二) LSTM
从RNN到Sequence2Sequence(二) LSTM

LSTM实现:时间序列预测

数据集:AirPassengers。1949 到 1960 一共 12 年,每年 12 个月的数据,一共 144 个数据,单位是 1000
数据集经过处理后得到训练样本

train_x : array([[x1,...x12],...]) 每个样本为长度为12的数组,代表连续12个月份的乘客人数。因为输入数据形状为:  [batch,时间步长,每个时刻的维度]
train_y : array([[y1],...]) 因为是时间序列预测,标签为一个具体的数值。

一、构建LSTM模型

'''定义LSTM cell组件,该组件将在训练过程中被不断更新参数'''
def LstmCell():
    lstm_cell = rnn.BasicLSTMCell(HIDDEN_SIZE, state_is_tuple=True)#
    return lstm_cell

'''定义LSTM模型'''
def lstm_model(X, y):
    # 输入x的shape 为: (?, 1, 12),表示 (batch_size,序列长度为1,序列每步的维度为12)
    '''以前面定义的LSTM cell为基础定义多层堆叠的LSTM,我们这里只有1层'''
    cell = rnn.MultiRNNCell([LstmCell() for _ in range(NUM_LAYERS)])

    '''将已经堆叠起的LSTM单元转化成动态的可在训练过程中更新的LSTM单元'''
    output, _ = tf.nn.dynamic_rnn(cell, X, dtype=tf.float32)
    # output 的shape为:  (?, 1, 40),表示 (batch_size,序列长度为1,隐层大小为40)
    '''根据预定义的每层神经元个数来生成隐层每个单元'''
    output = tf.reshape(output, [-1, HIDDEN_SIZE])
  
    '''通过无激活函数的全连接层计算线性回归,并将数据压缩成一维数组结构'''
    predictions = tf.contrib.layers.fully_connected(output, 1, None)

    '''统一预测值与真实值的形状'''
    labels = tf.reshape(y, [-1])
    predictions = tf.reshape(predictions, [-1])

    '''定义损失函数,这里为正常的均方误差'''
    loss = tf.losses.mean_squared_error(predictions, labels)

    '''定义优化器各参数'''
    train_op = tf.contrib.layers.optimize_loss(loss,
                                               tf.contrib.framework.get_global_step(),
                                               optimizer='Adagrad',
                                               learning_rate=0.6)
    '''返回预测值、损失函数及优化器'''
    return predictions, loss, train_op

二、训练所用的模块

learn = tf.contrib.learn
regressor = SKCompat(learn.Estimator(model_fn=lstm_model, model_dir='Models/model_2'))

tf.contrib.learn.Estimaor(模型,保存路径),以sklearn的方式定义了一个模型,可以调用fit和predict方法完成训练和预测。
Estimator里面还有一个叫SKCompat的类,如果使用x,y而不是input_fn来传参数的形式,需要用这个类包装一下。这里我们使用了x,y的输入形式。

三、训练和预测

'''以仿sklearn的形式训练模型,这里指定了训练批尺寸和训练轮数'''
regressor.fit(train_X, train_y, batch_size=BATCH_SIZE, steps=TRAINING_STEPS)
'''利用已训练好的LSTM模型,来生成对应测试集的所有预测值'''
predicted = np.array([pred for pred in regressor.predict(test_X)])

参考资料

  1. 快速理解LSTM,从懵逼到装逼
    https://zhuanlan.zhihu.com/p/88892937
  2. 零基础入门深度学习(6) - 长短时记忆网络(LSTM)
    https://zybuluo.com/hanbingtao/note/581764
  3. (数据科学学习手札40)tensorflow实现LSTM时间序列预测
    https://www.cnblogs.com/feffery/p/9130728.html