「Python数据分析系列」21. 自然语言处理(下)_数据与智能的博客-程序员ITS301

技术标签: 算法  python  编程语言  神经网络  大数据  

来源 |  Data Science from Scratch, Second Edition

作者 | Joel Grus

译者 | cloverErna

校对 | gongyouliu

编辑 | auroral-L

全文共5042字,预计阅读时间35分钟。

第二十一章 自然语言处理

 

6.  Word 向量

7.  递归神经网络

8.  示例:使用一个字符级的RNN

9.  以供进一步探索

6. Word 向量

NLP方面的许多最新进展都涉及到深度学习。在本章的其余部分,我们将使用第19章形成的机制。

一个重要的创新包括将单词表示为低维向量。这些向量可以被比较,加在一起,输入到机器学习模型中,或者任何你想用它们做的任何事情。它们通常具有良好的属性;例如,类似的词往往有相似的向量。也就是说,big的词向量非常接近large的词向量,所以在词向量上操作的模型可以(在某种程度上)免费处理像同义词这样的东西。

这些向量通常也会表现出令人愉快的算术性质。例如,在一些这样的模型中,如果你取了国王的向量,减去男人的向量,然后加上女人的向量,你最终会得到一个非常接近女王的向量的向量。思考这对向量实际上“学习”的含义是很有趣的,尽管我们不会在这里花时间。

想出大量词汇的这样的向量是一项困难的任务,所以我们通常会从文本语料库中学习它们。有几种不同的方案,但在高级级别上,任务通常是这样的:

1. 获取一堆文字。

2. 创建一个数据集,其目标是预测一个给定附近单词的单词(或者,预测给定一个单词的附近单词)。

3. 训练一个神经网络来完成这项任务。

4. 以训练过的神经网络的内部状态作为单词向量。

特别是,由于任务是预测一个给出附近单词的单词,发生在相似上下文中(因此有相似的附近单词)的单词应该具有相似的内部状态,因此具有相似的单词向量。

这里我们将使用余弦相似度来度量“相似度”,它是-1和1之间的一个数字,用来测量两个向量指向相同方向的程度:

a2bfb9a67af407abcf84711cc5e3622f.png

让我们学习一些单词向量,看看这是如何工作的。

首先,我们需要一个玩具数据集。常用的单词向量通常是从数百万甚至数十亿单词的训练中得到的。由于我们的玩具库无法处理这么多的数据,我们将创建一个具有一定结构的人工数据集: 

ce7c7a6bf79a2607cfd7d910be907e75.png

这将产生很多结构相似但单词不同的句子;例如,“绿色的船似乎很慢”。鉴于这种设置,颜色将主要出现在“类似的”的上下文中,名词也会出现,等等。所以如果我们能很好地分配单词向量,颜色应该得到类似的向量,等等。

注意

在实际使用中,你可能会有数百万个句子的语料库,在这种情况下,你会从句子中得到“足够”的上下文。在这里,只有50句话,我们必须让它们有些人工化。

如前所述,我们希望对我们的单词进行一次热编码,这意味着我们需要将它们转换为ID。我们将介绍一个词汇类来跟踪此映射:

68756154ae72568617ba930ec91a0358.png

c8d172599cee189d3c30255d87794775.png

这些都是我们可以手动做的事情,但是在课堂上使用它很不方便。我们应该测试一下:

76d62e425542052e0f023235b4ed7761.png

4d34e1d0ce35495bab20ee2dd9a687ae.png

我们还应该编写简单的辅助函数来保存和加载一个词汇表,就像我们的深度学习模型一样:

780b6df274ab96071dcfcdbb8f017771.png

我们将使用一个叫做跳过图的单词向量模型,该模型以一个单词作为输入,并生成在它附近可能看到的单词的概率。我们将给它训练对(单词,nearby_word),并尽量减少最小最大熵损失。

注意

另一个常见的模型,连续的单词包(CBOW),以附近的单词作为输入,并试图预测原始单词。

让我们来设计我们的神经网络。它的核心将是一个嵌入层,它以一个词ID作为输入,并返回一个词向量。在已知条件下,我们可以只为此使用一个查找表。

然后,我们将将单词向量传递给线性层,其输出数量与词汇表中的单词相同。与以前一样,我们将使用softmax将这些输出转换为附近单词上的概率。当我们使用梯度下降来训练模型时,我们将更新查找表中的向量。完成训练后,该查找表就会提供单词向量。

让我们来创建那个嵌入层。在实践中,我们可能希望嵌入单词以外的东西,因此我们将构建一个更通用的嵌入层。(稍后我们将编写一个专门为词向量编写的TextEmbedding子类。)

