咚,咚,那是谁
为了在自然环境中识别出人工智能,了解机器学习算法(我们在本书中称为人工智能)和传统程序(我们称为基于规则的程序)的差别十分重要。如果你做过基本的编程,或者使用过HTML语言来设计一个网站,那么你就是在使用基于规则的程序。你用一种计算机可以理解的语言写下一系列的指令或者规则,然后计算机就会严格按照你说的去执行。要用基于规则的程序解决一个问题,你必须具体知道完成任务所需的每一步,以及如何描述这些步骤。
然而,机器学习算法可以通过试错和评估自己在程序员指定的目标上是否达标,自行找到这些规则。这些目标可以是一个可供模仿的样本列表,一个亟待提高的游戏比分,或者是任何其他东西。在人工智能努力达到这些目标的过程中,它能够发现程序员可能完全不知道的规则与关联。与编写一个传统程序相比,编写一个人工智能程序更像是教导孩子。
基于规则的编程
假如我想要用人们更熟悉的、基于规则的编程方法来教计算机讲敲门笑话。我要做的第一件事就是想出所有的规则。我将会分析敲门笑话的规则,然后发现它符合下述的形式:
咚,咚
是谁?
[名字]
[名字]谁?
[名字][包袱]
一旦我把这种形式完全确定下来,就只剩下两个我们可以控制的空余位置了:[名字]和[包袱]。现在,问题归结为生成这两个部分。然而,我仍然需要一些规则来生成它们。
我可以先确定一系列可用的名字和包袱,比如以下:
名字 包袱
生菜 进来,外面很冷!
哈利 上去,外面很冷!
一打 任何人想让我进来吗?
橙子 你将会让我进来吗?
现在电脑就可以通过每次从这个列表中选择一个名字和包袱的组合,再把它放进模板中。这样不会产生任何新的敲门笑话,仅仅是给我提供一些我已经知道的敲门笑话。我也许会想做得更有趣一些,尝试把[外面很冷!]换成一些不同的短语比如[我被鳗鱼袭击了!]或者[不然我就会被吓得说不出话来]。之后,这个程序就可以产生新的笑话了:
咚,咚
那是谁?
哈利
哈利是谁?
哈利,上去,我被鳗鱼袭击了!
我可以把[鳗鱼]换成[愤怒的蜜蜂]或者[魔鬼鱼]或者任何其他东西。然后,我就可以让计算机生成更多的新笑话了。只要有足够多的规则,我就可以生成成百上千个笑话。
我也可以花很多时间来设计更多更高级的规则,这取决于我想要把事情弄得多复杂。我可以找一些已有的包袱,再想办法把它们转化成我们当前的形式。我甚至可以把发音规则、韵律、同义词、文化背景等都写进程序,试着让计算机能够重新排列组合得到有趣的包袱。如果我在这方面很聪明,我甚至可以生成一些人们从来没见过的包袱。(虽然有人真的这么做过,最后却发现这些包袱中含有一些太过模糊和过时的短语,以至于没有人能理解这些笑话。)无论我编写笑话的规则有多么复杂,我仍然是在告诉计算机如何具体地解决这个问题。
训练人工智能
但当我们训练人工智能来讲敲门笑话时,我们不会指定任何规则。人工智能必须自己找到这些规则。
我们唯一交给它的是一个已有的敲门笑话组成的集合,以及一些指令,它们本质上是这样的:“这里有一些笑话,去制造更多的笑话吧!”我交给它的学习材料是什么呢?那就是一箩筐随机的字和标点符号。
然后,我就去取咖啡了。
人工智能开始了工作。
它做的第一件事是猜测敲门笑话中的一些字符。到目前为止,它还是在百分百地瞎猜,所以最初的猜测可能是任何东西。比如说它猜测出了一些类似于“鍦ㄧ紪鐮侀敊璇,椂鐨勬樉绀烘儏鍐碉紝鍘熺悊鏄。互”的乱码。按照它的理解,这就是你讲敲门笑话的办法。
然后这个人工智能程序就开始研究敲门笑话到底该长成什么样子了。有可能它错得一塌糊涂。“没关系”,人工智能说,然后它会轻微调整一下自己的结构,这样下次它就会猜测得更准确一些。对于人工智能改变自己的程度,应当存在一个限度,因为我们不希望它努力记住见到的每一段文字。不过,通过尽可能少的调整,这个人工智能就可以发现它只是在输出字符“敲”和空格,这样它至少在有些时候是和我们给出的句子吻合的。在看到一批敲门笑话之后,它会进行一轮更正,它对于敲门笑话的理解大概就是下面的样子:
到现在为止,这并不是世界上最好的敲门笑话。但以此为起点,这个人工智能可以继续前进,学习第二批敲门笑话,然后再学习下一批。每一次,它都会调整自己生成笑话的形式,改进自己的猜测。
在几轮猜测和自我调整之后,它学到了更多的规则。它学会了把偶尔出现的问号放在每一行的末尾。它开始知道使用定语相关的词(特别是“的”)。它甚至开始尝试使用逗号。
生哈进,
敲生哈进 生哈进
面很一橙?
进打上
吗
冷进面上
菜面生进
子 哈
了 敲
了
它找到的生成敲门笑话的规则和现实的吻合程度如何呢?看起来,我们仍然缺点儿什么。
如果它想生成一些更具有可读性的敲门笑话,它就得找到一些确定这些字符排列顺序的规则。和以往一样,它是从猜测开始的。猜测“生”字后面永远是“菜”?事实表明,这个猜测不太合理。然后它开始猜测“进”字后面永远跟着“来”,这看起来更靠谱一点儿。它确实有一些进步。看,现在它心目中完美的笑话应该长这样:
进来
进来
进来
进来
进来 进来 进来
进来 进来
进来
进来
这还远不是一个敲门笑话——它听起来更像是无意义的重复。这个人工智能需要找到更多的规则。
于是,它又一次仔细研究数据集,尝试用一些新的方法来使用“进来”,寻找新的组合,来更好地模仿样本中的敲门笑话。
生菜进来 进来
哈利进来
进来
橙子 生菜 敲
进来 进来
谁?
很冷 上去
进来 很冷 上去
生菜 进来
一打
进来
进来
所有的这一切进展都发生在短短几分钟内。在我拿着我的咖啡回来之前,这个人工智能就已经发现敲门笑话应该以“咚,咚,那是谁?”作为开始了,这和已有的敲门笑话相吻合。它决定永远遵循这条规则。
但是,它需要更多的时间来发现敲门笑话的其他规律,然后这个人工智能就常常退化到只会耍自说自话的把戏——或者是演出一幕机器人版本的“谁在一垒?”的常见喜剧段子。
咚,咚
那是谁?
生菜
生菜是谁?
生里是谁?
哈利是谁?
哈菜是谁?
橙子是谁?
一打是谁?
很快,它就发现了这个模板剩下的部分:词语,但是你知道的,这并不确切:
咚,咚
那是谁?
哈利
生菜是谁?
一打想很冷进来
它有时也会把包袱写得过长:
咚,咚
那是谁?
哈利
生菜是谁?
一打想很冷进来将会橙子吗?很冷上去敲敲那是哈利生菜是谁一打想很冷进来将会橙子吗?很冷上去咚咚那是哈利生菜是谁
在训练中的某个时候,它学到了一只关于没有嘴唇的牛的笑话,从此以后这就成了它的最爱。你可能对这种笑话还不够熟悉,这个关于没有嘴唇的牛的笑话大概是这样的:
咚,咚
那是谁?
一只没有嘴唇的牛
一只没有嘴唇的牛是谁?
一只没有嘴唇的牛说哞哞哞哞哞哞哞哞哞哞
在这个人工智能看来,这是最棒的笑话。也就是说,花了一些时间后,这个人工智能认为每一个笑话的包袱都应该是“哞哞哞哞哞哞哞哞哞哞”。
咚,咚
那是谁?
生菜
生菜是谁?
哈利冷哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞哞……
好吧,它又发现了一条新规律。最终,它会(我猜是极不情愿地)降低用“哞哞哞哞哞哞哞哞哞哞”作为包袱的频率。不过即便如此,这些笑话还是存在一些问题,它们很像是两个人用通话质量不佳的电话所讲的敲门笑话,也许讲笑话的人根本搞不清楚到底是谁在讲笑话:
咚,咚
那是谁?
生菜
哈利 是谁?
哈利 是谁 是谁?
是谁 是谁?
一打想很冷进来?
最终,它将会彻底找出敲门笑话的结构,开始讲一些语言上通顺,却毫无意义的笑话。它们中的大多数都是直接从笑话数据集中抄袭来的:
咚,咚
那是谁?
罗宾。
罗宾是谁?
罗宾你!饭桶是我,我要走了。
咚,咚
那是谁?
打赌
牛是谁?
牛和没有嘴唇的眼镜。
爱尔兰
爱尔兰是谁?
爱尔兰你的钱,插嘴。
在这之后,它真的讲出了一个真正的笑话。它完全是自己编写了这个笑话,没有从数据集中抄袭,这个笑话不仅可以理解,而且好像……真的很好笑?
咚,咚
那是谁?
亚历克
亚历克是谁?
亚历克——敲门笑话。
人工智能是突然间开始理解敲门笑话以及双关语的奥秘的吗?几乎可以肯定,并不是,因为数据集实在是太小了。但是,人工智能拥有的自由度——对于所有可能字符的自由驾驭——让它可以尝试字符的全新组合,然后这些尝试中的某一个最终成功了。所以,这更像是无限猴子定理的胜利,而不是说我们确实有办法建立一个只有人工智能的喜剧俱乐部。
“这是数据,你要找出一种复制它的办法。”让人工智能建立自己的规则的美妙之处在于,一种固定的方法,可以适用于许多不同的问题。如果我没给这个讲笑话的算法一堆敲门笑话,而是给它一个不同的数据集,那么它就会学习模仿这个新的数据集。
它可以发明新的鸟的种类:
尤卡坦丛林鸭
船喙太阳鸟
西部叉喙啄木鸟
黑头绒
冰岛猎手
白雪枣晨的苍鹭罗宾
或者是新的化妆品的名字:
花式十
淡香水
华丽花朵
那些姑娘
女士圣诞
甚至是新的菜谱;
常规糖霜蛤蛎
主菜及汤
1磅鸡肉
1磅猪肉,切块
½瓣蒜切碎
1杯芹菜,切片
1份酒沫(约1/2杯)
6大汤匙电动搅拌器
1茶匙黑胡椒
1个洋葱,切碎
3杯为了一个水果的牛肉汤
1份新鲜粉碎的一半一半的牛奶;值得加水
把提纯过的柠檬汁和柠檬切片放在3夸脱(约3升)的平底锅中。
加入蔬菜,在酱料中加入鸡肉,和洋葱充分搅拌。加入月桂叶,轻轻盖上并小火煨3个小时。加入土豆和胡萝卜,继续小火煨。加热直到酱料煮沸。和馅饼一起端上桌。
如果切成薄片并将甜品煮熟,然后用炒锅煮。
冰箱冷藏不超过半个小时。
产量:6份