理解 Word Embedding,全面拥抱 ELMO

原文链接:https://www.infoq.cn/article/B8-BMA1BUfuh5MxQ687T

理解 Word Embedding,全面拥抱 ELMO

  • DataFun社区

阅读数:4238 2019 年 6 月 15 日

提到 Word Embedding ,如果你的脑海里面冒出来的是 Word2Vec ,Glove ,Fasttext 等。那我猜你有 80% 的概率是从事和 NLP 相关的工作或者至少是一个算法爱好者 ( 这貌似是一个真命题,哈哈 ) 。其实简单来说 Word Embedding 就是把词转换成向量的形式。计算机只识别二进制,智能问答系统,我们需要计算机理解的是文字。此时我们就需要将文字转换成数字,向量的形式。最简单的一种方式就是 one-hot 表示。这种方法没有语义的理解。把词汇表中的词排成一列,对于某个单词 A ,如果它出现在上述词汇序列中的位置为 k ,那么它的向量表示就是 ” 第 k 位为 1,其他位置都为 0 ” 的一个向量。这种表示表示学不到单词之间的关系 ( 任意两个单词向量的内积都为 0 ) ,并且如果词汇表很大,词向量会很长,带来维度上的灾难。无论是 Word2Vec 还是 Glove 和 Fasttext ,都完美的解决了上述两个问题,在训练的过程中,为每一个词生成一个向量,Word2Vec 训练的目的就是为了产生词向量,而 Fasttext 算法主要是为了做文本分类,词向量只是其副产物,中间会产生词向量。

这种方法在语义理解上效果比较好,可以将语义相似的词用相似的向量表示 ( 向量夹角小 ) ,但是有个缺点,训练好之后每个单词的表达就固定住了,以后使用的时候,不论新句子上下文单词是什么,这个单词的 Word Embedding 不会跟着上下文场景的变化而改变,如:“ 我喜欢吃苹果 ”,“ 很多人觉得苹果手机很好用 ” 。这两个句子中的苹果是不同的语义,表示不同的对象,没有办法表示出来。

历史总是惊人的相似,resnet 的出现颠覆了 cv 领域,刷爆了各大比赛的排行榜。Bert 登上历史的舞台,基本刷新了很多 NLP 任务的最好性能,有些任务还被刷爆了。牛顿曾经说过:如果说我看得比别人更远些,那是因为我站在巨人的肩膀上。同样,Bert 算法是站在 elmo ,GPT 等一系列算法的基础上。Bert 是近年来 NLP 重大进展的集大成者。之后我会逐步把这些都总结下来做成一个系列,第一篇我们先介绍语言模型预训练的鼻祖 ELMO ,ELMO 是 “ Embedding from Language Models ” 的简称,但论文题目是 “ Deep contextualized word representations ” ,这里面有两个关键词,一个是 deep ,一个是 context 。这两个词诠释了 ELMO 模型的精髓,利用深度网络学习单词的上下文。模型的本质和代码我会在下面的篇幅中逐步展开。

1. 理解 Word Embedding

我相信你或多或少都听过 FM 算法,目前推荐领域各种算法都可以看到 FM 的影子,FM 使得推荐领域达到了一个新的巅峰。无论是原始 FM 算法还是他的变形,FFM ,wide & deep ,DCN ,DeepFM ,会为每一个特征学习一个 latent vector 。这种特征 embedding 模式应该是 Word Embedding 方法的老前辈,这也充分体现了 Word Embedding 的重要性。

1.1 图像预训练

你可能会对这个题目比较好奇,我们要讲的是 Word Embedding ,这个是不是有点跑题了。之所以有这个章节,因为或许你会经常听到搞图像的人说,“ 我今天 Fine Tuning 了一个 base model ,我用 ImageNet 上训练的模型作为冷启动 ” 等一系列相关的内容。所以,我想花一点篇幅来解释一下图像领域的预训练。

