用 Intel MKL-DNN 加速 CPU 上的深度学习

https://zh.mxnet.io/blog/mkldnn

2赞

win10不可以pip安装这个吗?为啥win系统不支持mkl?

我们之前只测了Linux和Mac,接下来会测windows下的情况

@yajiedesign 在看windows上加mkldnn的pip

@mli你好,我自己下载了mxnet1.1.0的源代码,然后自己编码了mkldnn,之后自己编译mxnet源码,命令是:
make -j6 USE_OPENCV=0 USE_BLAS=openblas USE_MKLDNN=1,然后运行对比测试代码:
python example/image-classification/benchmark_score.py
结果输出如下:
INFO:root:network: alexnet
INFO:root:device: cpu(0)
/home/yuhailong/mxnet/mxnet-1.1.0/example/image-classification/common/…/…/…/python/mxnet/module/base_module.py:65: UserWarning: Data provided by label_shapes don’t match names specified by label_names ([] vs. [‘softmax_label’])
warnings.warn(msg)
INFO:root:batch size 1, image/sec: 0.363634
INFO:root:batch size 2, image/sec: 0.692053
INFO:root:batch size 4, image/sec: 1.324526
INFO:root:batch size 8, image/sec: 2.439384
INFO:root:batch size 16, image/sec: 4.155372
INFO:root:batch size 32, image/sec: 6.034794
INFO:root:network: vgg-16
INFO:root:device: cpu(0)
INFO:root:batch size 1, image/sec: 0.232238
INFO:root:batch size 2, image/sec: 0.409029
INFO:root:batch size 4, image/sec: 0.707874
INFO:root:batch size 8, image/sec: 0.994092
INFO:root:batch size 16, image/sec: 1.174787
INFO:root:batch size 32, image/sec: 1.285164
INFO:root:network: inception-bn
INFO:root:device: cpu(0)
INFO:root:batch size 1, image/sec: 0.028402
INFO:root:batch size 2, image/sec: 0.055161
INFO:root:batch size 4, image/sec: 0.111352
INFO:root:batch size 8, image/sec: 0.223585
INFO:root:batch size 16, image/sec: 0.443112
INFO:root:batch size 32, image/sec: 0.837961
INFO:root:network: inception-v3
INFO:root:device: cpu(0)
INFO:root:batch size 1, image/sec: 0.030091
INFO:root:batch size 2, image/sec: 0.059302
INFO:root:batch size 4, image/sec: 0.121320
INFO:root:batch size 8, image/sec: 0.230315
INFO:root:batch size 16, image/sec: 0.424866
INFO:root:batch size 32, image/sec: 0.752719
INFO:root:network: resnet-50
INFO:root:device: cpu(0)
INFO:root:batch size 1, image/sec: 0.074046
INFO:root:batch size 2, image/sec: 0.151813
INFO:root:batch size 4, image/sec: 0.300984
INFO:root:batch size 8, image/sec: 0.548719
INFO:root:batch size 16, image/sec: 1.017807
INFO:root:batch size 32, image/sec: 1.701143
INFO:root:network: resnet-152
INFO:root:device: cpu(0)
INFO:root:batch size 1, image/sec: 0.024533
INFO:root:batch size 2, image/sec: 0.051374
INFO:root:batch size 4, image/sec: 0.101497
INFO:root:batch size 8, image/sec: 0.189935
INFO:root:batch size 16, image/sec: 0.344986
INFO:root:batch size 32, image/sec: 0.600156
这个结果看起来速度比较慢,请问一下是我编译的哪里有问题吗,还是运行比较代码时需要指定什么参数?

设置一下这个环境变量MKLDNN_VERBOSE=1, 然后看看屏幕输出有没有MKL-DNN的函数被跑到。

另外你可以下载MKL库作为blas并加上如下设置,这样速度会快很多。

export KMP_AFFINITY=granularity=fine,noduplicates,compact,1,0
export OMP_NUM_THREADS=