在其构造函数中,我们将提供嵌入向量的数量和维数,以便它可以创建嵌入(最初是标准随机法):

85c74962ea8998db0cb1347474889005.png

在我们的例子中,我们一次只嵌入一个单词。然而,在其他模型中,我们可能想要嵌入一系列单词,并得到一系列单词向量。(例如,如果我们想训练前面描述的CBOW模型。)所以,另一种设计将采用单词ID序列。我们将坚持一次做一个,让事情更简单。

5f211b50af1bdfe11d750f03a7f7a98e.png

对于向后传递,我们将得到一个与所选嵌入向量对应的梯度,我们需要为self.embeddings构造相应的梯度,除了所选嵌入之外,每个嵌入都为零:

ecda57ca52bf5abd0d4a1858a2d25918.png

因为我们有参数和梯度,所以我们需要覆盖这些方法:

f3d6a6180732fd80e2c013c0e27c7006.png

如前所述,我们将需要一个专门用于词向量的子类。在这种情况下,我们的嵌入数量由我们的词汇量决定,所以我们将其传递入:

2ed3e28efc54209dff5594ee8491a4da.png

其他内置方法将正常工作,但我们将添加一些比较适用于文本处理的方法。例如,我们希望能够检索一个给定单词的向量。(这不是Layer界面的一部分,但我们总是可以自由地向特定的Layer添加额外的方法。)

927b5a16150f33d7a0adc728058c5808.png

这个数据下的方法将允许我们检索使用索引的字向量:

a3468b77166dc03b8ca37249cd86f80e.png

我们还希望嵌入层能告诉我们最接近给定单词的单词:

6b7d9d785c0024b2ec508572ee5f9ec1.png

fdc445cb33f8faf28388b58f9aa1deed.png

我们的嵌入层只是输出向量,我们可以将其输入到一个线性层中。

现在,我们已经准备好收集培训数据了。对于每个输入词,我们将选择它左边的两个单词和它右边的两个单词作为目标词。

让我们先将句子转为小写形式,并将其分割成单词:

65804f0949723debc86d41796e8fac90.png

此时,我们可以构建一个词汇表:

4759136ab36e6500cc5e4ac6b9b5f73e.png

bbbb1adf4bb4108db4ae3b4bffea7e4e.png

使用我们建立的机制,现在很容易创建我们的模型:

464a49dd27302865934c0bea9aefd4a2.png

使用第19章中的技术,可以轻松训练我们的模型:

3c893a041cd5edb7ef1149c993ea4e15.png

9f42c933b567538ad91f37477de92e87.png

当你看这列火车时,你可以看到颜色越来越接近,形容词越来越接近,名词越来越接近。

训练模型后,探索最相似的词语会非常有趣:

9f1d357e6b8c3843c71350f944d3800d.png

哪个结果(对我来说)会导致:

f438bb7c8c2cf9fead7ed2ef91000aca.png

(很明显,床和猫并不是很相似,但在我们的训练句子中,它们看起来是,这就是模型捕捉到的。)

我们还可以提取前两个主要组件并绘制它们:

0550361ac780ad26132be2719253e1ba.png

8a7e26c346bc4e086768fc0659260790.png

这表明类似的词语确实聚集在一起(图21-3):

d3b9bfda95ababab2b4f902267c6bee9.png

图21-3。Word向量

如果你感兴趣,那么训练CBOW词向量并不难。你得做一点工作。首先,你需要修改嵌入层,以便使用ID列表并输出嵌入向量列表作为输入。然后,你必须创建一个新的Layer(总和?)它取一个向量列表,并返回它们的和。

每个单词都表示一个训练示例,其中输入是周围单词的单词Id,目标是单词本身的独热编码。

修改后的嵌入层将周围的单词转换为向量列表,新的Sum层将向量列表分解为单个向量,线性层可以生成分数,然后可以softmax以得到一个概率分布,这个分布表示“鉴于此上下文最有可能的单词”概率。

我发现CBOW模型比skip-gram模型更难训练,但我鼓励你尝试一下。

7. 递归神经网络

我们在前一节中开发的单词向量通常被用作神经网络的输入。这样做的一个挑战是句子的长度不同:你可以认为3个单词的句子为[3,embedding_dim]张量,10个字的句子为[10,embedding_dim]张量。为了将它们传递到一个线性层,我们需要对第一个变长维数做一些事情。

一种选择是使用Sum层(或取平均值的变体);然而,句子中单词的顺序通常对其意义很重要。举个例子,“狗咬人”和“人咬狗”是两个非常不同的故事!

