- 深度学习
- 人工智能
- 机器学习
- 分布式训练
【免费下载链接】mxnet
Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more
本文是一份完整的 MXNet + oneDNN 集成指南:从 Linux、macOS、Windows 三大平台的编译安装开始,逐步讲解如何验证 oneDNN 后端是否真正生效、如何启用 Intel MKL BLAS 进一步提速,以及如何利用optimize_for图优化和 INT8 量化在 Intel 架构 CPU 上获得更好的训练与推理性能。读完本文,你将掌握一条可直接复制的"源码编译 — 功能验证 — 性能调优"完整链路。
oneDNN 在 MXNet 中的角色
oneDNN(oneAPI Deep Neural Network Library,原 MKL-DNN)是 Intel 开源的深度神经网络原语库,为卷积(convolution)、逐元素操作(eltwise)、reorder 等算子在 Intel 架构 CPU 上提供高度优化的 JIT 实现。MXNet 内置 oneDNN 支持,在 Linux、Windows 和 macOS 上以 oneDNN 为 CPU 后端编译后,预期能在 Intel 架构 CPU 上获得更好的训练和推理性能。
从构建系统看,CMakeLists.txt 中USE_ONEDNN选项的默认值会随平台自动调整:
- 在非 Apple、非 MSVC 的 x86_64 主机且非交叉编译环境下,
USE_ONEDNN默认开启(ON); - 其余平台(如 Apple、MSVC 或交叉编译)默认关闭(
OFF),需要显式传入-DUSE_ONEDNN=ON。
开启后,CMake 通过load_onednn()函数(CMakeLists.txt)以子目录方式引入3rdparty/onednn,并强制关闭 oneDNN 自带的测试与示例构建、启用静态链接与 primitive 缓存;同时定义编译宏-DMXNET_USE_ONEDNN=1(CMakeLists.txt),这是 MXNet 各算子和子图融合代码判断 oneDNN 可用性的关键开关。构建完成后,还会把dnnl_config.h、dnnl_version.h拷贝到仓库的 include/onednn/oneapi/dnnl/ 目录(CMakeLists.txt),供上层头文件引用。
Linux 下的源码构建
安装前置依赖
基于 Debian/Ubuntu 的系统,先安装编译工具与 MXNet 常用依赖:
sudo apt-get update sudo apt-get install -y build-essential git sudo apt-get install -y libopenblas-dev liblapack-dev sudo apt-get install -y libopencv-dev sudo apt-get install -y graphviz其中libopenblas-dev提供 BLAS 库,libopencv-dev用于图像相关的算子与数据迭代,graphviz用于模型可视化。
克隆 MXNet 源码
git clone --recursive https://gitcode.com/gh_mirrors/mx/mxnet.git cd mxnet注意--recursive会一并拉取子模块,其中就包括3rdparty/onednn、3rdparty/mshadow、3rdparty/dmlc-core等依赖。
三种推荐的构建组合
cmake/ChooseBlas.cmake决定了USE_BLAS的取值空间:mkl(Intel MKL)、Open(OpenBLAS)、Atlas(ATLAS)以及 macOS 下的apple(Accelerate)。USE_BLAS未显式指定时,CMake 会先尝试在MKLROOT、~/intel/mkl、/opt/intel/mkl、/opt/intel/oneapi/mkl/latest等路径下查找mkl_version.h,找到即自动切换为 MKL,否则回退到默认检测流程。
组合一:llvm OpenMP + Intel MKL/OpenBLAS(文档推荐)
mkdir build && cd build cmake -DUSE_CUDA=OFF -DUSE_ONEDNN=ON -DUSE_OPENMP=ON -DUSE_OPENCV=ON .. make -j $(nproc)组合二:Intel MKL + Intel OpenMP
mkdir build && cd build cmake -DUSE_CUDA=OFF -DUSE_ONEDNN=ON -DUSE_BLAS=mkl .. make -j $(nproc)组合三:OpenBLAS + GNU OpenMP(性能次优)
mkdir build && cd build cmake -DUSE_CUDA=OFF -DUSE_ONEDNN=ON -DUSE_BLAS=Open .. make -j $(nproc)文档特别提示:为了获得更好性能,推荐使用 Intel OpenMP 或 llvm OpenMP 作为运行时;否则默认使用 GNU OpenMP,可能得到次优性能。如果未安装完整的 Intel MKL,可以通过USE_BLAS=Open使用 OpenBLAS。另外,USE_OPENMP=OFF时,load_onednn()会把 oneDNN 的 CPU 运行时切到串行模式(ONEDNN_CPU_RUNTIME SEQ),所以默认保持USE_OPENMP=ON即可。
提示:仓库 config/distribution/linux_cpu.cmake 与 config/distribution/linux_cpu_mkl.cmake 分别提供了"CPU + oneDNN"与"CPU + oneDNN + MKL"的现成配置模板;CI 流水线(如 ci/docker/runtime_functions.sh)中的构建组合也可作为参考。
macOS 下的源码构建
安装前置依赖
macOS 自带的 clang 不支持 OpenMP,因此必须通过 Homebrew 安装 llvm 作为编译器,同时安装 OpenCV(用于计算机视觉算子)等依赖:
# 安装 Homebrew /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" # 安装依赖 brew update brew install pkg-config brew install graphviz brew tap homebrew/core brew install opencv brew tap homebrew/versions brew install llvm构建命令
git clone --recursive https://gitcode.com/gh_mirrors/mx/mxnet.git cd mxnet LIBRARY_PATH=$(brew --prefix llvm)/lib/ make -j $(sysctl -n hw.ncpu) CC=$(brew --prefix llvm)/bin/clang CXX=$(brew --prefix llvm)/bin/clang++ USE_OPENCV=1 USE_OPENMP=1 USE_ONEDNN=1 USE_BLAS=apple这条命令使用 llvm 的 clang/clang++ 作为编译器,显式开启 OpenMP、OpenCV 与 oneDNN,并指定USE_BLAS=apple使用 macOS 自带的 Accelerate 框架作为 BLAS 实现。sysctl -n hw.ncpu会返回机器 CPU 核数,用于并行编译。
Windows 下的源码构建
Windows 平台推荐使用 Microsoft Visual Studio 2015 或 2017 编译(2015 优先推荐)。
依赖准备(Visual Studio 2015)
- 安装 Visual Studio 2015(社区版即可);
- 安装 CMake 3;
- 下载 OpenCV 3 并解压,设置环境变量
OpenCV_DIR指向 OpenCV 的 build 目录(如C:\opencv\build),并将 OpenCV 的 bin 目录(如C:\opencv\build\x64\vc14\bin)加入PATH; - 若安装了 Intel MKL,设置
MKLROOT指向包含include和lib的 MKL 目录(通常在C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl),cmake 时传-DUSE_BLAS=mkl; - 若未安装 MKL,安装 OpenBLAS,并同时下载
mingw64.dll.zip加入PATH; - 设置环境变量
OpenBLAS_HOME指向包含include和lib的 OpenBLAS 目录。
生成 VS 解决方案并编译
打开 "VS2015 X64 Native Tools Command Prompt"(开始菜单 → Visual Studio 2015 → VS2015 X64 Native Tools Command Prompt),然后:
git clone --recursive https://gitcode.com/gh_mirrors/mx/mxnet.git cd C:\mxnet mkdir build cd build :: 方式一:oneDNN + OpenBLAS cmake -G "Visual Studio 14 Win64" .. -DUSE_CUDA=0 -DUSE_CUDNN=0 -DUSE_NVRTC=0 -DUSE_OPENCV=1 -DUSE_OPENMP=1 -DUSE_PROFILER=1 -DUSE_BLAS=Open -DUSE_LAPACK=1 -DUSE_DIST_KVSTORE=0 -DCUDA_ARCH_NAME=All -DUSE_ONEDNN=1 -DCMAKE_BUILD_TYPE=Release :: 方式二:oneDNN + Intel MKL(先加载 MKL 环境变量) "C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl\bin\mklvars.bat" intel64 cmake -G "Visual Studio 14 Win64" .. -DUSE_CUDA=0 -DUSE_CUDNN=0 -DUSE_NVRTC=0 -DUSE_OPENCV=1 -DUSE_OPENMP=1 -DUSE_PROFILER=1 -DUSE_BLAS=mkl -DUSE_LAPACK=1 -DUSE_DIST_KVSTORE=0 -DCUDA_ARCH_NAME=All -DUSE_ONEDNN=1 -DCMAKE_BUILD_TYPE=ReleaseCMake 成功后,用 msbuild 编译(也可在 Visual Studio 中打开生成的.sln编译):
msbuild mxnet.sln /p:Configuration=Release;Platform=x64 /maxcpucount编译产物为./build/Release/(或./build/Debug/)下的libmxnet.dll,oneDNN 的libmkldnn.dll位于./build/3rdparty/onednn/src/Release/。务必将所有用到的 dll(如libmkldnn.dll、libmklml*.dll、libiomp5.dll、libopenblas*.dll等)加入系统PATH(也可统一放入\windows\system32),否则加载 MXNet 时会报 "Not Found Dependencies"。
Visual Studio 2017
步骤与 2015 相同,只需把生成器换成"Visual Studio 15 Win64",并把 OpenCV 路径改为vc15版本:
cmake -G "Visual Studio 15 Win64" .. -DUSE_CUDA=0 -DUSE_CUDNN=0 -DUSE_NVRTC=0 -DUSE_OPENCV=1 -DUSE_OPENMP=1 -DUSE_PROFILER=1 -DUSE_BLAS=mkl -DUSE_LAPACK=1 -DUSE_DIST_KVSTORE=0 -DCUDA_ARCH_NAME=All -DUSE_ONEDNN=1 -DCMAKE_BUILD_TYPE=Release安装 Python 包并验证 oneDNN 后端
安装与冒烟测试
编译完成后安装 Python 绑定并做一次冒烟测试:
pip install numpy graphviz cd python sudo python setup.py install python -c "import mxnet as mx;print((mx.nd.ones((2, 3))*2).asnumpy());"预期输出:
[[ 2. 2. 2.] [ 2. 2. 2.]]也可以设置PYTHONPATH=[workdir]\mxnet\python(Windows 下)后直接导入,无需安装。
用单个卷积层验证 oneDNN
用 Gluon 构建一个 3×3 卷积层并前向一次,即可验证 oneDNN 后端是否被调用:
from mxnet import np from mxnet.gluon import nn num_filter = 32 kernel = (3, 3) pad = (1, 1) shape = (32, 32, 256, 256) conv_layer = nn.Conv2D(channels=num_filter, kernel_size=kernel, padding=pad) conv_layer.initialize() data = np.random.normal(size=shape) o = conv_layer(data) print(o)通过 DNNL_VERBOSE 查看原语执行细节
设置环境变量可让 oneDNN 输出详细的调试与性能剖析日志:
export DNNL_VERBOSE=1再次运行上面的代码,会得到类似下面的输出(关键日志逐行解读):
dnnl_verbose,info,oneDNN v2.3.2 (commit e2d45252ae9c3e91671339579e3c0f0061f81d49) dnnl_verbose,info,cpu,runtime:OpenMP dnnl_verbose,info,cpu,isa:Intel AVX-512 with Intel DL Boost dnnl_verbose,info,gpu,runtime:none dnnl_verbose,info,prim_template:operation,engine,primitive,implementation,prop_kind,memory_descriptors,attributes,auxiliary,problem_desc,exec_time dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:acdb:f0,,,32x32x256x256,8.34912 dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:Acdb32a:f0,,,32x32x3x3,0.0229492 dnnl_verbose,exec,cpu,convolution,brgconv:avx512_core,forward_inference,src_f32::blocked:acdb:f0 wei_f32::blocked:Acdb32a:f0 bia_f32::blocked:a:f0 dst_f32::blocked:acdb:f0,,alg:convolution_direct,mb32_ic32oc32_ih256oh256kh3sh1dh0ph1_iw256ow256kw3sw1dw0pw1,10.5898日志含义如下:
- 头几行
info记录 oneDNN 版本、CPU 运行时(OpenMP)与检测到的 ISA(此处为支持 Intel DL Boost 的 AVX-512),以及日志模板格式; reorder原语表明数据在abcd(NCHW)与acdb等阻塞内存布局之间发生了格式转换——oneDNN 为卷积选择的内部内存格式与 MXNet 默认布局不同,reorder 是两者之间必要的桥梁;convolution原语行显示实现为brgconv:avx512_core,prop_kind 为forward_inference,并给出内存描述符、算法(convolution_direct)、问题描述(mb32_ic32oc32_ih256oh256kh3sh1dh0ph1_iw256ow256kw3sw1dw0pw1)与执行耗时(微秒级)。
只要日志中出现dnnl_verbose,exec,cpu,convolution,...这类行,就说明卷积已经真实运行在 oneDNN 原语之上。更系统的 oneDNN 算子剖析方法可参考仓库 docs/python_docs/python/tutorials/performance/backend/ 目录下的性能剖析教程。
启用 MKL BLAS 进一步提升性能
oneDNN 之外,MKL BLAS 还能为线性代数类算子带来进一步的性能提升(提升幅度取决于模型的矩阵计算负载)。安装完整版 MKL 后,linalg命名空间下的所有算子都能获得 MKL 加速。
安装与编译
- 按 Intel 官网指引下载安装最新完整版 MKL(Linux 下也可通过 YUM/APT 软件源安装);
- 进入构建目录:
mkdir build && cd build; - 配置:
cmake -DUSE_CUDA=OFF -DUSE_BLAS=mkl ..; - 编译:
make -j; - 安装 Python 包:
cd python && sudo python setup.py install。
用线性求解器验证 MKL
from mxnet import np coeff = np.array([[7, 0], [5, 2]]) y = np.array([14, 18]) x = np.linalg.solve(coeff, y) print(x)设置环境变量打开 MKL 的详细日志:
export MKL_VERBOSE=1再次运行上述代码,会看到类似下面的输出(此处执行了 MKL 的SGESV原语,即单精度通用线性求解):
mkl-service + Intel(R) MKL: THREADING LAYER: (null) mkl-service + Intel(R) MKL: setting Intel(R) MKL to use INTEL OpenMP runtime mkl-service + Intel(R) MKL: preloading libiomp5.so runtime Intel(R) MKL 2020.0 Update 1 Product build 20200208 for Intel(R) 64 architecture Intel(R) Advanced Vector Extensions 512 (Intel(R) AVX-512) with support of Vector Neural Network Instructions enabled processors, Lnx 2.70GHz lp64 intel_thread MKL_VERBOSE SGESV(2,1,0x7f74d4002780,2,0x7f74d4002798,0x7f74d4002790,2,0) 77.58us CNR:OFF Dyn:1 FastMM:1 TID:0 NThr:56日志中的SGESV、执行耗时(77.58us)、线程数(NThr:56)等信息可用于确认 MKL 确实接管了线性代数运算。
图优化:optimize_for 与算子融合
要让 oneDNN 的潜力发挥到极致,建议配合图优化使用。MXNet 的optimize_forAPI 可以把计算图按子图方式切分并交给 oneDNN 后端执行,从而触发算子融合(如 Convolution + ReLU 融合进单个卷积原语)。
使用限制
使用该功能前需确认满足以下条件:
- 仅适用于推理(inference);
- 只有
HybridBlock的子类与Symbol可以调用optimize_for; - 即使编译的是 GPU 版 MXNet,该功能也只在 CPU 上运行。
代码示例
from mxnet import np from mxnet.gluon import nn data = np.random.normal(size=(32,3,224,224)) net = nn.HybridSequential() net.add(nn.Conv2D(channels=64, kernel_size=(3,3))) net.add(nn.Activation('relu')) net.initialize() print("=" * 5, " Not optimized ", "=" * 5) o = net(data) print(o) net.optimize_for(data, backend='ONEDNN') print("=" * 5, " Optimized ", "=" * 5) o = net(data) print(o)从日志看融合效果
开启DNNL_VERBOSE=1后,优化前后的日志对比如下(省略了张量打印):
===== Not optimized ===== [15:05:43] ../src/storage/storage.cc:202: Using Pooled (Naive) StorageManager for CPU dnnl_verbose,info,oneDNN v2.3.2 (commit e2d45252ae9c3e91671339579e3c0f0061f81d49) dnnl_verbose,info,cpu,runtime:OpenMP dnnl_verbose,info,cpu,isa:Intel AVX-512 with AVX512BW, AVX512VL, and AVX512DQ extensions dnnl_verbose,info,gpu,runtime:none dnnl_verbose,info,prim_template:operation,engine,primitive,implementation,prop_kind,memory_descriptors,attributes,auxiliary,problem_desc,exec_time dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:acdb:f0,,,32x3x224x224,8.87793 dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:Acdb64a:f0,,,64x3x3x3,0.00708008 dnnl_verbose,exec,cpu,convolution,brgconv:avx512_core,forward_inference,src_f32::blocked:acdb:f0 wei_f32::blocked:Acdb64a:f0 bia_f32::blocked:a:f0 dst_f32::blocked:acdb:f0,,alg:convolution_direct,mb32_ic3oc64_ih224oh222kh3sh1dh0ph0_iw224ow222kw3sw1dw0pw0,91.511 dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:Acdb64a:f0,,,64x3x3x3,0.00610352 dnnl_verbose,exec,cpu,eltwise,jit:avx512_common,forward_inference,data_f32::blocked:acdb:f0 diff_undef::undef::f0,,alg:eltwise_relu alpha:0 beta:0,32x64x222x222,85.4392 ===== Optimized ===== dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:Acdb64a:f0 dst_f32::blocked:abcd:f0,,,64x3x3x3,0.00610352 dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:Acdb64a:f0,,,64x3x3x3,0.00585938 dnnl_verbose,exec,cpu,reorder,jit:uni,undef,src_f32::blocked:abcd:f0 dst_f32::blocked:acdb:f0,,,32x3x224x224,3.98999 dnnl_verbose,exec,cpu,convolution,brgconv:avx512_core,forward_inference,src_f32::blocked:acdb:f0 wei_f32::blocked:Acdb64a:f0 bia_f32::blocked:a:f0 dst_f32::blocked:acdb:f0,attr-post-ops:eltwise_relu:0:1 ,alg:convolution_direct,mb32_ic3oc64_ih224oh222kh3sh1dh0ph0_iw224ow222kw3sw1dw0pw0,20.46对比可见:优化前需要分别执行convolution与eltwise(relu)两个原语;优化后日志中只剩一个convolution原语,且其attributes一栏出现了attr-post-ops:eltwise_relu:0:1——这正是 Convolution + ReLU 被融合进单个卷积原语的直接证据(post-ops 机制),省去了单独的 eltwise 原语及中间数据落盘。
从源码看,optimize_for在 python/mxnet/gluon/block.py 中定义(HybridBlock.optimize_for),它把"hybridize + 前向时图切分"的工作提前到一次显式调用中完成,随后即可直接export导出模型或运行推理。Symbol侧对应 python/mxnet/symbol/symbol.py 与 python/mxnet/symbol/numpy/_symbol.py 的同名方法。其关键参数包括:
backend:子图后端名称,在SubgraphBackendRegistry中注册,传'ONEDNN'即走 oneDNN 子图;clear:是否清除之前的优化结果(默认False);static_alloc/static_shape:静态分配内存 / 按不变输入形状优化,可进一步提升速度但会增加内存占用;inline_limit:允许内联的最大算子数(默认 2)。
基于 oneDNN 的 INT8 量化与推理
oneDNN 子图特性同时支持量化:把 FP32 模型校准为 (U)INT8 模型后,可在 Intel Xeon 可扩展平台上获得显著的推理性能提升。仓库提供了完整的可运行示例,见 example/quantization/README.md,包含三个脚本:
- imagenet_gen_qsym_onednn.py:从 FP32 模型生成校准后的量化模型;
- imagenet_inference.py:加载量化模型执行推理;
- launch_inference_onednn.sh:一键启动推理的脚本。
量化脚本的主要参数(默认值)如下:
| 参数 | 作用 | 默认值 |
|---|---|---|
--model | 待量化模型名;若禁用预训练,则需把模型放到脚本同目录的model目录下 | resnet50_v1 |
--epoch | 模型 epoch 数 | 0 |
--no-pretrained | 不从 MXNet / Gluon-CV 模型库下载预训练权重 | False |
--batch-size | 校准时的 batch size | 32 |
--calib-dataset | 校准数据集路径(RecordIO 格式) | data/val_256_q90.rec |
--image-shape | 输入图像的通道数、高、宽,逗号分隔 | 3,224,224 |
--num-calib-batches | 用于校准的 batch 数 | 默认值见脚本--help |
--exclude-first-conv | 是否排除第一个卷积层不量化 | False |
--shuffle-dataset | 是否打乱校准数据集 | False |
--calib-mode | 校准模式(如naive/entropy/min_max等) | 默认值见脚本--help |
--quantized-dtype | 量化数据类型,可选auto/int8/uint8 | auto |
示例用法:
python imagenet_gen_qsym_onednn.py --model resnet50_v1 --calib-dataset data/val_256_q90.rec --batch-size 32常见问题与后续支持
- 构建完成后 Python 导入失败或报缺库错误:检查所有 dll(Linux 下为
.so)是否位于LD_LIBRARY_PATH(Windows 为PATH)可搜索的目录; - 怀疑 oneDNN 未生效:设置
DNNL_VERBOSE=1,观察日志中是否出现convolution/reorder等dnnl_verbose,exec行; - 想要更深入的算子级剖析:参考 docs/python_docs/python/tutorials/performance/backend/ 目录下的性能剖析教程;
- oneDNN 相关的问题与 bug:可到 MXNet 的 oneDNN/MKL 标签下反馈;官方支持渠道还包括 Intel 的 MKL 与 oneDNN 官网。
从源码到性能验证,MXNet + oneDNN 的组合可以归结为一条清晰链路:选对构建组合(USE_ONEDNN=ON+ 合适的 BLAS/OpenMP)→ 用DNNL_VERBOSE确认原语真实执行 → 用optimize_for触发算子融合 → 必要时用 INT8 量化进一步压缩推理成本。按本文步骤操作,即可在 Intel 架构 CPU 上获得开箱即用的性能收益。
- 深度学习
- 人工智能
- 机器学习
- 分布式训练
【免费下载链接】mxnet
Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more
相关推荐
Apache MXNet 集成 oneDNN 完整指南:Linux/macOS/Windows 构建、图优化与 INT8 量化实战
Apache MXNet 集成 oneDNN 完整指南:Linux/macOS/Windows 构建、图优化与 INT8 量化实战 Apache MXNet 是
深度学习人工智能机器学习分布式训练mxnet-native:MXNet 纯 CPU(无 oneDNN)PyPI 包安装与使用指南
mxnet native:MXNet 纯 CPU(无 oneDNN)PyPI 包安装与使用指南 本篇指南聚焦 Apache MXNet 官方在 PyPI 上发布
深度学习人工智能机器学习分布式训练Intel oneDNN:释放CPU深度学习性能的终极利器
Intel oneDNN:释放CPU深度学习性能的终极利器 Intel oneDNN(深度神经网络库)是一款专为优化深度学习工作负载而设计的开源性能库,它能够显
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考