以下笔记1.吾爱NLP(5)—词向量技术-从word2vec到ELMo - 简书 (jianshu.com)
2.根据李宏毅老师2019最新的机器学习视频整理
视频地址:
https://www.bilibili.com/video/av46561029/?p=61
ppt下载地址:
http://speech.ee.ntu.edu.tw/~tlkagk/courses_ML19.html
3.ELMO、BERT、GPT视频笔记整理_腾讯新闻 (qq.com)https://new.qq.com/omn/20191117/20191117A06W0F00.html
"词、句子甚至是文章的嵌入已成为所有基于深度学习的自然语言处理(NLP)系统的重要组成部分,它们在固定长度的稠密向量中编码单词和句子,以大幅度提高神经网络处理文本数据的能力。
词是表义的一种基本单元。顾名思义,词向量是用来表示词的向量,也可被认为是词的特征向量。
词向量的获取方式可以大体分为两类:
- 一类是基于统计方法(例如:基于共现矩阵、SVD)
- 另一种是基于语言模型的
一、基于统计学方法
1. 基于共现矩阵的方式
通过统计一个事先指定大小的窗口内的word共现次数,以word周边的共现词的次数做为当前word的vector。具体来说,我们通过从大量的语料文本中构建一个共现矩阵来定义word representation。
例如,有语料如下:
I like deep learning.
I like NLP.
I enjoy flying.
则其共现矩阵X如下:
矩阵定义的词向量在一定程度上缓解了one-hot向量相似度为0的问题,但没有解决数据稀疏性和维度灾难的问题。
最早的技术是1-of-N encoding,把每一个词汇表示成一个向量,每一个向量都只有一个地方为1,其他地方为0。但是这么做词汇之间的关联没有考虑,因为不同词之间的距离都是一样的。
所以,接下来有了word class的概念,举例说dog、cat和bird都是动物,它们应该是同类。但是动物之间也是有区别的,如dog和cat是哺乳类动物,和鸟类还是有些区别的。
后来有了更进阶的想法,称作word embedding,我们用一个向量来表示一个单词,相近的词汇距离较近,如cat和dog。那word embedding怎么训练呢?比较熟知的就是word2vec方法。
2. SVD(奇异值分解)
既然基于co-occurrence矩阵得到的离散词向量存在着高维和稀疏性的问 题,一个自然而然的解决思路是对原始词向量进行降维,从而得到一个稠密的连续词向量。
首先,统计一个词语的共生矩阵X。X是一个|V|×|V| 大小的矩阵,Xij表示在所有语料中,词汇表V
中第i个词和第j个词同时出现的词数,|V|为词汇表的大小。对X做矩阵分解(如奇异值分解,Singular Value Decomposition [参考资料])得到矩阵正交矩阵U,对U进行归一化得到矩阵,即视为所有词的词向量:
SVD
SVD得到了word的稠密(dense)矩阵,该矩阵具有很多良好的性质:语义相近的词在向量空间相近,甚至可以一定程度反映word间的线性关系。
但这样的传统做法有很多问题:
- 由于很多词没有出现,导致矩阵极其稀疏,因此需要对词频做额外处理来达到好的矩阵分解效果;
- 矩阵非常大,维度太高
- 需要手动去掉停用词(如although, a,...),不然这些频繁出现的词也会影响矩阵分解的效果。
语言模型
在介绍词向量模型之前,先简单的介绍一个概念:语言模型。 语言模型旨在为语句的联合概率函数P(w1,...,wT)建模, 其中wi表示句子中的第i个词。语言模型的目标是,希望模型对有意义的句子赋予大概率,对没意义的句子赋予小概率。 这样的模型可以应用于很多领域,如机器翻译、语音识别、信息检索、词性标注、手写识别等,它们都希望能得到一个连续序列的概率。 以信息检索为例,当你在搜索“how long is a football bame”时(bame是一个医学名词),搜索引擎会提示你是否希望搜索"how long is a football game", 这是因为根据语言模型计算出“how long is a football bame”的概率很低,而与bame近似的,可能引起错误的词中,game会使该句生成的概率最大。
对语言模型的目标概率P(w1,...,wT),如果假设文本中每个词都是相互独立的,则整句话的联合概率可以表示为其中所有词语条件概率的乘积,即:
然而我们知道语句中的每个词出现的概率都与其前面的词紧密相关, 所以实际上通常用条件概率表示语言模型:
1. Word2Vec
2013年,Google团队发表了word2vec工具 [1]。word2vec工具主要包含两个模型:跳字模型(skip-gram)和连续词袋模型(continuous bag of words,简称CBOW),以及两种近似训练法:负采样(negative sampling)和层序softmax(hierarchical softmax)。值得一提的是,word2vec的词向量可以较好地表达不同词之间的相似和类比关系。
word2vec自提出后被广泛应用在自然语言处理任务中。它的模型和训练方法也启发了很多后续的词嵌入模型。本节将重点介绍word2vec的模型和训练方法。
在跳字模型中,我们用一个词来预测它在文本序列周围的词。
举个例子,假设文本序列是:
“I love you very much”
跳字模型所关心的是,给定“you”生成邻近词“I”、“love”、“very”和“much”的条件概率。
在这个例子中,“you”叫中心词,“I”、“love”、“very”和“much”叫背景词。
由于“you”只生成与它距离不超过2的背景词,该时间窗口的大小为2[与N-gram类似]。
我们来描述一下跳字模型[用最大似然估计的思想]:
假设词典索引集V的大小为|V|,且{0,1,…,|V|−1}。给定一个长度为T的文本序列中,文本序列中第t的词为w(t)。当时间窗口大小为m时,跳字模型需要最大化给定任一中心词生成所有背景词的概率:
上式的最大似然估计与最小化以下损失函数等价:
我们可以用v和u分别表示 中心词 和 背景词 的向量。
换言之,对于词典中索引为i的词,它在作为中心词和背景词时的向量表示分别是vi和ui。而词典中所有词的这两种向量正是跳字模型所要学习的模型参数。为了将模型参数植入损失函数,我们需要使用模型参数表达损失函数中的给定中心词生成背景词的条件概率。给定中心词,假设生成各个背景词是相互独立的。设中心词wc在词典中索引为c,背景词wo在词典中索引为o,损失函数中的给定中心词生成背景词的条件概率可以通过softmax函数定义为:
上式:给定任何一个中心词Wc,产生背景词Wo的概率
每一个词,在模型中有两个词向量,一个是作为中心词时的词向量,一个是作为背景词时的词向量
利用随机梯度下降求解:
当序列长度T较大时,我们通常在每次迭代时随机采样一个较短的子序列来计算有关该子序列的损失。然后,根据该损失计算词向量的梯度并迭代词向量。具体算法可以参考“梯度下降和随机梯度下降——从零开始”一节。 作为一个具体的例子,下面我们看看如何计算随机采样的子序列的损失有关中心词向量的梯度。和上面提到的长度为T的文本序列的损失函数类似,随机采样的子序列的损失实际上是对子序列中给定中心词生成背景词的条件概率的对数求平均。通过微分,我们可以得到上式中条件概率的对数有关中心词向量vc的梯度:
该式也可改写作:
上面的迭代更新计算开销太大!!每次都需要遍历整个字典,对应的解决方案在后面(这也是word2vec为啥这么牛逼的原因...厉害的不是这个工具本身,而是一种思想的应用)
随机采样的子序列有关其他词向量的梯度同理可得。训练模型时,每一次迭代实际上是用这些梯度来迭代子序列中出现过的中心词和背景词的向量。训练结束后,对于词典中的任一索引为i的词,我们均得到该词作为中心词和背景词的两组词向量vi和ui。在自然语言处理应用中,我们会使用跳字模型的中心词向量。
连续词袋模型与跳字模型类似,与跳字模型最大的不同是:
连续词袋模型用一个中心词在文本序列周围的词来预测该中心词。
举个例子,假设文本序列为:
“I love you very much”
连续词袋模型所关心的是,邻近词“I”、“love”、“very”和“much”一起生成中心词“you”的概率。
假设词典索引集的大小为V,且V={0,1,…,|V|−1}</nobr>。给定一个长度为T的文本序列中,文本序列中第t个词为wu(t)。当时间窗口大小为m时,连续词袋模型需要最大化由背景词生成任一中心词的概率
上式的最大似然估计与最小化以下损失函数等价:
我们可以用v和u分别表示背景词和中心词的向量(注意符号和跳字模型中的不同)。换言之,对于词典中索引为i的词,它在作为背景词和中心词时的向量表示分别是vi和ui。而词典中所有词的这两种向量正是连续词袋模型所要学习的模型参数。为了将模型参数植入损失函数,我们需要使用模型参数表达损失函数中的给定背景词生成中心词的概率。设中心词wc在词典中索引为c,背景词wo1、wo2、...wo2m在词典中索引为o1、o2、....o2m-1、o2m,损失函数中的给定背景词生成中心词的概率可以通过softmax函数定义为
和跳字模型一样,当序列长度T较大时,我们通常在每次迭代时随机采样一个较短的子序列来计算有关该子序列的损失。然后,根据该损失计算词向量的梯度并迭代词向量。 通过微分,我们可以计算出上式中条件概率的对数有关任一背景词向量voi(i=1,2,....2m)的梯度为:
该式也可写作
随机采样的子序列有关其他词向量的梯度同理可得。和跳字模型一样,训练结束后,对于词典中的任一索引为i的词,我们均得到该词作为背景词和中心词的两组词向量vi和ui。
在自然语言处理应用中,我们会使用连续词袋模型的背景词向量。
近似训练法
我们可以看到,无论是skip-gram(跳字模型)还是CBOW(连续词袋模型),每一步梯度计算的开销与词典V的大小相关。
因为计算softmax的时考虑了字典上的所有可能性
当词典较大时,例如几十万到上百万,这种训练方法的计算开销会较大。因此,我们将使用近似的方法来计算这些梯度,从而减小计算开销。常用的近似训练法包括负采样和层序softmax。
(1)负采样(Negative Sample)
我们以跳字模型为例讨论负采样。
实际上,词典V的大小之所以会在损失中出现,是因为给定中心词wc生成背景词wo的条件概率P(w0∣wc)
使用了softmax运算,而softmax运算正是考虑了背景词可能是词典中的任一词(使用了全部词),并体现在分母上。
下面,我们可以使用σ(x)=1/(1+exp(−x))函数来表达中心词wc和背景词wo同时出现在该训练数据窗口的概率。
σ(x)属于[0,1]
那么,给定中心词wc生成背景词wo的条件概率的对数可以近似为:
[上式的含义:中心词wc与背景词wo同时出(D=1)现概率,且中心词wc与噪音词wk不同时出现(D=0)的概率。]
假设噪声词wk在词典中的索引为ik,上式可改写为:
因此,有关给定中心词wc生成背景词wo的损失是
假设词典V很大,每次迭代的计算开销由O(|V|)变为O(|K|)。当我们把K取较小值时,负采样每次迭代的计算开销将较小。
当然,我们也可以对连续词袋模型进行负采样。有关给定背景词
wt-m、wt-m+1、...、wt+m生成中心词wc的损失:
在负采样中可以近似为:
同样,当我们把K取较小值时,负采样每次迭代的计算开销将较小。
(2)层序softmax[]
层序softmax是另一种常用的近似训练法。它利用了二叉树这一数据结构。树的每个叶子节点代表着词典V中的每个词。
假设L(w)为从二叉树的根节点到词w<的叶子节点的路径(包括根和叶子节点)上的节点数。设n(w,j)为该路径上第j个节点,并设该节点的向量为un(w,j)。以上图为例:L(w3)=4。设词典中的词wi的词向量为vi。那么,跳字模型和连续词袋模型所需要计算的给定词wi生成词w的条件概率为:
其中σ(x)=1/(1+exp(−x)),leftChild(n)是节点n的左孩子节点,如果判断x为真,[x]=1;反之[x]=−1。由于σ(x)+σ(−x)=1,给定词wi生成词典V中任一词的条件概率之和为1这一条件也将满足:
让我们计算给定词wi生成词w3的条件概率。我们需要将wi的词向量vi和根节点到w3路径上的非叶子节点向量一一求内积。由于在二叉树中由根节点到叶子节点w3的路径上需要向左、向右、再向左地遍历,我们得到:
整个遍历的路径已经通过Huffman编码唯一的确定了
在使用softmax的跳字模型和连续词袋模型中,词向量和二叉树中非叶子节点向量是需要学习的模型参数。
假设词典V很大,每次迭代的计算开销由O(|V|)下降至O(log2|V|)。
推荐资料:学习word2vec的经典资料
Tutorial-for-Word2vec | Study in IRLAB
2.ELMO
1)产生ELMO的动机
但是呢,同一个词是可能有不同的意思的,如下图中的bank,前两个指银行,后两个指河堤:
尽管有不同的意思,但使用传统的word embedding的方法,相同的单词都会对应同样的embedding。但我们希望针对不同意思的bank,可以给出不同的embedding表示。
根据上下文语境的不同,同一个单词bank我们希望能够得到不同的embedding,如果bank的意思是银行,我们期望它们之间的embedding能够相近,同时能够与河堤意思的bank相距较远。
基于这个思想,首先有了ELMO。
2)ELMO是什么
ELMO是Embeddings from Language Model的简称,ELMO是《芝麻街》中的一个角色。它是一个RNN-based的语言模型,其任务是学习句子中的下一个单词或者前一个单词是什么。
它是一个双向的RNN网络,这样每一个单词都对应两个hidden state,进行拼接便可以得到单词的Embedding表示。当同一个单词上下文不一样,得到的embedding就不同。
当然,我们也可以搞更多层:
这么多层的RNN,内部每一层输出都是单词的一个表示,那我们取哪一层的输出来代表单词的embedding呢?ELMO的做法就是我全都要:
在ELMO中,一个单词会得到多个embedding,对不同的embedding进行加权求和,可以得到最后的embedding用于下游任务。要说明一个这里的embedding个数,下图中只画了两层RNN输出的hidden state,其实输入到RNN的原始embedding也是需要的,所以你会看到说右下角的图片中,包含了三个embedding。
但不同的权重是基于下游任务学习出来的,上图中右下角给了5个不同的任务,其得到的embedding权重各不相同。
3.ELMO的论文
来自《Deep Contextualized Word Representations》(NAACL2018的best paper), 可以很方便用于下游NLP任务中。
ELMo使用双层BiLSTM来训练语言模型,创新是线性组合不同层的word vectors, 作为最终的word representation. 核心公式:
- 第一层是普通的word embedding 可以用wrod2vec或者glove来得到,或者使用character level得到token embedding》 这部分是general embedding,上下文无关。文中使用的character level的CNN+Highway.
- 后面连接两个biLSTM 去encode 输入(同时也有残差连接), 每一层LSTM得到的输出(隐状态) 作为每个词的上下文相关的word vectors.
- 这样每个词就会有(L+1)个词向量,L为biLSTM的层数.
- 词向量的线性组合,针对不同的任务,不同层的向量做不同的权重加和。 其中权重s是一个维度为L的vector,参与训练。
预训练的双向语言模型架构
论文的作者有预训练好的ELMo模型,映射层(单词到word embedding)使用的Jozefowicz的CNN-BIG-LSTM[5],即输入为512维的列向量。同时LSTM的层数L,最终使用的是2,即L=2。每层的LSTM的单元数是4096。每个LSTM的输出也是512维列向量。每层LSTM(含前、向后向两个)的单元个数是4096个(从1.1节可以知公式4m*2 = 4*512*2 = 4096)。也就是每层的单个lstm的输入是512维,输出也是512维。
一旦模型预训练完成,便可以用于nlp其他任务。在一些领域,可以对biLM(双向lstm语言模型)进行微调,对任务的表现会有所提高,这种可以认为是一种迁移学习(transfer learning)。
ELMo学到了什么
(1).一词多义
(2).词义消歧
ELMO 有什么值得改进的缺点呢?首先,一个非常明显的缺点在特征抽取器选择方面,ELMO 使用了 LSTM 而不是新贵 Transformer,Transformer 是谷歌在 17 年做机器翻译任务的“Attention is all you need”的论文中提出的,引起了相当大的反响,很多研究已经证明了 Transformer 提取特征的能力是要远强于 LSTM 的。如果 ELMO 采取 Transformer 作为特征提取器,那么估计 Bert 的反响远不如现在的这种火爆场面。另外一点,ELMO 采取双向拼接这种融合特征的能力可能比 Bert 一体化的融合特征方式弱,但是,这只是一种从道理推断产生的怀疑,目前并没有具体实验说明这一点。
4.ELMo简单上手
三种方法可以使用预训练好的elmo模型。
- elmo官方allenNLP发布的基于pytorch实现的版本[7];
- elmo官方发布的基于tensorflow实现的版本[8];
- tensorflow-hub中google基于tensorflow实现的elmo的版本[9]
本节内容介绍第三个版本。
tensorflow-hub,hub类似于github的hub,tensorflow-hub的目标就是讲机器学习的算法,包含数据、训练结果、参数等都保存下来,类似于github一样,拿来就可以直接用。所有人都可以在这里提交自己的模型及数据、参数等。这里实现的elmo是google官方实现并预训练好的模型。有人基于此模型+keras写的博客及代码教程大家可以参考下[10][11],此代码使用的google的elmo的第一个版本,目前最新的是第二个版本。
3. Bert
Bert是Bidirectional Encoder Representations from Transformers的缩写,它也是芝麻街的人物之一。Transformer中的Encoder就是Bert预训练的架构。李宏毅老师特别提示:如果是中文的话,可以把字作为单位,而不是词。
只是Transformer中的Encoder,那Bert怎么训练呢?文献中给出了两种训练的方法,第一个称为Masked LM,做法是随机把一些单词变为Mask,让模型去猜测盖住的地方是什么单词。假设输入里面的第二个词汇是被盖住的,把其对应的embedding输入到一个多分类模型中,来预测被盖住的单词。
另一种方法是预测下一个句子,这里,先把两句话连起来,中间加一个[SEP]作为两个句子的分隔符。而在两个句子的开头,放一个[CLS]标识符,将其得到的embedding输入到二分类的模型,输出两个句子是不是接在一起的。
实际中,同时使用两种方法往往得到的结果最好。
在ELMO中,训练好的embedding是不会参与下游训练的,下游任务会训练不同embedding对应的权重,但在Bert中,Bert是和下游任务一起训练的:
如果是分类任务,在句子前面加一个标志,将其经过Bert得到的embedding输出到二分类模型中,得到分类结果。二分类模型从头开始学,而Bert在预训练的基础上进行微调(fine-tuning)。
文中还有很多其他的应用,如单词分类:
如自然语言推理任务,给定一个前提/假设,得到推论是否正确:
最后一个例子是抽取式QA,抽取式的意思是输入一个原文和问题,输出两个整数start和end,代表答案在原文中的起始位置和结束位置,两个位置中间的结果就是答案。
具体怎么解决刚才的QA问题呢?把问题 - 分隔符 - 原文输入到BERT中,每一个单词输出一个黄颜色的embedding,这里还需要学习两个(一个橙色一个蓝色)的向量,这两个向量分别与原文中每个单词对应的embedding进行点乘,经过softmax之后得到输出最高的位置。正常情况下start end的话,说明是矛盾的case,此题无解。
Bert一出来就开始在各项比赛中崭露头角:
这里李宏毅老师还举例了百度提出的ERNIE,ERNIE也是芝麻街的人物,而且还是Bert的好朋友,这里没有细讲,感兴趣的话大家可以看下原文。
Bert学到了什么呢?可以看下下面两个文献(给大伙贴出来:https://arxiv.org/abs/1905.05950 和https://openreview.net/pdf?id=SJzSgnRcKX):