架构

时间:2024-04-16 09:13:04

此章节列出ONNX的高层次设计

参考https://onnxruntime.ai/docs/reference/high-level-design.html


关键目标

  1. 最大化并自动地利用不同平台上可用的定制加速器和运行时。
  2. 为定制加速器和运行时提供正确的抽象和运行时支持。我们称这种抽象为execution provider。它定义并向 ONNX Runtime 公开一组功能:它可以执行的一组单一或融合节点,其内存分配器等。定制加速器和运行时是execution providers的实例。
  3. 我们不希望execution providers总是能够完全在其设备上运行 ONNX 模型。这意味着 ONNX Runtime 必须能够在涉及多个execution providers的异构环境中执行单个模型。
  4. 提供支持高级优化,这些优化可以通过 graph-transformation API表达为模型到模型的转换。这些转换分为两类:全局转换(需要分析和转换整个图形)以及局部转换(可以被捕获为简单的(代数)重写规则(rewriting rules))。

高级系统架构

整个流程非常简单。

  1. 从一个 ONNX 模型开始,ONNX Runtime首先将模型图转换为其内存中的图表示形式。
  2. 它执行一系列与provider无关的优化
  3. 它根据可用的execution provider将图分割成一组子图。
  4. 每个子图都分配给一个execution provider。通过使用GetCapability()API 查询执行提供者的能力,以确保一个子图可以由execution provider执行。

在这里插入图片描述

关于切分的更多信息

ONNX Runtime 根据可用的执行提供程序将模型图分割成子图,每个子图对应一个独立的provider。ONNX Runtime 提供了一个默认的execution provider,用作无法推送到更专业但更高效的execution providers的运算符的后备执行。直观地说,我们希望尽可能地将计算推送到更专业的execution providers。

我们使用一种简单的图分割技术。可用的execution provider将按照特定顺序考虑,并且每个provider将被分配它能够处理的最大子图(可能不止一个)。ONNX Runtime 提供的默认execution provider将作为最后一个考虑,以确保完整性。在将来可以考虑更复杂的优化方法(甚至可以实现为复合的execution provider)。

在概念上,每个分区都被简化为一个单一的融合运算符(fused operator)。通过调用execution provider的 Compile() 方法来创建它,并将其包装为自定义运算符。目前只支持同步执行模式。execution provider公开其内存分配器,用于为execution provider分配输入张量。重写和分区将初始模型图转换为由运算符组成的新图,这些运算符分配给默认execution provider或其他已注册的execution provider。ONNX Runtime 执行引擎负责运行此图。

关键设计

  1. 多个线程可以调用同一个推理会话对象上的Run()方法。详细信息请参阅 API文档(API doc)。
  2. 为了实现这一点,所有内核的Compute()函数都是const的,这意味着内核是无状态的。
  3. execution provider对运算符的实现称为内核(kernel)。每个execution provider支持一部分(ONNX)运算符/内核。
  4. ONNX Runtime 保证默认execution provider支持所有运算符。
  5. 张量表示:ONNX Runtime 使用标准的张量运行时值表示。execution provider可以在内部使用不同的表示,但是在其子图的边界上将值转换为标准表示(或从标准表示转换位值)是它们的责任。