软件 2.0

本文翻译自:https://karpathy.medium.com/software-2-0-a64152b37c35
作者: Andrej Karpathy(OpenAI 创始团队成员,原特斯拉 AI 负责人)
发布时间:2017 年 11 月 12 日。

我发现,有时候人们把神经网络简单归类为机器学习工具箱里的一种工具。神经网络确实有其优势和局限,在某些情况下效果显著,有时候还能帮助人们在 Kaggle 竞赛中获胜。但遗憾的是,这种看法忽略了神经网络的真正意义。神经网络并不仅仅是一种分类工具,它们标志着软件开发方式的一次根本性变革,代表着软件 2.0 的时代。

我们所熟悉的软件 1.0 是用 Python、C++ 等语言编写的。这类软件包含了程序员为计算机撰写的明确指令。程序员通过编写代码的每一行,标定了程序空间中某一特定点,这一点展现了某种我们期望的行为。

text

与此相反,软件 2.0 的编写语言则更加抽象且对人类不那么友好,例如神经网络中的权重。在这种情况下,人类并不直接参与代码编写,因为涉及的权重实在太多了(典型的网络可能有数百万个权重),而且直接使用权重来编码是相当困难的(我自己也尝试过)。

text

反过来,我们采取的方法是先设定一个理想程序行为的目标(比如,“满足一系列输入输出配对的示例数据集”或“赢得一局围棋游戏”),然后编写一个程序的基础架构(即一种神经网络结构),这实际上是确定了程序空间中一个需要搜索的子集。接下来,我们利用可用的计算资源在这个空间内寻找一个有效的程序。对于神经网络而言,我们将搜索范围限制在程序空间的一个连续子集内,而且有点意外的是,通过反向传播和随机梯度下降,这个搜索过程可以变得相当高效。

text

为了更明确地说明这一比喻,在软件 1.0 中,由人工编写的源代码(比如一些 .cpp 文件)会被编译成能够执行实际工作的二进制文件。而在软件 2.0 中,源代码主要包括两部分:1)定义理想行为的数据集;2)神经网络架构,它为代码提供了基本框架,但许多细节(如权重)还需要填充。神经网络的训练过程实际上是将数据集编译成二进制文件——即最终的神经网络。在当今的大多数实际应用中,神经网络架构和训练系统正在变得越来越标准化,成为一种常规产品,因此大部分积极的“软件开发”实际上变成了策划、扩充、调整和清洗已标记的数据集。这种做法从根本上改变了我们对软件进行迭代的编程范式,团队也因此分为两个部分:2.0 程序员(数据标注者)负责编辑和扩展数据集,而少数 1.0 程序员则负责维护和改进训练代码的基础设施、分析工具、可视化和标注接口。

事实上,现实世界中有很大一部分问题存在这样一个特性:收集数据(或者更泛泛地说,确定一个理想的行为模式)比直接编写程序要简单得多。正因如此,再加上我接下来会提到的软件 2.0 程序的许多其他优点,我们正在见证整个行业的一场重大转变,大量的 1.0 代码正在转化为 2.0 代码。软件(1.0)正在改变世界,现在,人工智能(软件 2.0)又在改变软件本身。

转变进行时

我们来简要探讨一些正在进行的转变的具体例子。在以下这些领域中,当我们放弃尝试通过编写明确的代码来解决复杂问题,转而将这些代码迁移到软件 2.0 架构中时,我们已经看到了近几年的显著进步。

  • 视觉识别过去主要依赖工程化的特征,最后再加上一些机器学习(比如支持向量机 SVM)。但自从我们获取了大型数据集(例如 ImageNet)并在卷积神经网络架构的空间中进行搜索后,我们发现了更强大的视觉特征。最近,我们甚至开始对这些架构进行搜索,因为我们不再完全相信自己手动编写的架构。
  • 语音识别过去需要大量的预处理、高斯混合模型和隐马尔可夫模型,但如今几乎完全由神经网络构成。Fred Jelinek 在 1985 年曾有一句经常被引用的幽默话:“每次我解雇一个语言学家,我们的语音识别系统性能就会提高”。
  • 语音合成在历史上曾采用各种拼接机制,但如今最先进的模型是大型的卷积网络(例如 WaveNet),它们可以生成原始的音频信号。
  • 机器翻译通常采用基于短语的统计方法,但神经网络正在迅速成为主流。我最喜欢的架构是在多语言环境中训练的,单一模型能够将任何源语言翻译成任何目标语言,并且在弱监督(或完全无监督)的环境中进行训练。
  • 游戏领域,人们长期以来开发了显式手工编码的围棋程序,但 AlphaGo Zero(一个查看棋盘原始状态并进行下棋的卷积网络)现在已经成为迄今为止最强的围棋玩家。我预计我们将在其他领域,如 DOTA 2StarCraft,看到非常类似的结果。
  • 数据库领域,甚至人工智能之外的更传统系统也开始显现出转型的早期迹象。例如,“学习型索引结构的案例”中,神经网络取代了数据管理系统的核心组件,在速度上比缓存优化的 B 树快了高达 70%,同时在内存使用上节省了一个数量级。

你可能会注意到,我上面提到的许多链接都涉及 Google 完成的工作。这是因为 Google 目前正处于将大量自身的代码从软件 1.0 转换为软件 2.0 的前沿。“一种模型统治一切”提供了这种转变的早期草图,其中各个领域的统计力量被融合为对世界的一致理解。

软件 2.0 的好处

为什么我们应该更倾向于将复杂程序转化为软件 2.0 呢?一个显而易见的原因是它们在实践中效果更好。但还有很多其他方便的理由让我们更喜欢这个技术栈。让我们来看看软件 2.0(想象一下:卷积网络)与软件 1.0(想象一下:生产级别的 C++ 代码库)相比的一些优点。软件 2.0 具有以下特点:

