CS224U: Natural Language Understanding 是我在Stanford AI Certification Program 里的第一节课。 这篇Blog对知识点和学习心得做一个简单的总结。
最近几学期这门课的教授一直是Prof. Christopher Potts和Bill MacCartney,今年也不例外。两位都是真*巨佬,苹果的Siri就是Bill领导的产品之一。这学期因为COVID-19疫情的原因,无论是我们Online的学生还是Stanford的在校学生,课程都变成Online了,通过Zoom授课。这学期Online+在校学生大概有120+人。我这学期作业是跟一个Stanford本科的白人小哥一组,final project 是我跟白人小哥哥加一个在 Northwestern 的CS PhD。然而个final project因为疫情也变成optional的了。
Lecture 1, Introduction and course overview
NLP VS. NLU
第一节课,老师简单做了一些自我介绍,然后介绍了一个NLP(Natural Language Processing) 和NLU(Natural Language Understanding)的不同。我的理解是NLU是NLP下的一个小分支, NLU强调的机器对语言的理解,而NLP则强调对语言的处理。门课会涉及到Grounded Language Understanding,是一个典型的NLU问题。这门课用 Pragmatic Color Describer 来简单介绍了Grounding的概念。 当我用语言描述一个颜色的时候,我们所用的描述性词汇取决于周围的环境。有请我们的橘猫登场:
我们描述两只橘猫的时候,就可以用浅一点的那个只橘猫VS深色的橘猫来作区分。然而当对比的猫不是橘色的话,我们就需要描述橘色的深浅,只需要说橘猫即可。比如这样:
当我们使用对比描述语言的时候,我们假设说话对象对颜色深浅有跟我们一样的理解。这个理解就是Grounding。 有关Pragmatic Color Describer的具体内容后面会详细讲。
A brief history of NLU
这部分老师简单介绍了一下NLU的发展历史
- 1966: Eliza
- 1988: Latent Semantic Analysis
- 2011年1月: IBM Watson beats Jeopardy! Champions
- 2011年10月: Apple Siri launches in beta
- 2014年4月: Microsoft Cortana demoed
- 2016年5月: Google Assistant
CS224u topics
随后介绍了一下这学期会cover的NLU topics,八个topic,每个topic两个lecture。内容还是相当丰富的。
- Vector-space models
- Sentiment analysis
- Relation extraction
- Natural Language Inference
- Grounding
- Contextual word representations
- Adversarial testing
- Methods and metrics
随后教授介绍了各个方向的发展,并且介绍了一个本书SUPERINTELLIGENCE - NICK BOSTROM, 我读着觉得不错,主要讲的就是对AI的未来发展,和可能带来的相应的社会问题。没什么技术内容,用词简单, 有时间的朋友可以读读,当做练习英文也不错。
最后教授介绍了一下几个入门教程,包括设置课程的虚拟环境,PyTorch和Numpy的入门,等。强烈建议跟着教程设置一下虚拟环境,并克隆这门课的Github,有很多有用的东西。
Lecture 2, Distributed word representations
这节课讲的就是NLP里面最基础,但相当重要的Word Vector。 Prof. Potts从最开始的Co-occurrence矩阵,讲到到GloVe和Word2Vec等方法。
Vector representation的思想,是深度学习里的一个核心思想,我们就经常开玩笑说,“万物皆可Embedding”。比如在零售业,每一个商品,每一个门店,都可以用一个高维向量来表示。同理我们也可以通过这种向量来研究商品之间的关系。中国零售大佬阿里巴巴,和美国零售Walmart,Amazon都在这方面有深入的研究,这里附上一篇有关Product2Vec的论文,有兴趣的同学可以读一下( Studying Product Competition Using Representation Learning)。
现在Word vector representation已经是学术界默认的有效方法,然而其背后有着对语言学深刻的理解。这要追溯到这个语言学问题:什么定义了一个词的意思? 在这里的理解是,与这个词一同出现在一个句子的其他词定义了这个词的意义。
You shall know a word by the company it keeps. - Firth (1957)
“distributional statements can cover all of the material of a language without requiring support from other types of information. - Firth (1957)
最简单的Co-occurrence矩阵通过计算词汇同时出现的次数来反应词义信息。
如何构建Co-occurrence矩阵
Co-occurrence矩阵的构建有两个主要参数。
- Window Size: 以一个单词为中心,前后考虑co-occurrence的范围
- Scaling: 用于调整co-occurrence的数值
这里用莎士比亚的一句诗来举例: “For thy sweet love remembered such wealth brings That then I scorn to change my state with kings.”
这两个参数的选取,主要遵循以下逻辑
- 更大的window size和更平滑的scaling能获取更多的semantic information(语义信息)
- 更小的window size和更多的scaling能获取更多的syntactic information(句子结构信息)
用海量的句子,文章来计算co-occurrence矩阵,每个词与其他词一起出现的次数就能构成最简单的word vector。下图的每一行都可以看做一个word embedding。当然简单的计数并不能达到我们想要的效果,接下来会讲如何通过统计方法提高word vector的质量。然而基于窗口构建的co-occurrence有一个明显的缺点,像the, and, or, is等词汇跟其他词co-occurrence的频率非常高,但是包含词义的信息却非常少。后面会讲到一些reweighting的方法,比如PMI,PPMI,来改善这个情况。
如何比较两个向量
单词变成向量之后,我们需要系统的比较两个向量的方法。这门课介绍了以下几个方法:
- Euclidean distance
- Euclidean distance with L-2
- Cosine distance
- Matching-based methods
- KL divergence
Euclidean distance(欧几里得距离)
n维向量u, v之间的距离:
\[{euclidean(u, v)=\sqrt{\sum_{i=1}^{n}{|u_i - v_i|^2}}}\]Euclidean distance描述的是两点之间的直线距离。如果两个向量方向一致,大小不同的话,欧式距离也会非常大。通常word vector的方向比大小更重要,方向一致的word vector通常有着相近的词意,所以Euclidean distance不是比较word vector的合适方法。
Euclidean distance with L-2 norm
如果我们对向量进行归一化,那么向量大小都会变为1,这是用在用Euclidean distance就能排除向量大小的影响,从而只考虑向量方向的影响。
Cosine distance
Cosine distance只测量向量角度,向量大小完全无关。Cosine distance是NLP界最常用的word vector比较方法之一。
\[{cosine(u, v)=1 - {\frac{\sum_{i=1}^{n}{u_i \times v_i}}{||u||_2 \times ||v||_2}}}\]这里有点值得注意的是, euclidean distance + L-2 Normalization的排序是等同于cosine distance的。这两种方法的数值不完全相同,但是用来比较多个向量距离的时候排序是一样的。在word vector应用领域,可以认为是等价的。
Matching-based methods
Matching based在NLU领域用的并不多,这门课只是简单 提了一下,我在这就简单列一下公式。
KL divergence
KL divergence本身是一种比较两个概率分部的方法。想具体了解KL divergence的同学可以看这篇KL divergence。
\[D(p || q) = \sum_{i=1}^{n} {p_ilog(\frac{p_i}{q_i})}\]在NLU的运用中,如果我们要比较两个word vector我们首先要吧word vector变成一个和为1的概率分布,然后用KL divergence来比较距离。课上给出了这么一个例子。A, B, C都是变成和为1的概率分布了。使用KL的前提是,向量能被理解为概率分布,如果向量里面有负值,那么这个方法就不适用。
标准化Co-occurrence矩阵
我们已经简单讲了如何构建co-occurrence矩阵,并且通过co-occurrence矩阵引申出word vector的概念。然而靠词出现的频率产生的word vector有一个很严重的问题,就是词出现频率在语言理解里的意义并不大。举一个很简单的例子,妖魔鬼怪VS魑魅魍魉。这两个成语的意思基本一样,但是大家写作文的时候可能妖魔鬼怪出现的频率会高很多,因为魑魅魍魉实在太难写了,写错还要扣分不是。所以频率并不是一个非常好的方法,我们可以通过标准化的方法来减弱频率的影响。L-2 normalization和把向量转化为概率的方法。下面会讲一个常用的方法Observe/Expected。
Observed/Expected公式如下
这里该怎么理解这这个expected的计算呢?expected可以理解为在行和列的词都是独立事件的时候,这个词出现频率的期望值。在这张图给出的例子中,keep这个词出现了60次,tabs出现了21次。如果这两个词出现是独立事件的话,那么keep, tabs一起出现的概率应该是P(keep) * P(tabs) = 60/101 * 21/101。Observed/Expected是在比较实际情况和假设为独立事件的时候的不同。
在Observed/Expected的基础上,我们还可以得到Pointwise Mutual Information(PMI)和Positive PMI(PPMI)。PMI是log(Observed/Expected),而PPMI则是把所有PMI中因为log产生的负数改为0。值得注意的是数学上log(0)是没有定义的,但是在这个应用场景下log(0)=0。
TF-IDF
TF: Term frequency: P(word | document) IDF: Inverse document frequency (IDF)
教授还提到了t-test weighting,pairwise distance matrices等,但这些在这门课中用到的并不多,就不在这展开了。
Dimensionality reduction
Co-occurrence矩阵非常大,一个word representation可能会高达上千,上万维度,如果直接用的话并不能很好的提取词义信息,所以这里要用到降维的方法。这门课介绍了四种方法:
- Latent Semantic Analysis
- Singular value decomposition (SVD)
- Principal Components Analysis (PCA)
- Non-negative Matrix Factorization (NMF)
- Probabilistic LSA (PLSA; Hofmann 1999)
- Latent Dirichlet Allocation (LDA; Blei et al. 2003)
- t-SNE (van der Maaten and Hinton 2008)
- Autoencoders
- GloVe
- Word2Vec
这里LSA下面的方法在如今的NLP领域已经不那么常用了,而且SVD和PCA是比较基础的降维方法,这里就不展开讲。我们主要看看Autoencoder, GloVe, 和Word2Vec。
Autoencoder
Autoencoder是一类用来降维结构的深度神经网络结构。老师在lecture中给出了一个简单的Autoencoder模型的结构
Autoencoder结构与其他神经网络不一样的地方主要是,训练寻常的神经网络,我们需要一个输入X,和输出Y。但是训练Autoencoder, 我们只需要输入X即可,因为这里的输入和输出都是X。优化的目的是让输出层的X_hat等于输入层的X。以下就是图中描述的Autoencoder,这里的input_dim_和output_dim_是相等的都是X向量的维度。
import torch
import torch.nn as nn
def define_graph(self):
return nn.Sequential(
nn.Linear(self.input_dim_, self.hidden_dim),
nn.Tanh(),
nn.Linear(self.hidden_dim, self.output_dim_))
GloVe
GloVe是NLP界一个里程碑级别的成就,基本上所有NLP相关的课程都会讲到这个,我们就来简单看看GloVe就是怎么实现的。GloVe的优化目标是学习一组word vector使其点乘和他们co-occurrence的概率成正比。
在GloVe之前,生成word vector两大类方法是: 1. 基于co-occurrence矩阵的Matrix Factorization Methods,咱之前讨论的都是这一类方法。2: 基于local context window的Shallow Window-Based Methods。这类方法包括skip-gram model和continuous bag-of-words model。然而这两类方法都有明显的缺陷。第一类中有些高频的词汇,例如the, is, and等并不能很好的代表词意。第二类方法是我是基于local window,所以无法完全利用庞大的语料数据。