软件2.0(2017)

2020-07-09 03:45:26

我有时看到人们将神经网络称为“机器学习工具箱中的另一个工具”。他们有一些利弊,他们在这里或那里工作,有时你可以用他们来赢得卡格尔比赛。不幸的是,这种解释完全忽略了森林而忽视了树木。神经网络不仅仅是另一个分类器,它们代表着我们编写软件的方式发生根本性转变的开始。它们是软件2.0。

软件1.0的“经典堆栈”是我们都熟悉的-它是用Python、C++等语言编写的。它由程序员编写的对计算机的显式指令组成。通过编写每一行代码,程序员可以用一些所需的行为来标识程序空间中的特定点。

相比之下,软件2.0可以用更抽象的、人类不友好的语言来编写,比如神经网络的权重。没有人参与编写这段代码,因为有很多权重(典型的网络可能有数百万个权重),直接用权重编码有点困难(我试过了)。

取而代之的是,我们的方法是指定关于期望的程序的行为的某个目标(例如,“满足输入输出示例对的数据集”,或者“赢得围棋的游戏”),编写代码的粗略骨架(例如,神经网络结构),其标识要搜索的程序空间的子集,并且使用我们可以支配的计算资源来搜索该空间以寻找能够工作的程序。在神经网络的特定情况下,我们将搜索限制在程序空间的连续子集内,其中搜索过程可以通过反向传播和随机梯度下降而变得有效(有点令人惊讶)。

事实证明,现实世界中的很大一部分问题都具有这样的特性,即收集数据(或者更一般地说,识别所需的行为)要比显式编写程序容易得多。在这些情况下,程序员将被分成两个团队。2.0程序员手动管理、维护、按摩、清理和标记数据集;每个标记的示例都对最终系统进行编程,因为数据集通过优化被编译成软件2.0代码。同时,1.0程序员维护周围的工具、分析、可视化、标记界面、基础设施和培训代码。

让我们简要地研究一下这种正在进行的过渡的一些具体示例。在过去几年中,当我们放弃尝试通过编写显式代码来解决复杂问题,转而将代码过渡到2.0堆栈时,在这些方面我们都看到了改进。

视觉识别过去是由一些工程化的特征组成的,最后在顶部撒上一点机器学习(例如,支持向量机)。从那时起,我们通过获取大数据集(例如ImageNet)和在卷积神经网络结构空间中进行搜索,发现了更强大的视觉特征。最近,我们甚至不相信自己可以手工编写架构代码,而且我们也开始搜索这些架构。

语音识别过去涉及到大量的预处理、高斯混合模型和隐马尔可夫模型,但现在几乎完全由神经网络组成。1985年,弗雷德·耶利内克(Fred Jelinek)引用了一句非常相关、经常被引用的幽默名言:“每当我解雇一位语言学家,我们的语音识别系统的性能就会提高”。

语音合成历史上采用各种拼接机制,但今天最先进的模型是产生原始音频信号输出的大型ConvNet(例如,WaveNet)。

机器翻译通常采用基于短语的统计技术,但神经网络正在迅速占据主导地位。我最喜欢的架构是在多语言环境中接受培训的,在多语言环境中,单个模型可以从任何源语言转换为任何目标语言,也可以在弱监督(或完全无监督)环境中进行翻译。

玩游戏。显式手工编写的围棋程序已经开发了很长一段时间,但AlphaGo Zero(一种查看棋盘原始状态并下一步棋的ConvNet)现在已经成为该游戏中最强大的棋手。我预计我们将在其他领域看到非常类似的结果,例如DOTA 2,或星际争霸。

数据库。人工智能以外的更传统的系统也看到了过渡的早期迹象。例如,“学习索引结构的情况”用神经网络取代了数据管理系统的核心组件,在速度上比高速缓存优化的B-tree高出70%,同时节省了一个数量级的内存。

你会注意到我上面的很多链接都涉及到在谷歌完成的工作。这是因为谷歌目前正站在将自己的大量代码重写成软件2.0代码的前沿。“一种模式统治所有人”提供了这可能是什么样子的早期草图,在这种情况下,各个领域的统计实力被合并成对世界的一种一致的理解。

为什么我们应该更愿意将复杂的程序移植到软件2.0中呢?显然,一个简单的答案是,它们在实践中效果更好。但是,更喜欢这个堆栈还有很多其他方便的原因。让我们来看看与软件1.0(考虑:生产级C++代码库)相比,软件2.0(想一想:一个ConvNet)有哪些好处。软件2.0是:

在计算上是同质的。典型的神经网络在一阶上只由两种运算组成:矩阵乘法和零阈值(REU)。与经典软件的指令集相比,经典软件的指令集具有明显的异构性和复杂性。因为您只需要为一小部分核心计算原语(例如矩阵乘法)提供软件1.0实现,所以做出各种正确性/性能保证要容易得多。