下图对网络的训练进行了可视化,由图中可以看出:

第一个隐藏层主要提取图像的纹理,线条等特征,第二个隐藏藏提取人脸五官轮廓,第三个隐藏层提取了人脸的轮廓。Deep learning 底层的网络主要提取的是图像的基础特征,随着网络深度的加深,才会提取到更多的语义信息。换句话说就是高层特征和具体的任务相关。无论是图像分类还是图像检测,我们都需要图像的基础特征。因此我们当然可以使用在 ImageNet 上训练网络提取基础特征。ImageNet 数据集大,种类多,对于网络提取到的基础特征泛化能力强。这样总比我们随机初始化网络,在我们自己的数据上从头开始训练强。采用 ImageNet 上预训练的网络,有两种做法,一种是加载浅层网络的特征,在自己的任务上训练时,保持不变,前面的网络就像 “ 冻住 ” 了,反向传播时,不进行梯度更新,称之为 “ Frozen ” 。另外一种方式是浅层网络也随机训练变化,不过学习率相对于后面深层网络,会比较小,这个称之为 “ Fine Tuning ” 。

现在主流的 backbone 网络如 resnet ,inception ,FPN 等网络参数动不动就是上千万甚至上亿。在自己的数据集上从头开始训练网络,往往都是欠拟合,此时会借助预训练的方式。如果训练数据少,更适合用 “ Frozen ” 的方式,网络集中精力调整深层的网络。当训练数据集比较大的时候,可以使用 Fine-Tuning 的方式。

1.2 Word Embedding 预处理

言归正传,Word Embedding 计算词向量只是很小的一个功能,Word Embedding 更多的用处是用在预处理中。你可能会感觉到迷惑,Word Embedding 怎么作为预训练?就如我们前面介绍的,计算机识别的是数字。Word Embedding 只是将 character 转换成向量的过程,为具体的下游任务提供服务。如下图的智能问答系统,我们将每一个问题转换成词向量的形式,输送到网络里面进行训练。

和上面介绍的图像预训练一样,我们在具体训练中,既可以冻结词向量,也可以进行微调,我们可以把 embedding 看成网络的一部分。当然我们也可以随机初始化右边的 embedding 矩阵,训练的过程中,利用反向传播更新 embedding 矩阵。

现实任务中,我们同样面临这两个问题,一是我们的数据集可能有限,二是我们更关心的是需求本身,希望网络更多的关注在业务层面。

从以上两点出发,都可以看出 Word Embedding 作为预训练的重要性和必要性。

2. 理解 ELMO

通过上面,我们知道了 Word Embedding 作为上游任务,为下游具体业务提供服务。因此,得到单词的 Embedding 向量的好坏,会直接影响到后续任务的精度,这也是这个章节的由来。google 2013 年提出开的 word2vec 算是佳作 ( 我个人觉得,google 出品的好多都非常靠谱 ) ,算是开辟了词向量的新天地。缺点是对于每一个单词都有唯一的一个 embedding 表示,而对于多义词显然这种做法不符合直觉,而单词的意思又和上下文相关,ELMO 的做法是我们只预训练 language model ,而 word embedding 是通过输入的句子实时输出的, 这样单词的意思就是上下文相关的了, 这样就很大程度上缓解了歧义的发生。且 ELMO 输出多个层的 embedding 表示,试验中已经发现每层 LM 输出的信息对于不同的任务效果不同,因此对每个 token 用不同层的 embedding 表示会提升效果。

2.1 理论

ELMO 使用了双向循环神经网,包含了一个正向的和一个反向的 LSTM 。如图:

给定 k 个 token(t1,t2,,tk)token(t1,t2,⋯,tk) 是任务相关的 scale 参数。

