MLIR 编译器基础设施中 ONNX 模型的表示和参考降低
本项目由 onnx 维护
托管于 GitHub Pages — 主题作者 orderedlist
通常,onnx-mlir 将自定义加速器作为插件处理,这些插件可以在构建 onnx-mlir 和编译模型时开启/关闭。这种处理主要通过 cmake
进行,我们将在此文档中概述其流程。
除了本文档外,NNPA 加速器 可用作 onnx-mlir 中已部署的示例。
在 onnx-mlir 中,加速器的所有代码都应放在 src/Accelerators
下面的一个单独文件夹中。因此,支持加速器的第一步是在 src/Accelerators
内部为其创建一个文件夹。
该文件夹的名称将用作 onnx-mlir 中的加速器名称。具体来说,它用于
cmake
构建加速器文件夹内的代码,onnx-mlir
命令时为加速器编译模型,以及onnx-mlir-opt
命令时启用与加速器相关的 passes。文件夹的内容取决于每个加速器,具有一定的灵活性。但是,我们建议尽可能遵循与 onnx-mlir
根文件夹相同的结构。这有助于保持整个项目的一致性。
要在 onnx-mlir 中构建加速器,请在构建 onnx-mlir 时使用 cmake 变量 ONNX_MLIR_ACCELERATORS
。ONNX_MLIR_ACCELERATORS
接受一个以分号分隔的加速器名称列表。例如,
$ cd build
$ cmake .. -DONNX_MLIR_ACCELERATORS='accel1;accel2'
请注意,列表应加引号。
编译器命令 onnx-mlir
有一个选项,即 --maccel
,用于为选定的加速器编译模型。对于每个加速器,添加一个 --maccel=accel_name
条目。例如,
$ onnx-mlir --maccel=accel1 --maccel=accel2 model.onnx
只有已构建的加速器才能与 --maccel
一起使用。
加速器定义的 passes 可以通过 onnx-mlir-opt
命令使用选项 --maccel
来运行或测试,该选项与 onnx-mlir
中的 --maccel
类似(参见第 1.2 节)。例如,要调用加速器 accel1
定义的 pass --optimize-data-layout
$ onnx-mlir-opt --maccel=accel1 --optimize-data-layout model.mlir
只有已构建的加速器才能与 --maccel
一起使用。
每个加速器都需要定义一些宏。这些宏需要包含在 onnx_mlir::accel::Accelerator 中。这些宏是
INSTRUMENTSTAGE_ENUM_<accel_name>
INSTRUMENTSTAGE_CL_ENUM_<accel_name>
PROFILEIR_CL_ENUM_<accel_name>
OPTREPORT_ENUM_<accel_name>
OPTREPORT_CL_ENUM_<accel_name>
将 <accel_name>
替换为加速器的名称,例如如果您的加速器名为 ACCEL1
,则使用
#define INSTRUMENTSTAGE_ENUM_ACCEL1
#define INSTRUMENTSTAGE_CL_ENUM_ACCEL1
#define PROFILEIR_CL_ENUM_ACCEL1
#define OPTREPORT_ENUM_ACCEL1
#define OPTREPORT_CL_ENUM_ACCEL1
2.2 Dialects 和 passes
在 MLIR 中编写代码通常涉及设计 dialects 和 passes。支持加速器也是如此。因此,将加速器代码集成到 onnx-mlir 中就是要在 onnx-mlir 中注册 dialects 和 passes。
//===--------------------------------------------------------------------===//
// Hooks for onnx-mlir driver
//===--------------------------------------------------------------------===//
/// Add the transformations necessary to support the accelerator.
virtual void addPasses(mlir::OwningOpRef<mlir::ModuleOp> &module,
mlir::PassManager &pm,
onnx_mlir::EmissionTargetType &emissionTarget) const = 0;
//===--------------------------------------------------------------------===//
// Hooks for onnx-mlir-opt driver
//===--------------------------------------------------------------------===//
/// Register the MLIR dialects required to support an accelerator.
virtual void registerDialects(mlir::DialectRegistry ®istry) const = 0;
/// Register accelerator transformation passes to make available as
/// command line options.
virtual void registerPasses(int optLevel) const = 0;
//===--------------------------------------------------------------------===//
// Hooks for both onnx-mlir and onnx-mlir-opt drivers
//===--------------------------------------------------------------------===//
/// Configure passes for the accelerator.
virtual void configurePasses() const = 0;
//===--------------------------------------------------------------------===//
// Hooks for onnx-to-krnl pass
//===--------------------------------------------------------------------===//
/// Convert TensorType to MemRefType.
/// Acccelators may have special versions of TensorType. If not, override this
/// method and return nullptr.
virtual mlir::MemRefType convertTensorTypeToMemRefType(
const mlir::TensorType tensorType) const = 0;
/// Define conversion target to be used with ONNXToKrnl.
virtual void conversionTargetONNXToKrnl(
mlir::ConversionTarget &target) const = 0;
/// Define rewrite patterns to be used with ONNXToKrnl.
virtual void rewritePatternONNXToKrnl(mlir::RewritePatternSet &patterns,
mlir::TypeConverter &typeConverter, mlir::MLIRContext *ctx) const = 0;
//===--------------------------------------------------------------------===//
// Hooks for krnl-to-llvm pass
//===--------------------------------------------------------------------===//
/// Define conversion target to be used with KrnlToLLVM.
virtual void conversionTargetKrnlToLLVM(
mlir::ConversionTarget &target) const = 0;
/// Define rewrite patterns to be used with KrnlToLLVM.
virtual void rewritePatternKrnlToLLVM(mlir::RewritePatternSet &patterns,
mlir::LLVMTypeConverter &typeConverter, mlir::MLIRContext *ctx) const = 0;
我们提供了一个基类 onnx_mlir::accel::Accelerator,用户可以从中定义继承类并编写钩子来注册 dialects 和 passes。尽管 onnx-mlir 中有许多 passes,但我们仅为 onnx-to-krnl
和 krnl-to-llvm
这两个 passes 提供钩子。原因是原则上它们是 onnx-mlir 中的第一个和最后一个 passes。Pass onnx-to-krnl
是决定哪些 ONNX 运算符将在主机上运行(通过将它们降低到 Krnl dialect)或在加速器上运行(通过将它们降低到为加速器定义的 dialect)的地方。Pass krnl-to-llvm
是将 Krnl 和加速器运算符降低到 LLVM dialect 的地方,例如生成汇编代码或简单地调用加速器的外部 API。在 onnx-to-krnl
和 krnl-to-llvm
之间,可以有适用于加速器的任何 dialects 和 passes。
例如,对于 NNPA 加速器,我们定义了用于 onnx-to-krnl
的 ZHigh dialect 和用于 krnl-to-llvm
的 ZLow dialect。
加速器的测试应放在文件夹 test 中。具体而言,