另一种处理这一问题的方法是使用递归神经网络(RNNs),它在输入之间保持一个隐藏状态。在最简单的情况下,每个输入与当前隐藏状态组合以产生输出,然后将输出用作新的隐藏状态。这使得这些网络能够“记住”(在某种意义上)他们所看到的输入,并建立一个取决于所有输入及其顺序的最终输出。

我们将创建几乎最简单的RNN层,它将接受单个输入(例如,句子中的一个单词或单词中的一个字符),并在调用之间保持隐藏状态。

回想一下,我们的线性层有一个权重w,和一个偏差b。它接受了一个向量输入,并使用下面的逻辑产生了一个不同的向量作为输出:

df1d4517cb52750e3790d36e9a869544.png

这里我们希望合并隐藏状态,因此我们将有两组权重—一组应用于输入,另一组应用于以前的隐藏状态:

251ef0d5141fcdcdb3b759b2ba64a2fd.png

接下来,我们将使用输出向量作为隐藏值的新值。这并不是一个巨大的变化,但它将让我们的网络更好。

e85e5e4eee210e5b90f67bd9eaa574bf.png

你可以看到,我们将隐藏状态作为全0的向量开始,我们提供了一个函数,使用网络的人可以调用来重置隐藏状态。

考虑到此设置,forword函数就相当简单(至少,如果你能记住并理解我们的线性层是如何工作的):

0ff2894e44f5d21eea48ce6df363f469.png

be3973465844689fa281df54f82bed40.png

向后传递与我们的线性层中的一个相似,除了它需要计算一组额外的梯度:

0529acd855fc1acfa9cbbcb3e4fe948c.png

最后,我们需要重载params和grads的方法:

0f1e2557ce68643144cfb16c57d60aa5.png

注意

这个“简单”的RNN非常简单,因此你可能不应该在实践中使用它。

我们的SimpleRnn有一些不受欢迎的特性。一种是它的整个隐藏状态用于在每次调用输入时更新输入。另一种情况是,每次调用整个隐藏状态时都会被覆盖。这两种方法都使训练变得困难;特别是,它们使模型难以学习远程依赖关系。

由于这个原因,几乎没有人使用这种简单的RNN。相反,它们使用更复杂的变体,如LSTM(“长短期记忆”)或GRU(“门控单元”),它们具有更多的参数和用参数化的“门”,只允许每次更新一些状态(而某些状态被使用)。

这些变体并没有什么特别困难的;然而,它们涉及更多的代码,(在我看来)不会相应地更有启发意义。本章关于GitHub的代码包括一个LSTM实现。我鼓励你去看看,但这有点乏味,所以我们不会在这里进一步讨论。

我们实现的另一个奇怪之处是,它一次只需要“一步”,需要我们手动重置隐藏状态。一个更实际的RNN实现可以接受输入序列,在每个序列开始时将其隐藏状态设置为0s,并产生输出序列。我们的代码当然可以这样修改;同样,这将需要更多的代码和复杂性,而不会带来更深入的理解。

8. 示例:使用一个字符级的RNN

新聘请的品牌副总裁自己并没有想到达塔西安斯特这个名字,(因此)他怀疑一个更好的名字可能会给公司带来更多的成功。他要求你使用数据科学来提供被替代的候选建议。

RNNs的一个“很酷的”应用程序包括使用字符(而不是单词)作为输入,训练他们学习某些数据集中微妙的语言模式,然后使用它们从该数据集中生成虚构的实例。

例如,你可以训练一个RNN关于另类乐队的名字,使用训练过的模型为假的另类乐队生成新的名字,然后手工选择最有趣的乐队,并在推特上分享它们。真是太棒了!

看到这个技巧很多次后,你不再认为它非常聪明,你决定试试。

经过一番挖掘,你会发现启动加速器Y Combinator发布了其前100家(实际上是101家)最成功的初创公司的列表,这似乎是一个很好的起点。检查页面,你会发现公司的名称都生活在<b类=“h4“>标签中,这意味着很容易使用你的网络抓取技能来检索它们:

4078081648b84dbcdd12d044ee96b72a.png

和往常一样,页面可能会更改(或消失),在这种情况下,此代码将无法工作。如果是这样,你可以使用新学习的数据科学技能来修复它,或者只是从书的GitHub网站获取列表。

那么,我们的计划是什么呢?我们将训练一个模型来预测名称的下一个字符,并给定当前字符和表示我们迄今为止看到的所有字符的隐藏状态。