Pre-trained 的 language model 是用了两层的 LSTM ,对 token 进行上下文无关的编码是通过 CNN 对字符进行编码, 然后将三层的输出 scale 到 1024 维,最后对每个 token 输出 3 个 1024 维的向量表示。这里之所以将 3 层的输出都作为 token 的 embedding 表示是因为实验已经证实不同层的 LSTM 输出的信息对于不同的任务作用是不同的, 也就是所不同层的输出捕捉到的 token 的信息是不相同的。此时得到 token 的 embedding vector ,就包含了 context 的信息了。

2.2 代码分析

我看的是 TensorFlow 版本代码的实现,代码地址:

https://github.com/allenai/bilm-tf

关于代码如何运行,我就不在此展开了,作者的 readme 里面写的比较清楚。我们关心的是代码的运行流程和一些看论文不是很清楚的地方 ( 如 2.1 里面提到的 CNN 对字符编码等 ) 。整个代码的流程图如下,我会分模块逐步介绍。

2.2.1 加载 vocabulary

在这个模块中,读取 vocab_file 文件,加载到内存中,方便后续的查找。max_word_length 指的是每个单词的最大长度是多少,程序中默认的是 50。

复制代码
# 加载 vocabulary
def load_vocab(vocab_file, max_word_length=None):
if max_word_length:
return UnicodeCharsVocabulary(vocab_file, max_word_length,
validate_file=True)
else:
return Vocabulary(vocab_file, validate_file=True)

在 load_vocab 方法中,创建 UnicodeCharsVocabulary 对象并返回。在构造函数中,读取 vocab_file 文件,设置两个很重要的变量 _id_to_word 和 _word_to_id ,将索引转换成单词和单词转换成索引,前一个是数组,后一个是词典。并且将每一个单词的字符转换成对应的 ASCII 码值,每个单词对应了一个向量。将转换后的结果存放到了 _convert_word_to_char_ids 变量中,形状是 ( num_words,max_word_length ) 。还提供了一系列的方法,比如单词与索引的转换,对字符的编码等。

2.2.2 构造数据集生成器

在构造函数中,首先创建了 LMDataset 对象,一个用正向网络一个用于反向的网络。最主要的工作是将单词转换成对应的索引存到 ids 中,以及每个单词转换成 ASCII 码对应的向量存到 chars_ids 中。ids 是二维向量,chars_ids 是三维向量。有了这些,就可以构造 data generator 了。下面列出了最重要的一个方法,每次获取一个 batch 的数据。

复制代码
def _get_batch(generator, batch_size, num_steps, max_word_length):
"""Read batches of input."""
cur_stream = [None] * batch_size
no_more_data = False
while True:
#todo 输入大小
inputs = np.zeros([batch_size, num_steps], np.int32)
if max_word_length is not None:
#todo 每个单词的输入,将单词转化成数字
char_inputs = np.zeros([batch_size, num_steps, max_word_length],
np.int32)
else:
char_inputs = None
targets = np.zeros([batch_size, num_steps], np.int32)
for i in range(batch_size):
cur_pos = 0
while cur_pos < num_steps:
if cur_stream[i] is None or len(cur_stream[i][0]) <= 1:
try:
cur_stream[i] = list(next(generator))
except StopIteration:
# No more data, exhaust current streams and quit
no_more_data = True
break
#todo 这个地方减一是为了构造 target
how_many = min(len(cur_stream[i][0]) - 1, num_steps - cur_pos)
next_pos = cur_pos + how_many
inputs[i, cur_pos:next_pos] = cur_stream[i][0][:how_many]
if max_word_length is not None:
char_inputs[i, cur_pos:next_pos] = cur_stream[i][1][
:how_many]
#todo 构造 target 目标
targets[i, cur_pos:next_pos] = cur_stream[i][0][1:how_many+1]
cur_pos = next_pos
cur_stream[i][0] = cur_stream[i][0][how_many:]
if max_word_length is not None:
cur_stream[i][1] = cur_stream[i][1][how_many:]
if no_more_data:
# There is no more data. Note: this will not return data
# for the incomplete batch
break
X = {'token_ids': inputs, 'tokens_characters': char_inputs,
'next_token_id': targets}
yield X

