AI智识录

Andrej Karpathy:软件2.0(Software 2.0),2017


Listen Later

Andrej Karpathy 是一位杰出的人工智能科学家和工程师,以其在深度学习领域的深刻见解闻名。他曾担任特斯拉的AI总监,领导开发自动驾驶系统 Autopilot 的核心视觉技术,也是 OpenAI 的创始成员之一,深度参与了前沿AI的研究。除了在工业界的巨大成就,他也是一位极具影响力的教育家。他在斯坦福大学开设的课程 CS231n被公认为该领域的经典入门课。

他最著名的思想贡献是提出了“软件2.0”这一概念,清晰地阐述了神经网络正在从根本上改变软件的开发方式——从人类编写精确指令,转向通过数据和优化来“发现”程序。这使他不仅被看作是一位技术专家,更是一位能够洞察行业发展范式的思想者。

原文链接:karpathy.medium.com

以下是全文翻译:

我有时会看到人们将神经网络称为“你机器学习工具箱里的又一个工具”。它们有其优缺点,在某些场景下适用,有时你可以用它们来赢得 Kaggle 比赛。然而,不幸的是,这种解读完全是只见树木,不见森林。神经网络不仅仅是又一种分类器,它们代表了我们开发软件方式的一次根本性转变的开端。它们就是软件 2.0

软件 1.0 的“经典技术栈”是我们都所熟悉的——它由 Python、C++ 等语言编写。它包含了由程序员写给计算机的明确指令。通过编写每一行代码,程序员在巨大的程序空间中,定位到一个具有某种期望行为的特定点。

相比之下,软件 2.0 是用一种更为抽象、对人类不友好的语言编写的,例如神经网络的权重。没有人类参与编写这种代码,因为权重数量极其庞大(典型的网络可能有数百万个),而且直接用权重编码是相当困难的(我试过)。

取而代之,我们的方法是为期望的程序行为指定一个目标(例如,“满足一个由输入输出样本对组成的数据集”,或者“赢得一盘围棋比赛”),编写一个粗略的代码骨架(即神经网络架构)来确定一个要搜索的程序空间的子集,然后利用我们可支配的计算资源在这个空间里进行搜索,以找到一个有效的程序。在神经网络的案例中,我们将搜索范围限制在程序空间的一个连续子集内,在这个子集里,通过反向传播和随机梯度下降,搜索过程可以变得(有些出人意料地)高效。

为了让这个类比更清晰:在软件 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)并在卷积神经网络(CNN)架构的空间中进行搜索,我们发现了强大得多的视觉特征。最近,我们甚至不再相信自己能手动编码架构,而是开始对架构本身进行搜索。
  • 语音识别 过去涉及大量的预处理、高斯混合模型和隐马尔可夫模型,但如今几乎完全由神经网络构成。与此相关,有一句常被引用的、源于 1985 年的幽默名言,据说是 Fred Jelinek 说的:“每当我解雇一名语言学家,我们的语音识别系统性能就会提升。”
  • 语音合成 历史上一直采用各种拼接机制,但如今最先进的模型是大型卷积网络(例如 WaveNet),它们能直接生成原始的音频信号输出。
  • 机器翻译 通常采用基于短语的统计技术,但神经网络正迅速成为主导。我最喜欢的架构是在多语言环境下训练的,单一模型可以从任何源语言翻译到任何目标语言,并且是在弱监督(或完全无监督)的环境下进行的。
  • 游戏 人类明确手写的围棋程序已经开发了很长时间,但 AlphaGo Zero(一个观察棋盘原始状态并走棋的卷积网络)现在已经成为目前为止最强的围棋选手。我预计我们将在其他领域看到非常相似的结果,例如 DOTA 2 或星际争霸。
  • 数据库 人工智能之外的更传统系统也出现了转型的早期迹象。例如,“The Case for Learned Index Structures” 一文用神经网络取代了数据管理系统的核心组件,其速度比缓存优化的 B-Tree 快 70%,同时节省了一个数量级的内存。

你会注意到,我上面提到的许多链接都涉及到在谷歌完成的工作。这是因为谷歌目前正处于将自身大量代码重写为软件 2.0 的前沿。“一个模型统治一切”(One model to rule them all)提供了一个早期蓝图,展示了这种模式的未来:将各个领域的统计优势融合起来,形成对世界的一个统一连贯的理解。

软件 2.0 的好处

