如何使用 Python 和 Gensim 开发词嵌入
原文:
machinelearningmastery.com/develop-word-embeddings-python-gensim/
词嵌入是一种在自然语言处理中表示文本的现代方法。
嵌入算法如 word2vec 和 GloVe 是神经网络模型在机器翻译等自然语言处理问题上获得的最先进结果的关键。
在本教程中,您将了解如何使用 Gensim 在 Python 中为自然语言处理应用程序训练和加载字嵌入模型。
完成本教程后,您将了解:
- 如何在文本数据上训练自己的 word2vec 单词嵌入模型。
- 如何使用主成分分析可视化训练的单词嵌入模型。
- 如何加载谷歌和斯坦福的预训练 word2vec 和 GloVe 字嵌入模型。
让我们开始吧。
如何使用 Gensim
在 Python 中开发词嵌入照片由 dilettantiquity ,保留一些权利。
教程概述
本教程分为 6 个部分;他们是:
- 词嵌入
- Gensim 库
- 开发 Word2Vec 嵌入
- 可视化词嵌入
- 加载 Google 的 Word2Vec 嵌入
- 加载斯坦福的 GloVe 嵌入
词嵌入
单词嵌入是一种提供单词的密集向量表示的方法,可以捕获关于其含义的单词。
字嵌入是对简单的字袋模型字编码方案(如字数和频率)的改进,这些方案导致描述文档而不是字的含义的大且稀疏的向量(通常为 0 值)。
词嵌入通过使用算法来训练一组基于大的文本语料库的固定长度密集和连续值向量。每个单词由嵌入空间中的一个点表示,并且这些点基于围绕目标单词的单词被学习和移动。
它正在由公司定义一个单词,它保留了允许单词嵌入来学习单词含义的东西。单词的向量空间表示提供了一个投影,其中具有相似含义的单词在空间内局部聚类。
在其他文本表示中使用单词嵌入是导致机器翻译等问题的深度神经网络突破性表现的关键方法之一。
在本教程中,我们将研究斯坦福大学的研究人员如何使用 Google 和 GloVe 的研究人员使用两种不同的词嵌入方法 word2vec。
Gensim Python 库
Gensim 是一个用于自然语言处理的开源 Python 库,主要关注主题建模。
它被称为:
人类主题建模
Gensim 由捷克自然语言处理研究员RadimŘehůřek及其公司 RaRe Technologies 开发并维护。
它不是一个包括厨房水槽的 NLP 研究库(如 NLTK);相反,Gensim 是一个成熟,专注,高效的 NLP 工具套件,用于主题建模。最值得注意的是,本教程支持 Word2Vec 单词嵌入的实现,用于从文本中学习新的单词向量。
它还提供了用于加载几种格式的预训练单词嵌入以及使用和查询加载嵌入的工具。
我们将在本教程中使用 Gensim 库。
如果您没有 Python 环境设置,可以使用本教程:
使用pip
或easy_install
可以轻松安装 Gensim。
例如,您可以通过在命令行上键入以下内容来使用 pip 安装 Gensim:
pip install --upgrade gensim
如果您需要在系统上安装 Gensim 的帮助,可以查看 Gensim 安装说明。
开发 Word2Vec 嵌入
Word2vec 是一种用于从文本语料库中学习单词嵌入的算法。
有两种主要的训练算法可用于学习从文本嵌入;它们是连续的单词(CBOW)和跳过克。
我们不会深入研究算法,只是说它们通常会查看每个目标词的单词窗口,以提供上下文,反过来又意味着单词。该方法由 Tomas Mikolov 开发,以前在谷歌,目前在 Facebook。
Word2Vec 模型需要大量文本,例如整个维基百科语料库。然而,我们将使用一个小的内存中的文本示例来演示原理。
Gensim 提供 Word2Vec 类用于处理 Word2Vec 模型。
学习从文本嵌入的单词涉及将文本加载和组织成句子并将它们提供给新的Word2Vec()
实例的构造函数。例如:
sentences = ...
model = Word2Vec(sentences)
具体地,每个句子必须被分词,意味着被分成单词并准备好(例如,可能预先过滤并且可能转换为优选情况)。
句子可以是加载到内存中的文本,也可以是逐步加载文本的迭代器,这是非常大的文本语料库所必需的。
这个构造函数有很多参数;您可能希望配置的一些值得注意的参数是:
- 尺寸 :(默认为 100)嵌入的尺寸数,例如:表示每个标记(单词)的密集向量的长度。
- 窗口 :(默认值 5)目标字与目标字周围的字之间的最大距离。
- min_count :(默认值 5)训练模型时要考虑的最小字数;出现小于此计数的单词将被忽略。
- worker :(默认 3)训练时使用的线程数。
- sg :(默认为 0 或 CBOW)训练算法,CBOW(0)或跳过克(1)。
刚开始时,默认值通常足够好。如果您拥有大量核心,就像大多数现代计算机那样,我强烈建议您增加工作人员以匹配核心数量(例如 8)。
训练模型后,可通过“wv
”属性访问该模型。这是可以进行查询的实际单词向量模型。
例如,您可以打印所学习的令牌(单词)词汇,如下所示:
words = list(model.wv.vocab)
print(words)
您可以查看特定标记的嵌入向量,如下所示:
print(model['word'])
最后,通过调用单词向量模型上的save_word2vec_format()
函数,可以将训练好的模型保存到文件中。
默认情况下,模型以二进制格式保存以节省空间。例如:
model.wv.save_word2vec_format('model.bin')
入门时,您可以将学习的模型保存为 ASCII 格式并查看内容。
您可以通过在调用save_word2vec_format()
函数时设置 binary = False 来执行此操作,例如:
model.wv.save_word2vec_format('model.txt', binary=False)
然后可以通过调用Word2Vec.load()
函数再次加载保存的模型。例如:
model = Word2Vec.load('model.bin')
我们可以将所有这些与一个有效的例子结合在一起。
我们不会从文件中加载大型文本文档或语料库,而是使用预先分词的小型内存列表。训练模型并将单词的最小计数设置为 1,这样就不会忽略单词。
学习模型后,我们总结,打印词汇表,然后为单词’_ 句子 _'打印单个向量。
最后,模型以二进制格式保存到文件中,加载,然后进行汇总。
from gensim.models import Word2Vec
# define training data
sentences = [['this', 'is', 'the', 'first', 'sentence', 'for', 'word2vec'],
['this', 'is', 'the', 'second', 'sentence'],
['yet', 'another', 'sentence'],
['one', 'more', 'sentence'],
['and', 'the', 'final', 'sentence']]
# train model
model = Word2Vec(sentences, min_count=1)
# summarize the loaded model
print(model)
# summarize vocabulary
words = list(model.wv.vocab)
print(words)
# access vector for one word
print(model['sentence'])
# save model
model.save('model.bin')
# load model
new_model = Word2Vec.load('model.bin')
print(new_model)
运行该示例将打印以下输出。
Word2Vec(vocab=14, size=100, alpha=0.025)
['second', 'sentence', 'and', 'this', 'final', 'word2vec', 'for', 'another', 'one', 'first', 'more', 'the', 'yet', 'is']
[ -4.61881841e-03 -4.88735968e-03 -3.19508743e-03 4.08568839e-03
-3.38211656e-03 1.93076557e-03 3.90265253e-03 -1.04349572e-03
4.14286414e-03 1.55219622e-03 3.85653134e-03 2.22428422e-03
-3.52565176e-03 2.82056746e-03 -2.11121864e-03 -1.38054823e-03
-1.12888147e-03 -2.87318649e-03 -7.99703528e-04 3.67874932e-03
2.68940022e-03 6.31021452e-04 -4.36326629e-03 2.38655557e-04
-1.94210222e-03 4.87691024e-03 -4.04118607e-03 -3.17813386e-03
4.94802603e-03 3.43150692e-03 -1.44031656e-03 4.25637932e-03
-1.15106850e-04 -3.73274647e-03 2.50349124e-03 4.28692997e-03
-3.57313151e-03 -7.24728088e-05 -3.46099050e-03 -3.39612062e-03
3.54845310e-03 1.56780297e-03 4.58260969e-04 2.52689526e-04
3.06256465e-03 2.37558200e-03 4.06933809e-03 2.94650183e-03
-2.96231941e-03 -4.47433954e-03 2.89590308e-03 -2.16034567e-03
-2.58548348e-03 -2.06163677e-04 1.72605237e-03 -2.27384618e-04
-3.70194600e-03 2.11557443e-03 2.03793868e-03 3.09839356e-03
-4.71800892e-03 2.32995977e-03 -6.70911541e-05 1.39375112e-03
-3.84263694e-03 -1.03898917e-03 4.13251948e-03 1.06330717e-03
1.38514000e-03 -1.18144893e-03 -2.60811858e-03 1.54952740e-03
2.49916781e-03 -1.95435272e-03 8.86975031e-05 1.89820060e-03
-3.41996481e-03 -4.08187555e-03 5.88635216e-04 4.13103355e-03
-3.25899688e-03 1.02130906e-03 -3.61028523e-03 4.17646067e-03
4.65870230e-03 3.64110398e-04 4.95479070e-03 -1.29743712e-03
-5.03367570e-04 -2.52546836e-03 3.31060472e-03 -3.12870182e-03
-1.14580349e-03 -4.34387522e-03 -4.62882593e-03 3.19007039e-03
2.88707414e-03 1.62976081e-04 -6.05802808e-04 -1.06368808e-03]
Word2Vec(vocab=14, size=100, alpha=0.025)
您可以看到,通过一些准备文本文档的工作,您可以使用 Gensim 轻松创建自己的单词嵌入。
可视化词嵌入
在学习了文本数据的单词嵌入之后,可以通过可视化来探索它。
您可以使用经典投影方法将高维字向量缩减为二维图并将其绘制在图形上。
可视化可以为您的学习模型提供定性诊断。
我们可以从训练有素的模型中检索所有向量,如下所示:
X = model[model.wv.vocab]
然后我们可以在向量上训练投影方法,例如 scikit-learn 中提供的那些方法,然后使用 matplotlib 将投影绘制为散点图。
让我们看一下使用 Principal Component Analysis 或 PCA 的示例。
使用 PCA 绘制单词向量
我们可以使用 scikit-learn PCA 类创建单词向量的二维 PCA 模型,如下所示。
pca = PCA(n_components=2)
result = pca.fit_transform(X)
可以使用 matplotlib 如下绘制得到的投影,将两个维度拉出为 x 和 y 坐标。
pyplot.scatter(result[:, 0], result[:, 1])
我们可以更进一步,用图标本身注释图表上的点。没有任何良好偏移的粗略版本如下所示。
words = list(model.wv.vocab)
for i, word in enumerate(words):
pyplot.annotate(word, xy=(result[i, 0], result[i, 1]))
将这一切与上一节中的模型结合在一起,下面列出了完整的示例。
from gensim.models import Word2Vec
from sklearn.decomposition import PCA
from matplotlib import pyplot
# define training data
sentences = [['this', 'is', 'the', 'first', 'sentence', 'for', 'word2vec'],
['this', 'is', 'the', 'second', 'sentence'],
['yet', 'another', 'sentence'],
['one', 'more', 'sentence'],
['and', 'the', 'final', 'sentence']]
# train model
model = Word2Vec(sentences, min_count=1)
# fit a 2d PCA model to the vectors
X = model[model.wv.vocab]
pca = PCA(n_components=2)
result = pca.fit_transform(X)
# create a scatter plot of the projection
pyplot.scatter(result[:, 0], result[:, 1])
words = list(model.wv.vocab)
for i, word in enumerate(words):
pyplot.annotate(word, xy=(result[i, 0], result[i, 1]))
pyplot.show()
运行该示例将创建一个散点图,其中的点用单词注释。
鉴于这样一个小小的语料库用于拟合模型,很难从图中得出很多意义。
Word2Vec 模型 PCA 投影的散点图
加载 Google 的 Word2Vec 嵌入
训练自己的单词向量可能是给定 NLP 问题的最佳方法。
但它可能需要很长时间,一台具有大量 RAM 和磁盘空间的快速计算机,并且可能在输入数据和训练算法方面具有一些专业知识。
另一种方法是简单地使用现有的预训练单词嵌入。
除了 word2vec 的论文和代码,谷歌还在 Word2Vec 谷歌代码项目上发布了预训练的 word2vec 模型。
预先训练的模型只不过是包含令牌及其相关词向量的文件。预先训练的 Google word2vec 模型接受了谷歌新闻数据(约 1000 亿字)的训练;它包含 300 万个单词和短语,并且使用 300 维单词向量。
它是一个 1.53 千兆字节的文件。你可以在这里下载:
解压缩后,二进制文件(GoogleNews-vectors-negative300.bin)为 3.4 千兆字节。
Gensim 库提供了加载此文件的工具。具体来说,您可以调用KeyedVectors.load_word2vec_format()
函数将此模型加载到内存中,例如:
from gensim.models import KeyedVectors
filename = 'GoogleNews-vectors-negative300.bin'
model = KeyedVectors.load_word2vec_format(filename, binary=True)
在我的现代工作站上,加载大约需要 43 秒。
你可以做的另一个有趣的事情是用单词做一点线性代数算法。
例如,讲座和介绍文章中描述的一个流行的例子是:
queen = (king - man) + woman
这就是女王这个词是最接近的一个词,因为人们从国王那里减去了男人的概念,并添加了女人这个词。国王的“男人”被“女人”所取代,给了我们女王。一个非常酷的概念。
Gensim 提供了一个接口,用于在训练或加载的模型上的most_similar()
函数中执行这些类型的操作。
例如:
result = model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
print(result)
我们可以将所有这些放在一起如下。
from gensim.models import KeyedVectors
# load the google word2vec model
filename = 'GoogleNews-vectors-negative300.bin'
model = KeyedVectors.load_word2vec_format(filename, binary=True)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
print(result)
运行该示例加载 Google 预训练的 word2vec 模型,然后计算(王者)+女人=?对这些单词的单词向量进行操作。
正如我们所料,答案是女王。
[('queen', 0.7118192315101624)]
请参阅更多阅读部分中的一些帖子,了解您可以探索的更有趣的算术示例。
加载斯坦福的 GloVe 嵌入
斯坦福大学的研究人员也有自己的单词嵌入算法,如 word2vec,称为全局向量字表示,或简称 GloVe。
我不会在这里详细介绍 word2vec 和 GloVe 之间的差异,但一般来说,NLP 从业者似乎更喜欢基于结果的 GloVe。
与 word2vec 一样,GloVe 研究人员也提供预训练的单词向量,在这种情况下,可供选择。
您可以下载 GloVe 预训练的单词向量,并使用 gensim 轻松加载它们。
第一步是将 GloVe 文件格式转换为 word2vec 文件格式。唯一的区别是添加了一个小标题行。这可以通过调用glove2word2vec()
函数来完成。例如:
from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = 'glove.txt'
word2vec_output_file = 'word2vec.txt'
glove2word2vec(glove_input_file, word2vec_output_file)
转换后,文件可以像上面的 word2vec 文件一样加载。
让我们以一个例子来具体化。
您可以从 GloVe 网站下载最小的 GloVe 预训练模型。它是一个 822 兆字节的 zip 文件,有 4 种不同的模型(50,100,200 和 300 维向量),在维基百科数据上训练有 60 亿个令牌和 400,000 个单词词汇。
直接下载链接在这里:
使用模型的 100 维版本,我们可以将文件转换为 word2vec 格式,如下所示:
from gensim.scripts.glove2word2vec import glove2word2vec
glove_input_file = 'glove.6B.100d.txt'
word2vec_output_file = 'glove.6B.100d.txt.word2vec'
glove2word2vec(glove_input_file, word2vec_output_file)
您现在拥有 word2vec 格式的 GloVe 模型副本,文件名为glove.6B.100d.txt.word2vec
。
现在我们可以加载它并执行相同的(国王 - 男人)+女人=?按照上一节进行测试。完整的代码清单如下。请注意,转换后的文件是 ASCII 格式,而不是二进制格式,因此我们在加载时设置 binary = False 。
from gensim.models import KeyedVectors
# load the Stanford GloVe model
filename = 'glove.6B.100d.txt.word2vec'
model = KeyedVectors.load_word2vec_format(filename, binary=False)
# calculate: (king - man) + woman = ?
result = model.most_similar(positive=['woman', 'king'], negative=['man'], topn=1)
print(result)
运行该示例将打印“queen”的相同结果。
[('queen', 0.7698540687561035)]
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
Gensim
- gensim Python Library
- models.word2vec gensim API
- models.keyedvectors gensim API
- scripts.glove2word2vec gensim API
帖子
- 使用 Word2vec ,2016 年
- 数字人文学科的向量空间模型,2015
- Gensim Word2vec 教程,2014
摘要
在本教程中,您了解了如何使用 Gensim 在 Python 中开发和加载字嵌入层。
具体来说,你学到了:
- 如何在文本数据上训练自己的 word2vec 单词嵌入模型。
- 如何使用主成分分析可视化训练的单词嵌入模型。
- 如何加载谷歌和斯坦福的预训练 word2vec 和 GloVe 字嵌入模型。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
用于文本摘要的编解码器深度学习模型
原文:
machinelearningmastery.com/encoder-decoder-deep-learning-models-text-summarization/
文本摘要是从较大的文本文档创建简短,准确和流畅的摘要的任务。
最近深度学习方法已被证明在文本摘要的抽象方法中是有效的。
在这篇文章中,您将发现三种不同的模型,它们构建在有效的编解码器架构之上,该架构是为机器翻译中的序列到序列预测而开发的。
阅读这篇文章后,你会知道:
- Facebook AI Research 模型使用编解码器模型和卷积神经网络编码器。
- 使用 Encoder-Decoder 模型的 IBM Watson 模型,具有指向和分层注意力。
- 斯坦福/谷歌模型使用带有指向和覆盖的编解码器模型。
让我们开始吧。
用于文本摘要的编解码器深度学习模型
照片由HiếuBùi拍摄,保留一些权利。
型号概述
我们将查看三种不同的文本摘要模型,这些模型以撰写本文时作者所属的组织命名:
- Facebook 模型
- IBM 模型
- 谷歌模型
Facebook 模型
Alexander Rush 等人描述了这种方法。来自 Facebook AI Research(FAIR)的 2015 年论文“用于抽象句子摘要的神经注意模型”。
该模型是为句子摘要而开发的,具体为:
给定一个输入句子,目标是产生一个简明的摘要。 […]摘要生成器将 x 作为输入并输出长度 N <1 的缩短句子 y。 M.我们将假设摘要中的单词也来自相同的词汇表
这比完整的文档摘要更简单。
该方法遵循用于具有编码器和解码器的神经机器转换的一般方法。探索了三种不同的解码器:
- Bag-of-Words 编码器。输入句子使用词袋模型编码,丢弃词序信息。
- 卷积编码器。使用字嵌入表示,然后使用跨字和汇集层的时间延迟卷积层。
- 基于注意力的编码器。单词嵌入表示与上下文向量一起使用简单的注意机制,在输入句子和输出摘要之间提供一种软对齐。
编码器和解码器元件的网络图
取自“用于抽象句子摘要的神经注意模型”。
然后,在生成文本摘要时使用集束搜索,这与机器翻译中使用的方法不同。
该模型在标准 DUC-2014 数据集上进行评估,该数据集涉及为 500 篇新闻文章生成大约 14 个字的摘要。
这项任务的数据包括来自纽约时报和美联社有线服务的 500 篇新闻文章,每篇文章都配有 4 个不同的人工参考摘要(实际上不是头条新闻),上限为 75 字节。
该模型还在大约 950 万篇新闻文章的 Gigaword 数据集上进行了评估,其中给出了新闻文章第一句的标题。
使用 ROUGE-1,ROUGE-2 和 ROUGE-L 测量结果报告了两个问题,并且调谐系统显示在 DUC-2004 数据集上实现了最先进的结果。
与几个强大的基线相比,该模型显示了 DUC-2004 共享任务的显着表现提升。
IBM 模型
Ramesh Nallapati 等人描述了这种方法。来自 IBM Watson 的 2016 年论文“使用序列到序列 RNN 和超越的抽象文本摘要”。
该方法基于编解码器循环神经网络,注重机器翻译。
我们的基线模型对应于 Bahdanau 等人使用的神经机器翻译模型。 (2014)。编码器由双向 GRU-RNN(Chung 等,2014)组成,而解码器由具有与编码器相同的隐藏状态大小的单向 GRU-RNN 和源上的关注机制组成。 - 隐藏状态和目标词汇表上的软最大层以生成单词。
除了用于标记的词性和离散的 TF 和 IDF 特征的嵌入之外,还使用用于输入词的词嵌入。这种更丰富的输入表示旨在使模型在识别源文本中的关键概念和实体方面具有更好的表现。
该模型还使用学习开关机制来决定是否生成输出字或指向输入序列中的字,用于处理稀有和低频字。
…解码器配有一个“开关”,用于决定在每个时间步使用发生器还是指针。如果开关打开,则解码器以正常方式从其目标词汇表中产生一个单词。但是,如果关闭开关,则解码器生成指向源中的一个字位置的指针。
最后,该模型是分层的,因为注意机制在编码输入数据上的单词级和句子级操作。
具有分层关注的分层编码器。
取自“使用序列到序列的 RNN 及其后的抽象文本摘要”。
在 DUC-2003/2004 数据集和 Gigaword 数据集上评估了该方法的总共 6 种变体,两者都用于评估 Facebook 模型。
该模型还在来自 CNN 和 Daily Mail 网站的新的新闻文章集上进行了评估。
与 Facebook 方法和其他方法相比,IBM 方法在标准数据集上取得了令人瞩目的成果。
…我们将注意力编解码器应用于抽象概括的任务,具有非常有希望的结果,在两个不同的数据集上显着优于最先进的结果。
谷歌模型
Abigail See 等人描述了这种方法。来自斯坦福大学 2017 年论文“到达重点:利用指针生成器网络进行总结。”
一个更好的名字可能是“斯坦福模型”,但我试图将这项工作与合作者 Peter Liu(谷歌大脑)2016 年帖子标题为“文本摘要与 TensorFlow ”在谷歌上联系起来研究博客。
在他们的博客文章中,Peter Liu 等人。在 Google Brain 上引入了 TensorFlow 模型,该模型直接将用于机器翻译的编解码器模型应用于生成 Gigaword 数据集的短句的摘要。虽然没有在代码提供的文本文档之外提供结果的正式记录,但它们声称比模型的最新结果更好。
在他们的论文中,Abigail See 等人。描述了抽象文本摘要的深度学习方法的两个主要缺点:它们产生事实错误并且它们重复出现。
虽然这些系统很有前景,但它们表现出不良行为,例如不准确地复制事实细节,无法处理词汇外(OOV)词,以及重复自己
他们的方法旨在总结多个句子而不是单句概括,并应用于用于演示 IBM 模型的 CNN / Daily Mail 数据集。该数据集中的文章平均包含大约 39 个句子。
基线编解码器模型与字嵌入,双向 LSTM 用于输入和注意一起使用。探索了一种扩展,它使用指向输入数据中的单词来解决词汇表单词,类似于 IBM 模型中使用的方法。最后,覆盖机制用于帮助减少输出中的重复。
用于文本摘要的指针生成器模型
取自“到达点:使用指针生成器网络进行汇总”。
使用 ROUGE 和 METEOR 得分报告结果,与其他抽象方法和挑战采掘模型的得分相比,显示出最先进的表现。
我们的指针生成器模型覆盖率进一步提高了 ROUGE 和 METEOR 得分,令人信服地超越了最佳[比较]抽象模型…
结果确实表明可以使用基线 seq-to-seq 模型(带注意的编解码器),但不会产生竞争结果,显示了它们对方法的扩展的好处。
我们发现我们的基线模型在 ROUGE 和 METEOR 方面都表现不佳,实际上较大的词汇量(150k)似乎没有帮助。 …事实细节经常被错误地复制,通常用一个更常见的替代词替换一个不常见的(但是词汇表中)词。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
- 抽象句子摘要的神经注意模型(见代码),2015。
- 使用序列到序列 RNN 及其后的抽象文本摘要,2016。
- 达到要点:指针生成器网络汇总(见代码),2017 年。
- 使用 TensorFlow 进行文本摘要(参见代码),2016
- 驯服循环神经网络以实现更好的总结,2017 年。
摘要
在这篇文章中,您发现了文本摘要的深度学习模型。
具体来说,你学到了:
- 使用编解码器模型和卷积神经网络编码器的 Facebook AI Research 模型。
- 使用 Encoder-Decoder 模型的 IBM Watson 模型,具有指向和分层注意力。
- 斯坦福/谷歌模型使用带有指向和覆盖的编解码器模型。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
Keras 中文本摘要的编解码器模型
原文:
machinelearningmastery.com/encoder-decoder-models-text-summarization-keras/
文本摘要是自然语言处理中的一个问题,即创建源文档的简短,准确和流畅的摘要。
为机器翻译开发的编解码器循环神经网络架构在应用于文本摘要问题时已被证明是有效的。
在 Keras 深度学习库中应用这种架构可能很困难,因为为了使库清洁,简单和易于使用而牺牲了一些灵活性。
在本教程中,您将了解如何在 Keras 中实现用于文本摘要的编解码器架构。
完成本教程后,您将了解:
- 如何使用编解码器循环神经网络架构来解决文本摘要。
- 如何针对该问题实现不同的编码器和解码器。
- 您可以使用三种模型在 Keras 中实现文本摘要的架构。
让我们开始吧。
用于 Keras 中文本摘要的编解码器模型
照片由 Diogo Freire 拍摄,保留一些权利。
教程概述
本教程分为 5 个部分;他们是:
- 编解码器架构
- 文本摘要编码器
- 文本摘要解码器
- 阅读源文本
- 实现模型
编解码器架构
编解码器架构是一种组织循环神经网络的方法,用于具有可变数量的输入,输出或两者输入和输出的序列预测问题。
该架构涉及两个组件:编码器和解码器。
- 编码器:编码器读取整个输入序列并将其编码为内部表示,通常是称为上下文向量的固定长度向量。
- 解码器:解码器从编码器读取编码的输入序列并生成输出序列。
有关编解码器架构的更多信息,请参阅帖子:
编码器和解码器子模型都是联合训练的,意思是同时进行。
这是一项非常壮观的事情,因为传统上,挑战自然语言问题需要开发单独的模型,这些模型后来被串入管道,允许错误在序列生成过程中累积。
整个编码输入用作生成输出中每个步骤的上下文。虽然这有效,但输入的固定长度编码限制了可以生成的输出序列的长度。
编解码器架构的扩展是提供编码输入序列的更具表现形式,并允许解码器在生成输出序列的每个步骤时学习在何处关注编码输入。
这种架构的扩展称为注意。
有关编解码器架构中的注意事项的更多信息,请参阅帖子:
- 长期短期记忆循环神经网络的注意事项
编解码器架构受到关注,是一组自然语言处理问题,它产生可变长度的输出序列,例如文本摘要。
架构在文本摘要中的应用如下:
- 编码器:编码器负责读取源文档并将其编码为内部表示。
- 解码器:解码器是一种语言模型,负责使用源文档的编码表示在输出摘要中生成每个单词。
文本摘要编码器
编码器是模型的复杂性所在,因为它负责捕获源文档的含义。
可以使用不同类型的编码器,但是更常用的是双向循环神经网络,例如 LSTM。在编码器中使用循环神经网络的情况下,使用字嵌入来提供字的分布式表示。
亚历山大拉什等人。使用一个简单的词袋编码器来丢弃单词顺序和卷积编码器,明确地尝试捕获 n-gram。
我们最基本的模型只使用嵌入到 H 大小的输入句子的词袋,而忽略原始顺序的属性或相邻单词之间的关系。 […]为了解决一些词形的建模问题,我们还考虑使用深度卷积编码器来输入句子。
- 抽象句概括的神经注意模型,2015。
Konstantin Lopyrev 使用深度堆叠的 4 个 LSTM 循环神经网络作为编码器。
编码器作为输入被输入一个单词一次的新闻文章的文本。每个单词首先通过嵌入层,该嵌入层将单词转换为分布式表示。然后使用多层神经网络组合该分布式表示
- 使用循环神经网络生成新闻标题,2015 年。
Abigail See,et al。使用单层双向 LSTM 作为编码器。
将文章 w(i)的标记一个接一个地馈送到编码器(单层双向 LSTM)中,产生编码器隐藏状态序列 h(i)。
- 达到要点:利用指针生成器网络汇总,2017 年。
Ramesh Nallapati,et al。在编码器中使用双向 GRU 循环神经网络,并在输入序列中包含有关每个字的附加信息。
编码器由双向 GRU-RNN 组成…
- 使用序列到序列 RNN 及其后的抽象文本摘要,2016。
文本摘要解码器
在给定两个信息源的情况下,解码器必须在输出序列中生成每个字:
- 上下文向量:编码器提供的源文档的编码表示。
- 生成的序列:已作为摘要生成的单词或单词序列。
上下文向量可以是如在简单编解码器架构中的固定长度编码,或者可以是通过注意机制过滤的更具表现力的形式。
生成的序列提供很少的准备,例如通过字嵌入的每个生成的字的分布式表示。
在每个步骤 t,解码器(单层单向 LSTM)接收前一个字的字嵌入(在训练时,这是参考摘要的前一个字;在测试时它是解码器发出的前一个字)
- 达到要点:利用指针生成器网络汇总,2017 年。
亚历山大拉什等人。在x
是源文档的图表中干净地显示,enc
是提供源文档内部表示的编码器,yc
是先前的序列生成的单词。
用于文本摘要的解码器的输入示例。
取自“用于抽象句子摘要的神经注意模型”,2015 年。
一次生成一个单词需要运行模型,直到生成一些最大数量的摘要单词或达到特殊的序列结束标记。
必须通过为模型提供特殊的序列开始标记来启动该过程,以便生成第一个单词。
解码器将输入文本的最后一个单词后生成的隐藏层作为输入。首先,再次使用嵌入层将符号结束符号作为输入馈入,以将符号变换为分布式表示。 […]。在生成下一个单词时,生成每个单词后输入相同的单词作为输入。
- 使用循环神经网络生成新闻标题,2015 年。
Ramesh Nallapati,et al。使用 GRU 循环神经网络生成输出序列。
…解码器由单向 GRU-RNN 组成,其具有与编码器相同的隐藏状态大小
阅读源文本
根据所解决的特定文本摘要问题,该架构的应用具有灵活性。
大多数研究都集中在编码器中的一个或几个源句子上,但并非必须如此。
例如,编码器可以配置为以不同大小的块读取和编码源文档:
- 句子。
- 段。
- 页。
- 文献。
同样地,解码器可以被配置为汇总每个块或聚合编码的块并输出更广泛的概要。
亚历山大拉什等人在这条道路上做了一些工作。使用分层编码器模型,同时注意单词和句子级别。
该模型旨在使用源侧的两个双向 RNN 捕获这两个重要级别的概念,一个在单词级别,另一个在句子级别。注意机制同时在两个层面上运作
- 抽象句概括的神经注意模型,2015。
实现模型
在本节中,我们将介绍如何在 Keras 深度学习库中实现用于文本摘要的编解码器架构。
一般模型
模型的简单实现涉及具有嵌入输入的编码器,其后是 LSTM 隐藏层,其产生源文档的固定长度表示。
解码器读取表示和最后生成的单词的嵌入,并使用这些输入在输出摘要中生成每个单词。
Keras 中的一般文本摘要模型
这儿存在一个问题。
Keras 不允许递归循环,其中模型的输出自动作为输入提供给模型。
这意味着上面描述的模型不能直接在 Keras 中实现(但也许可以在像 TensorFlow 这样更灵活的平台中实现)。
相反,我们将看看我们可以在 Keras 中实现的模型的三种变体。
替代 1:一次性模型
第一种替代模型是以一次性方式生成整个输出序列。
也就是说,解码器仅使用上下文向量来生成输出序列。
替代 1 - 一次性文本摘要模型
以下是使用功能 API 在 Keras 中使用此方法的示例代码。
vocab_size = ...
src_txt_length = ...
sum_txt_length = ...
# encoder input model
inputs = Input(shape=(src_txt_length,))
encoder1 = Embedding(vocab_size, 128)(inputs)
encoder2 = LSTM(128)(encoder1)
encoder3 = RepeatVector(sum_txt_length)(encoder2)
# decoder output model
decoder1 = LSTM(128, return_sequences=True)(encoder3)
outputs = TimeDistributed(Dense(vocab_size, activation='softmax'))(decoder1)
# tie it together
model = Model(inputs=inputs, outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam')
这种模式给解码器带来了沉重的负担。
解码器可能没有足够的上下文来生成相干输出序列,因为它必须选择单词及其顺序。
备选 2:递归模型 A.
第二种替代模型是开发一种模型,该模型生成单个单词预测并递归调用。
也就是说,解码器使用上下文向量和到目前为止生成的所有单词的分布式表示作为输入,以便生成下一个单词。
语言模型可用于解释到目前为止生成的单词序列,以提供第二上下文向量以与源文档的表示相结合,以便生成序列中的下一个单词。
通过递归调用模型并使用先前生成的单词(或者更具体地说,在训练期间预期的前一个单词)来构建摘要。
可以将上下文向量集中或加在一起以为解码器提供更宽的上下文来解释和输出下一个字。
备用 2 - 递归文本摘要模型 A.
以下是使用功能 API 在 Keras 中使用此方法的示例代码。
vocab_size = ...
src_txt_length = ...
sum_txt_length = ...
# source text input model
inputs1 = Input(shape=(src_txt_length,))
am1 = Embedding(vocab_size, 128)(inputs1)
am2 = LSTM(128)(am1)
# summary input model
inputs2 = Input(shape=(sum_txt_length,))
sm1 = = Embedding(vocab_size, 128)(inputs2)
sm2 = LSTM(128)(sm1)
# decoder output model
decoder1 = concatenate([am2, sm2])
outputs = Dense(vocab_size, activation='softmax')(decoder1)
# tie it together [article, summary] [word]
model = Model(inputs=[inputs1, inputs2], outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam')
这更好,因为解码器有机会使用先前生成的单词和源文档作为生成下一个单词的上下文。
它确实给合并操作和解码器带来了负担,以解释它在生成输出序列时的位置。
备选 3:递归模型 B.
在该第三替代方案中,编码器生成源文档的上下文向量表示。
在生成的输出序列的每个步骤将该文档馈送到解码器。这允许解码器建立与用于在输出序列中生成单词的内部状态相同的内部状态,以便准备生成序列中的下一个单词。
然后通过对输出序列中的每个字一次又一次地调用模型来重复该过程,直到生成最大长度或序列结束标记。
备用 3 - 递归文本摘要模型 B.
以下是使用功能 API 在 Keras 中使用此方法的示例代码。
vocab_size = ...
src_txt_length = ...
sum_txt_length = ...
# article input model
inputs1 = Input(shape=(src_txt_length,))
article1 = Embedding(vocab_size, 128)(inputs1)
article2 = LSTM(128)(article1)
article3 = RepeatVector(sum_txt_length)(article2)
# summary input model
inputs2 = Input(shape=(sum_txt_length,))
summ1 = Embedding(vocab_size, 128)(inputs2)
# decoder model
decoder1 = concatenate([article3, summ1])
decoder2 = LSTM(128)(decoder1)
outputs = Dense(vocab_size, activation='softmax')(decoder2)
# tie it together [article, summary] [word]
model = Model(inputs=[inputs1, inputs2], outputs=outputs)
model.compile(loss='categorical_crossentropy', optimizer='adam')
您还有其他替代实现方案吗?
请在下面的评论中告诉我。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
文件
- 抽象句概括的神经注意模型,2015。
- 使用循环神经网络生成新闻标题,2015 年。
- 使用序列到序列 RNN 及其后的抽象文本摘要,2016。
- 达到要点:利用指针生成器网络汇总,2017 年。
有关
摘要
在本教程中,您了解了如何在 Keras 深度学习库中实现用于文本摘要的编解码器架构。
具体来说,你学到了:
- 如何使用编解码器循环神经网络架构来解决文本摘要。
- 如何针对该问题实现不同的编码器和解码器。
- 您可以使用三种模型在 Keras 中实现文本摘要的架构。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
用于神经机器翻译的编解码器循环神经网络模型
用于循环神经网络的编解码器架构是标准的神经机器翻译方法,其可以与传统的统计机器翻译方法相媲美并且在某些情
这种架构非常新颖,仅在 2014 年率先推出,但已被采纳为 Google 翻译服务的核心技术。
在这篇文章中,您将发现用于神经机器翻译的编解码器模型的两个开创性示例。
阅读这篇文章后,你会知道:
- 编解码器循环神经网络架构是 Google 翻译服务中的核心技术。
- 用于直接端到端机器翻译的所谓“ _Sutskever 型号 _”。
- 所谓的“ _Cho 模型 _”通过 GRU 单元和注意机制扩展了架构。
让我们开始吧。
用于神经机器翻译的编解码器循环神经网络模型
Fabio Pani 的照片,保留一些权利。
用于 NMT 的编解码器架构
具有循环神经网络的编解码器架构已成为神经机器翻译(NMT)和序列到序列(seq2seq)预测的有效和标准方法。
该方法的主要优点是能够直接在源语句和目标语句上训练单个端到端模型,以及处理可变长度输入和输出文本序列的能力。
作为该方法成功的证据,该架构是 Google 翻译服务的核心。
我们的模型遵循常见的序列到序列学习框架。它有三个组件:编码器网络,解码器网络和注意网络。
在这篇文章中,我们将仔细研究两个不同的研究项目,这些项目在 2014 年同时开发了相同的编解码器架构,并取得了成为人们关注的方法。他们是:
- Sutskever NMT 模型
- Cho NMT 模型
有关架构的更多信息,请参阅帖子:
Sutskever NMT 模型
在本节中,我们将研究 Ilya Sutskever 等开发的神经机器翻译模型。正如 2014 年论文“序列学习与神经网络”所述。由于缺乏更好的名称,我们将其称为“ _Sutskever NMT 模型 _”。
这是一篇重要的论文,因为它是第一个引入用于机器翻译的编解码器模型以及更普遍的序列到序列学习的模型之一。
它是机器翻译领域的一个重要模型,因为它是第一个在大型翻译任务上胜过基线统计机器学习模型的神经机器翻译系统之一。
问题
该模型适用于英语到法语的翻译,特别是 WMT 2014 翻译任务。
翻译任务一次处理一个句子,并且在训练期间将序列结束(&lt; EOS&gt;)标记添加到输出序列的末尾以表示翻译序列的结束。这允许模型能够预测可变长度输出序列。
注意,我们要求每个句子以特殊的句末符号“&lt; EOS&gt;”结束,这使得模型能够定义所有可能长度的序列上的分布。
该模型在数据集中的 12 百万个句子的子集上进行训练,包括 348,000 个法语单词和 30400 万个英语单词。选择此集是因为它是预先标记的。
源词汇量减少到 160,000 个最频繁的源英语单词和 80,000 个最常见的目标法语单词。所有词汇外单词都被“UNK”标记取代。
模型
开发了编解码器架构,其中整个读取输入序列并将其编码为固定长度的内部表示。
然后,解码器网络使用该内部表示来输出字,直到到达序列令牌的末尾。 LSTM 网络用于编码器和解码器。
想法是使用一个 LSTM 读取输入序列,一次一个步骤,以获得大的固定维向量表示,然后使用另一个 LSTM 从该向量中提取输出序列
最终的模型是 5 个深度学习模型的集合。在推断翻译期间使用从左到右的光束搜索。
用于文本翻译的 Sutskever 编解码器模型的描述
取自“使用神经网络的序列到序列学习”,2014。
型号配置
- 输入序列被颠倒了。
- 使用 1000 维字嵌入层来表示输入字。
- Softmax 用于输出层。
- 输入和输出模型有 4 层,每层 1,000 个单元。
- 该模型适合 7.5 个时期,其中进行了一些学习率衰减。
- 在训练期间使用批量大小的 128 个序列。
- 在训练期间使用梯度裁剪来减轻梯度爆炸的可能性。
- 批次由具有大致相同长度的句子组成,以加速计算。
该模型适用于 8-GPU 机器,其中每层在不同的 GPU 上运行。训练需要 10 天。
由此产生的实现速度达到每秒 6,300(英语和法语)的速度,小批量为 128.这种实现的训练大约需要 10 天。
结果
该系统的 BLEU 得分为 34.81,与使用 33.30 的统计机器翻译系统开发的基线得分相比,这是一个很好的分数。重要的是,这是神经机器翻译系统的第一个例子,它在大规模问题上胜过基于短语的统计机器翻译基线。
…我们获得了 34.81 的 BLEU 分数[…]这是迄今为止通过大型神经网络直接翻译获得的最佳结果。为了比较,该数据集上 SMT 基线的 BLEU 得分为 33.30
使用最终模型对最佳翻译列表进行评分,并将得分提高至 36.5,使其接近 37.0 时的最佳结果。
你可以在这里看到与论文相关的谈话视频:
<iframe allowfullscreen=“” frameborder=“0” gesture=“media” height=“281” src=“https://www.youtube.com/embed/-uyXE7dY5H0?feature=oembed” width=“500”></iframe>
Cho NMT 模型
在本节中,我们将讨论 Kyunghyun Cho 等人描述的神经机器翻译系统。他们在 2014 年的论文题为“学习短语表示使用 RNN 编解码器进行统计机器翻译。”我们将其称为“ _Cho NMT 模型 _”模型缺乏更好的名称。
重要的是,Cho 模型仅用于对候选翻译进行评分,并不像上面的 Sutskever 模型那样直接用于翻译。虽然对更好地诊断和改进模型的工作的扩展确实直接和单独使用它进行翻译。
问题
如上所述,问题是 WMT 2014 研讨会的英语到法语翻译任务。
源词汇量和目标词汇量仅限于最常见的 15,000 个法语和英语单词,涵盖了 93%的数据集,词汇单词中的单词被“UNK”取代。
模型
该模型使用相同的双模型方法,这里给出了编解码器架构的明确名称。
…称为 RNN 编解码器,由两个循环神经网络(RNN)组成。一个 RNN 将符号序列编码成固定长度的向量表示,而另一个 RNN 将该表示解码成另一个符号序列。
描述编解码器架构。
取自“使用 RNN 编解码器进行统计机器翻译的学习短语表示”。
实现不使用 LSTM 单位;相反,开发了一种更简单的循环神经网络单元,称为门控循环单元或 GRU。
…我们还提出了一种新型的隐藏单元,它受 LSTM 单元的推动,但计算和实现起来要简单得多。
型号配置
- 使用 100 维单词嵌入来表示输入单词。
- 编码器和解码器配置有 1 层 1000 GRU 单元。
- 在解码器之后使用 500 个 Maxout 单元汇集 2 个输入。
- 在训练期间使用 64 个句子的批量大小。
该模型训练了大约 2 天。
扩展
在论文“关于神经机器翻译的性质:编解码器方法”,Cho,et al。调查他们的模型的局限性。他们发现,随着输入句子长度的增加和词汇表之外的单词数量的增加,表现会迅速下降。
我们的分析表明神经机器翻译的表现受句子长度的影响很大。
它们提供了模型表现的有用图表,因为句子的长度增加,可以捕捉技能的优美损失,增加难度。
句子长度增加导致模特技能丧失。
取自“关于神经机器翻译的属性:编解码器方法”。
为了解决未知单词的问题,他们建议在训练期间大大增加已知单词的词汇量。
他们在一篇题为“通过联合学习协调和翻译的神经机器翻译”的后续论文中解决了句子长度的问题,其中他们建议使用注意机制。不是将输入语句编码为固定长度向量,而是保持编码输入的更全面表示,并且模型学习用于关注解码器输出的每个字的输入的不同部分。
每次所提出的模型在翻译中生成单词时,它(软)搜索源语句中的一组位置,其中最相关的信息被集中。然后,模型基于与这些源位置和所有先前生成的目标词相关联的上下文向量来预测目标词。
本文提供了大量技术细节;例如:
- 使用类似配置的模型,但具有双向层。
- 准备数据使得在词汇表中保留 30,000 个最常见的单词。
- 该模型首先使用长度最多为 20 个单词的句子进行训练,然后使用长度最多为 50 个单词的句子进行训练。
- 使用 80 个句子的批量大小,该模型适合 4-6 个时期。
- 在推理期间使用集束搜索来找到每个翻译的最可能的词序列。
这次模型需要大约 5 天的时间来训练。该后续工作的代码也是 。
与 Sutskever 一样,该模型在经典的基于短语的统计方法的范围内取得了成果。
也许更重要的是,所提出的方法实现了与现有的基于短语的统计机器翻译相当的翻译表现。考虑到所提出的架构或整个神经机器翻译系列仅在今年才被提出,这是一个引人注目的结果。我们相信这里提出的架构是朝着更好的机器翻译和更好地理解自然语言迈出的有希望的一步。
Kyunghyun Cho 也是 Nvidia 开发者博客 2015 年系列帖子的作者,该博客主题为神经机器翻译的编解码器架构,题为“ GPU 神经机器翻译简介”。 “该系列提供了对主题和模型的良好介绍;见第一部分,第二部分和第三部分。
进一步阅读
如果您希望深入了解,本节将提供有关该主题的更多资源。
- 谷歌的神经机器翻译系统:缩小人机翻译之间的差距,2016。
- 用神经网络进行序列学习的序列,2014。
- 用神经网络进行序列到序列学习的表示,2016。
- Ilya Sutskever 主页
- 使用 RNN 编解码器进行统计机器翻译的学习短语表示,2014。
- 通过联合学习对齐和翻译的神经机器翻译,2014。
- 关于神经机器翻译的特性:编解码器方法,2014。
- Kyunghyun Cho 主页
- 用 GPU 进行神经机器翻译的介绍( part1 , part2 , part3 ),2015。
摘要
在这篇文章中,您发现了两个用于神经机器翻译的编解码器模型的示例。
具体来说,你学到了:
- 编解码器循环神经网络架构是 Google 翻译服务中的核心技术。
- 用于直接端到端机器翻译的所谓“Sutskever 模型”。
- 所谓的“Cho 模型”,通过 GRU 单元和注意机制扩展了架构。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
浅谈词袋模型
原文:
machinelearningmastery.com/gentle-introduction-bag-words-model/
词袋模型是一种在使用机器学习算法对文本建模时表示文本数据的方式。
词袋模型易于理解和实现,并且在语言建模和文档分类等问题上取得了巨大成功。
在本教程中,您将发现用于自然语言处理中的特征提取的词袋模型。
完成本教程后,您将了解:
- 词袋模型是什么以及为什么需要表示文本。
- 如何为一组文档开发一个词袋模型。
- 如何使用不同的技巧来准备词汇和得分词。
让我们开始吧。
简单介绍字袋模型
照 Do8y ,保留一些权利。
教程概述
本教程分为 6 个部分;他们是:
- 文本问题
- 什么是词袋?
- 词袋模型的例子
- 管理词汇
- 得分词
- 词袋的局限性
文本问题
建模文本的一个问题是它很乱,机器学习算法等技术更喜欢定义明确的固定长度输入和输出。
机器学习算法无法直接使用原始文本;文本必须转换为数字。具体而言,是数字的向量。
在语言处理中,向量 x 从文本数据导出,以反映文本的各种语言属性。
- 第 65 页,自然语言处理中的神经网络方法,2017。
这称为特征提取或特征编码。
使用文本数据进行特征提取的一种流行且简单的方法称为文本的词袋模型。
什么是词袋?
单词袋模型(简称 BoW)是一种从文本中提取特征以用于建模的方法,例如使用机器学习算法。
该方法非常简单和灵活,并且可以以多种方式用于从文档中提取特征。
词袋是文本的表示,用于描述文档中单词的出现。它涉及两件事:
- 已知单词的词汇。
- 衡量已知单词的存在。
它被称为单词的“bag
”,因为关于文档中单词的顺序或结构的任何信息都被丢弃。该模型仅关注文档中是否出现已知单词,而不是文档中的位置。
句子和文档的一个非常常见的特征提取过程是词袋方法(BOW)。在这种方法中,我们查看文本中单词的直方图,即将每个单词计数视为一个特征。
- 第 69 页,自然语言处理中的神经网络方法,2017。
直觉是如果文档具有相似的内容,则文档是相似的。此外,仅从内容中我们就可以了解文档的含义。
词袋可以像你想的那样简单或复杂。复杂性在于决定如何设计已知单词(或标记)的词汇以及如何对已知单词的存在进行评分。
我们将仔细研究这两个问题。
词袋模型的例子
让我们用一个有效的例子制作词袋模型混凝土。
第 1 步:收集数据
下面是查尔斯·狄更斯(Charles Dickens)从“古腾堡计划”(Project Gutenberg)那本书出版的“双城记”一书中的前几行文本片段。
这是最好的时期,
这是最糟糕的时期,
这是智慧的时代,
这是愚蠢的时代,
对于这个小例子,让我们将每一行视为一个单独的“文档”,将 4 行视为我们的整个文档集。
第 2 步:设计词汇表
现在我们可以列出模型词汇表中的所有单词。
这里唯一的单词(忽略大小写和标点符号)是:
- “它”
- “是”
- “中的”
- “最好”
- “的”
- “时代”
- “最差”
- “年龄”
- “智慧”
- “愚蠢”
这是一个包含 24 个单词的语料库中 10 个单词的词汇。
第 3 步:创建文档向量
下一步是对每个文档中的单词进行评分。
目标是将每个自由文本文档转换为向量,我们可以将其用作机器学习模型的输入或输出。
因为我们知道词汇有 10 个单词,所以我们可以使用 10 的固定长度文档表示,在向量中有一个位置来对每个单词进行评分。
最简单的评分方法是将单词的存在标记为布尔值,0 表示不存在,1 表示存在。
使用我们词汇表中上面列出的单词的任意顺序,我们可以逐步浏览第一个文档(“_ 这是最好的时间 _”)并将其转换为二元向量。
该文件的评分如下:
- “它”= 1
- “是”= 1
- “the”= 1
- “最好”= 1
- “of”= 1
- “时代”= 1
- “最差”= 0
- “年龄”= 0
- “智慧”= 0
- “愚蠢”= 0
作为二二元量,这将如下所示:
[1, 1, 1, 1, 1, 1, 0, 0, 0, 0]
其他三份文件如下:
"it was the worst of times" = [1, 1, 1, 0, 1, 1, 1, 0, 0, 0]
"it was the age of wisdom" = [1, 1, 1, 0, 1, 0, 0, 1, 1, 0]
"it was the age of foolishness" = [1, 1, 1, 0, 1, 0, 0, 1, 0, 1]
所有单词的排序名义上都被丢弃了,我们有一致的方法从我们语料库中的任何文档中提取特征,准备用于建模。
与已知单词的词汇重叠但可能包含词汇表之外的单词的新文档仍然可以被编码,其中仅对已知单词的出现进行评分并且忽略未知单词。
您可以看到这可能会自然地扩展到大型词汇表和更大的文档。
管理词汇
随着词汇量的增加,文档的向量表示也会增加。
在前面的示例中,文档向量的长度等于已知单词的数量。
你可以想象,对于一个非常大的语料库,比如数千本书,向量的长度可能是数千或数百万个位置。此外,每个文档可以包含词汇表中很少的已知单词。
这导致具有许多零分数的向量,称为稀疏向量或稀疏表示。
稀疏向量在建模时需要更多的存储器和计算资源,并且大量的位置或维度可以使建模过程对于传统算法非常具有挑战性。
因此,当使用词袋模型时,存在减小词汇量的压力的压力。
有一些简单的文本清理技术可用作第一步,例如:
- 无视案例
- 忽略标点符号
- 忽略不包含太多信息的常用词,称为停止词,如“a”,“of”等。
- 修复拼写错误的单词。
- 使用词干算法将单词减少到词干(例如,“播放”来自“播放”)。
更复杂的方法是创建分组词的词汇表。这既改变了词汇表的范围,又允许词袋从文档中捕获更多的含义。
在这种方法中,每个单词或标记称为“克”。反过来,创建双字对词汇表称为二元词模型。同样,只有出现在语料库中的双字母才被建模,而不是所有可能的双字母。
N-gram 是一个 N-token 单词序列:2-gram(通常称为 bigram)是一个双字序列,如“请转”,“转动你的”,或“你的作业”,一个 3 克(通常称为三元音)是一个三字词序列,如“请转动你的”,或“转动你的作业”。
- 第 85 页,语音和语言处理,2009。
例如,上一节中第一行文字中的双字母组:“这是最好的时间”如下:
- “它是”
- “是的”
- “最好的”
- “最好的”
- “时代”
然后跟踪单词的词组称为三元组模型,一般方法称为 n-gram 模型,其中 n 表示分组单词的数量。
对于像文档分类这样的任务,通常一个简单的二元组方法比一组 1 克的词袋模型更好。
一个袋子的 bigrams 表示比词袋更强大,并且在许多情况下证明非常难以击败。
- 第 75 页,自然语言处理中的神经网络方法,2017。
得分词
一旦选择了词汇表,就需要对示例文档中单词的出现进行评分。
在工作示例中,我们已经看到了一种非常简单的评分方法:对单词存在与否的二进二元。
一些额外的简单评分方法包括:
- 计算。计算每个单词在文档中出现的次数。
- 频率。计算文档中所有单词中每个单词出现在文档中的频率。
字哈希
你可能还记得计算机科学中的哈希函数是一个将数据映射到固定大小的数字集的数学运算。
例如,我们在编程时在哈希表中使用它们,其中可能将名称转换为数字以进行快速查找。
我们可以在词汇表中使用已知单词的哈希表示。这解决了对于大文本语料库具有非常大的词汇表的问题,因为我们可以选择哈希空间的大小,该大小又是文档的向量表示的大小。
单词被确定性地散列到目标散列空间中的相同整数索引。然后可以使用二元分数或计数来对单词进行评分。
这称为“_ 哈希技巧 ”或“ 功能哈希 _”。
挑战在于选择一个哈希空间来容纳所选择的词汇量大小,以最小化冲突和权衡稀疏性的可能性。
TF-IDF
对单词频率进行评分的问题在于,高频率的单词在文档中开始占主导地位(例如,较大的分数),但是可能不包含与模型一样多的“信息内容”,因为稀有但可能是领域特定的单词。
一种方法是通过它们在所有文档中出现的频率来重缩放单词的频率,使得在所有文档中频繁出现的频繁单词(如“the”)的分数受到惩罚。
这种评分方法称为术语频率 - 反向文档频率,简称 TF-IDF,其中:
- 术语频率:是当前文档中单词频率的得分。
- 反向文档频率:是对文档中单词的罕见程度的评分。
分数是一个权重,并非所有单词都同样重要或有趣。
分数具有突出显示给定文档中不同(包含有用信息)的单词的效果。
因此,罕见术语的 idf 很高,而常用术语的 idf 可能很低。
- 第 118 页,信息检索简介,2008 年。
词袋的局限性
词袋模型非常易于理解和实现,并为您的特定文本数据提供了很大的灵活性。
它在语言建模和文档分类等预测问题上取得了巨大成功。
然而,它有一些缺点,例如:
- 词汇:词汇需要仔细设计,最具体的是为了管理大小,这会影响文档表示的稀疏性。
- 稀疏性:由于计算原因(空间和时间复杂度)以及信息原因,稀疏表示更难以建模,其中挑战是模型在如此大的代表空间中利用如此少的信息。
- 含义:丢弃单词顺序会忽略上下文,而忽略文档中单词的含义(语义)。上下文和意义可以为模型提供很多东西,如果建模可以说出不同排列的相同单词之间的区别(“这很有趣”vs“这是有趣的”),同义词(“旧自行车”与“二手自行车”) , 以及更多。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
用品
- 维基百科上的词袋模型
- 维基百科上的 N-gram
- 维基百科上的特征哈希
- 维基百科上的 tf-idf
图书
- 第六章,自然语言处理中的神经网络方法,2017。
- 第四章,语音和语言处理,2009。
- 第六章,信息检索简介,2008 年。
- 第六章,统计自然语言处理基础,1999。
摘要
在本教程中,您发现了使用文本数据进行特征提取的词袋模型。
具体来说,你学到了:
- 这些词汇模型是什么以及我们为什么需要它。
- 如何通过应用词袋模型来处理文档集合。
- 可以使用哪些技术来准备词汇和评分单词。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
文本摘要的温和介绍
原文:
machinelearningmastery.com/gentle-introduction-text-summarization/
文本摘要是创建较长文本文档的简短,准确和流畅摘要的问题。
非常需要自动文本摘要方法来解决在线可用的不断增长的文本数据量,以便更好地帮助发现相关信息并更快地消费相关信息。
在这篇文章中,您将发现自然语言处理中的文本摘要问题。
阅读这篇文章后,你会知道:
- 为什么文本摘要很重要,特别是考虑到互联网上提供的大量文本。
- 您可能每天都会遇到的文本摘要示例。
- 深度学习方法在自动文本摘要中的应用和前景。
让我们开始吧。
文本摘要的温和介绍
Dmitry Sumin 的照片,保留一些权利。
概观
这篇文章分为 5 部分;他们是:
- 文本摘要
- 什么是自动文本摘要?
- 文本摘要的示例
- 如何总结文本
- 深度学习文本摘要
文本摘要
有大量的文字材料,它每天都在增长。
想想互联网,包括网页,新闻文章,状态更新,博客等等。数据是非结构化的,我们可以做的最好的方法是使用搜索和浏览结果。
非常需要将大部分文本数据缩减为捕获显着细节的更短,更集中的摘要,以便我们可以更有效地导航它,以及检查较大的文档是否包含我们正在寻找的信息。
数字文档形式的文本信息很快就会累积到大量数据中。这些大量文档中的大部分都是非结构化的:它不受限制,并且没有被组织到传统数据库中。因此,处理文件是一项敷衍的任务,主要是由于缺乏标准。
- 第 xix 页,自动文本摘要,2014。
我们不可能手动创建所有文本的摘要;非常需要自动方法。
在 2014 年关于题为“ 自动文本摘要 ”的书中,作者提供了我们需要自动文本摘要工具的 6 个理由。
- 摘要减少了阅读时间。
- 在研究文档时,摘要使选择过程更容易。
- 自动摘要提高了索引的有效性。
- 自动摘要算法的偏差小于人类摘要。
- 个性化摘要在问答系统中非常有用,因为它们提供个性化信息。
- 使用自动或半自动摘要系统,商业抽象服务可以增加他们能够处理的文本数量。
- 第 4-5 页,自动文本摘要,2014。
现在我们知道我们需要自动文本摘要,让我们更好地定义文本摘要的含义。
什么是自动文本摘要?
自动文本摘要或仅文本摘要是创建较长文档的简短一致版本的过程。
文本摘要是从源(或多个源)中提取最重要信息以生成特定用户(或用户)和任务(或任务)的简化版本的过程。
- 第 1 页,自动文本摘要的进展,1999。
我们(人类)通常擅长这种类型的任务,因为它涉及首先理解源文档的含义,然后在新描述中提炼意义并捕获显着的细节。
因此,自动创建文本摘要的目标是使得到的摘要与人类编写的摘要一样好。
自动摘要工作的理想是开发一种技术,通过该技术,机器可以生成成功模仿人类生成的摘要的摘要。
- 第 2 页,创新文档摘要技术:革新知识理解,2014 年。
仅仅生成捕获源文档要点的单词和短语是不够的。摘要应该准确,并且应该作为新的独立文档流畅地阅读。
自动文本摘要是在保留关键信息内容和整体含义的同时生成简洁流畅的摘要的任务
- 文本摘要技术:简要调查,2017 年。
接下来,让我们通过一些例子来理解这种理解。
文本摘要的示例
更大的文档摘要有很多原因和用途。
可能会想到的一个例子是创建一篇长篇新闻文章的简明摘要,但是我们每天都会遇到更多的文本摘要案例。
在他们 1999 年关于题为“ 自动文本摘要的进展 ”主题的书中,作者提供了一个有用的列表,列出了每天的文本摘要示例。
- 头条新闻(来自世界各地)
- 大纲(学生笔记)
- 会议纪要(会议纪要)
- 预览(电影)
- 大纲(肥皂剧列表)
- 评论(书籍,CD,电影等)
- 摘要(电视指南)
- 传记(简历,ob 告)
- abridgments(儿童莎士比亚)
- 公告(天气预报/股市报告)
- 声音叮咬(当前问题上的政治家)
- 历史(显着事件的年表)
- 第 1 页,自动文本摘要的进展,1999。
很明显,我们阅读和使用摘要的次数比我们最初认为的要多。
如何总结文本
总结文本文档有两种主要方法;他们是:
1.提取方法。
2.抽象方法。
文本摘要的不同维度通常可以基于其输入类型(单个或多个文档),目的(通用,特定于域或基于查询)和输出类型(提取或抽象)来分类。
- 自动文本摘要方法评论,2016。
提取文本摘要涉及从源文档中选择短语和句子以构成新摘要。技术涉及对短语的相关性进行排序,以便仅选择与源的含义最相关的那些。
抽象文本摘要涉及生成全新的短语和句子以捕获源文档的含义。这是一种更具挑战性的方法,但也是人类最终使用的方法。传统方法通过从源文档中选择和压缩内容来进行操作。
…自动摘要有两种不同的方法:提取和抽象。摘要摘要方法通过识别文本的重要部分并逐字生成它们来工作; […]抽象概括方法旨在以新的方式产生重要的材料。换句话说,他们使用先进的自然语言技术解释和检查文本,以生成一个新的较短文本,传达原始文本中最重要的信息
- 文本摘要技术:简要调查,2017 年。
传统上,大多数成功的文本摘要方法都是提取方法,因为它是一种更简单的方法,但抽象方法可以为这个问题提供更一般的解决方案。
深度学习文本摘要
最近深度学习方法已经显示出有希望的文本摘要结果。
已经提出了通过应用深度学习方法进行自动机器翻译的方法,特别是通过将文本摘要的问题构建为序列到序列学习问题。
抽象文本摘要是生成标题或简短摘要的任务,该摘要由捕获文章或段落的显着想法的几个句子组成。 […]此任务也可以自然地转换为将源文档中的单词的输入序列映射到称为摘要的单词的目标序列。
- 使用序列到序列 RNN 及其后的抽象文本摘要,2016。
这些自动文本摘要的深度学习方法可以被认为是抽象方法,并通过学习特定于源文档的语言生成模型来生成全新的描述。
…序列到序列模型的最近成功,其中循环神经网络(RNN)既读取又自由生成文本,使得抽象概括成为可能
- 达到要点:利用指针生成器网络汇总,2017 年。
与提取方法相比,深度学习方法的结果还不是最先进的,但是在受约束的问题上取得了令人印象深刻的结果,例如为与其他抽象方法相媲美或超出其他抽象方法的新闻文章生成标题。
该方法的前景是,模型可以在没有专门的数据准备或子模型的情况下进行端到端的训练,并且模型完全是数据驱动的,无需编写专门的词汇表或专业预处理的源文档。
…我们提出了一种完全数据驱动的抽象句子摘要方法。 […]该模型结构简单,可以轻松地进行端到端的训练,并可以扩展到大量的训练数据。
- 抽象句概括的神经注意模型,2015
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
文字摘要论文
- 关于自动文本摘要方法的评论,2016。
- 关于文本摘要的评论文件,2016 年。
- 文本摘要技术:简要调查,2017 年。
深度学习文本摘要论文
- 抽象句概括的神经注意模型,2015
- 使用序列到序列 RNN 及其后的抽象文本摘要,2016。
- 达到要点:利用指针生成器网络汇总,2017 年。
图书
- 自动文本摘要的进展,1999。
- 自动文本摘要,2014 年。
- 创新文档摘要技术:革新知识理解,2014 年。
用品
摘要
在这篇文章中,您发现了自然语言处理中的文本摘要问题。
具体来说,你学到了:
- 为什么文本摘要很重要,特别是考虑到互联网上提供的大量文本。
- 您可能每天都会遇到的文本摘要示例。
- 深度学习方法在自动文本摘要中的应用和前景。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
编解码器循环神经网络中的注意力如何工作
原文:
machinelearningmastery.com/how-does-attention-work-in-encoder-decoder-recurrent-neural-networks/
注意力是一种机制,旨在提高机器翻译中编解码器 RNN 的表现。
在本教程中,您将发现编解码器模型的注意机制。
完成本教程后,您将了解:
- 关于编解码器模型和机器翻译的注意机制。
- 如何逐步实现关注机制。
- 注意机制的应用和扩展。
让我们开始吧。
- 2017 年 12 月更新:修正了第 4 步的小错字,谢谢 Cynthia Freeman。
教程概述
本教程分为 4 个部分;他们是:
- 编解码器模型
- 注意模型
- 工作注意的例子
- 注意力的扩展
编解码器模型
两篇论文介绍了用于循环神经网络的编解码器模型。
两者都开发了技术来解决机器翻译的序列到序列的性质,其中输入序列的长度与输出序列不同。
Ilya Sutskever,et al。在使用 LSTM 的文章“序列到神经网络的序列学习”中这样做。
Kyunghyun Cho,et al。在“学习短语表示使用 RNN 编解码器进行统计机器翻译”中这样做。这项工作和一些同一作者(Bahdanau,Cho 和 Bengio)后来开发了他们的特定模型以开发注意力模型。因此,我们将快速浏览本文所述的编解码器模型。
从高级别来看,该模型由两个子模型组成:编码器和解码器。
- 编码器:编码器负责逐步执行输入时间步长并将整个序列编码为称为上下文向量的固定长度向量。
- 解码器:解码器负责在从上下文向量读取时逐步执行输出时间步长。
编解码器循环神经网络模型。
取自“使用 RNN 编解码器进行统计机器翻译的学习短语表示”
我们提出了一种新颖的神经网络架构,它学习将可变长度序列编码成固定长度的向量表示,并将给定的固定长度向量表示解码回可变长度序列。
模型的关键在于整个模型(包括编码器和解码器)是端到端训练的,而不是单独训练元素。
一般地描述该模型,使得不同的特定 RNN 模型可以用作编码器和解码器。
作者不是使用流行的长期短期记忆(LSTM)RNN,而是开发和使用他们自己的简单类型的 RNN,后来称为门控循环单元(GRU)。
此外,与 Sutskever 等人不同。在模型中,来自前一时间步骤的解码器的输出被作为输入馈送以解码下一个输出时间步长。您可以在上图中看到这一点,其中输出 y2 使用上下文向量(C),从解码 y1 传递的隐藏状态以及输出 y1。
… y(t)和 h(i)也都以 y(t-1)和输入序列的摘要 c 为条件。
- 使用 RNN 编解码器进行统计机器翻译的学习短语表示,2014
注意模型
Dzmitry Bahdanau 等人提出了注意力。在他们的论文“神经机器翻译中通过联合学习来对齐和翻译”,这是他们以前在编解码器模型上工作的自然延伸。
提出注意作为对编解码器模型的限制的解决方案,该编解码器模型将输入序列编码为一个固定长度向量,从该向量解码每个输出时间步长。在解码长序列时,这个问题被认为是更多的问题。
这种编解码器方法的潜在问题是神经网络需要能够将源句子的所有必要信息压缩成固定长度的向量。这可能使神经网络难以处理长句,特别是那些比训练语料库中的句子长的句子。
- 通过联合学习对齐和翻译的神经机器翻译,2015。
建议将注意力作为对齐和翻译的方法。
对齐是机器翻译中的问题,其识别输入序列的哪些部分与输出中的每个单词相关,而翻译是使用相关信息来选择适当输出的过程。
…我们引入了编解码器模型的扩展,它学会了共同对齐和翻译。每次所提出的模型在翻译中生成单词时,它(软)搜索源语句中的一组位置,其中最相关的信息被集中。然后,模型基于与这些源位置和所有先前生成的目标词相关联的上下文向量来预测目标词。
- 通过联合学习对齐和翻译的神经机器翻译,2015。
注意模型不是将输入序列编码成单个固定的上下文向量,而是开发一个特定于每个输出时间步骤过滤的上下文向量。
注意力
取自“通过共同学习协调和翻译的神经机器翻译”,2015 年。
与编解码器纸一样,该技术应用于机器翻译问题并使用 GRU 单元而不是 LSTM 存储器单元。在这种情况下,使用双向输入,其中向前和向后提供输入序列,然后在传递到解码器之前将其连接。
我们将研究一个有效的例子,而不是重新迭代用于计算注意力的等式。
工作注意的例子
在本节中,我们将通过一个小的工作示例来注意具体。具体来说,我们将使用未向量化的术语逐步完成计算。
这将为您提供足够详细的理解,您可以将注意力添加到您自己的编解码器实现中。
这个有效的例子分为以下 6 个部分:
- 问题
- 编码
- 对准
- 权重
- 上下文向量
- 解码
1.问题
问题是一个简单的序列到序列预测问题。
有三个输入时间步骤:
x1, x2, x3
该模型需要预测一个时间步骤:
y1
在此示例中,我们将忽略编码器和解码器中使用的 RNN 的类型,并忽略双向输入层的使用。这些元素对于理解解码器中的注意力计算并不重要。
2.编码
在编解码器模型中,输入将被编码为单个固定长度向量。这是最后一个时间步的编码器模型的输出。
h1 = Encoder(x1, x2, x3)
注意模型需要在每个输入时间步长访问编码器的输出。本文将这些称为每个时间步的“_ 注释 _”。在这种情况下:
h1, h2, h3 = Encoder(x1, x2, x3)
3.对齐
解码器一次输出一个值,在最终输出当前输出时间步长的预测(y)之前,该值被传递到可能更多的层。
对准模型得分(e)每个编码输入(h)与解码器的当前输出的匹配程度。
分数的计算需要来自前一输出时间步骤的解码器的输出,例如, S(T-1)。为解码器的第一个输出进行评分时,这将为 0。
使用函数 a()执行评分。我们可以为第一个输出时间步骤评分每个注释(h),如下所示:
e11 = a(0, h1)
e12 = a(0, h2)
e13 = a(0, h3)
我们对这些分数使用两个下标,例如 e11,其中第一个“1”表示输出时间步长,第二个“1”表示输入时间步长。
我们可以想象,如果我们有一个带有两个输出时间步长的序列到序列问题,那么稍后我们可以按如下方式对第二个时间步的注释进行评分(假设我们已经计算了 s1):
e21 = a(s1, h1)
e22 = a(s1, h2)
e23 = a(s1, h3)
函数 a()在本文中称为对齐模型,并实现为前馈神经网络。
这是传统的单层网络,其中每个输入(s(t-1)和 h1,h2 和 h3)被加权,使用双曲正切(tanh)传递函数并且输出也被加权。
4.加权
接下来,使用 softmax 函数对准分数进行归一化。
分数的归一化允许它们被视为概率,指示每个编码的输入时间步长(注释)与当前输出时间步长相关的可能性。
这些标准化分数称为注释权重。
例如,我们可以计算 softmax 注释权重(a)给定计算的对齐分数(e)如下:
a11 = exp(e11) / (exp(e11) + exp(e12) + exp(e13))
a12 = exp(e12) / (exp(e11) + exp(e12) + exp(e13))
a13 = exp(e13) / (exp(e11) + exp(e12) + exp(e13))
如果我们有两个输出时间步长,则第二个输出时间步长的注释权重将按如下方式计算:
a21 = exp(e21) / (exp(e21) + exp(e22) + exp(e23))
a22 = exp(e22) / (exp(e21) + exp(e22) + exp(e23))
a23 = exp(e23) / (exp(e21) + exp(e22) + exp(e23))
5.上下文向量
接下来,将每个注释(h)乘以注释权重(a)以产生新的有人值守的上下文向量,从该向量上下文向量可以解码当前输出时间步长。
为简单起见,我们只有一个输出时间步骤,因此我们可以如下计算单个元素上下文向量(带括号以便于阅读):
c1 = (a11 * h1) + (a12 * h2) + (a13 * h3)
上下文向量是注释和标准化对齐分数的加权和。
如果我们有两个输出时间步长,则上下文向量将由两个元素[c1,c2]组成,计算如下:
c1 = a11 * h1 + a12 * h2 + a13 * h3
c2 = a21 * h1 + a22 * h2 + a23 * h3
6.解码
然后根据编解码器模型执行解码,尽管在这种情况下使用当前时间步长的有人值环境向量。
解码器的输出在本文中称为隐藏状态。
s1 = Decoder(c1)
在最终退出模型之前,这可以被馈送到附加层中作为时间步长的预测(y1)。
注意力的扩展
本节介绍 Bahdanau 等人的一些其他应用。注意机制。
硬和软的注意力
在 2015 年论文“展示,出席和讲述:神经图像标题生成与视觉注意”,Kelvin Xu,et al。使用卷积神经网络作为关于字幕照片问题的图像数据的特征提取器,将注意力应用于图像数据。
他们开发了两种注意机制,一种称为“_ 软注意 ”,它类似于上面用加权上下文向量引起的注意,第二种是“ 硬注意 _”,其中清晰的决策是关于每个单词的上下文向量中的元素。
他们还建议双重关注,注意力集中在图像的特定部分。
删除以前的隐藏状态
这种机制的一些应用已经简化了方法,以便从注释评分中删除上一个输出时间步骤(s(t-1))的隐藏状态(上面的步骤 3)。
两个例子是:
- 用于文档分类的分层注意网络,2016。
- 用于关系分类的基于注入的双向长短期记忆网络,2016
这具有不向模型提供先前解码的输出的想法的效果,其旨在帮助对准。
这在论文中列出的等式中有所说明,并且不清楚任务是对模型的有意改变还是仅仅是方程式的省略。在任何一篇论文中都没有讨论过放弃这个术语。
研究以前的隐藏状态
Minh-Thang Luong,et al。在他们的 2015 年论文中,“基于注意力的神经机器翻译的有效方法”明确地重新构建了在注释评分中使用先前的解码器隐藏状态。另请参见论文的演示文稿和相关的 Matlab 代码。
他们开发了一个框架来对比不同的注释评分方法。他们的框架调出并明确排除了注释评分中的先前隐藏状态。
相反,他们采用先前的注意上下文向量并将其作为输入传递给解码器。目的是允许解码器知道过去的对齐决定。
…我们提出了一种输入馈送方法,其中注意向量 ht 在下一步[…]与输入连接。具有这种连接的效果是双重的:(a)我们希望使模型充分了解先前的对齐选择;(b)我们创建一个跨越水平和垂直的非常深的网络
- 基于注意力的神经机器翻译的有效方法,2015。
以下是本文采用的这种方法的图片。注意虚线表示使用解码器参与隐藏状态输出(ht),在下一个时间步长向解码器提供输入。
将隐藏状态作为解码器的输入
取自“基于注意力的神经机器翻译的有效方法”,2015 年。
他们还开发了“_ 全局 ”与“ 本地 ”注意力,其中本地注意力是对学习固定大小窗口以在每个输出时间强加注意向量的方法的修改步。它被认为是 Xu 等人提出的“ 硬注意 _”的简单方法。
全球关注的缺点在于它必须关注每个目标词的源侧的所有单词,这是昂贵的并且可能使得翻译较长序列(例如段落或文档)变得不切实际。为了解决这一不足,我们提出了一种局部注意机制,它选择只关注每个目标词的一小部分源位置。
- 基于注意力的神经机器翻译的有效方法,2015。
在具有不同注释评分函数的全局和局部关注的论文中的分析表明,局部关注在翻译任务上提供了更好的结果。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
编解码器文件
- 使用 RNN 编解码器进行统计机器翻译的学习短语表示,2014。
- 用神经网络进行序列学习的序列,2014。
注意论文
- 通过共同学习对齐和翻译的神经机器翻译,2015。
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
- 用于文档分类的分层注意网络,2016。
- 用于关系分类的基于注入的双向长短期记忆网络,2016
- 基于注意力的神经机器翻译的有效方法,2015。
更多关于注意力
- 长期短期记忆循环神经网络的注意力
- 第 10 讲:神经机器翻译和注意模型,斯坦福大学,2017 年
- 第 8 讲 - 引起注意的语言,牛津大学。
摘要
在本教程中,您发现了 Encoder-Decoder 模型的注意机制。
具体来说,你学到了:
- 关于编解码器模型和机器翻译的注意机制。
- 如何逐步实现关注机制。
- 注意机制的应用和扩展。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
如何利用深度学习自动生成照片的文本描述
原文:
machinelearningmastery.com/how-to-caption-photos-with-deep-learning/
字幕图像涉及在给定图像(例如照片)的情况下生成人类可读的文本描述。
这对于人来说是一个简单的问题,但对机器来说非常具有挑战性,因为它既涉及理解图像的内容,又涉及如何将这种理解转化为自然语言。
最近,深度学习方法取代了传统方法,并且为图像自动生成描述(称为“字幕”)的问题实现了最先进的结果。
在这篇文章中,您将了解如何使用深度神经网络模型自动生成图像描述,例如照片。
完成这篇文章后,你会知道:
- 关于为图像生成文本描述的挑战以及结合计算机视觉和自然语言处理的突破的需要。
- 关于构成神经特征字幕模型的元素,即特征提取器和语言模型。
- 如何使用注意机制将模型的元素排列到编解码器中。
让我们开始吧。
概观
这篇文章分为 3 部分;他们是:
- 用文本描述图像
- 神经字幕模型
- 编解码器架构
用文本描述图像
描述图像是生成图像的人类可读文本描述的问题,例如对象或场景的照片。
该问题有时被称为“_ 自动图像注释 ”或“ 图像标记 _”。
对于人来说这是一个简单的问题,但对于机器来说却非常具有挑战性。
快速浏览图像就足以让人指出并描述有关视觉场景的大量细节。然而,这种卓越的能力已被证明是我们视觉识别模型的一项难以捉摸的任务
- 用于生成图像描述的深度视觉语义对齐,2015。
解决方案需要理解图像的内容并将其翻译成单词的含义,并且单词必须串在一起才能被理解。它结合了计算机视觉和自然语言处理,在更广泛的人工智能中标志着一个真正的挑战性问题
自动描述图像的内容是连接计算机视觉和自然语言处理的人工智能中的基本问题。
- Show and Tell:神经图像标题生成器,2015。
此外,问题可能存在困难;让我们看一下示例中问题的三种不同变化。
1.分类图像
为图像分配来自数百或数千个已知类之一的类标签。
将图像分类为已知类的示例
摘自“检测鳄梨到西葫芦:我们做了什么,我们要去哪里?”,2013 年。
2.描述图像
生成内容图像的文本描述。
为 photogaphs 生成的字幕示例
取自“用于视觉识别和描述的长期复发卷积网络”,2015 年。
3.注释图像
为图像上的特定区域生成文本描述。
具有描述的图像的注释区域的示例。
取自“用于生成图像描述的深度视觉语义对齐”,2015 年。
一般问题也可以扩展到在视频中随时间描述图像。
在这篇文章中,我们将把注意力集中在描述图像上,我们将其描述为’_ 图像字幕 _。
神经字幕模型
神经网络模型已经成为自动字幕生成领域的主导;这主要是因为这些方法展示了最先进的结果。
在用于生成图像标题的端到端神经网络模型之前的两种主要方法是基于模板的方法和基于最近邻居的方法以及修改现有标题。
在使用神经网络生成字幕之前,两种主要方法占主导地位。第一个涉及生成标题模板,这些模板根据对象检测和属性发现的结果填写。第二种方法基于首先从大型数据库中检索类似的字幕图像,然后修改这些检索到的字幕以适合查询。 […]这两种方法都已经不再支持现在占主导地位的神经网络方法。
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
用于字幕的神经网络模型涉及两个主要元素:
- 特征提取。
- 语言模型。
特征提取模型
特征提取模型是神经网络,其给定图像能够提取显着特征,通常以固定长度向量的形式。
提取的特征是图像的内部表示,而不是直接可理解的东西。
深度卷积神经网络或 CNN 用作特征提取子模型。可以直接在图像字幕数据集中的图像上训练该网络。
或者,可以使用预训练的模型,例如用于图像分类的现有技术模型,或者使用预先训练的模型并对问题进行微调的一些混合模型。
在为 ILSVRC 挑战开发的 ImageNet 数据集中使用表现最佳的模型很受欢迎,例如 Oxford Vision Geometry Group 模型,简称为 VGG。
[…]我们探索了几种处理过拟合的技术。不过拟合的最明显的方法是将我们系统的 CNN 组件的权重初始化为预训练模型(例如,在 ImageNet 上)
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
特征提取器
语言模型
通常,语言模型在给定已经存在于序列中的单词的情况下预测序列中下一个单词的概率。
对于图像字幕,语言模型是一种神经网络,给定从网络中提取的特征能够预测描述中的单词序列,并以已经生成的单词为条件建立描述。
使用循环神经网络(例如长短期记忆网络或 LSTM)作为语言模型是很流行的。每个输出时间步骤在序列中生成一个新单词。
然后使用字嵌入(例如 word2vec)对生成的每个字进行编码,并将其作为输入传递给解码器以生成后续字。
对模型的改进涉及在输出序列的词汇表中收集单词的概率分布并搜索它以生成多个可能的描述。可以对这些描述进行评分并按可能性排序。通常使用 Beam Search 进行此搜索。
可以使用从图像数据集中提取的预先计算的特征来独立地训练语言模型;它可以与特征提取网络或某种组合共同训练。
语言模型
编解码器架构
构建子模型的流行方法是使用编解码器架构,其中两个模型被联合训练。
[该模型]基于卷积神经网络,该网络将图像编码为紧凑表示,然后是生成相应句子的循环神经网络。训练该模型以最大化给定图像的句子的可能性。
- Show and Tell:神经图像标题生成器,2015。
这是为机器翻译开发的架构,其中输入序列(例如法语)由编码器网络编码为固定长度向量。然后,一个单独的解码器网络读取编码并以新语言生成输出序列,比如英语。
除了该方法令人印象深刻的技能之外,这种方法的好处是可以针对该问题训练单个端到端模型。
当适用于图像字幕时,编码器网络是深度卷积神经网络,并且解码器网络是 LSTM 层的栈。
[机器翻译]“编码器”RNN 读取源句子并将其转换为富的固定长度向量表示,其又用作生成目标句子的“解码器”RNN 的初始隐藏状态。在这里,我们建议遵循这个优雅的秘籍,用深度卷积神经网络(CNN)代替编码器 RNN。
- Show and Tell:神经图像标题生成器,2015。
CNN 和 LSTM 架构的示例。
取自“Show and Tell:A Neural Image Caption Generator”,2015。
带注意的字幕模型
编解码器架构的限制是使用单个固定长度表示来保持提取的特征。
通过在更丰富的编码中开发注意力在机器翻译中解决了这一问题,允许解码器在生成翻译中的每个单词时学习在何处注意。
通过允许解码器在描述中生成每个单词时学习将注意力放在图像中的哪个位置,已经使用关注方法来改进用于图像字幕的编解码器架构的表现。
最近在字幕生成方面的进步以及最近在机器翻译和对象识别中引起注意力的成功激发了我们的鼓舞,我们研究了可以在生成其标题时关注图像的显着部分的模型。
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
这种方法的一个好处是可以在描述中生成每个单词时准确地可视化注意的位置。
我们还通过可视化显示模型如何能够在输出序列中生成相应的单词时自动学习如何将注视固定在显着对象上。
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
用一个例子来说这是最容易理解的;见下文。
注意图像字幕的示例
取自“显示,参加和讲述:视觉注意的神经图像标题生成”,2015 年。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
文件
- Show and Tell:神经图像标题生成器,2015。
- 显示,参与和讲述:视觉注意的神经图像标题生成,2015。
- 用于视觉识别和描述的长期复发卷积网络,2015。
- 用于生成图像描述的深层视觉语义对齐,2015。
用品
- 维基百科上的自动图像注释
- Show and Tell:图片字幕开源于 TensorFlow ,2016 年。
- 演示:使用 ConvNets 和 Recurrent Nets ,Andrej Karpathy 和 Fei-Fei Li(幻灯片)进行自动图像捕获。
项目
- 项目:用于生成图像描述的深层视觉语义对齐,2015。
- NeuralTalk2:Torch 中的高效图像字幕代码,运行在 GPU ,Andrej Karpathy 上。
摘要
在这篇文章中,您发现了如何使用深度神经网络模型自动生成图像描述,例如照片。
具体来说,你学到了:
- 关于为图像生成文本描述的挑战以及结合计算机视觉和自然语言处理的突破的需要。
- 关于构成神经特征字幕模型的元素,即特征提取器和语言模型。
- 如何使用注意机制将模型的元素排列到编解码器中。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。
如何开发一个单词级神经语言模型并用它来生成文本
原文:
machinelearningmastery.com/how-to-develop-a-word-level-neural-language-model-in-keras/
语言模型可以基于序列中已经观察到的单词来预测序列中下一个单词的概率。
神经网络模型是开发统计语言模型的首选方法,因为它们可以使用分布式表示,其中具有相似含义的不同单词具有相似的表示,并且因为它们在做出预测时可以使用最近观察到的单词的大的上下文。
在本教程中,您将了解如何使用 Python 中的深度学习开发统计语言模型。
完成本教程后,您将了解:
- 如何准备文本以开发基于单词的语言模型。
- 如何设计和拟合具有学习嵌入和 LSTM 隐藏层的神经语言模型。
- 如何使用学习的语言模型生成具有与源文本类似的统计属性的新文本。
让我们开始吧。
- Update Apr / 2018 :修正了模型描述中 100 个输入字与实际模型中 50 个输入字之间的不匹配。
如何开发一个单词级神经语言模型并用它来生成文本
照片由 Carlo Raso 拍摄,保留一些权利。
教程概述
本教程分为 4 个部分;他们是:
- 柏拉图共和国
- 数据准备
- 训练语言模型
- 使用语言模型
柏拉图共和国
共和国是古典希腊哲学家柏拉图最着名的作品。
它被构建为关于城市国家内秩序和正义主题的对话(例如对话)
整个文本在公共领域免费提供。它可以在 Project Gutenberg 网站上以多种格式获得。
您可以在此处下载整本书(或书籍)的 ASCII 文本版本:
下载书籍文本并将其直接放在当前工作中,文件名为“republic.txt
”
在文本编辑器中打开文件并删除前后问题。这包括开头的书籍详细信息,长篇分析以及最后的许可证信息。
案文应以:
书 I.
我昨天和阿里斯顿的儿子格劳孔一起去了比雷埃夫斯,
…
结束
…
在这一生和我们一直描述的千年朝圣中,我们都应该好好相处。
将清理后的版本保存为’ _republic_clean。当前工作目录中的 _ txt’。该文件应该是大约 15,802 行文本。
现在我们可以从这个文本开发一个语言模型。
数据准备
我们将从准备建模数据开始。
第一步是查看数据。
查看文本
在编辑器中打开文本,然后查看文本数据。
例如,这是第一个对话框:
书 I.
我昨天和阿里斯顿的儿子 Glaucon 一起去了比雷埃夫斯,
我可以向女神祈祷(Bendis,Thracian
Artemis。);而且因为我想看看他们以什么样的方式
庆祝这个节日,这是一个新事物。我很满意居民的
游行;但是色雷斯人的情况也是如此,
即使不是更多,也是美丽的。当我们完成祈祷并观看
景观时,我们转向了城市的方向;在那一瞬间
Cephalus 的儿子 Polemarchus 偶然在我们回家的路上从
的距离看到了我们,并告诉他的仆人
跑去让我们等他。仆人背后披着斗篷
抓住我,并说:Polemarchus 希望你等。我转过身,问他的主人在哪里。
他说,如果你只是等待,那么他就是那个年轻人。
当然,我们会,Glaucon 说。几分钟后,Polemarchus
出现了,并与他一起出现了 Glaucon 的兄弟 Adeimantus,Nicias 的儿子 Niceratus 以及其他几位参加过游行的人。Polemarchus 对我说:我认为,苏格拉底,你和你的
同伴已经在前往城市的路上。我说,你没错。
…
您认为我们在准备数据时需要处理什么?
以下是我从快速浏览中看到的内容:
- 书/章标题(例如“BOOK I.”)。
- 英国英语拼写(例如“荣幸”)
- 标点符号很多(例如“ - ”,“; - ”,“? - ”等)
- 奇怪的名字(例如“Polemarchus”)。
- 一些漫长的独白,持续数百行。
- 一些引用的对话框(例如’…')
这些观察以及更多建议以我们可能希望准备文本数据的方式提出。
我们准备数据的具体方式实际上取决于我们打算如何对其进行建模,而这又取决于我们打算如何使用它。
语言模型设计
在本教程中,我们将开发一个文本模型,然后我们可以使用它来生成新的文本序列。
语言模型将是统计的,并且将预测给定输入文本序列的每个单词的概率。预测的单词将作为输入输入,进而生成下一个单词。
关键的设计决策是输入序列应该有多长。它们需要足够长以允许模型学习要预测的单词的上下文。此输入长度还将定义在使用模型时用于生成新序列的种子文本的长度。
没有正确的答案。有了足够的时间和资源,我们就可以探索模型用不同大小的输入序列学习的能力。
相反,我们将为输入序列的长度选择 50 个字的长度,有点任意。
我们可以处理数据,以便模型只处理自包含的句子并填充或截断文本以满足每个输入序列的这一要求。您可以将此作为本教程的扩展进行探索。
相反,为了使示例保持简洁,我们将让所有文本一起流动并训练模型以预测文本中句子,段落甚至书籍或章节中的下一个单词。
现在我们有一个模型设计,我们可以看看将原始文本转换为 50 个输入字到 1 个输出字的序列,准备好适合模型。
加载文字
第一步是将文本加载到内存中。
我们可以开发一个小函数来将整个文本文件加载到内存中并返回它。该函数名为 load_doc(),如下所示。给定文件名,它返回一个加载文本序列。
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
使用此函数,我们可以在文件’republic_clean.txt
’中加载文档的清洁版本,如下所示:
# load document
in_filename = 'republic_clean.txt'
doc = load_doc(in_filename)
print(doc[:200])
运行此代码段会加载文档并打印前 200 个字符作为完整性检查。
书 I.
我昨天和阿里斯顿的儿子 Glaucon 一起去了比雷埃夫斯,
我可以向女神祈祷(Bendis,Thracian
Artemis。);还因为我想知道什么
到现在为止还挺好。接下来,让我们清理文本。
干净的文字
我们需要将原始文本转换为一系列令牌或单词,我们可以将其用作训练模型的源。
基于查看原始文本(上文),下面是我们将执行的一些特定操作来清理文本。您可能希望自己探索更多清洁操作作为扩展。
- 将’ - '替换为空格,以便我们可以更好地分割单词。
- 基于空白区域的分词。
- 从单词中删除所有标点符号以减少词汇量大小(例如’What?‘变为’What’)。
- 删除所有非字母的单词以删除独立的标点符号。
- 将所有单词标准化为小写以减少词汇量。
词汇量大小与语言建模有很大关系。较小的词汇量会导致较小的模型更快地训练。
我们可以在一个函数中按此顺序实现每个清理操作。下面是函数 clean_doc(),它将加载的文档作为参数并返回一个干净的标记数组。
import string
# turn a doc into clean tokens
def clean_doc(doc):
# replace '--' with a space ' '
doc = doc.replace('--', ' ')
# split into tokens by white space
tokens = doc.split()
# remove punctuation from each token
table = str.maketrans('', '', string.punctuation)
tokens = [w.translate(table) for w in tokens]
# remove remaining tokens that are not alphabetic
tokens = [word for word in tokens if word.isalpha()]
# make lower case
tokens = [word.lower() for word in tokens]
return tokens
我们可以在加载的文档上运行此清理操作,并打印出一些标记和统计量作为完整性检查。
# clean document
tokens = clean_doc(doc)
print(tokens[:200])
print('Total Tokens: %d' % len(tokens))
print('Unique Tokens: %d' % len(set(tokens)))
首先,我们可以看到一个很好的令牌列表,它看起来比原始文本更清晰。我们可以删除’ Book I '章节标记等等,但这是一个好的开始。
['book', 'i', 'i', 'went', 'down', 'yesterday', 'to', 'the', 'piraeus', 'with', 'glaucon', 'the', 'son', 'of', 'ariston', 'that', 'i', 'might', 'offer', 'up', 'my', 'prayers', 'to', 'the', 'goddess', 'bendis', 'the', 'thracian', 'artemis', 'and', 'also', 'because', 'i', 'wanted', 'to', 'see', 'in', 'what', 'manner', 'they', 'would', 'celebrate', 'the', 'festival', 'which', 'was', 'a', 'new', 'thing', 'i', 'was', 'delighted', 'with', 'the', 'procession', 'of', 'the', 'inhabitants', 'but', 'that', 'of', 'the', 'thracians', 'was', 'equally', 'if', 'not', 'more', 'beautiful', 'when', 'we', 'had', 'finished', 'our', 'prayers', 'and', 'viewed', 'the', 'spectacle', 'we', 'turned', 'in', 'the', 'direction', 'of', 'the', 'city', 'and', 'at', 'that', 'instant', 'polemarchus', 'the', 'son', 'of', 'cephalus', 'chanced', 'to', 'catch', 'sight', 'of', 'us', 'from', 'a', 'distance', 'as', 'we', 'were', 'starting', 'on', 'our', 'way', 'home', 'and', 'told', 'his', 'servant', 'to', 'run', 'and', 'bid', 'us', 'wait', 'for', 'him', 'the', 'servant', 'took', 'hold', 'of', 'me', 'by', 'the', 'cloak', 'behind', 'and', 'said', 'polemarchus', 'desires', 'you', 'to', 'wait', 'i', 'turned', 'round', 'and', 'asked', 'him', 'where', 'his', 'master', 'was', 'there', 'he', 'is', 'said', 'the', 'youth', 'coming', 'after', 'you', 'if', 'you', 'will', 'only', 'wait', 'certainly', 'we', 'will', 'said', 'glaucon', 'and', 'in', 'a', 'few', 'minutes', 'polemarchus', 'appeared', 'and', 'with', 'him', 'adeimantus', 'glaucons', 'brother', 'niceratus', 'the', 'son', 'of', 'nicias', 'and', 'several', 'others', 'who', 'had', 'been', 'at', 'the', 'procession', 'polemarchus', 'said']
我们还获得了有关干净文档的一些统计量。
我们可以看到,干净的文字中只有不到 120,000 个单词,而且词汇量不到 7,500 个单词。这个很小,适合这些数据的模型应该可以在适度的硬件上进行管理。
Total Tokens: 118684
Unique Tokens: 7409
接下来,我们可以看看将标记整形为序列并将它们保存到文件中。
保存干净的文字
我们可以将长令牌列表组织成 50 个输入字和 1 个输出字的序列。
也就是说,51 个单词的序列。
我们可以通过从令牌 51 开始迭代令牌列表并将先前的 50 个令牌作为序列进行迭代,然后将该过程重复到令牌列表的末尾。
我们将令牌转换为以空格分隔的字符串,以便以后存储在文件中。
下面列出了将清洁令牌列表拆分为长度为 51 令牌的序列的代码。
# organize into sequences of tokens
length = 50 + 1
sequences = list()
for i in range(length, len(tokens)):
# select sequence of tokens
seq = tokens[i-length:i]
# convert into a line
line = ' '.join(seq)
# store
sequences.append(line)
print('Total Sequences: %d' % len(sequences))
运行此片段会创建一长串的行。
在列表上打印统计量,我们可以看到我们将有 118,633 种训练模式来适应我们的模型。
Total Sequences: 118633
接下来,我们可以将序列保存到新文件中以便以后加载。
我们可以定义一个新函数来保存文本行到文件。这个新函数叫做 save_doc(),如下所示。它将行和文件名列表作为输入。这些行以 ASCII 格式写入,每行一行。
# save tokens to file, one dialog per line
def save_doc(lines, filename):
data = '\n'.join(lines)
file = open(filename, 'w')
file.write(data)
file.close()
我们可以调用此函数并将训练序列保存到文件’republic_sequences.txt
’。
# save sequences to file
out_filename = 'republic_sequences.txt'
save_doc(sequences, out_filename)
使用文本编辑器查看文件。
你会看到每一行都沿着一个单词移动,最后一个新单词被预测;例如,以下是截断形式的前 3 行:
我知道了…看到了
我去了…看到我们
我从
下来…
完整的例子
将所有这些结合在一起,下面提供了完整的代码清单。
import string
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
# turn a doc into clean tokens
def clean_doc(doc):
# replace '--' with a space ' '
doc = doc.replace('--', ' ')
# split into tokens by white space
tokens = doc.split()
# remove punctuation from each token
table = str.maketrans('', '', string.punctuation)
tokens = [w.translate(table) for w in tokens]
# remove remaining tokens that are not alphabetic
tokens = [word for word in tokens if word.isalpha()]
# make lower case
tokens = [word.lower() for word in tokens]
return tokens
# save tokens to file, one dialog per line
def save_doc(lines, filename):
data = '\n'.join(lines)
file = open(filename, 'w')
file.write(data)
file.close()
# load document
in_filename = 'republic_clean.txt'
doc = load_doc(in_filename)
print(doc[:200])
# clean document
tokens = clean_doc(doc)
print(tokens[:200])
print('Total Tokens: %d' % len(tokens))
print('Unique Tokens: %d' % len(set(tokens)))
# organize into sequences of tokens
length = 50 + 1
sequences = list()
for i in range(length, len(tokens)):
# select sequence of tokens
seq = tokens[i-length:i]
# convert into a line
line = ' '.join(seq)
# store
sequences.append(line)
print('Total Sequences: %d' % len(sequences))
# save sequences to file
out_filename = 'republic_sequences.txt'
save_doc(sequences, out_filename)
您现在应该将训练数据存储在当前工作目录中的文件’republic_sequences.txt
’中。
接下来,让我们看看如何使语言模型适合这些数据。
训练语言模型
我们现在可以从准备好的数据中训练统计语言模型。
我们将训练的模型是神经语言模型。它有一些独特的特点:
- 它使用单词的分布式表示,以便具有相似含义的不同单词具有相似的表示。
- 它在学习模型的同时学习表示。
- 它学会使用最后 100 个单词的上下文预测下一个单词的概率。
具体来说,我们将使用嵌入层来学习单词的表示,并使用长期短期记忆(LSTM)循环神经网络来学习根据其上下文预测单词。
让我们从加载我们的训练数据开始。
加载序列
我们可以使用我们在上一节中开发的load_doc()
函数加载我们的训练数据。
加载后,我们可以通过基于新行的拆分将数据拆分为单独的训练序列。
下面的代码段将从当前工作目录加载’republic_sequences.txt
’数据文件。
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
# load
in_filename = 'republic_sequences.txt'
doc = load_doc(in_filename)
lines = doc.split('\n')
接下来,我们可以编码训练数据。
编码序列
单词嵌入层要求输入序列由整数组成。
我们可以将词汇表中的每个单词映射到一个唯一的整数,并对输入序列进行编码。之后,当我们做出预测时,我们可以将预测转换为数字并在同一映射中查找其关联的单词。
要进行此编码,我们将使用 Keras API 中的 Tokenizer 类。
首先,必须在整个训练数据集上训练 Tokenizer,这意味着它会找到数据中的所有唯一单词并为每个单词分配一个唯一的整数。
然后我们可以使用 fit Tokenizer 对所有训练序列进行编码,将每个序列从单词列表转换为整数列表。
# integer encode sequences of words
tokenizer = Tokenizer()
tokenizer.fit_on_texts(lines)
sequences = tokenizer.texts_to_sequences(lines)
我们可以访问单词到整数的映射,作为 Tokenizer 对象上名为 word_index 的字典属性。
我们需要知道稍后定义嵌入层的词汇表的大小。我们可以通过计算映射字典的大小来确定词汇表。
为单词分配从 1 到单词总数的值(例如 7,409)。嵌入层需要为此词汇表中的每个单词分配一个向量表示,从索引 1 到最大索引,并且因为数组的索引是零偏移,所以词汇结尾的单词索引将是 7,409;这意味着数组的长度必须为 7,409 + 1。
因此,在为嵌入层指定词汇表大小时,我们将其指定为比实际词汇大 1。
# vocabulary size
vocab_size = len(tokenizer.word_index) + 1
序列输入和输出
现在我们已经编码了输入序列,我们需要将它们分成输入(X
)和输出(y
)元素。
我们可以通过数组切片来做到这一点。
分离后,我们需要对输出字进行热编码。这意味着将它从整数转换为 0 值的向量,一个用于词汇表中的每个单词,用 1 表示单词整数值索引处的特定单词。
这样,模型学习预测下一个单词的概率分布,并且除了接下来的实际单词之外,所有单词的学习基础真实为 0。
Keras 提供 to_categorical(),可用于对每个输入 - 输出序列对的输出字进行热编码。
最后,我们需要为嵌入层指定输入序列的长度。我们知道有 50 个单词,因为我们设计了模型,但指定的一个很好的通用方法是使用输入数据形状的第二个维度(列数)。这样,如果在准备数据时更改序列的长度,则无需更改此数据加载代码;它是通用的。
# separate into input and output
sequences = array(sequences)
X, y = sequences[:,:-1], sequences[:,-1]
y = to_categorical(y, num_classes=vocab_size)
seq_length = X.shape[1]
适合模型
我们现在可以在训练数据上定义和拟合我们的语言模型。
如前所述,学习嵌入需要知道词汇表的大小和输入序列的长度。它还有一个参数来指定用于表示每个单词的维度。也就是说,嵌入向量空间的大小。
常用值为 50,100 和 300.我们在这里使用 50,但考虑测试更小或更大的值。
我们将使用两个 LSTM 隐藏层,每层有 100 个存储单元。更多的存储单元和更深的网络可以获得更好的结果。
具有 100 个神经元的密集完全连接层连接到 LSTM 隐藏层以解释从序列提取的特征。输出层将下一个单词预测为单个向量,即词汇表的大小,其中词汇表中的每个单词具有概率。 softmax 激活函数用于确保输出具有归一化概率的特征。
# define model
model = Sequential()
model.add(Embedding(vocab_size, 50, input_length=seq_length))
model.add(LSTM(100, return_sequences=True))
model.add(LSTM(100))
model.add(Dense(100, activation='relu'))
model.add(Dense(vocab_size, activation='softmax'))
print(model.summary())
定义网络的摘要打印为完整性检查,以确保我们构建了我们的预期。
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
embedding_1 (Embedding) (None, 50, 50) 370500
_________________________________________________________________
lstm_1 (LSTM) (None, 50, 100) 60400
_________________________________________________________________
lstm_2 (LSTM) (None, 100) 80400
_________________________________________________________________
dense_1 (Dense) (None, 100) 10100
_________________________________________________________________
dense_2 (Dense) (None, 7410) 748410
=================================================================
Total params: 1,269,810
Trainable params: 1,269,810
Non-trainable params: 0
_________________________________________________________________
接下来,编译模型,指定拟合模型所需的分类交叉熵损失。从技术上讲,该模型正在学习多分类,这是此类问题的合适损失函数。使用有效的 Adam 实现到小批量梯度下降并且评估模型的准确率。
最后,该模型适用于 100 个训练时期的数据,适当的批量大小为 128,以加快速度。
没有 GPU 的现代硬件上的训练可能需要几个小时。您可以使用更大的批量大小和/或更少的训练时期加快速度。
# compile model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
model.fit(X, y, batch_size=128, epochs=100)
在训练期间,您将看到表现摘要,包括在每次批次更新结束时从训练数据评估的损失和准确率。
你会得到不同的结果,但是预测序列中下一个单词的准确度可能只有 50%以上,这也不错。我们的目标不是 100%准确(例如记忆文本的模型),而是一种捕捉文本本质的模型。
...
Epoch 96/100
118633/118633 [==============================] - 265s - loss: 2.0324 - acc: 0.5187
Epoch 97/100
118633/118633 [==============================] - 265s - loss: 2.0136 - acc: 0.5247
Epoch 98/100
118633/118633 [==============================] - 267s - loss: 1.9956 - acc: 0.5262
Epoch 99/100
118633/118633 [==============================] - 266s - loss: 1.9812 - acc: 0.5291
Epoch 100/100
118633/118633 [==============================] - 270s - loss: 1.9709 - acc: 0.5315
保存模型
在运行结束时,训练的模型将保存到文件中。
在这里,我们使用 Keras 模型 API 将模型保存到当前工作目录中的文件’model.h5
’。
之后,当我们加载模型做出预测时,我们还需要将单词映射到整数。这是在 Tokenizer 对象中,我们也可以使用 Pickle 保存它。
# save the model to file
model.save('model.h5')
# save the tokenizer
dump(tokenizer, open('tokenizer.pkl', 'wb'))
完整的例子
我们可以把所有这些放在一起;下面列出了拟合语言模型的完整示例。
from numpy import array
from pickle import dump
from keras.preprocessing.text import Tokenizer
from keras.utils import to_categorical
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from keras.layers import Embedding
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
# load
in_filename = 'republic_sequences.txt'
doc = load_doc(in_filename)
lines = doc.split('\n')
# integer encode sequences of words
tokenizer = Tokenizer()
tokenizer.fit_on_texts(lines)
sequences = tokenizer.texts_to_sequences(lines)
# vocabulary size
vocab_size = len(tokenizer.word_index) + 1
# separate into input and output
sequences = array(sequences)
X, y = sequences[:,:-1], sequences[:,-1]
y = to_categorical(y, num_classes=vocab_size)
seq_length = X.shape[1]
# define model
model = Sequential()
model.add(Embedding(vocab_size, 50, input_length=seq_length))
model.add(LSTM(100, return_sequences=True))
model.add(LSTM(100))
model.add(Dense(100, activation='relu'))
model.add(Dense(vocab_size, activation='softmax'))
print(model.summary())
# compile model
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
# fit model
model.fit(X, y, batch_size=128, epochs=100)
# save the model to file
model.save('model.h5')
# save the tokenizer
dump(tokenizer, open('tokenizer.pkl', 'wb'))
使用语言模型
既然我们有一个训练有素的语言模型,我们就可以使用它。
在这种情况下,我们可以使用它来生成与源文本具有相同统计属性的新文本序列。
这是不切实际的,至少不是这个例子,但它给出了语言模型学到的具体例子。
我们将再次加载训练序列。
加载数据
我们可以使用上一节中的相同代码来加载文本的训练数据序列。
具体来说,load_doc()
功能。
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
# load cleaned text sequences
in_filename = 'republic_sequences.txt'
doc = load_doc(in_filename)
lines = doc.split('\n')
我们需要文本,以便我们可以选择源序列作为模型的输入,以生成新的文本序列。
该模型将需要 100 个单词作为输入。
稍后,我们需要指定预期的输入长度。我们可以通过计算加载数据的一行的长度从输入序列中确定这一点,并且对于同一行上的预期输出字减去 1。
seq_length = len(lines[0].split()) - 1
加载模型
我们现在可以从文件加载模型。
Keras 提供load_model()
功能,用于加载模型,随时可以使用。
# load the model
model = load_model('model.h5')
我们还可以使用 Pickle API 从文件加载 tokenizer。
# load the tokenizer
tokenizer = load(open('tokenizer.pkl', 'rb'))
我们准备使用加载的模型。
生成文本
生成文本的第一步是准备种子输入。
为此,我们将从输入文本中选择一行随机文本。一旦选定,我们将打印它,以便我们对使用的内容有所了解。
# select a seed text
seed_text = lines[randint(0,len(lines))]
print(seed_text + '\n')
接下来,我们可以一次创建一个新单词。
首先,必须使用我们在训练模型时使用的相同标记器将种子文本编码为整数。
encoded = tokenizer.texts_to_sequences([seed_text])[0]
该模型可以通过调用model.predict_classes()
直接预测下一个单词,该模型将返回具有最高概率的单词的索引。
# predict probabilities for each word
yhat = model.predict_classes(encoded, verbose=0)
然后,我们可以在 Tokenizers 映射中查找索引以获取关联的单词。
out_word = ''
for word, index in tokenizer.word_index.items():
if index == yhat:
out_word = word
break
然后,我们可以将此单词附加到种子文本并重复该过程。
重要的是,输入序列将变得太长。在输入序列编码为整数后,我们可以将其截断为所需的长度。 Keras 提供了pad_sequences()
函数,我们可以使用它来执行此截断。
encoded = pad_sequences([encoded], maxlen=seq_length, truncating='pre')
我们可以将所有这些包装成一个名为generate_seq()
的函数,该函数将模型,标记生成器,输入序列长度,种子文本和要生成的单词数作为输入。然后它返回由模型生成的一系列单词。
# generate a sequence from a language model
def generate_seq(model, tokenizer, seq_length, seed_text, n_words):
result = list()
in_text = seed_text
# generate a fixed number of words
for _ in range(n_words):
# encode the text as integer
encoded = tokenizer.texts_to_sequences([in_text])[0]
# truncate sequences to a fixed length
encoded = pad_sequences([encoded], maxlen=seq_length, truncating='pre')
# predict probabilities for each word
yhat = model.predict_classes(encoded, verbose=0)
# map predicted word index to word
out_word = ''
for word, index in tokenizer.word_index.items():
if index == yhat:
out_word = word
break
# append to input
in_text += ' ' + out_word
result.append(out_word)
return ' '.join(result)
我们现在准备在给出一些种子文本的情况下生成一系列新单词。
# generate new text
generated = generate_seq(model, tokenizer, seq_length, seed_text, 50)
print(generated)
综上所述,下面列出了从学习语言模型生成文本的完整代码清单。
from random import randint
from pickle import load
from keras.models import load_model
from keras.preprocessing.sequence import pad_sequences
# load doc into memory
def load_doc(filename):
# open the file as read only
file = open(filename, 'r')
# read all text
text = file.read()
# close the file
file.close()
return text
# generate a sequence from a language model
def generate_seq(model, tokenizer, seq_length, seed_text, n_words):
result = list()
in_text = seed_text
# generate a fixed number of words
for _ in range(n_words):
# encode the text as integer
encoded = tokenizer.texts_to_sequences([in_text])[0]
# truncate sequences to a fixed length
encoded = pad_sequences([encoded], maxlen=seq_length, truncating='pre')
# predict probabilities for each word
yhat = model.predict_classes(encoded, verbose=0)
# map predicted word index to word
out_word = ''
for word, index in tokenizer.word_index.items():
if index == yhat:
out_word = word
break
# append to input
in_text += ' ' + out_word
result.append(out_word)
return ' '.join(result)
# load cleaned text sequences
in_filename = 'republic_sequences.txt'
doc = load_doc(in_filename)
lines = doc.split('\n')
seq_length = len(lines[0].split()) - 1
# load the model
model = load_model('model.h5')
# load the tokenizer
tokenizer = load(open('tokenizer.pkl', 'rb'))
# select a seed text
seed_text = lines[randint(0,len(lines))]
print(seed_text + '\n')
# generate new text
generated = generate_seq(model, tokenizer, seq_length, seed_text, 50)
print(generated)
首先运行示例打印种子文本。
当他说一个人长大后可以学到很多东西,因为他不能学到更多东西,因为他可以跑得很多青春是时候任何特殊的辛劳,因此计算和几何以及所有其他教学要素都是一个
然后打印 50 个生成的文本。
辩证法的准备应该以怠惰挥霍者的名义呈现,其他人是多方面的,不公正的,是最好的,另一个是高兴的灵魂灵魂的开放,绣花者必须在
你会得到不同的结果。尝试运行几代产品。
你可以看到文字看似合理。实际上,添加连接将有助于解释种子和生成的文本。然而,生成的文本以正确的顺序获得正确的单词。
尝试运行几次示例以查看生成文本的其他示例。如果你看到有趣的话,请在下面的评论中告诉我。
扩展
本节列出了一些扩展您可能希望探索的教程的想法。
- Sentence-Wise Model 。基于句子分割原始数据并将每个句子填充到固定长度(例如,最长的句子长度)。
- 简化词汇。探索一个更简单的词汇,可能会删除词干或停止词。
- 调谐模型。调整模型,例如隐藏层中嵌入的大小或存储单元的数量,以查看是否可以开发更好的模型。
- 更深的型号。扩展模型以具有多个 LSTM 隐藏层,可能具有丢失以查看是否可以开发更好的模型。
- 预训练单词嵌入。扩展模型以使用预先训练的 word2vec 或 GloVe 向量来查看它是否会产生更好的模型。
进一步阅读
如果您要深入了解,本节将提供有关该主题的更多资源。
- Gutenberg 项目
- 柏拉图共和国古腾堡项目
- 维基百科上的共和国(柏拉图)
- 维基百科上的语言模型
摘要
在本教程中,您了解了如何使用单词嵌入和循环神经网络开发基于单词的语言模型。
具体来说,你学到了:
- 如何准备文本以开发基于单词的语言模型。
- 如何设计和拟合具有学习嵌入和 LSTM 隐藏层的神经语言模型。
- 如何使用学习的语言模型生成具有与源文本类似的统计属性的新文本。
你有任何问题吗?
在下面的评论中提出您的问题,我会尽力回答。