目录

将 Model 作为 Delegate 降低

受众:对应用委托在运行时加速其程序感兴趣的 ML 工程师。

后端委托是后端处理和执行 PyTorch 的入口点 利用 Specialized 的性能和效率优势的计划 后端和硬件,同时仍为 PyTorch 用户提供体验 接近 PyTorch 运行时的 PyTorch 运行时。后端委托通常由 ExecuTorch 或供应商。在程序中利用委派的方法是通过 standard entry point 。to_backend

前端接口

将程序委托给后端有三个流:

  1. 将整个模块降低到后端。这有利于测试后端和 预处理阶段。

  2. 将整个模块降低到后端,并将其与另一个模块组合。这 非常适合重复使用从其他流导出的降低模块。

  3. 根据分区器的模块的下部。这有利于 降低模型,该模型同时包含可降低节点和不可降低节点,并且 最简化的流程。

流程 1:降低整个模块

此流程从具有 Edge Dialect 表示的跟踪图形模块开始。自 降低它,我们调用以下函数,该函数返回一个(有关此函数的更多文档,请参阅导出 API 参考LoweredBackendModule)

# defined in backend_api.py
def to_backend(
    backend_id: str,
    edge_program: ExportedProgram,
    compile_spec: List[CompileSpec],
) -> LoweredBackendModule:

在这个函数中,后端的函数被调用,其中 生成一个已编译的 blob,该 blob 将发送到 flatbuffer 二进制文件。这 降低的模块可以直接捕获,也可以放回父模块中 捕获。最终,捕获的模块在 flatbuffer 的模型中序列化 ,这可以由 Runtime 加载。preprocess()

以下是此流程的示例:

from executorch.exir.backend.backend_api import to_backend
import executorch.exir as exir
import torch
from torch.export import export
from executorch.exir import to_edge

# The submodule runs in a specific backend. In this example,  `BackendWithCompilerDemo` backend
class LowerableSubModel(torch.nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, x):
        return torch.sin(x)

# Convert the lowerable module to Edge IR Representation
to_be_lowered = LowerableSubModel()
example_input = (torch.ones(1), )
to_be_lowered_exir_submodule = to_edge(export(to_be_lowered, example_input))

# Import the backend implementation
from executorch.exir.backend.test.backend_with_compiler_demo import (
    BackendWithCompilerDemo,
)
lowered_module = to_backend('BackendWithCompilerDemo', to_be_lowered_exir_submodule.exported_program(), [])

我们可以通过直接运行将程序序列化为 flatbuffer 格式:

# Save the flatbuffer to a local file
save_path = "delegate.pte"
with open(save_path, "wb") as f:
    f.write(lowered_module.buffer())

流程 2:降低整个模块和复合材料

或者,在流 1 之后,我们可以将这个降低的模块与另一个 模块:

# This submodule runs in executor runtime
class NonLowerableSubModel(torch.nn.Module):
    def __init__(self, bias):
        super().__init__()
        self.bias = bias

    def forward(self, a, b):
        return torch.add(torch.add(a, b), self.bias)


# The composite module, including lower part and non-lowerpart
class CompositeModel(torch.nn.Module):
    def __init__(self):
        super().__init__()
        self.non_lowerable = NonLowerableSubModel(torch.ones(1) * 0.3)
        self.lowerable = lowered_module

    def forward(self, x):
        a = self.lowerable(x)
        b = self.lowerable(a)
        ret = self.non_lowerable(a, b)
        return a, b, ret

composite_model = CompositeModel()
model_inputs = (torch.ones(1), )
exec_prog = to_edge(export(composite_model, model_inputs)).to_executorch()

# Save the flatbuffer to a local file
save_path = "delegate.pte"
with open(save_path, "wb") as f:
    f.write(exec_prog.buffer)

流程 3:分区

第三个流也从带有 Edge Dialect 的跟踪图形模块开始 表示法。要降低这个 graph 模块中的某些节点,我们可以使用 overloaded 函数

def to_backend(
    edge_program: ExportedProgram,
    partitioner: Partitioner,
) -> ExportedProgram:

此函数接受 a,该 a 向所有节点添加一个标签,该节点 是应该降低的。它将返回一个字典,将 tags 映射到 后端名称和模块编译规范。然后,标记的节点将 使用 Flow 1 的进程进行分区并降低到其映射的后端。 可用的帮助程序分区程序记录在这里。这些降低的模块 将入到顶级模块中并序列化。Partitionerpartition_tags

以下是该流程的示例:

import executorch.exir as exir
from executorch.exir.backend.backend_api import to_backend
from executorch.exir.backend.test.op_partitioner_demo import AddMulPartitionerDemo
from executorch.exir.program import (
    EdgeProgramManager,
    to_edge,
)
from torch.export import export
import torch

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

    def forward(self, x, y):
        x = x + y
        x = x * y
        x = x - y
        x = x / y
        x = x * y
        x = x + y
        return x

model = Model()
model_inputs = (torch.randn(1, 3), torch.randn(1, 3))

core_aten_ep = export(model, model_inputs)
edge: EdgeProgramManager = to_edge(core_aten_ep)
edge = edge.to_backend(AddMulPartitionerDemo())
exec_prog = edge.to_executorch()

# Save the flatbuffer to a local file
save_path = "delegate.pte"
with open(save_path, "wb") as f:
    f.write(exec_prog.buffer)

运行

在拥有带有 delegate 的程序后,要使用后端运行模型,我们需要注册后端。 根据委托实现,后端可以注册为全局变量的一部分,或者 在 main 函数中显式注册。

  • 如果它是在全局变量初始化期间注册的,则只要后端是静态链接的,它就会被注册。用户只需将库作为依赖项的一部分。

  • 如果供应商提供了 API 来注册后端,则用户需要将库作为依赖项的一部分包含在内,并调用供应商提供的 API 将后端显式注册为 main 函数的一部分。

文档

访问 PyTorch 的全面开发人员文档

查看文档

教程

获取面向初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并解答您的问题

查看资源