编者按:随着近年来深度学习取得的突破,其应用也开始不断开疆拓土。比方说在图像识别、语音识别乃至于围棋游戏等方面AI都已经比人厉害。但是这些大部分是把神经网络当成分类器来用。Tesla AI 总监,OpenAI前研究科学家Andrej Karpathy认为这种看法是一叶障目,其实神经网络的作用比这要大得多,它将是我们编写软件方式变革的开始,跟它引领的软件2.0相比,传统程序员写出来的代码将没有任何优势。而且我们如果将来能实现通用人工智能的话,一定会是软件2.0写出来的。
我有时候看见有人把神经网络称为是“你的机器学习工具箱的又一个工具”。我们认为这东西有利有弊,有时候你可以用来赢下Kaggle竞赛(注:大数据竞赛平台,已被Google收购)。不幸的是,这种解释完全是只见树木不见森林。神经网络不仅仅只是又一个分类器,而且还代表了我们编写软件方式的一个根本性转变的开始。它们是软件2.0。
软件1.0的“典型技术栈”我们都很熟悉——筒仓都是用我们熟悉的语言比如Python、C++等编写的。它包含有明确指令,那是程序员写给计算机的。但程序员写下的每一行代码都是在程序空间中一个特定的点,会产生某种我们希望看到的行为。
软件2.0就不一样,它是用神经网络权值编写的。这一代码的编写过程并没有任何人的参与,因为权值太多了(通常会有几百万),而且直接对权值进行编码是比较困难的(我试过)。相反,我们对想要的程序的行为指定了一些约束(比如样例输入输出对的数据集),然后利用我们可以调配的计算资源在程序空间中寻找能满足该约束的程序。在神经网络的情况下,我们把搜索限制在该程序空间的连续子集里面,通过反向传播和随机梯度下降搜索过程可以非常有效(多少有点令人惊讶)。
结果表明,很大一部分的现实世界问题都具备那种属性,即收集数据要比显式编程容易得多的属性。将来很大一部分的程序员都不在需要维护复杂的软件库,编写犬牙交错的程序或者分析其运行时。他们的工作将变成收集、清洗、操纵、标记和分析提供给神经网络的数据,并对其进行可视化。
软件2.0不会取代1.0(的确,“编译”2.0代码需要大量1.0的基础设施来进行训练和推理),但会逐步接管软件很大一部分过去是1.0负责的事。我们可以看看其中一些具体的例子:
视觉识别过去一般包含有一些设计好的功能,最好再加上一点机器学习的东西(比如SVM)。从此之后,我们开发出发现更强大图像分析程序的机制(ConvNet架构家族),最近我们已经开始搜索架构了。
语音识别过去往往牵涉到大量处理,高斯混合模型以及隐马尔科夫模型,但今天的语音识别几乎全都是神经网络的东西。
语音合成过去一度采用了各种拼接机制,但今天的最新模型是可生成裸音频信号输出的大型卷积网络(比如WaveNet)。
机器翻译过去曾经采用基于短语的统计技术,但神经网络正在迅速占据统治地位。我喜欢的架构是在多语言设定中受训的,也就是一个单模型可以将任何源语言翻译成任何目标语言,并且监督很少(或者彻底无监督)。
机器人有着悠久的问题分解传统,也就是把问题分解为传感模块、姿态估计、规划、控制以及不确定建模等,利用的是显式表示和算法而不是中间表示。我们跟目标还有相当的距离,但加州大学伯克利分校和Google的研究已经在提示我们,在表示所有这些代码方面,软件2.0也许能够做得好很多。
游戏。围棋程序久已有之,但AlphaGo Zero (一种查看棋盘裸状态然后走一步棋的卷积网络)现在已经成为有史以来最强大的围棋程序。我预计我们即将在DOTA2或者星际争霸等领域看到类似的结果。
你也许会注意到上述很多工作都是在Google完成的。这是因为在用软件2.0代码重写自身大部分这件事情上,Google目前走在最前列。“统治一切的模型”让我们对这种做法未来可能的样子可以先睹为快,那就是个体领域的统计强度被融入到对世界的一致理解当中。
为什么我们应该优先考虑将复杂程序移植到软件2.0?一个容易想到的答案显然是在实践中它表现得更出色。然而,优选这种技术栈还有很多其他的便利性理由。下面我们就来看看其中一些软件2.0的好处:
计算同构性。典型的神经网络是由两种操作构成的:矩阵乘法以及阈值转换(ReLU)。这跟典型软件的指令集相比,后者异构性显然更强且更复杂。由于你只需要针对少量核心计算基元(比如矩阵乘法)提供软件1.0的实现,保证程序的正确性/性能会变得容易许多。
容易变成硬件。作为推论,既然神经网络的指令集相对较小,把该网络实现成更接近硅片的东西,比如定制化ASIC、神经形态芯片等就容易多了。当低功耗智能变得无所不在时,世界也会发生改变。比方说,小型廉价的芯片可以内置预先训练好的ConvNet、语音识别器,WaveNet语音合成网络等,所有这些都可以集成到一个小型的ProtoBrain(游戏《最高指挥官》中信息大脑化地球人的原脑)内,然后附着到任何东西上面。
恒定的运行时。典型神经网络每一次迭代的争相传递都需要完全相同的FLOPS(浮点运算时间)。不管你的代码在庞大的C++代码库中的执行路径怎么变,其可变性依然为0。当然,你的计算图可能是动态的,但执行流通常仍然受到显著约束。这样一来我们几乎就能保证永远也不会陷入到意外的无限循环之中。
恒定的内存使用。这条跟上一条相关,由于没有了任何动态分配的内存,所以交换到磁盘,或者内存泄露这些导致你需要对代码追根溯源的可能性也几乎没有了。
高度可移植。相对于典型的二进制或者脚本,矩阵乘法序列在任何计算配置中运行起来都要容易得多。
非常敏捷。如果你的程序是C++代码,有人希望你把它的执行加快一倍(必要的话可以性能为代价)的话想把系统调优到新的要求是非常困难的。不过在软件2.0中我们可以把神经网络的通道撤掉一半然后重新进行训练——这样一来网络的速度就可以提高1倍,只是表现会稍微糟糕一点。这简直就像变魔法一样。相反,如果你正好拿到了更多的数据/计算,你马上就能通过追加通道然后对网络进行再训练来让程序表现更出色。
模块可以融合实现全局最优。我们的软件往往解耦为通过公共函数、API或者端点相互通信的模块。然而,如果两个原先是独立训练的软件2.0模块交互的话,我们很容易就可以通过整体来进行反向传播。如果你可以对web浏览器10层以下的底层系统指令自动进行重新设计来实现页面加载的更高效率的话,想想看这会有多么惊艳。有了2.0,这将变成默认之举。
很容易学。我喜欢开玩笑说深度学习很肤浅。它不是核物理,需要你有博士学位才能做出点有用的东西来。其基本概念只需要一点基础的线性代数、微积分、Python,然后听听CS231n的课程即可。当然,大量的专业知识和直觉掌握起来是需要时间的,所以准确点的说法是软件2.0技术栈入门容易精通很难。
比你厉害。最后,也是最重要的一点,在很大一部分的有价值的垂直领域应用中,至少在图像/视频,语音/语言以及文本方面,神经网络要比你我任何人能想出的代码都要好。
2.0技术栈也存在一些缺点。优化到最后我们会得到一个工作得很好的大型神经网络,但是我们却很难说出它是怎么做到的。在很多的应用领域中,我们都只能在我们可以理解的精确度为90%的模型与我们无法理解但精确度达到99%的模型之间做出选择。
2.0技术栈可能会以不够直观且令人尴尬的方式失效,或者更糟,2.0软件可能会“悄悄地失效”,比方说默默地接受训练数据中的偏见,这个是很难进行正确的分析和检查的,因为大多数情况下其规模都会轻易达到数百万之巨。
最后,我们还在探索这一技术栈的某些特殊属性。比方说,对抗和攻击例子的存在就聚焦了这一技术栈的不直观性。
如果你把神经网络看成是软件栈而不是仅仅只是个很好的分类器的话,很快你就会发现它在变革整个软件方面具有庞大的优势和潜能。
从长期来看,软件2.0的未来是光明的,因为很多人都越来越清楚,如果有朝一日我们能开发出AGI(通用人工智能)的话,那一定是用软件2.0写成的。
软件3.0会是啥样?那就完全得看AGI了。
原文链接:https://medium.com/@karpathy/software-2-0-a64152b37c35
编译组出品。编辑:郝鹏程。