1. 背景
随着人工智能和神经网络的发展,浮点运算的占比越来越大,而浮点运算本身又比较耗时,所以,对大批量数据进行浮点运算时常要耗费数月甚至数年的时间,如:神经网络模型的训练与应用。
2. 硬件加速
浮点运算基础版本使用的是数学协处理器FPU,其拥有8个80位的数据寄存器,所有的浮点运算都是在这8个寄存器上进行的。每个寄存器可以存放一个数据,而且部分寄存器拥有特殊用途,所以,FPU中无法进行运算加速。
后续出现的SSE在一定程度上提高了浮点运算速度。SSE开始支持128位的寄存器,每次可以存放4个单精度浮点数,因而可以一次处理4个同种类的运算。假设FPU要对1000组数据进行加法运算,需要执行1000次的加法指令;而用SSE的128位寄存器进行运算,最少只需执行250次的加法指令即可完成。
再后来出现的AVX以及64位环境下可用的AVX-512进一步扩大了寄存器的尺寸,AVX使用8个256位的寄存器,AVX-512使用8个512位的寄存器。若用AVX-512进行浮点加速,一次可以对16组单精度浮点数进行运算,沿用上例,1000组数据的加法用AVX-512执行的话,最少只需执行62.5次的加法指令即可完成,相对于FPU来说,运算时间减少了93.75%。
后续出现了不少其它的加速方式和配套硬件,典型的是现如今广泛使用的GPU和CUDA编程,其在神经网络模型训练过程中得到了广泛的使用。
3. 分析与总结
从上述讨论中可以看到,对于批量数据的单次同种运算,可以节省很大比例的运算时间。但是,在实际程序运行过程中进行统计和对比发现,加速效果远远达不到预期,甚至在少量环境下还会产生恶化,优化后的程序运行需要消耗更多的时间。
从任务总体过程来看,数据需要不停地在内存与寄存器之间进行传递,这部分操作消耗了大量的时间,甚至远远超过数据在寄存器中执行所消耗的时间,而这部分时间损耗未能得到优化。
这种问题尤其在神经网络这种连续多个运算级联的情形下会产生较大的影响。假设要对1000组数据先进行加法运算,在对运算结果求sin,最后对正弦结果做二值分类。硬件加速后的执行过程是:加载一批数据到寄存器-->加法运算-->把该批结果写回内存-->加载下一批数据到寄存器-->加法运算-->......-->加载一批和值到寄存器-->sin-->把该批结果写回内存-->加载下一批和值到寄存器-->sin-->......-->加载一批sin值到寄存器-->比较分类-->把该批分类结果写回内存-->加载下一批sin值到寄存器-->比较分类......可以看到,在这个过程中不断地重复着读内存、写内存,这不仅消耗大量时间,还打断了流程。如果不用硬件加速的话,可能会是这样的情形:读第一组数据到寄存器-->加法运算-->sin-->比较分类-->把结果写回内存-->读下一组数据到寄存器-->......孰优孰劣尚难评判
综上所述,对于浮点运算的加速,不能简单提高单次数据吞吐量,尤其是对于模型训练这种存在大量异种运算的任务,比硬件本身更重要的是优化算法本身,包括优化模型、计算方法、计算流程等。当然了,对于简单的浮点运算,提高单次吞吐量的硬件加速就能达成预期,譬如对于一大批数据仅执行一两次的同种运算。