基于CuDNN如何实现自动选取最优卷积算法?

何为最优


最优并不是绝对的,而是需要针对具体的应用场景而言.在深度学习应用中,训练时我们往往对训练速度有要求,希望越快越好,也就意味着能够在更短的时间训练完我们的模型,更小的调整参数的成本;而对于随着网络模型的深度加大,模型本身训练时所占用的显存空间很大,这时候就要求我们的选取的卷积算法能够竟可能的少占用临时显存空间.综上,这是一个时间与空间的权衡,本文会结合当前最新的CuDNN分析如何实现自动选取最优卷积算法.

时间与空间的权衡


速度越快的算法往往依赖于更大的临时空间,也就是所谓空间换时间,所以最优的卷积算法还是应该结合我们具体的需求来定义.

问题来源?CuDNN


CuDNN提供了多种卷积算法的实现,同时也提供了两类API,分别为get/find,用户自行调用得到满足特定条件下的最优卷积算法实现.其中GET类型方法是根据经验得到对应的卷积算法,比如输入的layout, filter的大小,卷积输入的数据类型等等,这个查找过程是常数级别,笔者亲测过.这个方法的好处是调用简单,CuDNN根据一些经验设定简易判断,同时给定是否有空间限制的选项,比如有workspace_limit, fastest,no_workspace_limit等.但是,通过这个API获得的卷积算法并不一定是最快的,读者可以自行验证.另外就是find类型的接口,原理是遍历一遍所有的卷积算法,返回一个perf结果,包括每个算法实际运行所需的时间以及临时空间大小,如果该卷积算法不支持当前的输入数据,那么状态就不为CUDNN_STATUS_SUCCESS.通过这种方式得到是最具有说服力,实测也是最快的,如果对空间存在限制,那么可以根据返回的perf结果进一步限制.

出于这个的原因,如何根据当前的应用场景和卷积输入,选取最优的卷积算法就成为一个值得考量的问题.本文主要是强调如何加速训练过程,而讨论的重点也是通过find方法.

Auto-tune

前一小节提到CuDNN提供了应对不同需求的卷积算法接口,本小节详细讨论一下通过find以及findEx实现卷积算法自动调优的一些细节.
1.提供三类选项给用户,指定是使用GET/FIND搜索,另外还可以提供接口用户直接指定卷积算法.
2.如果为GET方式,需要考虑是否有workspace空间大小的限制,比较简单.
3.如果为FIND方式,也就是穷举所有的卷积算法实现,从支持的卷积实现中再挑选最快或者临时空间满足要求并且最快的卷积算法.Find提供的接口中根据临时空间的申请方式分为两类,一类是cudnn自行通过cudaMalloc申请然后释放,一类是使用用户申请好的空间.第一类较为简单,缺点是用户无法对其中申请的空间进行有效管理,比如你当前使用了mempool,那么就很容易导致cudaMalloc失败.第二类方式则是适用于自己实现的内存管理器.各有利弊,实现时应该关注.

在博客系列中上一篇我大概总结了使用cudnnv7以及cuda 9.0 基于volta架构进行混合精度训练的方法.那么混合精度训练时,卷积算法的选取就需要额外的注意一下.
1.如果使用fp16输入,不满足调用专用fp16计算单元(tensor cores)时,得到的卷积算法如果依然使用fp16运算的话将大大影响卷积的速度.所以需要考虑转换成fp32进行运算,对比两个计算精度选取最快的.CUDNN文档中是将第一种称为TRUE_HALF_CONFIG,第二种为pseudo_half_config.

这里有一个前提是认为使用到tensorcore的卷积计算一定会比其他计算单元快.不论采取那种卷积算法(目前只有一种卷积算法支持tensorcore)
使用find类型最后会返回一个perf数据,其中包括有memory, status, time等数据,用户可以配置memory的限制,然后选取最小time的algo.


你可能感兴趣的:(深度学习)