CS224N课堂笔记(1) Introduction and Word Vectors
本文章为2019版CS224N中文笔记系列第一篇文章。本节,我们将讲述词的表示方法和词向量的计算。
斯坦福的CS224N(自然语言处理)与CS231N(计算机视觉)可以说是极受欢迎的人工智能课程了。笔者当初是看着2017版的CS224N和hackcs的中文博客入门自然语言处理的。
这几年NLP领域发展迅速,斯坦福也于3月11日放出了其2019冬季班CS224N的课程。秉着自己温习基础知识和便捷入门萌新学习的主旨,笔者决定重新刷一次最新版的CS224N并写一个中文课堂笔记。
建议读者在看完CS224N对应课堂视频后的第二天浏览一下本课堂笔记,以达到温习的作用。
资源
- 2017版的CS224N可见CS224N学习指南。
- 2019版内容刚于3月11日公布,暂时没有中文字幕。英文字幕版可见B站。
- 课堂PPT、配套代码和更多官方资料
关于课程
课程依旧是由Chris Manning老爷子作为颜值担当授课担当。主要聚焦于如何使用深度学习来自然语言处理。
前置知识:
- 微积分、概率论、线性代数基础知识
- 了解机器学习,知道梯度下降法等基本概念
- 了解DNN神经网络
2019最新公开版与2017版有些许改动,改动包括:
- 添加了character model, transformer, multitask learn等新内容。
- 使用pyTorch而非Tensorflow作为编程框架。
1. 词语的表示方法
计算机是以编码(如“UTF-8”编码)的形式存储语言文字的,计算机只会储存、传输代表文字的二进制数据。那如何让计算机理解语言文字呢?
1.1 WordNet(词网)
传统的一种用于自然语言处理的方法是使用词网(WordNet)——人为定义每一个词的各种属性。
如我们定义“好”、“优秀”、“不错”是一组同义词,表示质量好;“好”和“同意”、“赞同”是一组同义词,表示赞成;“好”还和“很”是同义词,表示程度,如“好冷”……
除了同义词,我们还可以定义词的其他属性,如从属关系:“熊猫”属于“熊类”,属于“食肉动物”,属于“哺乳动物”……
然而WordNet的缺点是十分明显的:
- 词之间缺少细微差别:我们将“好”和“优秀”作为同义词,但二者还是有区别的
- 不断会有词产生新的意思,需要不断更新
- WordNet定义过于主观
- 构建WordNet需要大量的人力
- 无法计算词之间的相似程度
1.2 离散符号
用数值的方法来表示每一个词。除了下述的三种方法,还有n_gram,tf-idf等方法。
方法一:
我们构建一个词典,假设该字典中有5000个常用的字,如[“的”, “我”, “你” …… “啊”]。
字典中“我”字出现在第二个位置,用数字2表示,“看”在字典中出现在第七百零三的位置,用数字703表示,“汽”这个词没有在字典中出现,以数字0表示。那么“今天我看见一辆汽车”可以用下面一串数来表示:
[102, 742, 2, 703, 1842, 12, 3729, 0, 2264]
该串数字由字典而确定,词典不同,该串数字不同。因此给定一个字典,我们可以用一串数字来表示一句话。
方法二:Bag of words(词袋模型)
我们可以用One-Hot(独热编码)的方式来表示词汇。
One-Hot编码是指,给定一个长度为N的字典,每个词用一个长度为N的向量来表示。其中只有一个地方为1,其他地方都为0。
假设一个词典只有8个词[“今”, “我”, “好”, “看”, “文”, “章”, “天”, “你”],”好”这个词在词典中的第三个词,可用一个长度为8的词向量来表示”好”
“好” = [0, 0, 1, 0, 0, 0, 0, 0]
词袋模型(Bag of words)忽略一句话的词序和语法,把一句话中所有的词的one-hot编码相加,我们就得到了这句话的向量表示。
“技术杂学铺的文章写得好好看啊” = [0, 0, 2, 1, 1, 1, 0, 0]
由于词袋模型忽略了词的先后顺序,”我看文章”和”文章看我”是用同一向量表示的,但二者的语义完全不同。
尽管如此,使用词袋模型的朴素贝叶斯算法在一些文本分类任务上的效果还是很好的。
方法三:word vectors(词向量)
和one-hot编码类似,我们依旧用一个向量来表示一个词。只不过这些词的取值不再是整数。
注:词向量(word vectors),也称词嵌入(word embedding)
词义相近的词,其词向量相近。(词向量相近可以是两个向量的欧式距离很小、又或者是两个向量的夹角很小)
我们将一个N维度的词向量用t-SNE降维算法压缩到二维上。可以看到,词义相近的词,在如下的二维图形上很接近。(take, get, make很接近,were, are, is很接近)
词向量另一个有趣的特点是,虽然其是由一串等长的浮点数表示的,但是词向量中暗含着某种语义。比如“国王”的词向量减去 “女王”的词向量约等于“男孩”词向量减“女孩”词向量;“中国” – “中国人” 约等于“德国” – “德国人”……
词向量是需要我们基于某种算法来进行学习的,目前没有统一的对每个词的词向量的定义(即没有定义“啊”这个词的词向量就必须是[0.1, 0.3, -0.2……],“好”的词向量就必须是[0.2, -0.1, -0.3……])。不过有开源的基于大量文本训练来的词向量库,读者可在github上找的此类词向量库。
2. 如何计算词向量
2.1 简介
我们假设一个词的意思由经常出现在其附近的单词给出的。(该假设可能很反直觉,但基于该假设的模型的效果真的很好。)
在这个假设下,我们可以用数学的方式,算出每个词的词向量。
我们有以下想法:
- 我们已知大量的文本数据
- 每个词由固定长度的词向量表示
- 遍历文本的每一个词,被遍历的词为中心词,中心词前后的n个词为上下文。
- 我们通过计算中心词和上下文词相似度的方式,计算在已知中心词的情况下,上下文词出现的概率,又或者预测在已知上下文的情况下中心词出现的概率。
- 不断调整词向量,最大化上述概率。
上述想法就是word2vec算法的核心。该算法通过预测文本中词出现的概率的方式来计算每个词的词向量。
该算法有很多细节值得我们来讨论。
首先,是上下文选取。一个中心词的上下文是该词前n个词和后n个词。n的取值认为设定。
比如 “我 今天 想 吃 苹果 ,因为 它 很 甜”,这句话分词后为[“我”, “今天”, “想”, “吃”, “苹果”, “,” ,“因为”, “它”, “很”, “甜”]。
如果中心词是“苹果”,那么当n=1时其上下文是[“吃”, “,”]。当n=2时,“苹果”的上下文是[“想”, “吃”, “,”, “因为”]。以此类推。
第二点是单词预测。
已知上下文,预测中心词的算法属于word2vec算法中的CBOW(Continuous Bag-of-Words Model),而已知中心词预测上下文则为word2vec算法中的skip-grams,二者虽然略有不同,但本质一样。
以已知上下文词汇,预测中心词为例。
在“我 今天 想 吃 苹果 , 因为 它 很 甜”中,依旧假设中心词为“苹果”,上下文的n=5。则预测问题就变成了“我 今天 想吃 ___ , 因为 它 很 甜”,这里,我们可以预测中心词为“苹果”,也可以预测为“香蕉”、“巧克力”、“葡萄”……但肯定不会是“房子”、“桌子”,这些词的上下文中有“吃”、“甜”的概率很低。
在“我今天想吃____,因为它很甜”中,我们想要空格处预测为“苹果”的概率最大,尽管“香蕉”、“巧克力”也符合语义,可是文本中的原话是“我今天想吃苹果,因为它很甜”,一切以文本为准。
但文本中还会有类似“巧克力很甜”,“我爱吃甜香蕉”这样的话,算法在这类的语句见得多了,就会认为“吃”,“甜”为上下文的时候,中心词可能为“香蕉”、“巧克力”。于是乎,“苹果”,“香蕉”,“巧克力”就有了相同的特性,其词向量也应该相近。
同理,已知中心词预测上下文就是“_____苹果_______________”,上下文可能为“甜”,“吃”等等。
我们进行单词预测这个任务的最终目的不是真的做到预测单词,而是希望以此来计算词向量。在上述任务中,“甜”,“吃”周围是食物的可能性更大,这些代表食物的词的词向量会比较相近。
第三点,word2vec中单词预测的算法到底是什么,如何依据最大化被预测单词的概率来调整词向量,我们在2.2中讲述。
2.2 词向量求解
以已知中心词,预测上下文为例(skip-grams模型)
2.2.1 目标函数
已知一句话中第t个位置的词Wt,我们需要预测其上下文的单词。
预测结果的好坏可以用如下目标函数来判断:
其中θ表示需要被优化的参数,即词向量。L(θ)表示的就是一段文本中所有已知中心词后,预测正确上下文词的概率的乘积。L(θ)越大,则表示我们的预测结果越好。
然而,所有概率都是小于1的值,大量小于1的值相乘会造成计算机下溢出(最后乘积的结果可能为零)。因此,我们需要改进一下目标函数。
我们对上述公式取对数即可解决下溢出问题。通常,我们习惯于最小化目标函数而非最大化目标函数,因此我们对函数取负数,原本最大目标函数的任务就变成了最小化新目标函数。另外,我们除以文本长度T,这样,该目标函数就和文本的长度无关了。
新的目标函数越小,则意味着我们预测单词这个任务做得越好。
2.2.2 概率公式
已知中心词c的上下文是o的概率为:
这里有两个词向量表(向量表的维度为 字典大小N * 词向量长度D,词向量长度人为定义,一般在100到300之间)。其中V代表中心词的词向量,U代表上下文词的词向量。
我们希望P(o|c)最大,即希望中心词c的中心词词向量V乘以其上下文o的上下文词向量U之后的结果足够大。
有机器学习基础的读者可以一眼看出该概率公式就是一个softmax公式。
我们计算中心词c的中心词词向量V和字典中所有词的上下文词向量U的点乘。结果取指数,使结果从(-∞, +∞)映射到(0, +∞)之间。再对其归一化,使结果分布在(0, 1)之间,且所有概率之和为1。
为何用两个词向量表?为何找出两个词向量表相乘后最大的那个为预测结果?一个直观的解释如下:
还是以“我 今天 想 吃 苹果 , 因为 它 很 甜”为例,知道中心词“苹果”,预测n=2的上下文。这是一个多分类问题,预测结果是词典中的一个。
训练数据为:
输入 X | 输出 Y |
苹果 | 想 |
苹果 | 吃 |
苹果 | , |
苹果 | 因为 |
将输入输出的文本根据字典,进行one-hot编码。那么我们的问题就会变成训练一个神经网络。输入一个词的one-hot编码,预测该词的上下文。
其中的中心词词向量V就是输入层到隐藏层之间的权重,上下文词向量就是隐藏层到输出层之间的权重。最后我们将输出层的结果进行softmax,使其分布在(0, 1)之间且总和为1。
理解了上图,自然就理解了知中心词求上下文的概率公式。
进阶内容:我们还会采用负采样的方式作为训练数据;整个模型中绝大部分计算都花在了softmax算法上,我们可以采用Hierarchical Softmax方法,来减少softmax的计算量。
2.2.3 词向量求解
上节可知,word2vec本质是一个神经网络,中心词词向量和上下文词向量都是该神经网络的参数。理解了这些,我们就可以采用常用的SGD(随机梯度下降)来求解神经网络的参数了。
起初,词向量是随机初始化的。(可采用的随机初始化方法有很多,比如让参数服从N(0, 1)的高斯分布)
之后采用随机梯度下降法来计算各个参数的梯度,再之后更新参数即可。
关于梯度下降的数学公式(数学求导流程),Chris Manning老爷子特别认真的在黑板上写了一遍。建议读者私底下也走一遍。
最后我们得到V,U两个词向量表。我们可以将这两个词向量表拼接在一起用。比如“因为”这个词的中心词词向量V为[0.1, 0.2, 0.3],上下文词向量为[-0.4, -0.5, -0.6],拼接后是[0.1, 0.2, 0.3, -0.4, -0.5, -0.6]。
但是更常用的是(也很反直觉)将两个词向量表相加,即“因为”这个词的词向量为V + U = [0.1, 0.2, 0.3] + [-0.4, -0.5, -0.6] = [-0.3, -0.3, -0.3]
实验证明这样的词向量效果更好。至于为什么,暂时没有数学上比较合理的解释。
word2vec算法除了可以计算词向量,还可以用于预测用户行为,从而做一个推荐系统!训练词向量时,我们输入一段文本序列。而预测用户行为时,我们输入用户的先后行为操作。你知道之后该怎么做了吗?相关介绍。
总结
本节,我们将讲述词的表示方法和词向量的计算。
- 词向量是如今自然语言处理中最常用的词语表达方式。语义相同的词,其词向量一般都很接近。
- 词向量时基于大量文本训练出来的。常见的算法有基于中心词预测上下文的skip-grams和基于上下文预测中心词的CBOW。
- 对词向量的训练本质上是对神经网络的训练。我们让神经网络预测单词出现的概率。但我们在意的不是预测结果,而是神经网络的参数。我们将神经网络的参数作为词向量,来进行以后的NLP任务。
2 thoughts on “CS224N课堂笔记(1) Introduction and Word Vectors”