转眼到了 CS50 AI 的最后一节课。

这节课讲的是当下热门中的热门——自然语言处理。

语言

之前我们都是把问题和算法转换为某一种机器语言让机器来执行,这一次我们要让机器理解人类的语言。

语法和语义(Syntax and Semantics)

涉及到自然语言,就不得不涉及一些语言学的知识——语法和语义。

语法是一门语言要遵循的基本原则。其实一些机器语言也是一样。比如,Python 在语法错误的时候会抛出 SyntaxError

语义则表示这段话要表示的内容。符合语法的语句不一定有语义,比如说这句话:

Colorless green ideas sleep furiously.

不同的语法结构组成的句子可能会表示同一个意思。

上下文无关语法(Context-Free Grammar)

正式语法(Formal Grammar)是一种对于某个语言来说,生成句子的规则。

我们可以用 parser 对每个单词进行分析,从而形成一个语法树。

语言,语言。自然语言和机器语言都是一种语言。所以我们在编译原理课程学习到的知识,也可以搬到自然语言中。

当然,有的时候,可能一句话有许多种语法树的可能。这时候就出现歧义了。如果是一门程序语言,很可能会报错。

nltk

nltk(Natural Language Toolkit) 是一个支持自然语言处理的库。

n-grams

n-grams 指的是从文本的样本中选出来的 n 长度的序列。

比如这句话中:

the quick brown fox jumps over the lazy dog

3-grams 是 “the quick brown”, “quick brown fox”, “fox jumps over”…

标记化(Tokenization)

Tokenization 的任务是把一句话切碎。只有把一句话切碎了,才能考虑 n-grams 的问题。

Markov Models

又是马尔科夫链。事实上,基于前面的 n-grams 和 tokenization,我们实际上可以实现一个马尔科夫链,基于概率,预测下一个最可能出现的单词是什么。

Bag-of-Words Model

一种对单词处理的简化模型是 Bag-of-Words 模型。望文生义,它的作用是,对于一个句子,忽略单词之间的次序,而是作为一个集合来处理。

虽然这种做法减少了掌握的信息,但是它便于处理,同时提供的结果也可以接受。

Naive Bayes

结合 Bags-of-Words 模型,我们可以利用朴素贝叶斯实现语句的情感分类效果。

比如,对于一个购物网站的许多评论,我们需要分出这些评论是好评还是差评。

思路是,把每个句子拆成单词,这一步利用了 Bags-of-Words Model。然后,利用贝叶斯公式,一番推导,就能得到某个给定句子是好评或是差评的概率。

下面就展开讲讲朴素贝叶斯。

为什么它朴素呢?因为它只考虑了单词和情感(更一般地,类别)之间的关系,而不考虑单词之间出现概率的影响(单词与单词独立)。

这个假设很可能 too simple, sometimes naive,因为,有的单词确实是成簇出现的。比如,my 出现后,grandson 出现的概率就会高一些。

但是朴素贝叶斯不考虑这件事,让概率计算变得简单。

数学分析一下。

我们想计算:

$$
P(HAPPY | foo, bar, baz)
$$

也就是在 foo, bar, baz 这三个单词出现的情况下,好评的概率。

由贝叶斯公式:

$$
P(HAPPY | foo, bar, baz)
= \frac{P((foo \land bar \land baz) | HAPPY) \cdot P(HAPPY)}{P(foo \land bar \land baz)} \
= \frac{P(HAPPY \land foo \land bar \land baz)}{P(foo \land bar \land baz)}
$$

因为我们考虑好评和差评两种对立的情形,所以,可以简化处理。因为对于一条评论来说,上面等式的分母是一样的。所以,我们可以不考虑分母,而是认为,等号左边和右边的分子成比例。

好评和差评都分别和等式右侧的分子成比例,并且是对立的事件。因此,我们可以对好评和差评分别计算比较好算的 joint 形式分子,再让它们加起来是 1 即可。

所以现在问题转换为了如何计算 $P(HAPPY \land foo \land bar \land baz)$。

推导一下:

$$
P(HAPPY \land foo \land bar \land baz)
= P((foo \land bar \land baz) | HAPPY) \cdot P(HAPPY)
= P(foo | HAPPY) \cdot P(bar | HAPPY) \cdot P(baz | HAPPY) \cdot P(HAPPY)
$$

其中,最后一个等号基于的就是朴素贝叶斯,也就是假设各个单词之间是相互独立的。

这样, $P(HAPPY)$ 可以通过训练集中好评句子占总体评价的比例来计算。$P(foo | HAPPY)$ 就可以通过包含 foo 的句子占所有好评的比例来计算。

有一个细节问题需要探讨。如果一个单词在好评中一次也没出现,而在差评中出现过,按照上述方法计算得到的概率是,差评 100%!似乎不太合理。

要修复这个问题,课可以使用 Additive Smoothing,对于每个单词,假设其出现的次数比真实次数多一些。一个特殊的 Additive Smoothing 叫 Laplace Smoothing,加的值是 1。

Word Representation

前面还没有接触到数据表示层面,在计算机内表示单词,把它数字化是明智的想法。

一种表示方法叫 One-Hot Representation,独热码。也就是在向量中,只有一位是 1,其余都是 0。

这种表示方法很简单,但是,开销太大。当单词数量增加的时候,难以表示。此外,这种表示方法无法表示单词之间的亲缘关系。比如,authored 和 wrote 应该有相近的意思。

为此,另一种表示方法叫分布式表示。单词好像 scatter around 整个高维线性空间。