num_steps 是序列的长度,也就是我们用于训练 RNN 的时候,考虑了几个时间步长。

2.2.3 构造模型

模型使用了两层的双向循环 LSTM 网络。训练模型的时候有两种方式,一种是为一个单词随机初始化一个 Embedding 向量,还有一种是为每一个单词的每个字母初始化一个随机向量。第一种方式是常见的,我们重点介绍一下第二种,其实理解明白了也就很简单了。tokens_characters 是网络的一个输入,我们在前面小节中已经提到了,我们会把每个字符转换成一个数字。下面展示了一个例子,一个英文单词字母对应的 utf-8 编码。

因此,english 对应的向量就是 [ 101 , 110 , 103 , 108 , 105 , 115 , 104 ] ,当然这个还不是完整的向量,还有开始和结束的特殊字符,以及为了保持向量长度一样的填充字符等。此时,你应该稍微明白一点了吧。embedding_weights 是字符的权重向量,这个是需要随机初始化的,因为我们的目的就是为每一个字符学习到一个 Embedding 向量。现在捋一下,输入到网络中的 tokens_characters 会利用 embedding_lookup 方法,查询到每一个字符对应的 Embedding 向量,结果形状的大小为 ( batch_size, unroll_steps, max_chars, embed_dim ) ,此时你想到了什么。哇塞,一个四维的向量,这不就是标准的图像形状的大小吗?当然第一反应就是利用 CNN 操作。我们在后三个维度上做卷积操作,unroll_steps 看做图像的高度,max_chars 看做宽度,embed_dim 是通道。卷积核的高度去固定值 1,这样可以保证我们的卷积是在同一个单词上进行操作的。最后使用 pooling 操作,确保一个单词得到一个唯一的向量,引用一张网友画的比较形象的图:

复制代码
#todo # 字符的输入
self.tokens_characters = tf.placeholder(DTYPE_INT,
shape=(batch_size, unroll_steps, max_chars),
name='tokens_characters')
# the character embeddings
with tf.device("/cpu:0"):
#todo 字符的 embedding 矩阵
self.embedding_weights = tf.get_variable(
"char_embed", [n_chars, char_embed_dim],
dtype=DTYPE,
initializer=tf.random_uniform_initializer(-1.0, 1.0)
)
# shape (batch_size, unroll_steps, max_chars, embed_dim)
# todo 构造输入数据
self.char_embedding = tf.nn.embedding_lookup(self.embedding_weights,
self.tokens_characters)

2.2.4 其它

模型构造好后,会计算损失,保存一些中间值,供下游任务使用。关于代码的一些细节,可以参考我写有注释版的代码。

https://github.com/horizonheart/ELMO

作者介绍

王腾龙,滴滴算法工程师,中科院硕士,主要研究方向为机器学习与 Deepctr 。

本文来自 DataFun 社区

原文链接

https://mp.weixin.qq.com/s/zfoQd-IOpTU-qCEuRHTU_A

AI深度学习NLP

收藏

评论

微博

发表评论

注册/登录 InfoQ 发表评论

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/480331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

肝了1W字!文本生成评价指标的进化与推翻

一只小狐狸带你解锁 炼丹术&NLP 秘籍作者&#xff1a;林镇坤&#xff08;中山大学研一&#xff0c;对文本生成和猫感兴趣&#xff09;前言文本生成目前的一大瓶颈是如何客观&#xff0c;准确的评价机器生成文本的质量。一个好的评价指标&#xff08;或者设置合理的损失函数…

美团大脑 | 知识图谱的建模方法及其应用

本文转载自公众号: 美团技术团队.作为人工智能时代最重要的知识表示方式之一&#xff0c;知识图谱能够打破不同场景下的数据隔离&#xff0c;为搜索、推荐、问答、解释与决策等应用提供基础支撑。美团大脑围绕吃喝玩乐等多种场景&#xff0c;构建了生活娱乐领域超大规模的知识图…

