在开始实施之前,至少要理解一些基础知识。在高层次中,RNN( recurrent neural network)用于处理序列,如每日股票价格,句子、传感测量 - 每次一个单元,同时保留之前序列中的记忆(称为状态)。
LSTM(长短期记忆网络)单元
LSTM有3个不同的门和权重向量:有一个“遗忘”门用于丢弃无关信息;一个用于处理当前输入的“输入”门,一个“输出”门用于在每个时间步中生成预测。然而,正如Chollet指出的那样,尝试为单元中的每个元素指定特定含义意义不大。
每个单元的功能最终由训练期间学习的参数(权重)决定。你可以随意标记每个单元部分,但这并不是有效使用的必要条件!
我们可以通过多种方式制定训练RNN编写文本的任务,本文中使用专利摘要。但是,我们会选择将其训练为多对一序列映射器。也就是说,我们输入一系列单词并训练模型预测下一个单词。在传递到LSTM层之前,将使用嵌入矩阵(预训练的或可训练的)将单词映射到整数然后映射到向量。
当我们去写一个新的专利摘要时,我们传入一个单词的起始序列,对下一个单词进行预测,更新输入序列,进行下一个预测,将单词添加到序列中并继续生成单词。
该方法的步骤概述如下:
请记住,这只是问题的一个表述:我们还可以使用字符级模型或对序列中的每个单词进行预测。与机器学习中的许多概念一样,这没有一个标准答案,但这种方法在实践中很有效。
即使具有神经网络有强大的表示能力,获得高质量,干净的数据集也是至关重要的。该项目的原始数据来自USPTO PatentsView,你可以在其中搜索有关在美国申请的任何专利的信息。我搜索了“神经网络”这个术语并下载了最终的专利摘要 - 总共3500个。我发现最好在窄的领域上进行训练,你也可以尝试使用不同的专利。
专利摘要数据
我们首先将专利摘要作为字符串列表。我们模型的主要数据准备步骤是:
# Don't remove punctuation or uppercase
tokenizer = Tokenizer(num_words=None,
filters='#$%&()*+-<=>@[\\]^_`{|}~\t\n',
lower = False, split = ' ')
上一步将所有摘要转换为整数序列。下一步是创建一个用于训练网络的监督机器学习问题。你可以以多种方式为文本生成设置RNN任务,但我们将使用以下方法:
features = []
labels = []
training_length = 50
# Iterate through the sequences of tokens
for seq in sequences:
# Create multiple training examples from each sequence
for i in range(training_length, len(seq)):
# Extract the features and label
extract = seq[i - training_length:i + 1]
# Set the features and label
features.append(extract[:-1])
labels.append(extract[-1])
features = np.array(features)
Keras是一个很棒的库:它让我们用几行可理解的Python代码构建最先进的模型。也许其他神经网络库更快或有更好的灵活性,但没有什么能够超越Keras的开发时间和易用性。
下面是一段简单的LSTM的代码:
from keras.models import Sequential
from keras.layers import LSTM, Dense, Dropout, Masking, Embedding
model = Sequential()
# Embedding layer
model.add(
Embedding(input_dim=num_words,
input_length = training_length,
output_dim=100,
weights=[embedding_matrix],
trainable=False,
mask_zero=True))
# Masking layer for pre-trained embeddings
model.add(Masking(mask_value=0.0))
# Recurrent layer
model.add(LSTM(64, return_sequences=False,
dropout=0.1, recurrent_dropout=0.1))
# Fully connected layer
model.add(Dense(64, activation='relu'))
# Dropout for regularization
model.add(Dropout(0.5))
# Output layer
model.add(Dense(num_words, activation='softmax'))
# Compile the model
model.compile(
optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy'])
LSTM网络布局
一旦建立了网络,我们仍然必须为其提供预训练的字嵌入。还有,你可以在网上找到大量的嵌入训练的不同语料库(大量文本)。们使用的是斯坦福大学提供的,它有100、200或300个维度(我们用100)。这些嵌入来自GloVe(Global Vectors for Word Representation)算法,并在维基百科上进行了训练。
# Load in embeddings
glove_vectors = '/home/ubuntu/.keras/datasets/glove.6B.100d.txt'
glove = np.loadtxt(glove_vectors, dtype='str', comments=None)
# Extract the vectors and words
vectors = glove[:, 1:].astype('float')
words = glove[:, 0]
# Create lookup of words to vectors
word_lookup = {word: vector for word, vector in zip(words, vectors)}
# New matrix to hold word embeddings
embedding_matrix = np.zeros((num_words, vectors.shape[1]))
for i, word in enumerate(word_idx.keys()):
# Look up the word embedding
vector = word_lookup.get(word, None)
# Record in matrix
if vector is not None:
embedding_matrix[i + 1, :] = vector
这样做是为词汇表中的每个单词分配一个100维向量。如果单词没有预训练的嵌入,则该向量是全零。
学习嵌入,这意味着表示只适用于一个任务。当使用预训练的嵌入时,我们希望嵌入式学习的任务足够接近我们的任务,因此嵌入是有意义的。如果这些嵌入是通过tweets进行训练的,我们可能不会期望它们能够很好地工作,但由于它们接受过维基百科数据的训练,因此它们推广到适用于很多语言处理任务。
如果你有大量数据和计算机时间,通常最好为特定任务学习自己的嵌入。在notebook中我采用了这两种方法,学习嵌入的性能稍好一些。
通过准备训练和验证数据,构建网络以及加载嵌入,我们基本已经准备好为我们的模型学习如何编写专利摘要。然而,在训练神经网络时,最好的步骤是以Keras回调的形式使用ModelCheckpoint和EarlyStopping:
使用提前停止意味着我们不会过拟合训练数据,不会浪费时间去训练那些不能提高性能的额外周期。模型检查点意味着我们可以访问最佳模型,如果我们的训练在1000个周期中断,我们也不会失去所有进展!
from keras.callbacks import EarlyStopping, ModelCheckpoint
# Create callbacks
callbacks = [EarlyStopping(monitor='val_loss', patience=5),
ModelCheckpoint('../models/model.h5'), save_best_only=True,
save_weights_only=False)]
history = model.fit(X_train, y_train,
batch_size=2048, epochs=150,
callbacks=callbacks,
validation_data=(X_valid, y_valid))
from keras import load_model
# Load in model and evaluate on validation data
model = load_model('../models/model.h5')
model.evaluate(X_valid, y_valid)
当然,虽然高指标很好,但重要的是网络是否可以产生合理的专利摘要。使用最佳模型,我们可以探索模型生成能力。如果你想在自己的硬件上运行它,你可以在GitHub上找到notebook和预训练好的模型(models)。
为了产生输出,我们使用从专利摘要中选择的随机序列为网络的‘种子“,使其预测下一个单词,将预测添加到序列中,并继续对我们想要的单词进行预测。部分结果如下:
输出也不错!有些时候很难确定哪个是计算机生成的,哪个是机器生成的。有一部分原因在于专利摘要的性质,大多数时候,摘要看起来并不像是人类写的。
网络的另一个用途是用我们自己的起始序列播种它。我们可以使用我们想要的任何文本,并看看网络会怎么生成:
作为RNN的最终测试,我创建了一个游戏来猜测是人还是模型在生成输出。这是第一个示例,其中两个选项来自计算机,一个来自人类:
这一次,第三个是人写的。
我们可以使用其他步骤来解释模型,例如找到不同的输入序列会激活哪些神经元。我们还可以查看学习嵌入(或使用Projector工具将其可视化),这些我们下次讨论。我们现在知道如何实现一个有效模拟人类文本的RNN。
注意,要认识到RNN没有语言理解的概念。它实际上是一种非常复杂的模式识别机器。尽管如此,与马尔可夫链或频率分析等方法不同,RNN基于序列中的元素排序进行预测。从哲学角度讲,你或许可以认为人类只是极端模式识别机器,因此RNN只是像人类这样的机器一样运作。
RNN的使用范围远远超出了文本生成到机器翻译,图像字幕和身份识别。虽然我们在这里介绍的这个应用程序不会取代任何人类,但可以想象,通过更多的训练数据和更大的模型,神经网络将能够合成新的,更合理的专利摘要。
双向LSTM单元