一代深度学习框架研究( 三 )


MindSpore采用的S2S自动微分技术兼顾了可编程性和性能,一方面它能够与编程语言保持一致的编程体验,另一方面它是IR粒度的可微分技术,可复用现代编译器的优化能力,性能也更好 。
S2S自动微分技术使用了高效易调试的可微编程架构 。首先在接口层提供Python编程接口,包括控制流表达,有利于用户快速入门 。样例代码如下 。
def cost(x,y):return x * (x + y)
@mindspore
def test_grad (x,y):
return grad_all(cost)(x,y)
def main():
test_grad (2,1)
第一步:用Python代码定义一个计算图(函数) 。
第二步:利用MindSpore提供的反向接口进行自动微分,这一步的结果是一个反向的计算图(函数) 。
第三步:给定一些输入,就能获取第一步中的计算图(函数)在给定输入处的导数 。
在此样例中,自动微分的结果是图中所有输入的导数 。MindSpore的反向接口同样提供选项计算某一个或者一部分输入的导数 。
其次,IR粒度的可微分技术能够把用户定义的网络源代码通过解析验证等过程,转化为MindSpore定义的IR,也就是MindSpore IR 。在IR的基础上应用IR更变器方法(IR mutator method),最终生成反向代码 。在此过程中也应用了算子融合等技术,进一步提升了反向性能 。
MindSpore对控制流的表达如图4所示,包括循环和条件 。可以看到代码编程风格与原生Python保持一致,更重要的是MindSpore在生成控制流的反向时不会对循环进行展开,而是在IR基础上进行反向计算,避免了表达式膨胀,从而提升了性能 。

一代深度学习框架研究

文章插图
图4 MindSpore对控制流的表达
相比其他框架,MindSpore可以降低20%的核心代码量,降低了开发门槛,整体提升50%以上的效率 。同时,MindSpore天然支持编译优化,进一步提升了代码运行效率,有效降低了科研工程门槛 。
MindSpore图层面的自动微分样例代码如下 。
class Net(Cell):
def __init__(self):
self.w = Parameter(Tensor(np.ones([10])))
def forward(x,y):
return x + y
#定义网络
net = Net()
x = Tensor(np.ones([10]))
y = Tensor(np.ones([10]))
#自动微分推导
gout = grad_all (net)(x,y)
除了图层面的自动微分以外, MindSpore同时支持算子层面的自动微分 。在提供深度学习主要网络的算子的同时,MindSpore自带的张量引擎(tensor engine)支持用户使用Python特定领域语言(domain specific language,DSL)自定义算子,并且提供算子级的自动微分接口 。通过使用Python DSL,用户可以在Python中自定义算子,如同数学中用公式定义函数一样 。而张量引擎的算子自动微分接口可以直接对DSL定义的算子进行微分,正如数学中使用统一的微分符号表示求导一样,这样一来,代码的书写更加简洁直观,更贴近用户的书写习惯 。样例代码如下 。
def sigmoid(x)
#前向算子的 DSL 实现
from te.lang.cce import vrec,vadds,vexp,vmuls
res = vrec(vadds(vexp(vmuls(x,-1.0)),1.0))
return res
def sigmoid _ad(dout,x)
import te
#前向算子引用
out = sigmoid(x)
#前项算子自动微分后生成反向算子
dx]= te.differentiate(out,[x],dout)
return dx
这里的前项算子是用户用DSL自定义的算子,也是算子级自动微分的求解目标 。接下来利用张量引擎提供的反向接口推导出反向算子 。对于多输入的算子来说,反向算子接口可以指定一个或者多个前向算子的输入,然后对这些输入同时进行自动微分计算 。另外,与图层面的自动微分不同,算子级的自动微分额外接收反向图中上一层算子(对应正向图的下一层算子)的微分结果作为输入,然后使用链式法则计算出该层反向算子的结果 。数学中高阶导数是通过对函数反复使用微分算子计算得到的,同样,在MindSpore中,用户可以通过对算子反复使用反向接口来计算算子的高阶导数 。
MindSpore的算子级自动微分接口不仅可以自动生成反向算子,还提供了进一步手动优化导数公式的可能 。MindSpore的算子级自动微分功能把算子分割成若干步简单函数的复合运算后,先是利用已知基础函数的导数和求导法则分步求导,然后利用链式法则计算复合函数的导数,最后使用张量引擎内置的数学公式简化器进行化简 。这可以满足绝大部分用户对自动微分的需要 。但是对于部分有更高性能要求或者代码部署要求的用户,MindSpore提供接口让用户可以使用自己优化过的导数公式代替某一步或者若干步自动生成的导数公式 。样例代码如下 。


推荐阅读