Page 329 - 《软件学报》2020年第9期
P. 329
2950 Journal of Software 软件学报 Vol.31, No.9, September 2020
外,由稀疏性带来的冗余操作不仅局限于卷积参数直接参与的计算指令.对于输入元素 Input n,c,h,w ,如果与它进行
计算的所有参数取值都为 0,那么对它的访问也同样是冗余的,相应的访存指令可以删除.同样地,如果计算某个
卷积输出结果涉及的全部参数取值均为 0,那么对它的存储操作也是冗余的.因此,如果从稠密的卷积计算中识
别并删除由稀疏参数造成的冗余指令,便可以获得针对稀疏参数的卷积代码.我们的稀疏算子代码生成方法就
基于删除冗余操作指令的思想.
为了实现冗余指令的识别和删除,我们需要解决以下几个问题:第一,需要建立一种算子的中间表示,这种
中间表示能够支持分析模型参数与计算指令的对应关系;其次,中间表示需要支持快速准确的指令依赖分析;最
后,由于相同的算子可能被用在不同的神经网络中,对应不同的稀疏参数取值,所以该中间表示应该能够作为模
板,适配不同的稀疏参数,并生成相应的代码.
面对上面的问题,我们设计了一种算子中间表示.该中间表示基于英伟达 PTX(parallel thread execution)形
式.PTX 是英伟达设计的一套虚拟的体系结构和指令集,而且是 GPU 程序编译过程中的中间结果.图 4 展示了
GPU 程序使用英伟达 nvcc 编译器的编译过程以及各阶段输出结果的形式.
.cubin
.cu 文件 cudafe .gpu 文件 cicc .ptx 文件 ptxas
文件
Fig.4 nvcc compilation stages and imtermediate results
图 4 nvcc 编译阶段与中间结果示意图
下面分别介绍该算子中间表示如何解决上面的 3 个问题.首先是建立每个模型参数与依赖的指令序列之
间映射的问题.在算法 1 中,每个卷积参数可以由作为下标的循环变量 k,c,r,s 唯一确定,而同时,循环变量也可以
确定一次迭代中具体的计算.所以,一个直接的策略就是通过循环变量将卷积涉及的乘累加(fused multiply-add,
简称 FMA)指令与对应的卷积参数联系起来.但是在后续编译器的指令调度过程中,编译器可能会对指令的顺
序进行调整.所以在最终生成的代码中,乘累加指令出现的顺序与循环遍历的顺序是不一致的.我们需要设计新
的机制,将卷积参数与对应的指令关联起来.考虑到模型参数和 GPU 指令两方面的特点,我们采用了一种基于
参数取值的关联机制.GPU 的代数运算指令通常有一种直接编码立即数操作数的形式,例如,图 5 展示了编码了
立即数的单精度浮点数乘累加指令 FFMA,指令 FFMA R 3 ,R i ,1.2,R 2 表示执行 R 3 =R i ×1.2+R 2 的计算,作为操作数
之一的立即数 1.2 会直接编码在指令中.这种形式的指令能够将参与计算的数据与指令直接关联起来.
RegMap
RegMap
R3→R2
RegMap
R3→R2
Fig.5 Example of intermediate representation template and sparse code generation
图 5 中间表示模板与稀疏代码生成示意图