昇腾社区首页
中文
注册
开发者
下载

Graph Lowering实现

Graph Lowering遍历图上的算子,依次调用算子的Lowering函数,如果算子没有Lowering函数,则会执行默认的Lowering函数。

算子Lowering函数原型示例如下,输入一个GE图上的算子节点,返回Lowering是否成功,并在内部完成节点的Scalar表达,将结果存储在属性上。

1
graphStatus(const NodePtr &node);

Graph Lowering整体分为三步:

  1. 依次调用每个节点的Lowering函数,获得其对应的Loop表达。
  2. 在Loop表达上进行index和range的推导,从而将中间过程中的View类表达到输入数据的搬运方式上。
  3. 结合Loop表达推导出的index和range信息,生成一套轴的AscGraph。

调用完节点Lowering函数后,并不会立即将节点转换为AscBackend融合节点类型,而是将每个节点的每个输出Tensor关联一个KernelBox对象:KernelBox用于表达一个算子输出Tensor的计算类过程。其核心部分定义如下:

1
2
3
4
5
6
7
8
class KernelBox {
  public:
   bool IsExternKernel() const; // 是否是Extern类型(即需要走原始的GE IR实现),取值为true,表示走原始GE IR实现
    // 处理从该KernelBox中加载一个元素时的行为,对于Extern或者Realize后的KernelBox,等同于直接从其输出Anchor上Load数据。而对于能继续融合的KernelBox,则会返回其内部的计算过程
   LoopVar Load() const;
   // 进行Realize,即需要为该KernelBox生成AscBackend节点,如果为true,则表示可融合
   void Realize(bool persistent = true); 
 };

单输出多引用

对于单输出多引用的算子,可能出现多个计算对其输出的加载方式不一致的情况。GraphLowering会基于重计算进行Lowering,即对于一个可以继续融合的节点,如果其输出被多个节点使用,例如下面例子中的第一个Abs,那么在使用该输出的每个节点对应的KernelBox中,均会包含第一个Abs的计算。通过重计算,能够处理同一份数据按照不同方式进行搬运的场景。

图中CSE(Common Subexpression Elimination,公共表达式消除) 是编译器优化、代码生成以及数学计算中常用的一种优化技术,其核心目标是识别并复用表达式中重复出现的子表达式,以减少冗余计算,提升效率。

融合与终止融合策略

在执行Lowering时,如何决定是否进行融合以及终止融合,本节给出当前的融合范围控制策略:

  1. KernelBox的类型为Reduction类型。
  2. KernelBox中的Loop节点总数超过阈值,当前阈值64。
  3. KernelBox中的Load节点数量超过阈值,当前阈值8。
  4. KernelBox作为一个无法Lowering的节点的输入(在默认Lowering函数中触发)。
  5. KernelBox归属的节点包含输入或输出控制边(跨节点的Fuse会丢失准确的控制信息)。
  6. KernelBox所属的节点的stream label信息与使用KernelBox作为输入的节点的stream label不一致。(如果任意一方未标记,则认为一致)。
  7. 遇到Exp算子会立即Realize。
  8. 控核scope不同核的算子不会融合到同一个融合算子。
  9. 没有使用到的输入会被提前Realize。例如Zeroslike。
  10. 如果算子带有_super_kernel_scope属性,会直接跳过。
  11. 带有_disable_autofuse_scope会跳过lowering。
  12. 实际属性和算子IR不一致。
  13. 算子的dtype校验如果不支持会跳过。
  14. 纯scalar图会跳过融合(以单个Ascbackend为限)。

对于不支持Lowering的算子,会调用默认的Lowering实现,默认的Lowering函数会完成两个动作:

  1. 将所有输入Anchor对应的KernelBox进行Realize,终止融合。
  2. 将自身节点输出Anchor对应的KernelBox设置为ExternKernel类型的KernelBox。

当前使用默认Lowering实现的场景有三类,处理方式完全一致:

  • 节点无法进行Lowering表达。
  • 节点可以使用Lowering表达,但是未实现。
  • 节点可以使用Lowering表达,且已经实现,但是由于无符号化推导结果,导致表达结果无效。

为节点编写Lowering实现时,无需考虑是否有符号化结果,因为会在Loop函数中进行判断。无论具体情况如何,最终Lowering后的KernelBox都是一致的,均为ExternKernel类型的KernelBox。

融合回滚策略

回滚是指在Lowering阶段,由于不感知具体的CanFuse/Schedule/Codegen能力,导致生成的AscBackend融合节点性能低于原始节点。此时,应该如何将该AscBackend节点回滚至原始节点去执行。当前的回滚策略是:

如果AscBackend融合节点对应的原始GE IR节点数少于阈值(当前阈值为2),则回滚为原始节点执行。