很容易烤成硅。作为推论,由于神经网络的指令集相对较小,因此更接近硅(例如,使用定制ASIC、神经形态芯片等)来实现这些网络要容易得多。当低能智能在我们周围变得无处不在时,世界将会改变。例如,小而便宜的芯片可以带有预先训练的ConvNet、语音识别器和WaveNet语音合成网络,所有这些都集成在一个可以连接到东西上的小原脑中。

恒定的运行时间。典型的神经网络前传的每一次迭代都需要完全相同数量的FLUPS。根据您的代码通过一些庞大的C++代码库可能采用的不同执行路径,没有可变性。当然,您可以使用动态计算图,但是执行流通常仍然受到很大的限制。这样,我们几乎可以保证永远不会发现自己处于意想不到的无限循环中。

持续的内存使用。与上述相关的是,任何地方都没有动态分配的内存,因此交换到磁盘的可能性也很小,或者您必须在代码中查找的内存泄漏。

它非常便携。与传统的二进制或脚本相比,矩阵乘法序列在任意计算配置上运行要容易得多。

它非常敏捷。如果您有一个C++代码,并且有人希望您将其速度提高一倍(如果需要,会以牺牲性能为代价),那么针对新规范调优系统将是非常重要的。然而,在软件2.0中,我们可以使用我们的网络,删除一半的信道,重新训练,然后就可以了-它的运行速度正好是原来的两倍,而且工作得稍差一些。这是魔术。相反,如果您碰巧获得了更多的数据/计算,只需添加更多通道和再培训,您就可以立即使您的程序工作得更好。

模块可以融合成一个最佳的整体。我们的软件通常被分解成通过公共函数、API或端点进行通信的模块。但是,如果最初单独培训的两个软件2.0模块相互作用,我们可以很容易地通过整体进行反向传播。想想看,如果你的网络浏览器能够自动重新设计10个堆叠下来的低级系统指令,以达到更高的网页加载效率,那该是多么令人惊叹。在2.0中,这是默认行为。

比你强多了。最后,也是最重要的一点是,在很大一部分有价值的垂直领域中,神经网络是比你或我能想出的任何代码更好的一段代码,目前这些垂直领域至少涉及任何与图像/视频和声音/语音有关的内容。

2.0堆栈也有自己的一些缺点。在优化结束时,我们剩下的是运行良好的大型网络,但很难说清楚是如何进行的。在许多应用领域,我们可以选择使用我们理解的90%的精确度模型,也可以选择我们不理解的99%精确度的模型。

2.0栈可能会以不直观和令人尴尬的方式失败,或者更糟糕的是,它们可能会“默默失败”,例如,通过在它们的训练数据中默默地采用偏差,在大多数情况下,当它们的大小很容易达到数百万时,很难正确地分析和检查这些偏差。

最后,我们还在探索这个堆栈的一些特殊属性。例如,敌意例子和攻击的存在突显了这种堆栈的非直觉性。

软件1.0是我们编写的代码。软件2.0是优化器基于评估标准(例如“正确分类此训练数据”)编写的代码。很可能是任何程序不明显但可以重复评估其性能的设置(例如,您是否正确地对某些图像进行了分类?你会赢围棋吗?)。将受到这种转换的影响,因为优化可以找到比人类编写的代码好得多的代码。

我们看待趋势的镜头很重要。如果您认识到软件2.0是一种新的、新兴的编程范例,而不是简单地将神经网络视为机器学习技术类中相当好的分类器,那么外推就会变得更加明显,显然还有更多的工作要做。

特别是,我们已经构建了大量的工具来帮助人们编写1.0代码,例如具有语法突出显示、调试器、分析器、Go to def、Git集成等功能的强大IDE。在2.0堆栈中,编程是通过累积、消息和清理数据集来完成的。例如,当网络在一些硬的或罕见的情况下出现故障时,我们不会通过编写代码来修复这些预测,而是通过包含这些情况的更多标签示例来修复这些预测。谁来开发第一个软件2.0IDE,这些IDE帮助所有的工作流程来积累、可视化、清理、标记和采购数据集?也许IDE会根据每个示例的损失来冒泡出网络怀疑被错误标记的图像,或者通过用预测播种标签来帮助标记,或者基于网络预测的不确定性推荐有用的示例来标记。

同样,Github是一个非常成功的软件1.0代码之家。软件2.0 Github还有空间吗?在本例中,存储库是数据集,提交由标签的添加和编辑组成。

在短期/中期内,软件2.0将在任何重复评估可能且成本低廉,并且算法本身难以明确设计的领域中变得越来越流行。从长远来看,这种范式的前景是光明的,因为很多人越来越清楚,当我们开发AGI时,它肯定会用软件2.0编写。