使用 oneDNN 构建 MXNet:Linux/macOS/Windows 三步安装与 Intel CPU 性能优化实战
2026/9/21 16:00:54 网站建设 项目流程
  • 深度学习
  • 人工智能
  • 机器学习
  • 分布式训练

【免费下载链接】mxnet

Lightweight, Portable, Flexible Distributed/Mobile Deep Learning with Dynamic, Mutation-aware Dataflow Dep Scheduler; for Python, R, Julia, Scala, Go, Javascript and more

项目地址:https://gitcode.com/gh_mirrors/mx/mxnet
点击查看免费下载

本文是一份完整的 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.hdnnl_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/onednn3rdparty/mshadow3rdparty/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)

  1. 安装 Visual Studio 2015(社区版即可);
  2. 安装 CMake 3;
  3. 下载 OpenCV 3 并解压,设置环境变量OpenCV_DIR指向 OpenCV 的 build 目录(如C:\opencv\build),并将 OpenCV 的 bin 目录(如C:\opencv\build\x64\vc14\bin)加入PATH
  4. 若安装了 Intel MKL,设置MKLROOT指向包含includelib的 MKL 目录(通常在C:\Program Files (x86)\IntelSWTools\compilers_and_libraries\windows\mkl),cmake 时传-DUSE_BLAS=mkl
  5. 若未安装 MKL,安装 OpenBLAS,并同时下载mingw64.dll.zip加入PATH
  6. 设置环境变量OpenBLAS_HOME指向包含includelib的 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=Release

CMake 成功后,用 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.dlllibmklml*.dlllibiomp5.dlllibopenblas*.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 加速。

安装与编译

  1. 按 Intel 官网指引下载安装最新完整版 MKL(Linux 下也可通过 YUM/APT 软件源安装);
  2. 进入构建目录:mkdir build && cd build
  3. 配置:cmake -DUSE_CUDA=OFF -DUSE_BLAS=mkl ..
  4. 编译:make -j
  5. 安装 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

对比可见:优化前需要分别执行convolutioneltwise(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 size32
--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/uint8auto

示例用法:

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/reorderdnnl_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

项目地址:https://gitcode.com/gh_mirrors/mx/mxnet
点击查看免费下载
上一篇:pgmpy结构学习实战:PC算法与Hill Climbing搜索详解
下一篇:aniGamerPlus高級技巧:自定義分辨率與批量下載秘籍

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询