从I到R:人工智能语言简史
整理 | apddd
出品 | AI科技大本营(ID:rgznai100)
语言的界限就是我与世界的界限。——维特根斯坦编程语言之所以能持续吸引新用户,大多并非源于语言自身特性,而是因其成为了某种流行系统的一部分。AI编程语言的历史亦大抵如此。
史前时代
高级语言出现前,人们就已经在开发复杂的AI应用程序,比如IPL(Information Processing Language),仅比机器语言略高级(国际象棋程序NSS、Logic Theorist和General Problem Solver,都是使用IPL在IBM计算机上开发)。
IPL引入的大量特性如今仍在使用,比如列表、递归、高阶函数、符号,甚至能将元素列表映射到一个迭代并处理该列表的函数的生成器。
尽管IPL大获成功并广泛部署在当时的计算机架构上,但它很快被一种更高级的语言所取代,在几乎60年后仍在使用。
LISP叱咤六十年
彼时,许多AI问题都被视为搜索问题,1956年,John McCarthy创建了一种称为alpha-beta剪枝的树搜索剪枝模式。资源有限的早期计算机系统上,内存和计算能力受到严重限制,但这项技术,使开发人员能编写逻辑复杂的程序。当时AI游戏应用程序,普遍应用了alpha-beta剪枝算法。
LISP是从AI研发中孕育出来的——因为AI对应用程序有独特需求,不断有语言被创造出来。
这年8月的达特茅斯会议,虽没有达成普遍的共识,但是却为会议讨论的主题起了一个名字:人工智能。因此,1956年也被称为人工智能元年。
达特茅斯会议之后,McCarthy致力于为AI工作开发一种专注于IBM 704平台的语言(IBM是当时对AI研究有大量资助)。1957年,在同一平台上引入了FORTRAN,而IBM用一种称为FORTRAN List Processing Language (FLPL) 的语言将FORTRAN扩展用于列表处理,成功用于IBM的平面几何学项目,但作为FORTRAN的扩展,FLPL缺少一些关键特性,例如递归、条件表达式。
LISP的演化,经历了三个阶段:
1. 1956至1958年夏天,John McCarthy完成了对LISP的大部分构想(部分基于FLPL)。
作为编程语言,McCarthy在设计LISP时,遵循的主要原则包括:
- 使用符号表达式(symbolic expression),而非数值(number)计算——创新之处还在于,舍弃了人们熟悉的中缀表示法,而以前缀表示法代之,这样可以简化逻辑、代数运算,否则得额外加入一个翻译程序——在编写大型程序时,这种设计令LISP较同一时代的其他几种符号语言(如SNOBOL)更具优势。
McCarthy后来评价道:“这个明智的选择,好比计算机采用二进制而非十进制,并且有过之无不及。”这是种违反直觉的表达方式,在当时能够被接受,也是因为1950年代,在计算机上输入和输出与今天大不相同(穿孔卡片,而非更直观的显示器),那时的程序员们不大在意前缀还是中缀。
- 符号表达式及其他信息,都以“列表”(list)结构,储存在内存中——这样才能既像句子一样表达信息,又适合作为程序代码精确执行,进行逻辑演绎;
- 在外部媒介,以多重列表和S-expression表示信息;
- 函数由一小组选择和构造操作组成;
- 构造函数用于组成更复杂的函数;
- 由条件表达式选择函数执行的分枝,条件表达式的布尔值,可起到连接程序的作用;例如(M, N1, N2)——依据M的取值,执行N1或N2,其优点在于缩短了代码,并提高了可读性
- 函数中引入递归条件表达式;
- 使用Lambda表达式为函数命名——以使函数可匿名优雅地作为参数递归调用——McCarthy曾说:“Church的书其余部分我都没读懂,因此只借用了这么一个概念,而没照搬他那套更通用的机制来定义函数。比如Church就不是用条件表达式——但对计算机来说,条件表达式反而顺理成章。”
- LISP程序亦是LISP数据;
- eval既是函数,也是解释器;
- 引入垃圾回收机制;
- 数学上简洁也是语言的设计目标,因而要克制语言核心功能。
这些原则多数由LISP原创。而且仅用quote、atom、eq、car、cdr、cons和cond七个操作符构造,令它既成为优雅的数学系统(对于可计算函数,以及递归,比图灵机和当时的递归函数理论都要简洁得多),又是实用的编程语言。从语言角度看,这是它经久不衰的原因之一(仍在广泛使用,仅次于FORTRAN,第二古老的高级编程语言)。
在千禧年伊始,曾将LISP重新带回大众视野的YC创始人Paul Graham这样评价:“McCarthy对编程的贡献,有如欧几里德对几何的贡献。……与其说LISP是他的设计,不如说是他的发现。”
2. 1958年秋,至1962年,语言被真正实现,并开始应用于AI
McCarthy最初的设想,是开发一个编译器,但在当时的技术条件下,编译器是个大工程,要先做些验证工作,例如子程序链接、堆栈的处理、擦除之类的大致范本。于是McCarthy的第一步,是手工把函数翻译成汇编语言,以及子程序,完成一个可以读取、打印list结构的“LISP环境”。
代码起初使用M-expressions语法(现代语言中,如果你用过Mathematica/Wolfram,就是这种语法),为的是与FORTRAN尽可能接近,而现代LISP使用S-expression:
M-expressions表示函数和参数 f[x;y]
S-expressions表示函数和参数 (f x y)
第一个LISP实现,是Steve Russell在IBM 704上实现的,他用更低阶的机器语言编写了通用求值器,这样在解释器里,就可以运行LISP程序了——REPL(读取-求值-输出循环,越来越多现代编程语言开始包含这个功能)。
现代LISP方言里,仍在使用的car(返回列表的第一项)和cdr(返回列表第一项之后的其他项)(读音分别为:/kɑːr/和/ˈkʊdər/)两个操作符,是IBM 704汇编语言的两个宏。
提到Steve Russell,他还和同学编写了视频游戏的始祖《Spacewar!》,另外,当年他还是湖畔中学编程小组两位同学Bill Gates和Paul Allen的指导老师。
LISP 1.5是第一个被广泛使用的版本,1962年,由McCarthy和他在MIT的同事完成。
3. 1962年之后,多种LISP标准出现,不同领域融入了不同想法
1968年,MIT的Terry Winograd(后来他去了斯坦福大学,还成了Google创始人之一Larry Page的PhD导师)用LISP开发了一个开创性的程序SHRDLU( http://hci.stanford.edu/winograd/shrdlu/ ),能使用自然语言与用户进行交互。
程序代表着一个积木世界,用户可以与该世界进行交互:“拿起大个儿红色积木”、“一块积木能否支撑锥体?”。这个积木世界中的自然语言理解和规划的演示,让当时的人们对AI和LISP语言抱有极大希望。
作为编程语言,LISP 1.5有诸多限制,比如数值计算非常缓慢,用寄存器块表示对象,以及GC都没实现,而对AI研究来说,当时科研机构里最流行的PDP-10处理能力和内存也都已经无法胜任,LISP 2和之后出现的硬件——Lisp Machine工作站修正了这些问题。
Lisp Machine商业价值巨大,众多产品中,从MIT AI Lab分化的商业品牌Symbolics对后人的影响最深远——不单因为symbolics.com是第一个.com域名,它的商业化过程,也是黑客文化的分水岭,MIT黑客社区开放合作的文化几乎因此终结,作为反抗Richard Stallman发起GNU。
冬眠与新生命
1974至1993年是AI开发和资助的一个不稳定时期。其中1980年,专家系统曾经短暂重燃了人们对AI的关注并带来了资金。这段时间,LISP继续被用在一系列应用中,通过各种方言得到传播——主要靠着Common LISP、Scheme、Clojure和Racket生存了下来。
LISP背后的概念继续通过这些语言和其他语言而扩展到了函数领域之外,例如LISP继续为最老的计算机代数系统Macsyma(由MIT AI小组开发)提供支持,是Mathematica、Maple的鼻祖。
但这个时期孕育出了新的方法,比如连接机制方法再次兴起,以及新的神经网络方法提出,AI研究走入近代。
LISP方言激增(流行的有Maclisp、ZetaLisp、NIL等),导致了名为Common LISP出现,该语言主要改良自MacLisp,集当时的流行方言特性之大成。1994年,Common LISP被批准为美国国家标准协会X3.226-1994标准。
在这个时间段,其他语言开始相继出现,它们不一定专注于AI,但推动了AI的发展。C语言是专为UNIX系统设计的的一种系统语言,但它很快发展为一种最流行的语言(具有各种变体,比如 C++),从系统到嵌入式设备开发都在使用它。
计算架构和AI理论都发生了变化,在AI应用上,LISP已经不是唯一选择,C/C++、Prolog都颇受欢迎,例如深蓝的核心用C编写,Watson解析自然语言部分用的是Prolog(读者们熟悉的AlphaGo主要以C++和Lua写成)。
一种名为Prolog (Programming in Logic)的关键语言在法国开发出来。该语言实现了一个称为霍恩子句的逻辑子集,它允许使用事实和规则来表示信息,而且允许对这些关系执行查询。下面的简单Prolog示例演示了如何定义一个事实(苏格拉底是一个凡人)和一条规则(规定凡人终有一死):
man( socrates ). // Fact: Socrates is a man.
mortal( X ) :- man( X ). // Rule: All men are mortal.
Prolog继续被用在各种领域,而且拥有许多变体,这些变体合并了诸多特性,比如面向对象、编译为原生机器码的能力,以及流行语言(如 C)的接口。
Prolog在这段时间的关键应用之一是开发专家系统。这些系统支持将知识整理为事实,然后利用一些规则基于此信息进行推理。这些系统的问题在于,它们很脆弱,而且将知识保留在系统中既麻烦又容易出错。
Prolog和LISP 不是唯一用于开发生产系统的语言。1985年,C语言集成生产系统 (CLIPS) 被开发出来,成为了构建专家系统使用最广泛的系统。CLIPS在一个由规则和事实组成的知识系统上运行,但它是用C编写的,而且提供了一个C扩展接口来提高性能。
专家系统的失败是导致第二个AI寒冬来临的一个因素。它们的前景和交付能力的缺乏导致AI研究资金显著减少。但是,这个灰色时期孕育出了新的方法,比如连接机制方法再次兴起,并让我们进入了近代时期。
近代时期
AI的近代时期开始从实用的角度考虑该领域,而且非常成功地将AI方法应用到实际问题上,包括AI历史发展初期的问题。尽管新语言被应用来解决AI问题,但AI的主力(LISP和Prolog)继续得到应用并取得成功。在这个时代,连接机制和新的神经网络方法也再次兴起。
在这个时期,多样化的编程语言开始出现,一些基于计算机科学中的新概念,另一些基于关键特征(比如多泛型和容易学习)。Python属于后一种类别的关键语言。它是一种通用解释型语言,它包含来自许多语言的特性(比如面向对象特性和受LISP启发的函数特性)。
Python在智能应用程序开发中的实用之处在于,在该语言外有许多模块可用。这些模块涵盖了机器学习(scikit-learn、Numpy)、自然语言和文本处理 (NLTK),以及包含广泛的拓扑结构的许多神经网络库。
R语言(以及使用它的软件环境)大抵遵循Python模型。这是一种用于统计编程和数据挖掘的开源环境,使用C语言开发。
因为大量现代机器学习实质上是统计性的,所以使用R有颇多便利,自2000年发布稳定版本以来越来越受欢迎。R包括大量的涵盖各种技术的库,还包括使用新特性扩展该语言的能力。
随着回归到连接机制架构,新应用应运而生,改变了图像和视频处理和识别的局面。深度学习被用于识别图像或视频中的物体,通过自然语言提供图像或视频的文本描述,甚至通过实时检测道路和物体为自动驾驶车辆铺平道路。其网络可能非常庞大,以至于传统计算架构无法高效处理。但通过引入图形处理单元 (GPU),现在可以应用这些网络。
此时,需要使用新的语言将传统CPU和GPU结合起来。Open Computing Language (OpenCL) 的开放标准语言允许在包含数千个处理单元的GPU上执行类似C或C++的程序,并允许通过CPU统筹安排GPU内的操作并行性。
结语
影响语言兴衰的另一股暗流,是流水线般的现代软件产业,它令一切工程朝着这样的方向一去不返——工程师需要像零部件一样,随时可被替代,员工通过培训即可上岗,再强大的编程语言亦无法抵抗这股潮流,然而所谓的“工业最佳实践”,对开发字处理软件,与构建精巧的思维系统是一回事吗?
(本文为 AI科技大本营整理文章,转载请微信联系 1092722531。)