前面提到了利用caffe训练模型时,只用单个CPU核的问题,通过openblas的方式解决了,但即使多个核用上了,但速度还是超级慢。


就目前使用的网络而言,1min只能跑30 iter(1个iter 128个样本),即30*128 = 3840 样本/min, 为什么如此之慢呢?是不是代码出了问题,或者哪里的设置不对?


尝试和lenet进行对比,利用8核CPU根据lenet训练mnist,大概8min完成10000iter(一个iter 64个样本),即10000*64/8 = 80000 样本/min


从这里的对比来看,lenet的训练速度还是正常的,网上也有提出训练lenet花费了10min左右。那么为什么速度差别这么大呢?应该是网络计算量的原因。


通过https://dgschwend.github.io/netscope/#/editor可以查看网络的计算量,在左侧输入网络的deploy.prototxt文件即可,然后按shift + enter即可查看网络的计算量。
分析发现lenet网络的计算量为2.29M,而我们的网络的计算量为36.08M,这样就分析清楚了,3840*36.08 = 138547.2,而80000*2.29 = 183200,还是比较接近的。因此训练的速度应该就是这样了。


另外又将caffe下的训练速度和tensorflow下的训练进行对比,发现很奇怪的事情

tensorflow    
  caffe 

 GPU 
  700 iter/min 
 1500 iter/min  

 CPU 
  200 iter/min 
 20 iter/min

 
难道caffe的CPU速度如此之慢?还不明白是为啥。




再做一次实验,在tensorflow和caffe利用mnist数据集训练lenet网络(网络结构根据caffe中的example修改,另外写一个tensorflow的lenet网络),看一下耗时。
得到的数据如下:
用mnist训练lenet, 10000 iter, 每个batch 64个样本


  GPU + CPU CPU 核数无限制 CPU 8核
 tensorflow 50s 219s 258s
 caffe 30s 1000s+
 900s


从这里可以看出,caffe在GPU模式下确实速度会比tensorflow快,但CPU模式下的速度却要慢很多。(这里有个问题就是caffe在CPU模式下用的核越多,速度却变慢了,这个问题其他人也有提到,不明所以)




查资料,有提到说openblas需要用OpenMP编译,即使用openblas的多线程形式,有可能默认通过apt-get下载安装的openblas并没有使用了openmp。在前面的博客提到了如何安装openblas以及使用cpu的多核进行训练。


1、首先对比一下通过apt-get安装的openblas和自己编译安装的openblas的区别
通过 sudo apt-get install libopenblas-dev安装的openblas在默认目录/usr/lib下,可以通过ldd命令查看其使用的so库,结果如下
-Bash 代码

1 

ldd /usr/lib/libopenblas.so 

2 

  

3 

linux-vdso.so.1 =>  (0x00007fffb435a000) 

4 

libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa84028b000) 

5 

libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa84006d000) 

6 

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa83fca3000) 

7 

/lib64/ld-linux-x86-64.so.2 (0x0000560783ce6000) 



再手动编译安装openblas 

  

首先从https://github.com/xianyi/OpenBLAS下载openblas, 

然后unzip OpenBLAS-xxx, 

再 make USE_OPENMP=1 

再sudo make install 

即把openblas安装到了 /opt/OpenBLAS目录下 



安装好之后, 

-Bash 代码 

01 

ldd /opt/OpenBLAS/lib/libopenblas.so 

02 

  

03 

linux-vdso.so.1 =>  (0x00007fffe6988000) 

04 

libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007f3876368000) 

05 

libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007f387614a000) 

06 

libgfortran.so.3 => /usr/lib/x86_64-linux-gnu/libgfortran.so.3 (0x00007f3875e2f000) 

07 

libgomp.so.1 => /usr/lib/x86_64-linux-gnu/libgomp.so.1 (0x00007f3875c20000) 

08 

libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007f3875857000) 

09 

/lib64/ld-linux-x86-64.so.2 (0x000055933fb64000) 

10 

libquadmath.so.0 => /usr/lib/x86_64-linux-gnu/libquadmath.so.0 (0x00007f387561a000) 

11 

libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007f3875404000)




由此可见通过自己编译安装的openblas,再调用了libgomp等其它的库。


2、通过openblas编译caffe


通过apt-get安装的openblas,默认在/usr/lib中,因此编译caffe,修改caffe中的Makefile.config中的BLAS即可,再编译即可
但要使用自己编译的openblas来编译caffe,在Makefile.config中有个blas的lib和include的目录设置,但设置后,不能有效


最终通过export LD_LIBRARY_PATH=/opt/OpenBLAS/lib才搞定,


再用ldd build/lib/libcaffe.so, 就可以看到这里面用的是/opt/OpenBLAS/lib中的so库。




3、再看一下两者的训练速度对比


通过apt-get安装的方式,openblas可以设置OPENBLAS_NUM_THREADS=N来设置使用多少个CPU核
而通过自己编译安装的openblas,则可以设置OMP_NUM_THREADS=N来设置使用多少个进程


通过OMP_NUM_THREADS来设置,会发现,基本无效,用1个进程,用4个进程和用8个进程,速度基本无变化




尴尬啊,这个问题还是解决不了啊




参考博文:
Caffe:CPU模式下使用openblas-openmp(多线程版本)




就caffe使用openblas+openmp,设置OMP_NUM_THREADS,训练速度却不能提升的问题,进行调研,没有太好的解决方案,在网上看到有说进程加速依赖于网络结构,有些网络结构可以加速,有些不行。也有说设置OMP_NUM_THREADS=1就好。众说纷纭,不知所以然。




如果这条路走不通,那么可能的解决方案有如下几个:


1、OPENMP的加速方案,有人在caffe提交了pull request,据说可以加速5-10倍,https://github.com/BVLC/caffe/pull/439,但caffe没有接受该PR,为了代码的稳定性


2、intel版本的caffe,据说是做过加速的,可能存在的问题:(1)、是否收费,有没有用intel的MKL库,这个库应该是收费的,(2)、产品需要做开源代码的认证(intel的caffe版本,我司应该没有做过认证)(https://software.intel.com/en-us/articles/comparison-between-intel-optimized-caffe-and-vanilla-caffe-by-intel-vtune-amplifier)


3、再退回到tensorflow,用tensorflow的c/c++ API,存在问题:(1)、tensorflow的C/C++训练模型,参考较少;(2)、tensorflow的c/C++未实现auto differentiation?


4、再转战其它框架,抓狂






目前寄希望于在caffe中使用MKL库和使用intel优化的caffe版本。




前面碰到的一个就是通过设置OMP_NUM_THREADS无效果,设置它的值越大,训练速度越慢,设置一个较小的值时,反而训练速度更快,做了一些尝试,发现如果用adam优化算子,则设置OMP_NUM_THREADS无效果,如果用其它的则有效,通过把adam算子替换,再设置OMP_NUM_TRHEADS=8时大概会有3倍速度的提升。
-Bash 代码

1 

base_lr: 0.001 

2 

momentum: 0.9 

3 

momentum2: 0.999 

4 

  

5 

lr_policy: "fixed" 

6 

type: "Adam" 

-Bash 代码 

1 

base_lr: 0.001 

2 

momentum: 0.9 

3 

  

4 

lr_policy: "step" 

5 

gamma: 1 

6 

stepsize: 5000




但上面的配置涉及到学习率调整的问题,以及参数的微调,没能达到和Adam一样的准确率。


那么开始转战使用intel的mkl库,以及intel的caffe版本。


使用intel的caffe版本主要参考这个intel出的性能对比说明  
Benefits of Intel® Optimized Caffe* in comparison with BVLC Caffe*
https://software.intel.com/en-us/articles/comparison-between-intel-optimized-caffe-and-vanilla-caffe-by-intel-vtune-amplifier

在这里,说明了,使用intel的caffe+mkl,可以达到多大性能的提升。




首先来看一下,如何在原生的caffe中使用intel的mkl库。


mkl库和atlas、openblas的功能一致,需要下载安装后,在caffe中的makefile.config文件中进行配置即可。
下载mkl库,需要先到intel网上进行注册申请,https://software.intel.com/en-us/mkl。申请后,一般会受到一封邮件,里面包含了注册码等信息,然后再申请一个intel的账号,就可以下载mkl了,会得到类似“l_mkl_2018.1.163.tgz”文件名的mkl压缩包,之后就可以进行安装了。但是我申请了,等了四五天都没有收到邮件,不知道哪里有问题,可以找其他同事也试一试。


下载安装文件后,在Ubuntu下解压缩,tar -xvzf l_mkl_2018.1.163.tgz, 进入到解压后的目录下,运行./install.sh 根据提示操作,完成mkl库的安装,安装后,默认在/opt/intel目录下会有mkl的lib和include。


完成mkl库的安装,然后就是重新编译caffe。


在caffe的主目录下,配置Makefile.config, 修改BLAS的内容,如下:


-Bash 代码 

1 

BLAS := mkl 

2 

BLAS_INCLUDE := /opt/intel/mkl/include 

3 

BLAS_LIB := /opt/intel/mkl/lib/intel64




另外,在编译caffe,和openblas类似,也需要导入lib库到LD_LIBRARY_PATH,因此先执行
-Bash 代码

1 

export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/opt/intel/mkl/lib/intel64




再make clean, make all -j32,就可以完成编译了。
再用ldd build/tools/caffe 可以看到依赖于libmkl_rt.so这个库了。
但是只是用mkl库编译原生的caffe,训练速度提升不明显,感觉和OpenBLAS开多个线程的区别不大。提升很有限。


那么继续尝试intel的caffe版本,首先需要下载intel的caffe 源码,


git clone https://github.com/intel/caffe


(这里需要确保git clone正常可以用,后面在编译intel-caffe的时候也需要用到,会下载mkl-dnn的源码等)
然后配置Makefile.config文件,和之前使用mkl库的方式一样,配置blas为mkl。然后就开始make就行了。


如果是通过windows下载了intel-caffe,然后拷贝到linux上,再解压,可能会有些.sh文件无执行权限,编译时会出错。




如果编译无误了后,就可以开始执行了,可以发现,确实速度有很大的提升,大概相比于原生的caffe有7-8倍速度的提升,和intel官方给的数据可能有一点偏差,主要是用原生的caffe+mkl的速度没有intel官方说的那么慢。


但我在训练我的网络碰到了一些问题,准确率不上升,但是用caffe自带的网络结构训练mnsit和cifar10,是没有问题。


一开始检查发现,intel-caffe会默认有一些网络结构的优化,在src/caffe/net.cpp中,去掉优化后,还是有问题,于是重新开始搭建网络结构,一层一层的搭,发现增加第三个卷积层,就会出错,完全相同的网络结构,完全相同的数据,但在intel-caffe和原生的caffe表现不同,intel-caffe开始训练不动,准确率不上升了。百思不得其解,也无从下手解决该问题,机缘巧合发现,稍微修改下网络结构有效,即将第三个卷积核的大小从5改为9或11,就好了,一切正常。


这个问题,可能比较奇怪,也不知道怎么解决,大多人数人应该不会遇到吧。


好的,这样子,就可以用intel加速后的caffe版本了。速度确实快了不少。