计算上的同质性。一个典型的神经网络主要由两种操作组成:矩阵乘法和零阈值(ReLU)。这与经典软件的复杂多样的指令集相比,显得更为单一和简单。你只需要为少数核心计算原语(比如矩阵乘法)提供软件 1.0 实现,这样就更容易保证各种正确性和性能。

易于集成到硅片中。由于神经网络的指令集相对较小,因此更容易将这些网络实现得更接近硅片,例如使用定制的 ASIC神经形态芯片等。当低功耗智能在我们周围普及时,世界将发生变化。比如,小型、廉价的芯片可以整合预训练的卷积网络、语音识别器和 WaveNet 语音合成网络,形成一个你可以连接到各种设备上的小型原型大脑。

恒定的运行时间。典型神经网络前向传播的每次迭代都使用相同数量的浮点运算。与庞大的 C++ 代码库中可能出现的不同执行路径相比,这里没有任何变化。当然,虽然你可能有动态计算图,但执行流通常还是相当受限的。这样我们几乎可以保证永远不会陷入意外的无限循环。

恒定的内存使用。与前者相关,由于没有任何地方使用动态分配的内存,因此几乎不会出现交换到磁盘或需要在代码中追踪的内存泄漏问题。

高度可移植性。与传统的二进制文件或脚本相比,一系列矩阵乘法在任何计算配置上都更容易运行。

非常灵活。如果你有一个 C++ 代码,有人希望你将其运行速度提高一倍(即使需要牺牲性能),这将是一个非常棘手的问题。然而,在软件 2.0 中,我们可以简单地取出网络的一半通道,重新训练,然后它就以两倍的速度运行,性能略有下降。这简直就像魔法。相反,如果你获得了更多的数据或计算资源,你可以通过增加更多通道和重新训练来立即提高程序的性能。

模块可以融合成最优整体。我们的软件通常由多个模块组成,它们通过公共函数、API 或端点进行通信。但是,如果两个原本分别训练的软件 2.0 模块发生交互,我们可以轻松地在整个系统中进行反向传播。想象一下,如果你的网页浏览器能够自动重新设计低层系统指令,深入到 10 层堆栈,以提高加载网页的效率,那会有多么神奇。或者,如果你导入的计算机视觉库(比如 OpenCV)能够针对你的特定数据自动调整。在软件 2.0 的世界里,这已经成为了默认行为。

它比你更出色。最后,也是最重要的一点,神经网络是比你或我能编写的任何代码都更高效的代码,在许多重要的领域里,至少包括图像/视频处理和声音/语音处理,这一点已经得到了证明。

软件 2.0 的缺点

软件 2.0 架构同样有着它自身的缺点。在优化过程结束时,我们得到了表现良好的庞大网络,但很难理解它们的工作原理。在众多应用领域中,我们可能会面临这样的选择:使用一种我们能理解的准确率为 90% 的模型,还是选择一种我们不理解但准确率高达 99% 的模型。

软件 2.0 架构可能以一种不直观和令人尴尬的方式失败,或者更糟糕的是,它们可能会“悄无声息地失败”。例如,它们可能无意中继承了训练数据中的偏见,这在大多数情况下非常难以适当地分析和检查,因为这些数据的规模往往达到数百万。

最后,我们还在不断发现这种架构的一些独特属性。比如,对抗性示例攻击的存在就凸显了这个架构的非直观特性。

软件 2.0 编程

软件 1.0 是我们手动编写的代码。而软件 2.0 则是由优化过程基于评估标准(如“正确地分类这些训练数据”)编写的代码。在任何程序的结构不明显,但其性能可以反复评估的情况下(例如 —— 你是否正确地分类了一些图像?你是否在围棋游戏中取得了胜利?),这种转变都极有可能发生。因为优化过程能够找到比人类编写的更优秀的代码。

text

我们用来观察趋势的视角至关重要。如果我们认识到软件 2.0 是一种新兴的编程范式,而不仅仅是将神经网络视作机器学习技术中的一种优秀分类器,那么关于这一趋势的推断就会变得更加明显,同时也意味着还有很多工作要做。

特别是,我们为辅助人类编写 1.0 代码积累了大量的工具,如功能强大的集成开发环境(IDE),提供语法高亮、调试器、性能分析器、转到定义、git 集成等功能。而在软件 2.0 架构中,编程工作主要是通过积累、调整和清理数据集来完成的。例如,当网络在某些复杂或罕见的情况下失败时,我们不是通过编写代码来修正预测,而是通过增加更多这类情况的标记示例。谁会开发出首个软件 2.0 IDE,帮助处理积累、可视化、清理、标记和获取数据集的所有工作流程?比如,这个 IDE 可能会突出显示网络怀疑标记错误的图像,基于每个样本的损失进行辅助标记,或者根据网络预测的不确定性建议标记哪些样本。

同样地,GitHub 是软件 1.0 代码的成功平台。但对于软件 2.0 来说,是否有一个类似的平台?在这种情况下,仓库是数据集,提交包括标签的添加和编辑。

像 pip、conda、docker 这样的传统包管理器和相关服务基础设施帮助我们更容易地部署和组合二进制文件。那么,我们如何有效部署、共享、导入和使用软件 2.0 二进制文件呢?神经网络的 conda 等效工具是什么?

短期来看,软件 2.0 将在任何可以重复评估且成本较低的领域变得越来越普遍,特别是在那些难以明确设计算法的领域。考虑整个软件开发生态系统以及它如何适应这种新编程范式,将是一个令人兴奋的机会。长期来看,这种范式的前景十分光明,因为越来越明显的是,当我们发展出通用人工智能(AGI)时,它肯定会使用软件 2.0 来编写。