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
   325   326   327   328   329   330   331   332   333   334   335