深度学习:计算性能
1、命令式和符号式混合编程
命令式编程,它使用编程语句改变程序状态:
def add(a, b):
return a + b
def fancy_func(a, b, c, d):
e = add(a, b)
f = add(c, d)
g = add(e, f)
return g
fancy_func(1, 2, 3, 4)
在运行语句e = add(a, b)时,Python会做加法运算并将结果存储在变量e中,从而令程序的状态发生改变。类似地,后面的2条语句f = add(c, d)和g = add(e, f)会依次做加法运算并存储变量。
与命令式编程不同,符号式编程通常在计算流程完全定义好后才被执行符号式编程的程序需要下面3个步骤:
- 定义计算流程;
- 把计算流程编译成可执行的程序;
- 给定输入,调用编译好的程序执行。
对比这两种编程方式:
- 命令式编程更方便。当我们在Python里使用命令式编程时,大部分代码编写起来都很直观。同时,命令式编程更容易调试。这是因为我们可以很方便地获取并打印所有的中间变量值,或者使用Python的调试工具。
- 符号式编程更高效并更容易移植。一方面,在编译的时候系统容易做更多优化;另一方面,符号式编程可以将程序变成一个与Python无关的格式,从而可以使程序在非Python环境下运行,以避开Python解释器的性能问题。
大部分深度学习框架在命令式编程和符号式编程之间二选一。
- TensorFlow使用了符号式编程
- PyTorch使用了命令式编程
- Gluon提供混合式编程
- 在混合式编程中,我们可以通过使用HybridBlock类或者HybridSequential类构建模型。
- 默认情况下,它们和Block类或者Sequential类一样依据命令式编程的方式执行。
- 当我们调用hybridize函数后,Gluon会转换成依据符号式编程的方式执行。
2、 异步计算
异步计算:当你调用一个使用GPU的函数时,操作会排队到特定的设备上,但不一定要等到以后才执行。
在诸多的深度学习框架中,
- MXNet和TensorFlow之类则采用了一种异步编程(asynchronous programming)模型来提高性能,
- 而PyTorch则使用了Python自己的调度器来实现不同的性能权衡。对于PyTorch来说GPU操作在默认情况下是异步的。
通过后端异步处理
📣
通过PyTorch的基准输出比较快了几个数量级。NumPy点积是在CPU上执行的,而PyTorch矩阵乘法是在GPU上执行的,后者的速度要快得多。
默认情况下,GPU操作在PyTorch中是异步的。强制PyTorch在返回之前完成所有计算,这种强制说明了之前发生的情况:计算是由后端执行,而前端将控制权返回给了Python。
3、自动并行计算
深度学习框架(例如,MxNet和PyTorch)会在后端自动构建计算图。利用计算图,系统可以了解所有依赖关系,并且可以选择性地并行执行多个不相互依赖的任务以提高速度。
通常,一个运算符会用到所有CPU或单块GPU上全部的计算资源。
例如,dot运算符会用到所有CPU(即使是一台机器上有多个CPU处理器)或单块GPU上所有的线程。
如果每个运算符的计算量足够大,只在CPU上或者单块GPU上并行运行多个运算符时,每个运算符的运行只分到CPU或单块GPU上部分计算资源。
即使这些计算可以并行,最终计算性能的提升可能也并不明显。