在机器学习中,经常遇到稀疏向量,稀疏矩阵。如何高效处理这些稀疏对象,决定了一些模型能否在线落地应用。目前正在专攻这方面,自己瞎琢磨,走了不少弯路,也有一点心得。这里记录下来,不断总结。
当遇到计算瓶颈时:
-
算法层面改进
这是最直接,收益也最大的。
比如在千万级以上的向量空间中搜索最近邻居,暴力的两两计算代码层面无论如何加速计算量依然太大了。
faiss通过预训练聚类和向量压缩大大减少搜索时的计算量。上亿级别搜索也能在毫秒级完成。例外情况是计算量本身不是特别大,而且在代码层面很方便加速,改进对CPU负载的也不是特别大。比如利用avx和openmp,这时直接代码加速也是可行的。
-
第三方库
当要在代码层面加速时,首先考虑已有的第三方库。选择库时第一原则轻量,稳定,而不是花哨,功能强大。
BLAS实现中openblas最好用,但是只支持稠密矩阵。MKL支持稀疏矩阵,性能也最好,但是编译链接很麻烦。
-
手动优化
BLAS库适用场景是超大矩阵和超大向量,一次计算结果写回内存。如果计算步骤过多,中间结果读写内存会有很大开销,这时比较适合手动优化。
手动优化需要充分利用寄存器和缓存,尽量让中间结果在寄存器和缓存中保存。其实挺难的,而且现代硬件已经特别复杂,自己臆想的一些手段不一定就符合硬件的喜好。所以验证很重要。
并行计算
当并行数不大时,可以直接使用cpu并行。但是cpu核心毕竟比较少,大规模并行GPU更有优势,这是目前正在尝试的方向。
心得:
- 工程实现常常要对公式做变换,利于向量计算或并行计算。因此理解核心算法才能做出取舍和变换。
- 多多学习第三方库的优秀算法,第三方库的实现通常为了考虑通用性优化没有做到极致。而为了适应手头的需求可以各种魔改,优化就是特化。