众所周知,在GPU上可以采用许多图形API进行开发,例如OpenCL、OpenGLES、Vulkan等等,那么如何进行选择,选择的依据又是什么呢?这里就要提到一个比较重要的概念——平台厂商对于各API的优化力度。例如在高通的Adreno系列GPU上,我们就采用OpenCL进行开发,因为高通对OpenCL实现了许多扩展,并且Adreno的硬件针对OpenCL有专属的优化,例如对Image对象的读取就有L1Cache进行加速(如下图所示),因此将Weights和Feature Map保存在Image对象上能显著提升性能。所以在Adreno上适合采用OpenCL进行开发。而在其他GPU上情况就有所不同,例如在Mali上,Image对象的读写性能甚至比普通的Buffer读写还要慢很多。因此在开发前要调研平台厂商对各API的支持情况再做选择。 图片来自 Qualcomm® Snapdragon™ Mobile Platform OpenCL General Programming and Optimization
目前TensorFlow作为主流训练框架,有灵活性高,扩展性强等优点,但同时也带来一个问题,那就是过细的算子粒度严重限制了终端推断的性能。以谷歌官方开源的MobileNetSSD模型为例,其NMS(non maximum suppression)运算的实现包含了652个节点,若每个节点逐个运算则会发生数百次内存读写,这显然是不划算的,因此VCAP将这652个节点转换为融合为一个NMS层, 这样只需几次读写即可完成计算。 在推断过程中,一些特定的算子可以再度进行融合,进一步的减少内存读写次数,最经典的就是Convolution+Batchnorm+ReLU组合,将这三个算子融合可以避免在Batchnorm层和ReLU层再进行内存的读取。