我们为什么应该倾向于将复杂的程序移植到软件 2.0?显然,一个简单的答案是它们在实践中效果更好。然而,还有很多其他便利的原因让我们更偏爱这个技术栈。让我们来看看软件 2.0(可以想象成一个卷积网络)相比于软件 1.0(可以想象成一个生产级的 C++ 代码库)的一些好处。软件 2.0 是:

  • 计算同质化 (Computationally homogeneous)。一个典型的神经网络,从宏观上看,只由两种运算层层叠加而成:矩阵乘法和零点阈值(ReLU)。相比之下,传统软件的指令集要异构和复杂得多。因为你只需要为少数核心计算原语(例如矩阵乘法)提供软件 1.0 的实现,所以更容易做出各种正确性/性能的保证。
  • 易于固化到芯片中 (Simple to bake into silicon)。作为推论,由于神经网络的指令集相对较小,将这些网络更紧密地实现在芯片上要容易得多,例如使用定制的 ASIC、神经形态芯片等等。当低功耗的智能在我们周围变得无处不在时,世界将会改变。例如,小而便宜的芯片可以内置一个预训练好的卷积网络、一个语音识别器和一个 WaveNet 语音合成网络,所有这些都集成在一个你可以附加到任何东西上的小型“原始大脑”中。
  • 恒定的运行时间 (Constant running time)。典型的神经网络前向传播的每一次迭代都消耗完全相同的浮点运算次数(FLOPS)。代码不会因为通过庞大的 C++ 代码库时走了不同的执行路径而产生任何变化。当然,你也可以有动态计算图,但执行流程通常仍然受到很大限制。这样,我们也几乎可以保证永远不会陷入意料之外的无限循环。
  • 恒定的内存使用 (Constant memory use)。与上一点相关,代码中没有任何动态分配的内存,所以也几乎不可能出现需要换页到磁盘的情况,或者需要你在代码中到处寻找的内存泄漏。
  • 高度可移植 (It is highly portable)。相比于传统的二进制文件或脚本,一系列的矩阵乘法在任意计算配置上运行起来要容易得多。
  • 非常敏捷 (It is very agile)。如果你有一个 C++ 代码库,有人想让它快一倍(如有必要,可以牺牲性能),那么要为这个新规格调整系统将是非常不平凡的。然而,在软件 2.0 中,我们可以拿来我们的网络,去掉一半的通道,重新训练,然后——它就以两倍的速度运行,效果差一点点。这简直是魔法。反之,如果你碰巧获得了更多的数据/计算资源,你只需增加更多通道并重新训练,就可以立即使你的程序效果变得更好。
  • 模块可以融合成一个最优的整体 (Modules can meld into an optimal whole)。我们的软件通常被分解为通过公共函数、API 或端点进行通信的模块。然而,如果两个最初分开训练的软件 2.0 模块进行交互,我们可以轻易地在整个系统中进行反向传播。想象一下,如果你的网页浏览器能够自动重新设计底层第 10 层的系统指令,以实现更高的网页加载效率,那该有多神奇。或者,如果你导入的计算机视觉库(如 OpenCV)可以根据你的特定数据进行自动调优。对于 2.0 来说,这是默认行为。
  • 它比你更强 (It is better than you)。最后,也是最重要的一点,在一个很大部分有价值的垂直领域,神经网络是一段比你或我能写出的任何代码都要好的代码。这些领域目前至少包括与图像/视频和声音/语音相关的一切。
软件 2.0 的局限性

2.0 技术栈也有它自己的一些缺点。在优化的最后,我们得到的是一些效果很好的大型网络,但很难说清楚它们是如何工作的。在许多应用领域,我们将面临一个选择:是使用一个我们能理解的、准确率 90% 的模型,还是一个我们不理解的、准确率 99% 的模型。

2.0 技术栈可能会以一些不合直觉、令人尴尬的方式失败,或者更糟的是,它们会“静默失败”,例如,悄悄地继承了训练数据中的偏见,而当模型规模动辄数百万时,要恰当地分析和检查这些偏见是非常困难的。

最后,我们仍在探索这个技术栈的一些奇特属性。例如,对抗性样本和攻击的存在,突显了这种技术栈的不直观性。

在 2.0 技术栈中编程

软件 1.0 是我们写的代码。软件 2.0 是优化过程根据一个评估标准(例如“正确分类这些训练数据”)写出的代码。很可能,任何程序逻辑不明显、但可以反复评估其性能的场景(例如——你是否正确分类了一些图像?你是否赢得了围棋比赛?)都将经历这种转型,因为优化过程能找到比人类写出的好得多的代码。

我们看待趋势的视角至关重要。如果你认识到软件 2.0 是一种新兴的编程范式,而不仅仅是把神经网络看作是机器学习技术中的一个相当不错的分类器,那么未来的推演就变得更加清晰,而且很明显,还有更多的工作要做。

具体来说,我们已经建立了大量的工具来帮助人类编写 1.0 代码,例如功能强大的集成开发环境(IDE),具有语法高亮、调试器、性能分析器、函数跳转、git 集成等功能。在 2.0 技术栈中,编程是通过积累、处理和清洗数据集来完成的。例如,当网络在某些困难或罕见的情况下失败时,我们不是通过写代码来修复这些预测,而是通过加入更多这些情况的标记样本。谁将会开发出第一批软件 2.0 的 IDEs,来帮助完成积累、可视化、清洗、标注和采购数据集的全部工作流程?也许这个 IDE 会主动提示那些网络根据单一样本损失怀疑被错误标注的图像,或者通过用预测结果来预填充标签来辅助标注,或者根据网络预测的不确定性来建议有用的待标注样本。

同样,Github 是软件 1.0 代码非常成功的家园。那么是否存在一个软件 2.0 的 Github 空间呢?在这种情况下,代码仓库就是数据集,而提交(commit)则由标签的增添和编辑构成。

在短期内,软件 2.0 将在任何可以进行廉价、重复评估,并且算法本身难以明确设计的领域变得越来越普遍。思考整个软件开发生态系统,以及如何使其适应这种新的编程范式,存在着许多激动人心的机会。而在遥远的未来,这个范式的未来是光明的,因为越来越清楚的是,当我们开发出通用人工智能(AGI)时,它必然是用软件 2.0 编写的。

...more
View all episodesView all episodes
Download on the App Store

AI智识录By RayHu