• 文件 >
  • 將模型作為委託進行 Lowering
快捷方式

將模型作為委託進行 Lowering

受眾:機器學習工程師,對應用委託以加速執行時程式感興趣的人員。

後端委託是後端處理和執行 PyTorch 程式的入口點,旨在利用專用後端和硬體的效能和效率優勢,同時仍為 PyTorch 使用者提供接近 PyTorch 執行時的體驗。後端委託通常由 ExecuTorch 或供應商提供。在程式中利用委託的方式是透過標準入口點 to_backend

前端介面

將程式委託給後端有三種流程

  1. 將整個模組 Lowering 到後端。這適用於測試後端和預處理階段。

  2. 將整個模組 Lowering 到後端,並將其與其他模組組合。這適用於重用從其他流程匯出的 Lowering 模組。

  3. 根據分割槽器 Lowering 模組的部分。這適用於 Lowering 包含可 Lowering 和不可 Lowering 節點的模型,是最簡化的流程。

流程 1:Lowering 整個模組

此流程從帶有 Edge Dialect 表示的跟蹤圖模組開始。要對其進行 Lowering,我們呼叫以下函式,該函式返回一個 LoweredBackendModule(關於此函式的更多文件可以在 匯出 API 參考 中找到)

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

在此函式內部,會呼叫後端的 preprocess() 函式,該函式生成一個編譯後的 blob,該 blob 將被寫入到 flatbuffer 二進位制檔案中。Lowering 後的模組可以直接捕獲,或者放回父模組中進行捕獲。最終,捕獲的模組會序列化到 flatbuffer 模型中,該模型可以由執行時載入。

以下是此流程的一個示例

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:Lowering 整個模組並組合

或者,在流程 1 之後,我們可以將此 Lowering 後的模組與另一個模組組合

# 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 表示的跟蹤圖模組開始。要 Lowering 此圖模組中的某些節點,我們可以使用過載的 to_backend 函式

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

此函式接收一個 Partitioner,它會為所有需要 Lowering 的節點新增標籤。它將返回一個 partition_tags 字典,將標籤對映到後端名稱和模組編譯規範。然後,帶有標籤的節點將使用流程 1 的過程進行分割槽並 Lowering 到其對映的後端。可用的輔助分割槽器文件可以在此處找到。這些 Lowering 後的模組將被插入到頂層模組中並進行序列化。

以下是此流程的一個示例

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)

執行時

獲得帶有委託的程式後,要在後端上執行模型,我們需要註冊後端。根據委託實現的不同,後端可以作為全域性變數的一部分註冊,也可以在 main 函式內部顯式註冊。

  • 如果後端是在全域性變數初始化期間註冊的,那麼只要它是靜態連結的,後端就會被註冊。使用者只需要將庫作為依賴項包含進來即可。

  • 如果供應商提供 API 來註冊後端,使用者需要將庫作為依賴項包含進來,並呼叫供應商提供的 API 來在 main 函式中顯式註冊後端。

文件

訪問 PyTorch 的全面開發者文件

檢視文件

教程

獲取針對初學者和高階開發者的深度教程

檢視教程

資源

查詢開發資源並獲得問題解答

檢視資源