比如,[-0.34, -0.08, 0.02, -0.18, …] (he)

word2vec

word2vec 是一种生成单词分布式表示的算法。是通过 Skip-Gram Architecture 实现的。

很神奇。每个单词的向量值并不重要,但是考虑关联就很重要了。

比如,对某个单词,找到它周围最近的 10 个邻居,就能找到 10 个近义词。

此外,更神奇的是,考虑 king 和 man 的距离差。让 woman 加上这个距离差,求最近的一个单词。你猜到了,可以得到 queen!

神经网络

又来了。是的,对于语言,我们也可以用到神经网络。尤其是翻译过程。

此外,由于语言的输入输出不是定长的,所以需要用到 Recurrent Neural Network。

但 Recurrent Neural Network 有个很大的问题。它的操作基础是,每次重现,都要把先前的所有信息和新的输入信息保存到新输出中。随着输入规模的增大,很可能输出保存不下这么庞大的信息。

此外,各个输入的权重是不一样的,可能有的输入比其他输入更重要。

Attention

解决这个问题,需要用到 Attention。其实它的想法很简单,就是对每个输入生成一个权重。把$权重 \times 输入$ 的值作为最终考虑的值。

不过,到底如何生成 Attention 的权重就是研究的重点了。

Transformers

当然,Recurrent Neural Network 的一个问题是,计算的太慢。

唉,其实到最后,底层原理就那些。并行化,不就是行波进位加法器和先行进位加法器的区别吗?

所以 transformers 是一个新的训练架构。每个输入是同时被输入到神经网络中的,输入的信息除了单词本身,还有单词位置的编码。此外,还会使用到许多 self-attention 步骤来理解输入的上下文。

在输出阶段,也涉及到注意力机制,不仅注意已经输出了什么,还关注之前的输入。

结束了

这周是第七周。经过了七周的学习,总算是完成了 CS50AI 的学习。

回过头来,到底什么是 AI 呢?AI 是那种让人类觉得似乎有知觉的智能体。换句话说,其实搜索问题、博弈问题、分类问题都是 AI 领域的问题。不过,让 AI 彻底火起来的应该算是 22 年的 ChatGPT,当 AI 能够和人类对话,甚至是表达自己的看法时,才让普罗大众意识到,AI 时代来临了。

现在 AI 真的是非常火爆的课题,黄渡计系的老师有 80% 以上都在往 AI 靠拢。就算是没有 all in AI 的,也在把 AI 作为研究的辅助工具,和自己的领域结合。

虽然我对 AI 不太感冒,我的意思是,不太想把 AI 作为自己从事的领域。但我其实不排斥把 AI 用到日常生活中。其实 AI 早就渗透到我的生活中了。现在的 chatgpt.com 就和几十年前的 google.com 一样,不能离开。

很有意思的一个事情是,每当一个新技术出来的时候,总是有人担心,啊,是不是人类要被取代了。AI 绘图刚出来的几年前,确实很多画师担心过。现在呢?是那些已经被 AI 取代的画师沉默了,还是照样歌舞升平呢?说不清楚。

AI 最后到底发展成什么样子呢?不清楚。有人说,只由 0,1 组成的计算机永远不可能觉醒智能,还有《细胞生物学》的作者翟中和院士,他认为细胞要比任何一台计算机精巧。

确实是这样。物理层面的计算机,确实只是由 0 和 1 组成,但事情不能这么看。要是从物理层面来看,生物的细胞不过是一堆分子(有结构的)堆砌。几亿年前可能有先知会这样讲:只由分子组成的细胞不可能形成什么智能!

不是的。现在,虽然计算机是硅基生命,基于冯诺依曼架构组成的有序系统。但是,现在这个系统已经复杂到了人类无法深入探寻的阶段。这两天在写 AI 课程的作业,老师让结合机器学习进行迷宫问题的求解。我说这种结合是脱裤子放屁,因为机器学习适合的场景是不存在高效算法问题。已经有了 A* 和 Dijkstra,学习?学个屁!

所以说,AI 解决的问题是,人类已经想不到一个可行的算法来解决的问题。比如说,人脸识别,不可能有一个人把照片的像素点 hard code 到程序的逻辑中,然后来判断。再比如对弈问题,人类也找不到可以把每个棋局各种步骤的先后次序表示出来的算法。还有自然语言处理等等。人类解决不了的问题,诉诸 AI 来解决。

最后呢,问题确实是解决了,但是怎么解决的呢?没人知道。人们只知道理论基础,嗯,是有一堆 layers,还有好多参数发挥作用。但是,怎么发挥作用的呢?人们只能说出个大概,但更底层的说不出来了。比如说三羧酸循环,人们知道这个反应是什么,很复杂了已经。但是,更底层呢,每个反应是怎么发生的,涉及到哪些细胞器,这些已经研究的差不多了,但更底层呢?从一个细胞分裂开始,到这个细胞死去,中间发生了什么?

生物学上研究不明白这些问题,计算机领域同样不明白。是啊,有反向传播算法,有 transformer 架构,但更底层的呢?就像人类不知道自己这些思维是怎么形成的一样,他们也不知道 AI 是如何智能的。哈哈,有点像养一个小孩子,小孩就是长大了,参加了高考,又开始培育下一代。但这到底是怎么实现的呢?

总结一下,我想说的是,计算机的载体确实很简单,就是一堆含硅物体。但是,在这个基础上形成的那种虚的智能深不可测,就像细胞如何诞生了智能一样。

完。