与往常一样,我们将实际预测字符上的概率分布,并训练模型以最小化SoftmaxCrossEntropy损失。

一旦我们的模型被训练,我们可以使用它来生成一些概率,根据这些概率随机采样一个字符,然后将该字符作为下一个输入。这将允许我们使用学习到的权重来生成公司名称。

首先,我们应该根据名称中的字符构建一个词汇:

ea605d75bc697ce291ea9806f25c28c5.png

此外,我们将使用特殊令牌来表示公司名称的开始和结束。这允许模型了解哪些字符应该开始一个公司名称,也可以了解一个公司名称何时完成。

我们只使用正则表达式字符开始和结束,(幸运的是)它们不会出现在我们的公司列表中:

2915b50cd6d78046c9811f2c9e81a2a8.png

对于我们的模型,我们将对每个字符进行一次独热编码,通过两个SimpleRnns,然后使用线性层为每个可能的下一个字符生成分数:

d15d3c34268a7d3f91473787cb5759f9.png

想象一下,目前我们已经训练了这个模型。让我们使用“主题建模”中的sample_from函数,编写使用它生成新公司名称的函数:

9ffb3300830cde9ad6162e9159201e75.png

bb4852cca7fb1132a548bba8d8fcdfca.png

最后,我们已经准备好训练我们的角色级的RNN了。这将需要一段时间!

53c70d2a00365f895a9f71ce535df5a8.png

75a6a997539f8137ba2477be33d8a8b6.png

训练后,模型从列表中生成一些实际名称(这并不奇怪,因为模型具有相当多的容量而没有大量的训练数据),以及一些与训练名称(脚本、链接、诗歌)类似看起来真正有创意的名称(Benuus, Cletpo, Equite, Vivest),以及垃圾但仍然类似单词的名称(SFitreasy, Sint ocanelp, GliyOx, Doorboronelhav)。

不幸的是,就像大多数角色级的RNN输出一样,这些输出只是有点聪明,而品牌的副总裁最终无法使用它们。

如果我将隐藏的维度提升到64,我就会从列表中逐字得到更多的名字;如果我把它放到8,我得到的大多是垃圾。所有这些模型大小的词汇表和最终权重可以在该书的GitHub网站上找到,你可以自己使用load_weights和load_vocab来使用它们。

如前所述,本章的GitHub代码还包含一个LSTM实现,你可以作为公司名称模型中SimpleRnns的替换品。

9. 以供进一步探索

•  NLTK是Python的一个流行的NLP工具库。它有自己的整本书,可以在网上阅读。

•  gensim是一个用于主题建模的Python库,它比我们的从头开始的模型更好。

•  spaCy是“Python中的工业强度的自然语言处理”的库,也很受欢迎。

•  安德烈·卡帕蒂有一篇著名的博客文章,“递归神经网络的不合理有效性”,非常值得一读。

•  我的日常工作包括建立AllenNLP,一个用于做NLP研究的Python库。(至少,在这本书出版的时候,它确实是这样的。)该库完全超出了这本书的范围,但你可能仍然会发现它很有趣,而且它有一个很酷的交互式演示界面,可以演示许多最先进的NLP模型。

48f47d442d47714e301d1e0651db8378.png

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_43045873/article/details/120359446

智能推荐

Redis —— 项目使用:缓存数据(一)_小白的码BUG之路的博客-程序员ITS301

情景: 当查询数据库的时候,把查询结果保存到Redis中,下次再查询的时候,先查询redis缓存中是否存在用户查询的数据,有则直接返回,没有再去查数据库,结果再保存到数据库中。现实中的应用场景,比如某明星,很多粉丝都查询这个明星的信息,同样的信息一条可能查几百万次,这种情况就可以用这种缓存。步骤: 搭建SSM框架:具体可以参考另一篇博客https://blo...

设置nextcloud上传文件的大小_努力的老周的博客-程序员ITS301_nextcloud修改最大上传

文档说明根据nextcloud的官方文档,缺省可以上传的最大文件大小为 512M。以下是管理员官方文档的说明,摘自https://docs.nextcloud.com//server/14/admin_manual/configuration_files/big_file_upload_configuration.html:The default maximum file size for...

IDEA如何新建一个source folder_ppppppg的博客-程序员ITS301_idea创建folder

在eclipse中可以很快新建完成,然而在IDEA中找了很久。首先需要在新建一个普通的Direction,新建完成后点击左上角File,找到Project Structure,然后,选择Modules,找到刚刚创建的普通direction,右击选择source即可。...

自定义控件之——标题栏_LXLYHM的博客-程序员ITS301_自定义组件标题栏