最全Java面试208题,涵盖大厂必考范围!强烈建议收藏~

这些题目是去百度、小米、乐视、美团、58、猎豹、360、新浪、搜狐等一线互联网公司面试被问到的题目,熟悉本文中列出的知识点会大大增加通过前两轮技术面试的几率。 一.java基础面试知识点 java中和equals和hashCode的区别 int、char、long各占多少字节数 int与integer的区别…

大规模事理常识知识系统“学迹”的定位、应用与不足

我们于3月16正式对外发布了一个面向事理的实时学习和搜索系统Demo&#xff0c;取名叫“学迹”&#xff0c;取自“学事理&#xff0c;知行迹”(https://xueji.zhiwenben.com)。“学迹”的发布&#xff0c;进一步拓宽了现有知识库的门类&#xff0c;为进一步获取特定事件的概念解…

数据结构--散列表 Hash Table

文章目录1.线性探测 哈希表代码2.拉链法 哈希表代码1. 散列表用的是数组支持按照下标随机访问数据的特性&#xff0c;所以散列表其实就是数组的一种扩展&#xff0c;由数组演化而来。可以说&#xff0c;如果没有数组&#xff0c;就没有散列表。 2. 散列函数&#xff0c;设计的基…

论文浅尝 | 面向自动分类归纳的端到端强化学习

动机术语层次在许多自然语言处理任务中扮演着重要角色。然而&#xff0c;大部分现有的术语层次是人工构建的&#xff0c;其覆盖范围有限&#xff0c;或者某些领域上不可用。因此&#xff0c;最近的工作集中在自动化的术语层次归纳(automatictaxonomy induction)上。之前的研究工…

最新天猫Java面试题(含总结):线程池+并发编程+分布式设计+中间件

一面&#xff1a; HashMap实现原理&#xff0c;ConcurrentHashMap实现原理 红黑树&#xff0c;为什么允许局部不平衡 TCP&#xff0c;UDP区别&#xff0c;为什么可靠和不可靠 一次HTTP请求的全过程&#xff0c;包括域名解析、定位主机等 TCP三次握手 MySQL事务是什么&…

重磅!吴恩达家的NLP课程发布啦!

关注小夕并星标&#xff0c;解锁自然语言处理搜索、推荐与算法岗求职秘籍文 | 灵魂写手rumor酱美 | 人美心细小谨思密达斯坦福计算机系副教授、人工智能实验室主任、Coursera平台联合创始人、前百度首席科学家、机器学习入门必备网课CS229的主讲人——吴恩达Andrew Ng老师再放大…

情报领域因果推理智能项目概览:以DAPAR为例

美国国防高级研究计划局&#xff08;Defense Advanced Research Projects Agency&#xff09;&#xff0c;简称DARPA&#xff0c;提出了旨在从推进人工智能常识推理能力发展、深化机器学习理论研究和推进国防部复杂问题中应用人工智能、深化美军对人工智能的研究和应用的“的下…

论文浅尝 | 基于模式的时间表达式识别

本文转载自公众号:南大Websoft. 时间表达式识别是自然语言理解中一个重要而基础的任务。在以前的研究工作中&#xff0c;研究人员已经发现时间词的类型信息可以给识别提供明显的帮助。本文中我们以词类型序列作为表达式模式&#xff0c;提出了基于模式的时间表达式识别方法&…

大数据项目(四)————用户画像

原文地址&#xff1a;https://blog.csdn.net/Jorocco/article/details/81428996 1、用户画像概述 用来勾画用户&#xff08;用户背景、特征、性格标签、行为场景等&#xff09;和联系用户需求与产品设计的&#xff0c;旨在通过从海量用户行为数据中炼银挖金&#xff0c;尽可能…

最强阿里面试126题:数据结构+并发编程+Redis+设计模式+微服务

