[译] 神经网络、类型论和函数式程序设计
Neil Zhu,简书ID Not_GOD,University AI 创始人 & Chief Scientist,致力于推进世界人工智能化进程。制定并实施 UAI 中长期增长战略和目标,带领团队快速成长为人工智能领域最专业的力量。
作为行业领导者,他和UAI一起在2014年创建了TASA(中国最早的人工智能社团), DL Center(深度学习知识中心全球价值网络),AI growth(行业智库培训)等,为中国的人工智能人才建设输送了大量的血液和养分。此外,他还参与或者举办过各类国际性的人工智能峰会和活动,产生了巨大的影响力,书写了60万字的人工智能精品技术内容,生产翻译了全球第一本深度学习入门书《神经网络与深度学习》,生产的内容被大量的专业垂直公众号和媒体转载与连载。曾经受邀为国内顶尖大学制定人工智能学习规划和教授人工智能前沿课程,均受学生和老师好评。
Christopher Olah 新作 原文
一个 AdHoc 的领域
深度学习,尽管已经获得相当的成果,还是一个年轻的领域。尽管被称作人工神经网络的模型已经被人们研究了数十年,但是那时的工作看起来却与现代的研究成果关系不大。
一般来说,年轻的领域都是从一种 ad-hoc 的方式开始的。慢慢地,成熟起来的领域的理解会和早期的先行者的理解差异较大。例如,在分类学中,近千年来人们都将植物和动物组织在一起的,在我们对进化和分子生物学理解深入后才改变了禁锢已久的观念。在化学领域,人类研究了好长时间的化学反应,但是真正让我们认识转变的其实是发现不可约的元素,而后是因为原子模型的发现。这些都是伟大的发现,而科学和数学的历史中已经不断地上演这样的不同程度的桥段了。
现在看起来,深度学习可能就出在这样的一种状态下。
同时,深度学习有着极其成功的工具作为支撑。虽然工具看起来并不是根本性的;它是被偶然发现的一些东西,不过拥有着规律性的属性。作为一个领域,我们还没有获得某种统一的洞察或者共通的理解。实际上,该领域还有好几个流派!
所以我猜测,很可能在 30 年后,回过来看深度学习,会大不相同的。
深度学习未来三十年
如果我们觉得深度学习在 30 年后变化非常大,也就意味着:我们将如何看到?当然,没有人能够真正知道我们如何理解这个领域。但是来做个推测也是很有趣的。
当前,三种流派正在争夺作为理解深度学习的方式。一个就是神经科学流派,把深度学习类比于生物学。一个是表示流派,关注数据的转换和流形假设。最后一个,就是概率流派,将神经网络解释称一种寻找潜在变量的方法。这些流派并不是互斥的,但是在思维方式上存在着相当大的差异。
这篇文章尝试扩展了表示流派,并给出一个可能的答案:深度学习研究了优化和函数式程序设计的关联。
在这个观点下,深度学习中表示流派的想法就对应于函数式程序设计中的类型论。我们将深度学习看做是成果颇丰的两个领域的联结。我能够看到的是,美妙和自然的现象就是作为数学家的我可以相信这可以给出一些有关真实世界的某种根本性的认知。
这的确是一种极强推测性的想法。我并不是想要证明这个想法。只是希望来论述一些关于这个想法的合理性,我们也可以从这个方向来推测深度学习的今后的演变。简言之:我尝试给出了一个美学观点,而非一个事实论证。本文试着给出这个自然又简洁的想法,对深度学习给出一个全面的解释。
优化 和 函数复合
深度学习的一个特别之处是它研究了深度神经网络——拥有多层的神经网络。通过众多的网络层,这些模型逐渐地将数据进行扭曲,最终转换成一种容易解决最终任务的形式。
简单的神经网络这些层上的细节不断地在变化。而不变的一点是层之间的顺序关系。
每个层都是一个函数,作用于上一层的输出上。整体上看,神经网络是复合函数形成的链。而我们就是通过优化这个复合函数的链来完成既定任务的。
我注意到在神经网络中的每个模型其实都包含优化复合函数的过程。这也是本文所要研究的关键之处。
表示即类型
借助每个层,神经网络转换数据,将数据转成适合最终任务的形式。我们也称这些被转换后的数据为“表示”。
表示对应于类型。
粗略地看来,在计算机科学中的类型是一种将某种数据嵌入到 n
个比特中的方式。类似地,深度学习中的表示就是一种将数据流形嵌入到 n
个维度的方法。
正如两个函数仅在类型一致时才能够复合,两个层也是仅能够在其表示相符的时候进行复合。错误表示的数据对神经网络来说,毫无作用。在训练的过程中,邻接的层会确认好他们之间交互的表示;而网络的性能则会依赖于使用网络期待的表示的数据。
在一个极其简单的神经网络架构中,只包含一个线性的序列的若干层,这不会很有趣。一层输出的表示需要匹配下一层的输入——这有什么好玩的!?这不是易见的么。
但是很多神经网络拥有更加复杂的架构,所以这个约束也会变得很有意思。举个例子,想象一个有多个类似类型输入的神经网络,进行着多个相关任务。可能会同时获取RGB 图像和灰度图像作为输入。就想象成网络正在学习人的图片,试着对年龄和性别做出预测。因为输入的类型的相似性还有任务的相似性,在一个模型中来做所有的事就很有用了,训练数据可以帮助所有的任务。结果就是多个输入层映射到了一个表示,多个输出从共同的表示映射出来。
也许这个例子有点太刻意,但是映射不同类型的数据到同样的表示上可以达成一些很棒的效果。例如,通过映射两种语言下的词到同一个表示,我们可以找到那些我们开始时并没能发现的对应的词之间的翻译。还有就是通过映射图像和词到同样的表示上,我们就可以将图像分出那些我们从没看到的类别上!
表示和类型可以被看成是深度学习和函数程序设计分别对应的基础构成单元。深度学习的一个主要流派——流形和表示,整个就是关注神经网络扭变数据到新的表示上。而已知的集合、逻辑、拓扑和函数式程序设计之间的关联也揭示出表示和类型之间的联系可能更加具有根本性。
深度学习 和 函数式程序设计
现代神经网络背后关键思想之一就是可以在网络中使用一个神经元的若干拷贝。
在程序设计中,函数的抽象则是根本的。我们可以通过函数来减少重复代码数十倍、百倍乃至千倍。这样不仅减少了我们需要编写和维护的代码量,加速了开发的进程,而且降低了引入 bug 的风险,让我们能够更容易地找到错误。
在神经网络中使用一个神经元的多个配置就类比于在程序设计中使用函数。这样的话,我们需要学习的东西更少,当然模型训练会变快,并能够得到一个较好的模型。这种技术——也称为 权重捆绑(weight tying)——是深度学习中常见的现象级结果。
当然,我们也不是任意地在网络中的所有地方去使用神经元的拷贝。为了让模型起到作用,需要按照一定的方式办事,利用数据中的一些结构来设计权重捆绑。实践中,通常会有一些广泛使用的模式,例如递归层和卷积层。
这些神经网络的模式其实就是更高阶的函数——也就是说,一些将函数作为参数的函数。诸如此类的东西在函数式程序设计中已经被广泛研究过了。实际上,很多网络模式对应于极其常见的函数,如 fold
。唯一不同的是,这里接受的是神经网络的块(chunk)而不是正常的函数作为参数。
-
Encoding RNN:就是
folds
。通常让神经网络接受可变长度的列表作为输入,如将:
-
Generating RNN:就是
unfold
。通常让神经网络可以产生一个列表形式的输出,如句子中的词:
- General RNN:就是累积的映射(Accumulating Map)。通常对一个序列上的元素进行预测的时候使用。例如在语音识别的时候,我们希望基于过去的上下文环境预测每个时间步的声音代表的词:
- Bidirectional RNN:是更加复杂的变体,我为了加点料所以提出来。用函数式程序设计中的术语,他们有组合的左和右的累积的映射(a left and a right accumulating map zipped together)。通常用来进行对一个有着过去和未来的序列进行预测。
- 卷积神经网络:类似于映射(map)。正常的映射将一个函数作用于每个元素。卷积神经网络同时会看邻居元素,作用一个函数在包围每个元素的窗口上。
二维的卷积神经网络特别需要注意。它们在目前的计算机视觉领域取得了成功。(参见这里) 二维卷积网络
- Recursive 神经网络:也称为TreeNet,是catamorphisms,fold的一种推广。自底向上地重建数据结构。多数用在自然语言处理中,让神经网络能够对分析树进行操作。
上面的例子展示了如何将神经网络中的常见模式和自然而简单的函数式程序对应起来。
新的程序设计
这些模式就是可以组合起来形成更大的网络的构建单元。正如这些构建单元,相应的组合就是包含神经网络输出块的函数式程序。函数式程序提供了高层次的结构,块本身是灵活的部分可以通过基于由函数式程序提供的框架学会完成实际的任务。
这些构建单元的组合可以做到相当出色的工作。我们看看下面的例子:
- Sutskever, et al. (2014)通过组合 encoding RNN 和 generating RNN 给出了英法翻译任务上最佳的性能。用函数式程序设计的术语,本质上就是在英语句子上进行 fold 然后使用 unfold 产生法语翻译。
- Vinyals, et al. (2014)使用卷积神经网络和生成式 RNN 生成图像描述。本质上,使用卷积网络重建图像,然后使用 unfold 结果向量成一个描述它的语句。
而这些模型可以看做是一种可微分函数式程序设计。
但是,也不是这么抽象的东西!这个过程中其实有函数式程序设计的味道,即使没有使用这类编程语言。在我听了同事关于模型高层次的报告,it has a very different feeling to it than people talking about more classical models. 人们会用很多不同的方式讨论问题,当然就会有很多的关于深度学习理解的差异——但是常常也会有潜在的感觉——深度学习和函数式程序设计有相似之处。
感觉会出现一种新的程序设计,诸如可微分的函数式程序设计。我们写非常粗糙的函数式程序,包含这些灵活的、可学习模块,并给这些拥有大量数据的程序定义正确的行为。接着应用梯度下降或者其他的优化算法。最终得到的结果就是一种可以完成更加重要的工作的程序,它可以完成那些我们人类都无法确切知道如何直接解决的问题,例如对图像进行描述的自动生成。
我个人认为函数式程序设计和优化技术的自然交叉是相当美妙的。
结论
再说一遍,这个想法非常的美妙。同时,这篇文章也是非常奇怪的,发布出来我其实也很忐忑。这里,我持的是一种预测的观点,并没有太多证据支撑,除了我自己对这个想法的激情。实话说,采取最为客观的观点,我感觉这个想法是错误的,因为大多数未经验证的想法最终都是错误。但是也有可能是正确地,想法本身还是值得去探讨的。
更进一步,我自己也可能不是那个最合适的人选去在这个方向上进行探究——例如,其中最为明显的工作就是去从 homotopy 类型论的角度来分析神经网络,但是我并没有这方面的专业知识。所以,本文的想法其实还是刚刚开始的阶段,需要更多的探讨研究。所以发布这篇文章也许是最为合适的做法。
最后,我期望这篇文章能够激发出更多地讨论和产生更多的关于深度学习真正在做什么的思考。我猜测,后面会有一波重要的探讨。
另外,如果我不能猜测的话,还要来写博客干嘛?!真心希望,我自己能够找到热情和理性之间的平衡。
Acknowledgments
Firstly, I’m incredibly grateful to Greg Corrado and Aaron Courville. They are the deep learning researchers I know who most strongly empathize with these ideas, and I’m really grateful for their intellectual support.
Several other people have had really extended and helpful conversations with me. Sebastian Zany spent several hours talking about type theory and neural networks with me. Michael Nielsen gave thorough feedback on a draft of this essay. Chas Leichner thought really deeply about these ideas, and was very encouraging. A big thank you to the three of them!
I’m also thankful for the comments of James Koppel, Luke Vilnis, Sam Bowman,Greg Brockman and Rob Gilson. Finally, I’ve spoken with a number of other people about these ideas in the last few months – thanks to all of them!
附录:常见神经网络层的函数式命名
Deep Learning Name | Functional Name |
---|---|
Learned Vector | Constant |
Embedding Layer | List Indexing |
Encoding RNN | Fold |
Generating RNN | Unfold |
General RNN | Accumulating Map |
Bidirectional RNN | Zipped Left/Right Accumulating Maps |
Conv Layer | “Window Map” |
TreeNet | Catamorphism |
Inverse TreeNet | Anamorphism |
人工智能时代每个人都将面临挑战,想要了解更多相关知识和实践经验,请关注公众号“UniversityAI”。
UAI 人工智能