oneDNN 执行提供程序
前身为“DNNL”
使用英特尔 oneDNN 执行提供程序,利用英特尔® 深度神经网络数学核心库 (Intel® DNNL) 优化的原语来加速 ONNX Runtime 的性能。
Intel® oneAPI 深度神经网络库是一个用于深度学习应用程序的开源性能库。该库在英特尔® 架构和英特尔® 处理器图形架构上加速深度学习应用程序和框架。Intel DNNL 包含矢量化和线程化的构建模块,可用于通过 C 和 C++ 接口实现深度神经网络 (DNN)。
ONNX Runtime 的 oneDNN 执行提供程序 (EP) 由英特尔和微软合作开发。
目录
构建
有关构建说明,请参阅构建页面。
用法
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 使用块状布局(例如:通道被 16 阻断的 nhwc – nChw16c)来利用 AVX512 的向量操作。为获得最佳性能,我们避免重排序(例如:Nchw16c 到 nchw)并将块状布局传播到下一个原语。
子图优化通过以下步骤实现这一点。
- 解析 ONNX Runtime 图并创建子图的内部表示。
- 子图操作符 (DnnlFunKernel) 遍历 DNNL 节点并创建向量 DNNL 核。
- DnnlFunKernel 的计算函数遍历并将数据绑定到向量中的 DNNL 原语,然后提交向量进行执行。
子图(IR)内部表示
DnnlExecutionProvider::GetCapability() 解析 ONNX 模型图并创建 DNNL 算子子图的 IR(内部表示)。每个子图包含一个 DnnlNodes 向量、输入、输出及其所有 DnnlNodes 的属性。可能存在同名属性,因此我们将属性名称加上节点名称及其索引作为前缀。子图的唯一 ID 被设置为一个属性。
DnnlNode 具有指向其输入和输出的索引以及指向其父节点的指针。DnnlNode 直接从其父节点读取块状内存以避免数据重排序。
子图类
DnnlConv、DnnlPool 等原语均派生自 DnnlKernel 基类。
以下 UML 图展示了子图类。
子图执行
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 核并绑定输入数据。然后我们将原语向量提交到 DNNL 流。
支持范围
支持的操作系统
- Ubuntu 16.04
- Windows 10
- Mac OS X
支持的后端
- CPU