oneDNN 执行提供程序

前身为“DNNL”

使用 Intel® oneDNN 执行提供程序,通过针对深度神经网络优化的 Intel® 数学核心函数库 (Intel® DNNL) 基元加速 ONNX Runtime 的性能。

Intel® oneAPI 深度神经网络函数库是一个用于深度学习应用程序的开源高性能函数库。该函数库加速了深度学习应用程序和框架在 Intel® 架构和 Intel® 处理器显卡架构上的运行。Intel DNNL 包含向量化和线程化的构建块,您可以使用 C 和 C++ 接口来实现深度神经网络 (DNN)。

ONNX Runtime 的 oneDNN 执行提供程序 (EP) 由 Intel 和 Microsoft 合作开发。

目录

构建

有关构建说明,请参阅 构建页面

用法

C/C++

DNNLExecutionProvider 执行提供程序需要注册到 ONNX Runtime,以便在推理会话中启用。

Ort::Env env = Ort::Env{ORT_LOGGING_LEVEL_ERROR, "Default"};
Ort::SessionOptions sf;
bool enable_cpu_mem_arena = true;
Ort::ThrowOnError(OrtSessionOptionsAppendExecutionProvider_Dnnl(sf, enable_cpu_mem_arena));

C API 详情请参见此处

Python

当使用由 DNNL 执行提供程序构建的 ONNX Runtime 的 Python wheel 时,它将自动优先于 CPU 执行提供程序。Python API 详情请参见此处

子图优化

DNNL 使用分块布局(例如:nhwc,通道按 16 分块 – nChw16c),以利用 AVX512 的向量操作。为了获得最佳性能,我们避免重排序(例如:Nchw16c 到 nchw)并将分块布局传播到下一个基元。

子图优化通过以下步骤实现:

  1. 解析 ONNX Runtime 图并创建子图的内部表示 (IR)。
  2. 子图算子 (DnnlFunKernel) 遍历 DNNL 节点并创建一个 DNNL 核向量。
  3. DnnlFunKernel 的计算函数迭代并绑定数据到向量中的 DNNL 基元,然后提交向量执行。

子图 (IR) 内部表示

DnnlExecutionProvider::GetCapability() 解析 ONNX 模型图并创建 DNNL 算子子图的 IR(内部表示)。每个子图包含一个 DnnlNodes 向量、输入、输出以及其所有 DnnlNodes 的属性。可能存在同名的属性。因此,我们使用节点名称及其索引作为属性的前缀。子图的唯一 ID 被设置为一个属性。

DnnlNode 包含其输入和输出的索引以及指向其父节点的指针。DnnlNode 直接从其父节点读取分块内存以避免数据重排序。

MKL-DNN Node

子图类

DnnlConv、DnnlPool 等基元派生自 DnnlKernel 基类。

以下 UML 图描绘了子图类。

MKL-DNN subgraph

子图执行

DnnlExecutionProvicer::Compute() 函数创建 DnnlFuncKernel 并调用其 Compute 函数。

DnnlFuncKernel::Compute 函数创建 SubgraphPrimitve 池并将对象添加到映射中。

SubgraphPrimitve 构造函数调用以下成员函数:

SubgraphPrimitve::CreatePrimitives()
    for (auto& mklnode : mklnodes) {
      if (mklnode.name == "Conv") {
        kernel.reset(new DnnlConv());
        kernels.push_back(kernel);
      } else if (mklnode.name == "BatchNormalization-Relu") {
        kernel.reset(new DnnlBatchNorm());
        context_.kernels.push_back(kernel);
      } else if (mklnode.name == "MaxPool") {
        kernel.reset(new DnnlPool());
        context_.kernels.push_back(kernel);
      } 
      .
      .
      .

在 CreatePrimitives 方法中,我们迭代 DnnlNodes 并创建 DnnlKernel 对象,并将 DNNL 基元添加到向量中。它还会读取属性。这只在第一次迭代时执行一次。

SubgraphPrimitve::Compute()
   for (auto& kernel : kernels) {
      kernel->Bind(input_tensors, output_tensors);
    }
    stream->submit(net);

在 SubgraphPrimitve::Compute() 方法中,我们遍历 Dnnl Kernels 并绑定输入数据。然后我们将基元向量提交给 DNNL 流。

支持范围

支持的操作系统

  • Ubuntu 16.04
  • Windows 10
  • Mac OS X

支持的后端

  • CPU

附加资源