@pengzhao-intel你好,有几个问题想问您:
1、我加上export MKLDNN_VERBOSE=1后, 没有打印出MKLDNN的相关信息,我都是用源码自己编译,我编译mxnet-1.1.0的时候用的make -j6 USE_OPENCV=0 USE_BLAS=openblas USE_MKLDNN=1有什么问题?
2、我在Makefile中没有找到MKLDNN的设置宏,只找到了MKLML的宏,是不是现在的Makefile文件有问题?
3、我希望在单核上测试单线程的计算速度,所以不能使用openmp来测试。
多谢!

@yhl41001 如果从源码编译,你可以试试直接拉master branch:)

你的CPU是什么型号,如果我有可以给你个参考数据。

@pengzhao-intel你好,我也下载的版本是这样的:
git clone --recursive -b v1.1.0 https://github.com/apache/incubator-mxnet.git mxnet-1.1.0
我的CPU型号:Intel® Xeon® CPU E5-2690 v4 @ 2.60GHz,系统是ubuntu16.04.
这个只是我的测试机,还有其他型号的CPU,但只有配置文件弄好了,编译在各个CPU上差别应该不大吧。
麻烦您看一下我之前的编译有哪些配置问题吗?

@pengzhao-intel你好,问题已经解决了,原因是我用
git clone --recursive -b v1.1.0 https://github.com/apache/incubator-mxnet.git mxnet-1.1.0
这个方法下载下来的代码,Makefile中没有添加mkldnn的设置选项,然后用
git clone --recursive https://github.com/apache/incubator-mxnet.git
这个命令下载下来的Makefile是对的,重新编译后就可以,加速也达到了文档所说的速度。
非常感谢!

太好了:)

@pengzhao-intel非常感谢,建议您可以把1.1.0里的Makefile也加上mkldnn的选项,可能会有人不下载master分支而是下载指定版本,以免造成不必要的麻烦。多谢!

@yhl41001 因为1.1.0的release里还没有集成mkldnn。目前只在master branch中有mkldnn的功能,并有可能会在1.2.0中release出来。如果你希望在1.1.0的code中使用mkl的featrue,建议在make时加上USE_MKL2017=1和USE_MKL2017_EXPERIMENTAL=1。

1赞

@TaoLv多谢了,我已经解决了。
因为blog里给出的可以下载的版本是1.1.0版本,所以我就下载了1.1.0版本的源码。

pip install —-pre mxnet-mkl

链接中的文档,这里有误,中间两个横杠,一个是中文的,一个是英文的。

1赞

使用中如果有什么问题,欢迎提问:)

1赞

linux里需要把–pre放在最后面才能安装

pip install mxnet-mkl --pre

吊吊吊吊吊吊调调地道吊吊吊do我到我我奥ID啊都i

速度从2个核不到到了14核

1赞

控制线程的数量是怎麼設置的?跑mkl-dnn的編譯測試程序cpu四個內核負載都是滿的,跑mxnet的只用了2個內核設置了環境變量也沒有變化。

OMP_NUM_THREADS环境变量可以控制线程数。你的机器几个物理核,有开超线程吗?

关于mxnet-mkldnn只用一半的cpu核的问题@pengzhao-intel

我的cpu信息如下:

Architecture:          x86_64
CPU op-mode(s):        32-bit, 64-bit
Byte Order:            Little Endian
CPU(s):                28
On-line CPU(s) list:   0-27
Thread(s) per core:    1
Core(s) per socket:    14
Socket(s):             2
NUMA node(s):          2
Vendor ID:             GenuineIntel
CPU family:            6
Model:                 79
Model name:            Intel(R) Xeon(R) CPU E5-2690 v4@ 2.60GHz
Stepping:              1
CPU MHz:               3499.539
BogoMIPS:              5205.87
Virtualization:        VT-x
L1d cache:             32K
L1i cache:             32K
L2 cache:              256K
L3 cache:              35840K
NUMA node0 CPU(s):     0-13
NUMA node1 CPU(s):     14-27

