精华内容
下载资源
问答
  • 双隐层LSTM和双向LSTM

    2020-03-21 13:01:15
    使用双隐层LSTM模型(DHLSTM)和双向LSTM(Bi-LSTM)模型两种方法,实现MNIST数据集分类
  • 具有双向LSTM-CNN的命名实体识别 命名实体识别的双向LSTM_CNN的keras实现。 原始论文可以在找到 该实现与原始论文的不同之处在于: 不考虑词典 使用存储桶可加快培训速度 使用nadam优化程序代替SGD 结果 该模型在约...
  • Matlab多层lstm代码使用具有CNN功能的深度双向LSTM在视频序列中进行动作识别 我们已经使用caffe模式使用matlab脚本“ oneFileFeatures ...”从视频中提取了深层功能。 每个CSV文件代表一个视频的功能。 使用“ ...
  • ner-lstm, 基于多层双向LSTM的命名实体识别 这里知识库包含实现以下Arxiv预编译中所述方法的代码: https://arxiv.org/abs/1610.09756,在 ICON-16 会议( http://aclweb.org/anthology/W/W16/W16-63.pd
  • 3DCNN与Long short team memory(LSTM)和双向LSTM相结合,可根据对视频流中事件的以往观察来预测异常事件。 可以看出,与带有双向LSTM的3DCNN相比,带有LSTM的3DCNN导致精度提高。 实验是在UCF犯罪数据集上进行的...
  • 基于双向LSTM/keras/tensorflow的中文分词,语料为人民日报,分词准确率高达97%
  • 使用双向长短期记忆 (biLSTM) 进行需求预测这是一个回归问题。 在这个问题中,我们想根据过去记录中的 3 个因素来预测未来的需求。 您可以更改选择的数量(过去的记录数量)。 此外,您可以更改输入的数量。 例如,...
  • 双向LSTM的上下文感知中文微博情感分类
  • 带有词嵌入的双向LSTM方法用于句子边界检测
  • 双向LSTM进行命名实体识别NER
  • 此模型既可以用于训练词向量,也可以将句子表示成句子向量,质量都比较高
  • 双向LSTM

    万次阅读 2018-05-15 20:31:55
    双向LSTM是传统LSTM的扩展,可以提高序列分类问题的模型性能。在输入序列的所有时间步长可用的问题中,双向LSTM在输入序列上训练两个而不是一个LSTM。输入序列中的第一个是原样的,第二个是输入序列的反转副本。这...

    双向LSTM是传统LSTM的扩展,可以提高序列分类问题的模型性能。

    在输入序列的所有时间步长可用的问题中,双向LSTM在输入序列上训练两个而不是一个LSTM。输入序列中的第一个是原样的,第二个是输入序列的反转副本。这可以为网络提供额外的上下文,并导致更快,甚至更充分的学习问题。

    在本教程中,您将发现如何使用Keras深度学习库在Python中开发用于序列分类的双向LSTM。

    完成本教程后,您将知道:

    如何开发一个小的、可设计的、可配置的序列分类问题。

    如何为序列分类开发LSTM和双向LSTM。

    如何在双向LSTM中应用中比较合并模式的性能。

     

    让我们开始吧

    如何开发带有Keras的Python序列分类的双向LSTM(照片版权所有Cristiano Medeiros Dalbem)

     

    概观

    本教程分为6部分; 他们是:

    1. 双向LSTM
    2. 序列分类问题
    3. LSTM序列分类
    4. 双向LSTM序列分类
    5. 将LSTM和双向LSTM作比较
    6. 比较双向LSTM不同的合并模式

    环境

    本教程假定您已安装Python SciPy环境。您可以使用Python 2或3与此示例。

    本教程假定您使用了TensorFlow(v1.1.0 +)或Theano(v0.9 +)后台,安装了Keras(v2.0.4 +)。

    本教程还假定您已经安装了scikit-learn,Pandas,NumPy和Matplotlib。

    如果您需要帮助设置您的Python环境,请参阅这篇文章:

    双向LSTM

    双向循环神经网络(RNNs)的概念很简单。

    它涉及复制网络中的第一个循环层,使得现在有两层并排,然后将输入序列原样提供给第一层的输入,并将输入序列的反向副本提供给第二层。

    为了克服常规RNN的局限[…],我们提出了可以使用特定时间框架的过去和未来的所有可用输入信息进行训练的双向循环神经网络(BRNN)。

    这个想法是将负责正时间方向(正向状态)的部分和负时间方向的一部分(后向状态)分割成正常RNN的状态神经元,

    – Mike Schuster和Kuldip K. Paliwal,Bidirectional Recurrent Neural Networks,1997

    这种方法对于LSTM的递归神经网络有重大影响。

    双向提供序列的使用最初在语音识别领域是合理的,因为有证据表明整个话语的上下文用于解释所说的内容而不是线性解释。

    依靠未来的知识视乎违背了因果关系。我们怎么能把我们对所听到的事情的理解建立在还没有听到的事情上呢?然而,人类就是这样做的。从未来的角度看,我们听到的声音、单词甚至是句子一开始都毫无意义。我们必须记住的是,真正在线的任务之间的区别即:每次输入后都需要一个输出和某些输入段结束时才需要输出。

    – Alex Graves和Jurgen Schmidhuber,Framangular Phoneme Classification with Bidirectional LSTM and Other Neural Network Architectures,2005

    使用双向LSTM可能不会对所有序列预测问题都有意义,但是可以对适合的领域提供更好的结果。

    我们发现双向网络比单向网络显着更有效

    – Alex Graves和Jurgen Schmidhuber,Framangular Phoneme Classification with Bidirectional LSTM and Other Neural Network Architectures,2005

    要知道,输入序列中的时间步仍然一次处理一个,只是同时在网络的从两个方向通过输入序列而已。

    Keras中的双向LSTM

    Keras通过双向层包装器支持双向LSTM 。

    这个包装器需要一个循环层(例如第一个LSTM层)作为参数。

    它还允许你指定合并模式,也就是在传递到下一个层之前,如何组合前向和后退输出。选项有:

    • ‘ sum’:输出相加。
    • ‘ mul’:输出相乘。
    • ‘ concat’:输出连接在一起(默认),将输出数量提高到下一层的两倍。
    • ‘ ave’:输出的平均值。

    默认模式是连接,这是双向LSTM研究中经常使用的方法。

    序列分类问题

    我们将定义一个简单的序列分类问题来探索双向LSTM。

    该问题被定义为0和1之间的随机值序列。该序列作为每个时间步长每个数字的问题的输入。

    二进制标签(0或1)与每个输入相关联。输出值全为0.一旦序列中的输入值的累积和超过阈值,则输出值从0翻转为1。

    使用序列长度的1/4。

    例如,下面是10个输入时间步长(X)的序列:

     0.63144003 0.29414551 0.91587952 0.95189228 0.32195638 0.60742236 0.83895793 0.18023048 0.84762691 0.29165514

    相应的分类输出(y)为:

     0 0 0 1 1 1 1 1 1 1

    我们可以在Python中实现。

    第一步是生成一系列随机值。我们可以使用随机模块中的random()函数

    1# create a sequence of random numbers in [0,1]
    2 
    3X= array([random()for _in range(10)])

    我们可以将阈值定义为输入序列长度的四分之一。

    1# calculate cut-off value to change class values
    2 
    3limit = 10/4.0

    可以使用cumsum()NumPy函数计算输入序列的累积和。该函数返回累积和值的序列,例如:

    1pos1, pos1+pos2, pos1+pos2+pos3, …

    然后,我们可以计算输出序列,以确定每个累积和值是否超过阈值。

    1# determine the class outcome for each item in cumulative sequence
    2 
    3= array([0 if x < limitelse 1 for in cumsum(X)])

    下面的名为get_sequence()的函数将所有这些函数一起绘制,作为输入序列的长度,并返回一个新的问题情况的X和Y组件。

    01from randomimport random
    02 
    03from numpyimport array
    04 
    05from numpyimport cumsum
    06 
    07 
    08 
    09# create a sequence classification instance
    10 
    11def get_sequence(n_timesteps):
    12 
    13# create a sequence of random numbers in [0,1]
    14 
    15= array([random() for in range(n_timesteps)])
    16 
    17# calculate cut-off value to change class values
    18 
    19limit = n_timesteps/4.0
    20 
    21# determine the class outcome for each item in cumulative sequence
    22 
    23= array([0 if x < limitelse 1 for in cumsum(X)])
    24 
    25return X, y

    我们可以用新的10个时间步序来测试这个函数,如下所示:

    1X, y = get_sequence(10)
    2 
    3print(X)
    4 
    5print(y)

    运行示例首先打印生成的输入序列,然后输出匹配的输出序列。

     

     

     

    [ 0.22228819 0.26882207 0.069623 0.91477783 0.02095862 0.71322527

    0.90159654 0.65000306 0.88845226 0.4037031 ]

    [0 0 0 0 0 0 1 1 1 1]

    LSTM用于序列分类

    我们可以通过开发用于序列分类问题的传统LSTM来开始。

    首先,我们必须更新get_sequence()函数,以将输入和输出序列重新形成3维以满足LSTM的期望。预期的结构具有尺寸[样本,时间步长,特征]。分类问题具有1个样本(例如一个序列),可配置的时间步长数量和每个时间步长的一个特征。

    分类问题具有1个样本(例如一个序列),可配置的时间步长数量和每个时间步长的一个特征。

    因此,我们可以按如下顺序重新整理。

    1# reshape input and output data to be suitable for LSTMs
    2 
    3= X.reshape(1, n_timesteps, 1)
    4 
    5= y.reshape(1, n_timesteps, 1)

    更新的get_sequence()函数如下所示。

    01# create a sequence classification instance
    02def get_sequence(n_timesteps):
    03# create a sequence of random numbers in [0,1]
    04X= array([random()for _in range(n_timesteps)])
    05# calculate cut-off value to change class values
    06limit= n_timesteps/4.0
    07# determine the class outcome for each item in cumulative sequence
    08y= array([0 if x < limitelse 1 for xin cumsum(X)])
    09# reshape input and output data to be suitable for LSTMs
    10X= X.reshape(1, n_timesteps,1)
    11y= y.reshape(1, n_timesteps,1)
    12return X, y

    我们将把序列定义为具有10个时间步长。

    接下来,我们可以为问题定义一个LSTM。输入层将具有10个时间步长,其中1个特征为一组,input_shape =(10,1)。我们将把序列定义为具有10个时间步长。

    第一个隐藏层将具有20个存储单元,输出层将是完全连接的层,每个时间步长输出一个值。在输出端使用S形激活函数来预测二进制值。

    在输出层周围使用TimeDistributed包装层,以便在提供的完整序列作为输入时,可以预测每个时间步长的一个值。这要求LSTM隐藏层返回一个值序列(每个时间步长一个),而不是整个输入序列的单个值。

    最后,因为这是二进制分类问题,所以使用二进制日志丢失(Keras中的binary_crossentropy)。使用有效的ADAM优化算法找到权重,并计算每个时期报告的精度度量。

    1# define LSTM
    2 
    3model = Sequential()
    4 
    5model.add(LSTM(20, input_shape=(101), return_sequences=True))
    6 
    7model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    8 
    9model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])

    LSTM将接受1000次训练。将为每次训练生成一个新的随机输入序列,以使网络适合。这样可以确保模型不会记住单个序列,也可以通过推广解决方案来解决所有可能的随机输入序列。

    01# train LSTM
    02 
    03for epochin range(1000):
    04 
    05# generate new random sequence
    06 
    07X,y = get_sequence(n_timesteps)
    08 
    09# fit model for one epoch on this sequence
    10 
    11model.fit(X, y, epochs=1, batch_size=1, verbose=2)

    一旦被训练,网络将被评估另一个随机序列。然后将预测与预期输出序列进行比较,以提供系统技能的具体示例。

    1# evaluate LSTM
    2 
    3X,y = get_sequence(n_timesteps)
    4 
    5yhat = model.predict_classes(X, verbose=0)
    6 
    7for in range(n_timesteps):
    8 
    9print('Expected:', y[0, i], 'Predicted', yhat[0, i])

    完整的示例如下所示。

    01from randomimport random
    02 
    03from numpyimport array
    04 
    05from numpyimport cumsum
    06 
    07from keras.modelsimport Sequential
    08 
    09from keras.layersimport LSTM
    10 
    11from keras.layersimport Dense
    12 
    13from keras.layersimport TimeDistributed
    14 
    15 
    16 
    17# create a sequence classification instance
    18 
    19def get_sequence(n_timesteps):
    20 
    21# create a sequence of random numbers in [0,1]
    22 
    23= array([random() for in range(n_timesteps)])
    24 
    25# calculate cut-off value to change class values
    26 
    27limit = n_timesteps/4.0
    28 
    29# determine the class outcome for each item in cumulative sequence
    30 
    31= array([0 if x < limitelse 1 for in cumsum(X)])
    32 
    33# reshape input and output data to be suitable for LSTMs
    34 
    35= X.reshape(1, n_timesteps, 1)
    36 
    37= y.reshape(1, n_timesteps, 1)
    38 
    39return X, y
    40 
    41 
    42 
    43# define problem properties
    44 
    45n_timesteps = 10
    46 
    47# define LSTM
    48 
    49model = Sequential()
    50 
    51model.add(LSTM(20, input_shape=(n_timesteps, 1), return_sequences=True))
    52 
    53model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    54 
    55model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])
    56 
    57# train LSTM
    58 
    59for epochin range(1000):
    60 
    61# generate new random sequence
    62 
    63X,y = get_sequence(n_timesteps)
    64 
    65# fit model for one epoch on this sequence
    66 
    67model.fit(X, y, epochs=1, batch_size=1, verbose=2)
    68 
    69# evaluate LSTM
    70 
    71X,y = get_sequence(n_timesteps)
    72 
    73yhat = model.predict_classes(X, verbose=0)
    74 
    75for in range(n_timesteps):
    76 
    77print('Expected:', y[0, i], 'Predicted', yhat[0, i])

    运行示例打印每个时期随机序列的日志丢失和分类精度。

    这提供了一个清晰的想法,模型如何推广到序列分类问题的解决方案。运行示例打印每个时期随机序列的日志丢失和分类精度。

    我们可以看到,该模型表现良好,达到90%和100%准确度的最终精度。不完美,但对我们的目的有好处。

    将新随机序列的预测与预期值进行比较,显示出具有单个错误的大多数正确的结果。

    01...
    02 
    03Epoch1/1
    04 
    050s - loss:0.2039 - acc:0.9000
    06 
    07Epoch1/1
    08 
    090s - loss:0.2985 - acc:0.9000
    10 
    11Epoch1/1
    12 
    130s - loss:0.1219 - acc:1.0000
    14 
    15Epoch1/1
    16 
    170s - loss:0.2031 - acc:0.9000
    18 
    19Epoch1/1
    20 
    210s - loss:0.1698 - acc:0.9000
    22 
    23Expected: [0] Predicted [0]
    24 
    25Expected: [0] Predicted [0]
    26 
    27Expected: [0] Predicted [0]
    28 
    29Expected: [0] Predicted [0]
    30 
    31Expected: [0] Predicted [0]
    32 
    33Expected: [0] Predicted [1]
    34 
    35Expected: [1] Predicted [1]
    36 
    37Expected: [1] Predicted [1]
    38 
    39Expected: [1] Predicted [1]
    40 
    41Expected: [1] Predicted [1]

    双向LSTM用于序列分类

    现在我们知道如何为序列分类问题开发LSTM,我们可以扩展示例来演示双向LSTM。

    我们可以通过用双向层包装LSTM隐藏层来实现,如下所示:

    1model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1)))

    这将创建隐藏层的两个副本,一个适合输入序列,一个在输入序列的反转副本上。默认情况下,这些LSTM的输出值将被连接。

    这意味着,代替时分布层接收到20个输出的10个时间步长,它现在将接收10个20(20个单位+20个单位)输出的10个时间步长。

    完整的示例如下所示。

    01from randomimport random
    02from numpyimport array
    03from numpyimport cumsum
    04from keras.modelsimport Sequential
    05from keras.layersimport LSTM
    06from keras.layersimport Dense
    07from keras.layersimport TimeDistributed
    08from keras.layersimport Bidirectional
    09  
    10# create a sequence classification instance
    11def get_sequence(n_timesteps):
    12# create a sequence of random numbers in [0,1]
    13X= array([random()for _in range(n_timesteps)])
    14# calculate cut-off value to change class values
    15limit= n_timesteps/4.0
    16# determine the class outcome for each item in cumulative sequence
    17y= array([0 if x < limitelse 1 for xin cumsum(X)])
    18# reshape input and output data to be suitable for LSTMs
    19X= X.reshape(1, n_timesteps,1)
    20y= y.reshape(1, n_timesteps,1)
    21return X, y
    22  
    23# define problem properties
    24n_timesteps= 10
    25# define LSTM
    26model= Sequential()
    27model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps,1)))
    28model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    29model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['acc'])
    30# train LSTM
    31for epochin range(1000):
    32# generate new random sequence
    33X,y= get_sequence(n_timesteps)
    34# fit model for one epoch on this sequence
    35model.fit(X, y, epochs=1, batch_size=1, verbose=2)
    36# evaluate LSTM
    37X,y= get_sequence(n_timesteps)
    38yhat= model.predict_classes(X, verbose=0)
    39for iin range(n_timesteps):
    40print('Expected:', y[0, i],'Predicted', yhat[0, i])

     

    运行示例,我们看到与上一个示例类似的输出。

    使用双向LSTM具有允许LSTM更快地学习问题的效果。

    从运行结束时来看,这并不太明显,但随着时间的推移,也越来越明显。

    01...
    02 
    03Epoch1/1
    04 
    050s - loss:0.0967 - acc:0.9000
    06 
    07Epoch1/1
    08 
    090s - loss:0.0865 - acc:1.0000
    10 
    11Epoch1/1
    12 
    130s - loss:0.0905 - acc:0.9000
    14 
    15Epoch1/1
    16 
    170s - loss:0.2460 - acc:0.9000
    18 
    19Epoch1/1
    20 
    210s - loss:0.1458 - acc:0.9000
    22 
    23Expected: [0] Predicted [0]
    24 
    25Expected: [0] Predicted [0]
    26 
    27Expected: [0] Predicted [0]
    28 
    29Expected: [0] Predicted [0]
    30 
    31Expected: [0] Predicted [0]
    32 
    33Expected: [1] Predicted [1]
    34 
    35Expected: [1] Predicted [1]
    36 
    37Expected: [1] Predicted [1]
    38 
    39Expected: [1] Predicted [1]
    40 
    41Expected: [1] Predicted [1]

    将LSTM与双向LSTM进行比较

    在这个例子中,我们将比较训练中的传统的LSTM与双向LSTM的模型的性能。

    我们将调整实验,使模型只能训练250个时期。这样,我们可以清楚地了解每个模型的学习方式如何展开,以及双向LSTM的学习行为如何不同。

    我们将比较三种不同的型号; 具体如下:

    1. LSTM(按原样)
    2. 带有输入序列LSTM(例如,您可以通过将LSTM图层的“go_backwards”参数设置为“True”来实现)
    3. 双向LSTM

    这种比较将有助于表明双向LSTM实际上可以增加一些东西,而不仅仅是带有逆转输入序列。

    我们将定义一个函数来创建和返回具有前向或后向输入序列的LSTM,如下所示:

    01def get_lstm_model(n_timesteps, backwards):
    02 
    03model = Sequential()
    04 
    05model.add(LSTM(20, input_shape=(n_timesteps, 1), return_sequences=True, go_backwards=backwards))
    06 
    07model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    08 
    09model.compile(loss='binary_crossentropy', optimizer='adam')
    10 
    11return model

    我们可以为双向LSTM开发类似的功能,其中可以将合并模式指定为参数。可以通过将合并模式设置为值’concat’来指定连接的默认值。

    01def get_bi_lstm_model(n_timesteps, mode):
    02 
    03model = Sequential()
    04 
    05model.add(Bidirectional(LSTM(20, return_sequences=True), input_shape=(n_timesteps, 1), merge_mode=mode))
    06 
    07model.add(TimeDistributed(Dense(1, activation='sigmoid')))
    08 
    09model.compile(loss='binary_crossentropy', optimizer='adam')
    10 
    11return model

    最后,我们定义一个函数来拟合模型,并且检索和存储每个训练时期的损失,然后在模型拟合之后返回收集的损失值的列表。这样我们可以从每个模型配置中绘制日志丢失并进行比较。

    01def train_model(model, n_timesteps):
    02 
    03loss = list()
    04 
    05for in range(250):
    06 
    07# generate new random sequence
    08 
    09X,y = get_sequence(n_timesteps)
    10 
    11# fit model for one epoch on this sequence
    12 
    13hist = model.fit(X, y, epochs=1, batch_size=1, verbose=0)
    14 
    15loss.append(hist.history['loss'][0])
    16 
    17return loss

    将这一切放在一起,下面列出了完整的例子。

    首先创建一个传统的LSTM,并对日志损失值进行匹配。这与使用反向输入序列的LSTM重复,最后是具有级联合并的LSTM。

    001from randomimport random
    002 
    003from numpyimport array
    004 
    005from numpyimport cumsum
    006 
    007from matplotlibimport pyplot
    008 
    009from pandasimport DataFrame
    010 
    011from keras.modelsimport Sequential
    012 
    013from keras.layersimport LSTM
    014