BAT技术面试范围 数据结构与算法&#xff1a;最常见的各种排序&#xff0c;最好能手写 Java高级&#xff1a;JVM内存结构、垃圾回收器、回收算法、GC、并发编程相关&#xff08;多线程、线程池等&#xff09;、NIO/BIO、各种集合类的比较优劣势&#xff08;底层数据结构也要…

AdaX:一个比Adam更优秀,带”长期记忆“的优化器

关注小夕并星标&#xff0c;解锁自然语言处理搜索、推荐与算法岗求职秘籍文 | 苏剑林&#xff08;追一科技&#xff0c;人称苏神&#xff09;美 | 人美心细小谨思密达前言这篇文章简单介绍一个叫做AdaX的优化器&#xff0c;来自《AdaX: Adaptive Gradient Descent with Exponen…

金融情报挖掘:面向公开文本的期货事件聚合与传导因素分析

金融情报挖掘是情报领域的一个重要分支&#xff0c;通过对金融领域信息进行提取和分析&#xff0c;发现关联线索&#xff0c;对传导关联进行建模&#xff0c;能够挖掘出市场变动的规律&#xff0c;最终辅助决策。 例如&#xff0c;国内外资本市场&#xff0c;衍生品市场热点不断…

论文浅尝 | 知识图谱的单样本关系学习

链接&#xff1a;http://cn.arxiv.org/pdf/1808.09040动机如今的知识图谱规模很大但是完成度不高&#xff0c;long-tail关系在知识图谱中很常见&#xff0c;之前致力于完善知识图谱的方法对每个关系都需要大量的训练样本&#xff08;三元组&#xff09;&#xff0c;而新加入的关…

POJ 1200 Crazy Search 查找有多少种不同的子串(hash)

文章目录1.采用map解题2.采用hash查找题目链接&#xff1a; http://poj.org/problem?id1200题目大意&#xff1a;给定子串长度&#xff0c;字符中不同字符数量&#xff0c;以及一个字符串&#xff0c;求不同的子串数量。1.采用map解题 把子串插入map&#xff0c;map自动去重&…

金融行业如何用大数据构建精准用户画像?

原文地址&#xff1a;https://www.jianshu.com/p/6e0a0ca5948e 1. 什么是用户画像&#xff1f;2. 用户画像的四阶段用户画像的焦点工作就是为用户打“标签”&#xff0c;而一个标签通常是人为规定的高度精炼的特征标识&#xff0c;如年龄、性别、地域、用户偏好等&#xff0c;最…

最全BAT前端开发面试80题:算法+html+js+css!含答案大赠送!

最全前端开发面试题目&#xff1a;包含算法网络css面试jsh5面试题目&#xff0c;尾部有最全BAT前端面试经典77题和答案&#xff0c;想要的就快来领走吧~&#xff08;领取方式见文末&#xff09; 一、前端算法面试 1、基本排序的方式 冒泡、快排、桶排、堆排序、归并排序、插入…

超一流 | 从XLNet的多流机制看最新预训练模型的研究进展

关注小夕并星标&#xff0c;解锁自然语言处理搜索、推荐与算法岗求职秘籍文 | 老饕&#xff08;某厂研究员&#xff0c;祖传调参&#xff09;美 | 人美心细小谨思密达导读作为 NLP 近两年来的当红炸子鸡&#xff0c;以 ELMo/BERT 为代表的语言预训练技术相信大家已经很熟悉了。…

论文浅尝 | 神经网络与非神经网络简单知识问答方法的强基线分析

来源&#xff1a;NAACL 2018链接&#xff1a;http://aclweb.org/anthology/N18-2047本文关注任务为面向简单问题的知识库问答&#xff08;仅用KB中的一个事实就能回答问题&#xff09;。作者将任务划分为实体检测&#xff0c;实体链接&#xff0c;关系预测与证据整合&#xff0…