一贯作风,先看效果图,再实现编写自定义属性文件atts.xml,自定义属性中涉及到的属性有左右两边的button的背景图,中间标题的内容,字体大小,字体颜色。[java] view plain copy"1.0" encoding="utf-8"?>        "TopBar">          "lef

电子设计比赛的STM32知识准备_aec153的博客-程序员ITS301_电子设计大赛需要用到stm32hz吗

电子设计比赛的STM32知识准备欢迎使用观看我的新手教程第一天(2021年7月13日)功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入欢迎使用观看我的新手教程这是我第一次参加电子设计比赛(国赛),选择的是高频类,也是第一次接触S

选择语句详解(C++)_黑马星云的博客-程序员ITS301_c++选择语句

目录if条件选择语句关系运算逻辑运算switch选择语句if条件选择语句 “老师,我这次考试通过了没有?” 如果老师被问到这个问题,他会如何回答?是的,他会根据不同的条件选择不同的回答: 如果考试成绩大于等于60,那就回答:“恭喜你,你通过了这次考试”;否则那就回答“很遗憾,你没有通过这次考试”。 这就是现实世界中的条件选择——根据不同的条件做出不同的动作。那么,在C++程序中,我们又该如何表达这种条件选择呢?if语句:如果……...

随便推点

计算机图像处理的未来发展,探讨计算机图像处理技术的发展趋势与展望_sea88sea的博客-程序员ITS301

摘 要:随着我国科学技术的飞速发展,计算机已经在多个行业和领域实现应用和普及,对促进我国社会以及经济发展起到关键的推动作用。计算机图像处理技术与我国社会发展具有直接关系,因此,一定要注重此方面的研究和探讨,把握时代的脉搏,找准未来的发展方向。该文主要针对计算机图像处理技术的发展趋势与展望进行分析和探讨,希望为相关行业提供参考和借鉴。关键词:计算机图像处理技术 发展趋势 未来展望 探讨谏缁峄疃?人类...

win7搭建mysql php5.2_win7下搭建WAMP图解(PHP运行环境:win7+Apache2.2+php5.2.8+MySQL5.5)附安装包..._Max Snow的博客-程序员ITS301

Apache版本:httpd-2.2.25-win32-x86-openssl-0.9.8y(openssl表示有openssl模块, 可给Apache配置SSL安全链接)php版本:php-5.2.8-Win32(亲自试过很多个版本, 只有这个版本的安装包比较全. 最新版的很多都缺少libmysql.dll包)MySQL版本:mysql-5.5.28-win32,下载需注册账号第一步:关于Apa...

activiti7关联mysql_解决Springboot2.1.x配置Activiti7单独数据源问题_李国凤的博客-程序员ITS301

1|1简介最近基于最新的Activiti7配置了SpringBoot2。简单上手使用了一番。发现市面上解决Activiti7的教程很少,采坑也比较多,在Activiti6配置数据源和Activiti7有所区别,基于Activiti6在Activiti7里是无法正常使用的。接下来让我们看下区别。1|2问题Activiti6多数据源配置6的配置比较简单点。先加入配置:# activiti 数据源spr...

Windows“未安装任何音频输出设备“,扬声器红叉不可用_dajidaxian的博客-程序员ITS301_笔记本未安装音频设备红叉

确认硬件没有问题双系统debian能够正常使用,就windows时扬声器符号有一个红叉,排除硬件故障;亦没动过BIOS排除网上说的BIOS设置问题;网上也有提到注册表,服务未启动等原因,请自行检查。也用命令行检查过系统完整性,嫌麻烦用U盘保留应用与数据重装过,都未解决。。。哎可能对您有用的解决方法一句话:“Windows Audio”服务登录账户身份是否设置为“本地系统账户”。您们可能跟我情况不尽相同,不行可以试试走走流程????走流程:通过windows设置“更新和安全”-“疑难解答”-“其

Oracle 日常基本命令_珹先生的博客-程序员ITS301

文章目录Oracle 日常基本命令用户与权限创建用户给用户修改密码修改自己的密码删除用户给用户赋权限收回用户权限系统权限:是数据库管理相关的权限:connnect 角色:resource 角色:dba 角色:表空间创建表空间必须使用 system 用户创建创建用户指定默认表空间修改用户默认表空间:查看表空间:查看用户默认表空间:表结构的操作创建表:修改表添加列修改列删除列修改表的名称修改列名查看表结构约束非空(NOT NULL)添加非空删除非空唯一(UNIQUE)添加修改唯一删除唯一主键(PRIMARY K

推荐文章

热门文章

相关标签