Page 330 - 《软件学报》2020年第9期
P. 330
董晓 等:面向稀疏卷积神经网络的 GPU 性能优化方法 2951
在此之上,我们再建立卷积参数位置与参数取值之间的映射.具体来说,我们随机生成取值不相同且非 0 的
模板参数,取值不同保证了由参数取值可以唯一确定参数的位置.在编译卷积算子模板的过程中,我们将模板参
数作为立即数提供给编译器;同时,我们将涉及模型参数的循环进行展开,使得这些参数被编码到相应的计算指
令中.这样,通过解析指令中立即数的取值,便可以唯一确定参数的位置.同时,循环展开消除了循环控制相关指
令,也给编译器更大的空间进行指令调度等优化,有利于编译器生成性能更好的代码.由于循环展开会导致指令
数目增多,使得编译生成的文件增大.我们在第 3.7 节对编译生成的文件体积以及循环展开对运行时指令获取
的影响进行了分析.
PTX 也适合进行高效的指令间依赖关系分析.PTX 程序符合静态单赋值(SSA)的形式,且使用虚拟寄存器.
PTX 代码中使用的每个寄存器都有唯一的一次定值,因此建立寄存器之间的依赖关系十分简单.通过解析指令
中的寄存器的名字,我们可以高效地追踪指令之间的依赖关系.最后,由于我们生成的是不含 0 的模板参数,所以
每个模型参数可能涉及的指令都被保留在了中间表示模板中.所以不论具体的稀疏参数如何,该中间表示都能
用于生成对应的稀疏程序.图 5 展示了对应的模板中间表示的例子.
2.3 稀疏算子代码生成
基于算子的中间表示模板,我们设计了结合具体的稀疏参数生成对应稀疏卷积代码的算法.稀疏算子代码
生成算法主要完成两项工作:首先是将模板参数替换为真实的稀疏参数,保证计算过程中使用参数的正确性;第
二是识别由稀疏参数带来的冗余指令,并对其进行删除;同时,还需要维护由于删除指令导致的寄存器依赖关系
的变化,以保证程序的正确性.以上工作通过对 PTX 中间表示模板的遍历完成,该算法的伪代码见算法 2.
算法 2. 稀疏算子代码生成算法.
输入:ptxTemp,中间表示模板;paramTemp,模板参数;paramReal,真实稀疏参数;
输出:ptxCode,为真实稀疏参数生成的 PTX 代码.
初始化 2 个 Map valueMap,regMap 为空
for valTemp in paramTemp, valReal in paramReal do
valueMap[valTemp]=valReal //建立模板参数与真实参数的映射
end for
for inst in ptxTemp do
if inst.op==FFMA then //rd=rs+rt*imme
if regMap.find(inst.rt)!=null then
inst.rt=regMap[inst.rt] //将源寄存器 rt 替换为其他寄存器
end if
if regMap.find(inst.rs)!=null then
inst.rs=regMap[inst.rs] //将源寄存器 rs 替换为其他寄存器
end if
if valueMap.find(inst.imme)!=null then
inst.imme=valueMap[inst.imme] //进行参数替换
if inst.imme==0 then
regMap[inst.rd]=inst.rs //建立寄存器映射
continue
end if
end if
if regMap.find(inst.rd)!=null then
regMap.remove(inst.rd)
end if