正文
相对来说,命令式编程(Imperative Programming)则更像剑宗。剑宗注重招式的灵活与变化。远如当年剑宗第一高手 NumPy,近如贵为五岳之一的 Torch 都是采用命令式编程的接口。他和符号式编程最大的不同在于,命令式编程并没有描述算法和执行两个阶段,因此用户可以在执行完一个语句后,直接使用该语句的结果。这对于深度学习算法的调试和可视化等都是非常重要的特性。命令式编程的缺点在于,由于算法是一边执行一边描述的,因此对算法的优化是一个挑战。
究竟是「以剑御气」还是「以气御剑」?其实两者应该相辅相成。如果你空有一身内力却无一丁点剑招,就会像是刚得到逍遥子毕生内力的虚竹,想到巧妙复杂的深度学习模型只能干瞪眼却无法实现。如果你空有华丽招式而不精进内力,别人以拙破巧,你优美的模型只会被别人用简单粗暴的高性能,大模型和大数据给击倒。正因如此,五岳新贵 MXNet 同时支持符号式和命令式编程接口。用户可以选择在性能优先的部分使用符号式编程,而在其余部分使用灵活性更高的命令式编程。不过这种分而治之的方式给用户带来了额外的选择负担,并没有将两者融汇贯通。因此,我们进一步基于 MXNet,开发了 MinPy,希望将这两者取长补短——使用命令式编程的接口,获得符号式编程的性能。
MinPy 的剑宗招式
在编程接口上,MinPy 继承了剑宗第一高手 NumPy 老先生的精髓。正所谓「无招胜有招」。没有特殊语法的语法才是好语法。于是在使用 MinPy 时,你只需要简单改写一句 import 语句:
import
minpy.numpy
as
np
就能够开始使用 MinPy 了。由于是完全的命令式编程的接口,编程的灵活性被大大提高。我们来看以下两个例子。
例 1: 调试和打印变量值
在 Tensorflow 中,如果需要打印某个变量,需要在打印语句前加上 control_dependencies。因为如果没有这条语句,Print 这个运算并不会出现在所需要求的 x 变量的依赖路径上,因此不会被执行。而在 MinPy 中,我们保持了和 NumPy 一样的风格,因此可以直接使用 Python 原生的 print 语句。
例 2: 数据依赖的分支语句
数据依赖的分支语句是符号编程的另一个难点。比如在 Tensorflow 中,每个 branch 是一个 lambda,而并非直接运算。其原因在于符号编程将算法描述和实际执行分为两个部分,在没有算出来 x 和 y 的值之前,是无法知道究竟会取哪个分支的。因此,用户需要将分支的描述写成 lambda,以便在能在运行时再展开。这些语法虽然细微,但是仍然会对初学者带来负担。相对的,在 MinPy 中,由于采用命令式编程的接口,所以一切原生的 if 语句都可以使用。除了以上这些编程方面的区别外,MinPy 还提供了以下功能。