用mxnet-mkldnn跑benchmark_score.py的结果很好,下面是resnet-50的结果:

INFO:root:batch size 16, image/sec: 82.011372
INFO:root:batch size 32, image/sec: 86.430563
INFO:root:batch size 64, image/sec: 90.050148
INFO:root:batch size 128, image/sec: 90.267582
INFO:root:batch size 256, image/sec: 90.518156

查看cpu使用情况,发现只用了14个cpu,剩下14个处于空闲状态。具体cpu利用率如下:

Threads:  20 total,  14 running,   6 sleeping,   0 stopped,   0 zombie
%Cpu(s): 49.2 us,  0.9 sy,  0.0 ni, 50.0 id,  0.0 wa,  0.0 hi,  0.0 si,  0.0 st
KiB Mem : 13191868+total, 12510168+free,  5682128 used,  1134872 buff/cache
KiB Swap:        0 total,        0 free,        0 used. 12540582+avail Mem 

  PID USER      PR  NI    VIRT    RES    SHR S %CPU %MEM     TIME+ COMMAND                                          nTH  P 
29480 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.55 python                                            20 16 
29482 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.55 python                                            20 12 
29483 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.55 python                                            20 17 
29484 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.55 python                                            20 18 
29486 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.53 python                                            20  8 
29490 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.53 python                                            20 10 
29491 daodao    20   0 4993856 1.786g  33724 R 99.9  1.4   0:37.53 python                                            20 21 
29478 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.37 python                                            20 27 
29479 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.54 python                                            20 15 
29481 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.54 python                                            20  6 
29485 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.54 python                                            20  9 
29487 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.53 python                                            20 20 
29488 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.53 python                                            20 19 
29489 daodao    20   0 4993856 1.786g  33724 R 99.7  1.4   0:37.53 python                                            20 11 
29468 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:01.59 python                                            20  3 
29471 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:00.00 python                                            20  1 
29474 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:00.00 python                                            20 15 
29475 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:00.00 python                                            20 16 
29476 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:00.00 python                                            20  4 
29477 daodao    20   0 4993856 1.786g  33724 S  0.0  1.4   0:00.00 python                                            20 17 

我的理解:这应该是考虑到大多数cpu都开启了超线程,一个core上有两个硬件超线程,如果同时使用一个core上的两个Thread运算,L1-L3 cache等资源会有很大冲突,反而不如一个线程跑的快,从而默认设置只用一个core上的一个Thread。同理,

export KMP_AFFINITY=granularity=fine,compact,1,0
export vCPUs=`cat /proc/cpuinfo | grep processor | wc -l`
export OMP_NUM_THREADS=$((vCPUs / 2))

就是设置每个core上启动一个thread,避免资源冲突。而我的cpu每个core上只有一个thread,28个core都是物理核,不是超线程,如果全部用起来,启动28个thread,其之间应该也不会有太大冲突,应该能提升性能。这种情况下,想咨询一下如何让mkldnn使用所有的cpu?望指教。

后记,看了下engine中的代码,发现相对于以前的版本添加了很多设置omp-thread的部分和BulkStatus(应该是把多个cpunormal操作整合成一个大op去执行)。发现直接设置OMP_NUM_THREADS可以调用所有的cpu。export OMP_NUM_THREADS=28后速度如下:

INFO:root:batch size 16, image/sec: 126.780864
INFO:root:batch size 32, image/sec: 126.437795
INFO:root:batch size 64, image/sec: 116.306735
INFO:root:batch size 128, image/sec: 117.576966
INFO:root:batch size 256, image/sec: 135.782432

初步看利用率确实高了些,但这是最简单的设置方法,部分cpu中应该存在竞争关系。是否可以进一步细粒度分配cpu:engine本身占用小部分,计算线程占用大部分从而避免cpu冲突?

1赞