多流表达功能

功能简介

大模型推理场景下,对于一些可并行的场景,可以划分多个stream提升执行效率。通过在脚本中指定每个算子的执行stream,将原本需要串行的多个算子分发到不同stream进行并行计算,多个stream上的计算形成overlap,从而降低整体计算耗时。

对于并行来说,包含如下两种:

  • 计算与计算并行:一般是基于数据依赖关系,分析出可以并行的多条计算分支,指定stream并行。
  • 计算与通信并行:一般是针对没有数据依赖的通信操作,提前使用通信资源执行通信任务。

本功能主要处理aclgraph间资源并发,尤其针对Cube计算资源未完全使用的场景。若Cube计算资源已完全使用,不建议开启本功能,可能会造成额外的调度,从而导致原计算性能劣化。

使用约束

使用方法

  1. 用户自行分析模型脚本中可进行并行计算的算子。

  2. 开启多流表达。

    使用如下with语句块,语句块内下发的算子切换至“stream”参数指定的流计算,语句块外的算子使用默认流计算。

    with torch.npu.stream(stream: torch.npu.Stream):
    
  3. (可选)控制并行计算的时序。

    通过torch.npu.Event()、torch.npu.Event.record()、torch.npu.Event.wait()系列原生接口实现时序控制。

  4. (可选)延长内存释放时机。

    Eager模式场景下,脚本中如果涉及多stream内存复用,一般会调用PyTorch的tensor.record_stream原生接口延迟内存释放。

  5. (可选)配置限核。

    参考AI Core和Vector Core限核功能章节配置,可以防止出现性能达不到预期,卡死等情况出现。

使用示例

import torch
import torch_npu


class Model(torch.nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, in1, in2, in3, in4):
        stream1 = torch.npu.Stream()
        stream2 = torch.npu.Stream()
        event1 = torch.npu.Event()
        event2 = torch.npu.Event()

        add_result = torch.add(in1, in2)
        # B在默认流上创建
        B = in3 + in4
        # 插入一个record用于同步,对于event1.wait(stream1)后的任务需要等record执行完毕才能执行
        event1.record()
        with torch.npu.stream(stream1):
            # torch.mm算子(mm_result)等待torch.add算子(add_result)以及B计算执行完再执行
            event1.wait(stream1)
            # B在stream1上使用
            mm_result = torch.mm(B, in4)
            # 插入一个record用于同步,对于event2.wait(stream2)后的任务需要等record执行完毕才能执行
            event2.record()
            # record_stream B在stream'1'上使用,延长Tensor B对应内存的生命周期
            B.record_stream(stream1)
        mm1 = torch.mm(in3, in4)
        with torch.npu.stream(stream2):
            # torch.add算子(add2)等待torch.mm算子(mm_result)执行完再执行
            event2.wait(stream2)
            add2 = torch.add(in3, in4)
        return add_result, mm_result, mm1, add2

model = Model().to("npu")
model = torch.compile(model, backend="npugraph_ex", fullgraph=False, dynamic=False)

in1 = torch.randn(1000, 1000, dtype = torch.float16).npu()
in2 = torch.randn(1000, 1000, dtype = torch.float16).npu()
in3 = torch.randn(1000, 1000, dtype = torch.float16).npu()
in4 = torch.randn(1000, 1000, dtype = torch.float16).npu()
result = model(in1, in2, in3, in4)

图 1 多流表达示意图

图中实线框展示了多流并行执行的时序控制关系,用户在脚本中通过event1和event2控制流间数据依赖,确保具有依赖关系的计算任务按正确顺序执行。虚线框标注了npugraph_ex在编图时自动插入的record、wait等同步点,形成执行闭环,目的是让从流的算子能够被捕获到。(CUDA Graph相同逻辑,切换到从流需要用开头和结尾的两对record、wait以实现流捕获)。