选自Julia Blog
作者:Mike Innes等人
机器之心编译
任何机器学习系统复杂到一定程度,都会包含一个临时开发的、不合规范的、充满错误的、运行速度很慢的、只有一半功能的编程语言实现。(格林斯潘第十定律)
我们很高兴看到机器学习大爆发,以及机器学习模型的复杂度和用来构建模型的框架。越来越多的顶尖模型更多地涉及到编程问题,通常它们需要支持循环和递归等编程结构,这给创建它们的工具(编程语言)带来了一些有趣的问题。
尽管机器学习没有专用的语言,但有的机器学习框架(如 TensorFlow)在 Python API 下高效地创建了「新语言」,而一些系统(如 PyTorch)重新使用 Python 作为建模语言。我们想问的是,需要为机器学习定制新语言吗?如果需要,为什么?更重要的是,未来完美的机器学习语言可能是什么样子?
隐藏在机器学习系统后的语言
TensorFlow(TF)已经算是着一种「编程语言」了,因为在这个框架下我们完全可以使用它所提供的类和对象编写一个模型。大家使用 Python 和 TF 库进行编程,因此这个结论似乎有点令人惊讶。但是,TF 要求你在其内部语言内使用 Python 代码构建表达式树,然后 TF 再进行评估。
事实上,你可以用任何语言进行「懒惰的」TensorFlow 风格编程。如下面的 JavaScript 代码,就在这种风格中实现了一个小功能(add):
function add(a,b) {
return `${a}+${b}`;
}
x = 1; y = 2
z = add('x', 'y') // 'x+y'
eval(z) // 3
x = 4
eval(z) // 6
这里,我们进行的是元编程(metaprogramming)——编写写代码的代码。上例中,源语言和目标语言是一样的(JavaScript),它们也可以是不同的语言(如在处理 C 语言的 C 预处理器中),我们也可以使用数据结构(AST)来代替字符串,原则是一样的。在 TensorFlow 中,Python 是元语言,我们使用 TF 这种基于静态计算图的语言编写程序。如果你不信,想一下 TensorFlow 的图甚至支持变量适应范围(variable scoping)和控制流(control flow)等编程结构,而不是使用 Python 语法,你可以通过一个 API 管理这些结构。
TensorFlow 和类似工具的呈现方式是「库」,但它们是极其不寻常的库。大部分库提供一套简单的函数和数据结构,而不是全新的编程系统和运行时(runtime)。
为什么创建新语言?
创建新语言的核心原因非常简单:ML 研究需要极高的算力,简化建模语言可以使添加特定的优化和特征变得简单。训练模型要求极高的硬件支持、合适的数值、低解释器开销和多种并行化。通用语言如 Python 勉强可以提供这些特征,但 TensorFlow 可以无缝处理它们。
不过有一个障碍。这些优化依赖于简单化的假设(ML 模型不是递归的,或不需要自定义梯度),这使得将这些优化或应用部署到小型设备变得简单。不幸的是,对于工程师来说,模型复杂度目前出现直线上升的趋势,而研究者享受破坏这些假设的过程。现在模型要求条件分支(比较简单)、重复循环(没有那么简单但也不是不可能)、递归树(几乎不可能)。在 ML 的很多分支,包括神经网络和概率编程中,模型越来越像程序,包括推断其他程序的程序(如程序生成器和解释器),且具备不可微组件,如蒙特卡罗树搜索。构建提供完全灵活性且达到顶尖性能的运行时非常困难,但是最强大的模型和突破性的结果需要这二者。使用机器学习和复杂树结构数据需要可微且递归的算法。
该方法的另一个缺陷是,目前需要上面讨论的元编程。构建和评估表达树对程序员和编译器都是额外的负担。很难进行推断,因为现在代码有两个执行时间,每个具备不同的语言语义(language semantics),逐步调试等操作将变得更加困难。这可以通过为新的运行时创建语法来解决,但是其工作量不亚于创建全新的编程语言。
仅用 Python 就可以了吗?
机器学习模型开始需要编程语言的全部力量,Chainer 和其他人率先使用「define-by-run」方法,该方法中 Python 程序本身就是模型,使用运行时自动微分(AD)作为导数。从易用性的角度来看这种方法很有意思:如果你想要一个进行树运算的递归模型,只需要写下来,让 AD 来施展它的魔力!我们很难不高估这种感觉,使用新的无障碍方法对于研究来说是宝贵的。
但是,让 Python 满足机器学习的复杂计算要求比你想象的还要难得多。大量研究开始开发快速语言(如 PyTorch),但并没有加快 Python 的速度。Python 的语义使它很难提供模型级别的并行化,或者为小型设备编译模型。
MXNet Gluon 正在探索利用二者,至少在一定程度上。其想法是将基础的动态自动微分和生成可优化「静态子图」的代码追踪方法联系起来。不幸的是,这只是把不相关的实现和 API 混在一起而已。这种方法也受限制,MXNet 不仅使用它的图来做 kernel 级别的优化,还用于高级别的图调度(graph scheduling),如在多个 GPU 上分割模型。此外,目前尚不明确这些混合如何对此进行处理。
适合机器学习的语言是什么样的?
很少有其它领域像机器学习一样有语言级的设计需求,但在形式化推理或集群计算等领域,量身定制的语言已经证明它们是高效的解决方案。同样,我们希望看到新的或现有的语言能完美地支持机器学习所需要的数值计算、自动微分计算、并行计算和概率计算等能力。
当前机器学习语言一个明显的挑战是在性能方面难以取得一致性,即早期的混合方法需要更多的开发工作。我们期待未来的机器学习语言将支持任意混合的方法(即静态计算图内可能混合了其它动态或静态计算图),并且在编译动态代码时能更好地部署。理想情况下,这种新型语言将只有单个灵活的「计算图格式」。这种计算图格式应该有一种语法和静态描述的方法以表示动态的行为,换句话说,它应该看起来更像一个标准的编程语言。
可编程语义将达到新的灵活性水平,并且它可以通过类似宏(Macros)的特征实现。这将允许通过指定代码应该有怎样的纯数据流语义,而在核心系统的顶部构建像多 GPU 训练那样的特征。此外,它也能允许概率编程语言所需要的各种编程操作,或 NLP 模型中常需要手动实现的向量化或批量化等。
与编程语言社区一样,机器学习工程师非常关注传统的自动微分领域。机器学习语言可以从真正实现一阶导的语言中获取灵感与经验,这样的语言可以很容易将符号与运行时(runtime)技术结合在一起,将正向与反向模式的自动微分技术混合在一起,所有这些都不会导致性能上的损失。
ML 研究将需要越来越强大的类型系统(type systems)、用户自定义类型和更多的扩展手段。目前在英伟达 GPU 上对阵列式支持的硬编码已经足够了,但像前沿的稀疏机器学习,新型 TPU、Nervana 和 FPGA 等面向机器学习模型部署的硬件都需要更高的灵活性。
若目前存在添加新型硬件支持或新型数据表征的新型语言,那么用户可以简单地通过高级代码,而不需要改变原来的系统就能添加硬件支持或数据表征方式。当然,我们期望机器学习语言能从现有的数值计算语言中获取灵感,因为这些语言已经能很好地处理特定的任务了。
此外,机器学习工程师对传统的软件工程问题越来越感兴趣,例如在维护和扩展生产系统等方面。机器学习编程模型使得在组件之间更难以创建接口,对模型的重训练可以轻松地实现向后兼容。机器学习语言可以像常规语言一样将这些问题的解决方案结合起来,但这仍然是一个开放性问题。
软件工程 2.0?(图片来自 XKCD)
任何新语言共同面临的问题就是它们都需要一套新的库和生态系统,从而让人们编写的代码能够不断从中获得支援。例如:如果选择不重用 Python 的生态系统,TensorFlow 开发者们需要为图语言中的图像处理和文件 IO 等任务重新写库,在这一部分做出巨大贡献的项目是 SciPy。这可能是我们快速发展的唯一出路,机器学习参与者们也不能从更为广泛的 HPC 和数学社区中分裂出去。一个理想条件下的机器学习生态系统是理想的数学生态系统,这些社区之间的合作将使所有人的力量都获得倍增。
我们期待新的发展来自各个维度。Graph IR 和 XLA、ONNX、NNVM 等格式正在变得前所未有的复杂,同时也在受到传统语言设计的启发,甚至可能会出现表面语法,以成为完整意义上的编程语言。TensorFlow XLA 已经开始面向专用编译器堆栈发展,现在包含 TVM、DLVM、myelin,以及其它正在进行的工作。除此之外,像 PyTorch JIT、Gluon 和 Tangent 正努力使 Python 本身成为更好的建模语言,尽管这项任务面临的挑战很大。在刚刚把机器学习归类为数值编程语言问题后,我们在 Julia 社区中看到了解决这些语言级别问题的极好的基础,开发者们正在持续推动像 Knet、Flux、Cassettle、CUDAnative、DataFlow.jl 等工具的发展。
结论:机器学习推理工具
机器学习模型已经成为极度泛化的信息处理系统,被用于进行越来越高级、越来越复杂、抽象的任务;循环、递归、高阶模型、甚至堆栈机和语言解释器全部都可以以基本组建的组合形式来实现。机器学习是一种新的编程范式,尽管对于初学者来说其中含有太多的数值、可微分和并行化。对于任何工程领域,这些可用工具都会对未来工作的质量和范围产生深远影响。
所有这些都预示着机器学习系统的设计者们面临着非常大的挑战。尽管如此,我们还有一些好消息:如果有一方面仍未解决的话,过去的几十年里,计算机语言的研究者们已经深入讨论了同样的问题。为了深入探知这一领域的全部,机器学习和编程语言社区需要通力合作,所以,真正的挑战是整合这两个群体之间不同的专业知识。
我们能否建立起一套面向数学、衍生和并行,同时又不牺牲传统编程思想优势的新语言工具?这将是未来十年里计算机语言领域里人们面临的主要问题。
原文地址:https://julialang.org/blog/2017/12/ml&pl
本文为机器之心编译,转载请联系本公众号获得授权。
✄------------------------------------------------
加入机器之心(全职记者/实习生):hr@jiqizhixin.com
投稿或寻求报道:content@jiqizhixin.com
广告&商务合作:bd@jiqizhixin.com