DirectML 执行提供程序
DirectML 执行提供程序是 ONNX Runtime 的一个组件,它使用 DirectML 来加速 ONNX 模型的推理。DirectML 执行提供程序能够显著缩短使用通用 GPU 硬件的模型的评估时间,而无需牺牲广泛的硬件支持或安装供应商特定的扩展。
DirectML 是一个高性能、硬件加速的 DirectX 12 库,用于 Windows 上的机器学习。DirectML 为各种受支持的硬件和驱动程序上的常见机器学习任务提供 GPU 加速。
当单独使用时,DirectML API 是一个低级 DirectX 12 库,适用于高性能、低延迟的应用程序,如框架、游戏和其他实时应用程序。DirectML 与 Direct3D 12 的无缝互操作性,以及其低开销和跨硬件的一致性,使得 DirectML 成为加速机器学习的理想选择,既需要高性能,又需要跨硬件的结果的可靠性和可预测性至关重要。
DirectML 执行提供程序目前使用 DirectML 版本 1.15.2,并支持高达 ONNX opset 20 (ONNX v1.15),但 Gridsample 20: 5d 和 DeformConv 除外,它们尚不支持。评估需要更高 opset 版本的模型不受支持,并且会产生较差的性能。注意:DirectML ONNX opset 支持可能与 ONNX Runtime 的支持不同,后者可以在此处找到。
目录
安装
带有 DirectML EP 的 ORT 预构建包发布在 Nuget.org 上。请参阅:安装 ONNX Runtime。
要求
DirectML 执行提供程序需要支持 DirectX 12 的设备。最近几年发布的大多数商用显卡都支持 DirectX 12。以下是一些兼容硬件的示例
- NVIDIA Kepler(GTX 600 系列)及以上
- AMD GCN 第 1 代(Radeon HD 7000 系列)及以上
- Intel Haswell(第 4 代酷睿)HD 集成显卡及以上
- Qualcomm Adreno 600 及以上
DirectML 在 Windows 10 版本 1903 和相应版本的 Windows SDK 中引入。
构建
构建 DirectML 执行提供程序的要求
- Visual Studio 2017 工具链
- Windows 10 SDK (10.0.18362.0) for Windows 10, version 1903(或更新版本)
要构建包含 DML EP 的 onnxruntime,请向 build.bat
提供 --use_dml
标志。例如
build.bat --config RelWithDebInfo --build_shared_lib --parallel --use_dml
DirectML 执行提供程序支持为 x64(默认)和 x86 架构构建。
请注意,您可以构建 带有 DirectML 的 ONNX Runtime。这允许在构建过程中自动下载 DirectML 可再发行软件包。在 NuGet 文档上查找其他许可信息。
用法
当将 C API 与启用 DML 的 onnxruntime 构建版本一起使用时,可以使用 include/onnxruntime/core/providers/dml/dml_provider_factory.h
中包含的两个工厂函数之一来启用 DirectML 执行提供程序。
OrtSessionOptionsAppendExecutionProvider_DML
函数
创建一个 DirectML 执行提供程序,它在具有给定 device_id
(也称为适配器索引)的硬件适配器上执行。设备 ID 对应于 IDXGIFactory::EnumAdapters 给出的硬件适配器的枚举顺序。device_id
为 0 始终对应于默认适配器,通常是系统上安装的主显示 GPU。请注意,在具有多个 GPU 的系统中,主显示器 (GPU 0) 通常不是性能最高的 GPU,尤其是在具有双适配器的笔记本电脑上,其中电池寿命优先于性能。因此,您可以在任务管理器的性能选项卡中仔细检查以查看哪个 GPU 是哪个。负数 device_id
无效。
C API 示例
OrtStatus* OrtSessionOptionsAppendExecutionProvider_DML(
_In_ OrtSessionOptions* options,
int device_id
);
C# API 示例
安装 Nuget 包 Microsoft.ML.OnnxRuntime.DirectML/1.14.1 并使用以下代码启用 DirectML EP
SessionOptions sessionOptions = newSessionOptions();
sessionOptions.GraphOptimizationLevel = GraphOptimizationLevel.ORT_ENABLE_ALL;
sessionOptions.AppendExecutionProvider_DML(0);
SessionOptionsAppendExecutionProvider_DML1
函数
使用给定的 DirectML 设备创建一个 DirectML 执行提供程序,该提供程序在提供的 D3D12 命令队列上执行工作。DirectML 设备和 D3D12 命令队列必须具有相同的父 ID3D12Device,否则将返回错误。D3D12 命令队列的类型必须为 DIRECT
或 COMPUTE
(请参阅 D3D12_COMMAND_LIST_TYPE)。如果此函数成功,则一旦创建推理会话,它将保持对 dml_device
和 command_queue
对象的强引用。
OrtStatus* SessionOptionsAppendExecutionProvider_DML1(
_In_ OrtSessionOptions* options,
_In_ IDMLDevice* dml_device,
_In_ ID3D12CommandQueue* cmd_queue
);
配置选项
DirectML 执行提供程序不支持在 onnxruntime 中使用内存模式优化或并行执行。在 InferenceSession 创建期间提供会话选项时,必须禁用这些选项,否则将返回错误。
如果使用 onnxruntime C API,则必须调用 DisableMemPattern
和 SetSessionExecutionMode
函数来设置 DirectML 执行提供程序所需的选项。
请参阅 onnxruntime\include\onnxruntime\core\session\onnxruntime_c_api.h。
OrtStatus*(ORT_API_CALL* DisableMemPattern)(_Inout_ OrtSessionOptions* options)NO_EXCEPTION;
OrtStatus*(ORT_API_CALL* SetSessionExecutionMode)(_Inout_ OrtSessionOptions* options, ExecutionMode execution_mode)NO_EXCEPTION;
如果直接创建 onnxruntime InferenceSession 对象,则必须在 onnxruntime::SessionOptions
结构上设置适当的字段。具体来说,execution_mode
必须设置为 ExecutionMode::ORT_SEQUENTIAL
,并且 enable_mem_pattern
必须为 false
。
此外,由于 DirectML 执行提供程序不支持并行执行,因此它不支持在同一推理会话上对 Run
进行多线程调用。也就是说,如果推理会话使用 DirectML 执行提供程序,则一次只能有一个线程调用 Run
。如果多个线程在不同的推理会话对象上操作,则允许它们同时调用 Run
。
性能调优
当在创建会话时知道张量形状时,DirectML 执行提供程序工作效率最高。以下是一些性能优势
- 常量折叠可以更频繁地发生,从而减少评估期间的 CPU/GPU 副本和停顿。
- 在创建会话时而不是在首次评估期间发生更多初始化工作。
- 权重可以在 DirectML 中预处理,从而实现更高效的算法。
- 图形优化在 DirectML 中发生。例如,可以删除 Concat 运算符,并且可以为运算符的输入和输出使用更优化的张量布局。
通常,当在会话创建期间知道模型输入的形状时,OnnxRuntime 会在创建该会话时推断模型其余部分的形状。
但是,如果模型输入包含自由维度(例如批量大小),则必须采取其他步骤来保留上述性能优势。这些包括
- 编辑模型以将输入的自由维度(通过 ONNX 使用“dim_param”指定)替换为固定大小(通过 ONNX 使用“dim_value”指定)。
- 在使用 OnnxRuntime AddFreeDimensionOverrideByName ABI 创建会话时,指定模型输入中命名维度的值。
- 编辑模型以确保输入的自由维度具有注释(例如“DATA_BATCH”或自定义注释)。然后,在创建会话时,为每个注释指定维度大小。这可以使用 OnnxRuntime AddFreeDimensionOverride ABI 完成。
示例
可以在 samples/c_cxx/fns_candy_style_transfer 下找到使用 DirectML 执行提供程序的 onnxruntime 的完整示例