背景
笔者正在做一个c++/python混合的项目,其中有一部分涉及升级网络推理。原有网络已经使用tensorflow/keras训练完成。
可选方案
- tensorflow-lite:tensorflow-lite模块是tensorflow针对边缘计算和服务部署推出的模块,可以在不同平台和编程语言下进行神经网络的推理,号称做了性能优化,并且可以对模型进一步压缩,提高计算性能。
- 原生tensorflow:原生tensorflow在python中使用非常方便,但是在c++中使用时,编译令人秃头。
- Eigen:Eigen是C++中最主流的矩阵运算库之一,做了十分极致的优化。
对比
tensorflow vs. tflite
由于作者比较懒,就直接拿实际要用的网络做实验了。网络结构时mix of experts的两级结构,第一部分由两个隐藏层,每层32个神经元,输出N个参数,作为权重。第二部分是专家网络,也是两个隐藏层,但是一共有N个网络,根据前面的N个参数,对参数进行加权平均,再使用平均值后的参数进行计算。专家网络规模较大,论文原文使用了8个专家网络,专家网络每层512个神经元的网络结构。本文使用不同规模的专家网络对tf和tflite的性能进行测试,由于最终应用还是在CPU上跑,所以使用了i5-6500。
(单位:秒)
模型 | 4-128-128 | 8-128-128 | 4-256-256 | 8-256-256 | 4-512-512 | 8-512-512 | 4-1024-1024 | 8-1024-1028 |
---|---|---|---|---|---|---|---|---|
tf-lite | 0.0035 | 0.0068 | 0.0090 | 0.017 | 0.030 | 0.055 | 0.10 | 0.19 |
tf | 0.0084 | 0.0087 | 0.0090 | 0.010 | 0.011 | 0.013 | 0.019 | 0.029 |
模型一栏的A-B-C表示A个专家,专家网络两个隐藏层的大小分别为B和C。tf使用pip安装,未专门编译,没有AVX加成。
从表格数据可以看出,tf和tf-lite的计算复杂度不同。tf-lite复杂度更高,对小模型性能好,但是scalibility较弱,而tf的scalibility强。猜测tf-lite为了提高性能,阉割了多线程优化部分的功能。
tensorflow vs. Eigen
同样由于作者比较懒,这一部分只做了矩阵乘法的测试,但是结果很显然是有GPU用GPU,没GPU用CPU多线程的tensorflow吊打老老实实单线程跑的Eigen。
实验测试了两个N×N的矩阵乘法性能,时间单位为毫秒。测试平台是双路E5-2696v4/四路GTX 1080Ti,内存管够。tensorflow依然使用pip安装,无AVX加成,C++编译器使用gcc-8。
N | 32 | 64 | 128 | 256 | 512 |
---|---|---|---|---|---|
Eigen -O0 | 0.287 | 2.03 | 10.8 | 69.5 | 533 |
Eigen -O3 | 3.05 | 16.6 | |||
tf gpu | 0.460 | 0.829 | |||
tf cpu | 0.573 | 1.89 |
不开优化的c++程序运行极慢,使用优化之后性能提高几十倍,测试中O1 O2 O3优化性能都差不多,猜测主要优化了矩阵乘法里面的循环。但是即使如此,还是比tf gpu慢了20倍,而且复杂度更高。同样是cpu,由于tensorflow使用多线程,所以速度仍然比Eigen快,特别是在44C88T这种超多核心的服务器上,对于“小矩阵”的计算甚至能接近GPU。理论上用C++ mkl加上simd优化,应该能接近tf cpu的性能。
小结
综上,原生tensorflow仍然是大型神经网络推理的最佳选择。对于小型神经网络,可以尝试tf lite,特别是内置的模型压缩功能。用C++徒手写矩阵计算的方式吃力不讨好。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。