• 文件 >
  • 在 C++ 中使用模組擴充功能執行 ExecuTorch 模型
捷徑

在 C++ 中使用模組擴充功能執行 ExecuTorch 模型

作者: Anthony Shoumikhin

在 C++ 中執行 ExecuTorch 模型教學中,我們探索了用於執行匯出模型的較低階 ExecuTorch API。雖然這些 API 提供了零開銷、極佳的彈性與控制,但對於常規使用而言,它們可能繁瑣且複雜。為了簡化此流程並使其類似於 Python 中 PyTorch 的 Eager 模式,我們在常規 ExecuTorch 執行階段 API 上引入了 Module 外觀 API。Module API 提供了相同的彈性,但預設使用常用的元件,例如 DataLoaderMemoryAllocator,隱藏了大多數複雜的細節。

範例

讓我們看看如何使用 ModuleTensorPtr API 執行從 匯出至 ExecuTorch 教學 產生的 SimpleConv 模型。

#include <executorch/extension/module/module.h>
#include <executorch/extension/tensor/tensor.h>

using namespace ::executorch::extension;

// Create a Module.
Module module("/path/to/model.pte");

// Wrap the input data with a Tensor.
float input[1 * 3 * 256 * 256];
auto tensor = from_blob(input, {1, 3, 256, 256});

// Perform an inference.
const auto result = module.forward(tensor);

// Check for success or failure.
if (result.ok()) {
  // Retrieve the output data.
  const auto output = result->at(0).toTensor().const_data_ptr<float>();
}

現在的程式碼簡化為建立一個 Module 並對其呼叫 forward(),無需額外的設定。讓我們仔細看看這些和其他 Module API,以更好地了解其內部運作。

API

建立 Module

建立 Module 物件是一個快速操作,不涉及大量的處理時間或記憶體配置。 除非使用專用的 API 明確要求,否則 ProgramMethod 的實際載入會在第一次推論時延遲發生。

Module module("/path/to/model.pte");

強制載入 Method

若要隨時強制載入 Module(以及底層的 ExecuTorch Program),請使用 load() 函式

const auto error = module.load();

assert(module.is_loaded());

若要強制載入特定的 Method,請呼叫 load_method() 函式

const auto error = module.load_method("forward");

assert(module.is_method_loaded("forward"));

您也可以使用方便的函式來載入 forward 方法

const auto error = module.load_forward();

assert(module.is_method_loaded("forward"));

注意: Program 會在載入任何 Method 之前自動載入。 如果先前的嘗試成功,後續載入它們的嘗試將不會生效。

查詢元資料

使用 method_names() 函式取得 Module 包含的一組方法名稱

const auto method_names = module.method_names();

if (method_names.ok()) {
  assert(method_names->count("forward"));
}

注意: 第一次呼叫 method_names() 時,將強制載入 Program

若要內省關於特定方法的雜項元資料,請使用 method_meta() 函式,該函式會傳回 MethodMeta 結構

const auto method_meta = module.method_meta("forward");

if (method_meta.ok()) {
  assert(method_meta->name() == "forward");
  assert(method_meta->num_inputs() > 1);

  const auto input_meta = method_meta->input_tensor_meta(0);
  if (input_meta.ok()) {
    assert(input_meta->scalar_type() == ScalarType::Float);
  }

  const auto output_meta = method_meta->output_tensor_meta(0);
  if (output_meta.ok()) {
    assert(output_meta->sizes().size() == 1);
  }
}

注意: 第一次呼叫 method_meta() 時,也會強制載入 Method

執行推論

假設預先知道 Program 的方法名稱及其輸入格式,您可以使用 execute() 函式直接按名稱執行方法

const auto result = module.execute("forward", tensor);

對於標準的 forward() 方法,上述內容可以簡化

const auto result = module.forward(tensor);

注意: 第一次呼叫 execute()forward() 時,將載入 ProgramMethod。 因此,第一次推論將花費更長的時間,因為模型會延遲載入並準備執行,除非先前已明確載入。

設定輸入和輸出

您可以使用下列 API 設定方法的個別輸入和輸出值。

設定輸入

輸入可以是任何 EValue,其中包括張量、純量、清單和其他支援的類型。 若要設定方法的特定輸入值

module.set_input("forward", input_value, input_index);
  • input_value 是一個 EValue,代表您要設定的輸入。

  • input_index 是要設定的輸入之從零開始的索引。

例如,若要設定第一個輸入張量

module.set_input("forward", tensor_value, 0);

您也可以一次設定多個輸入

std::vector<runtime::EValue> inputs = {input1, input2, input3};
module.set_inputs("forward", inputs);

注意: 您可以跳過 forward() 方法的方法名稱引數。

透過預先設定所有輸入,您可以執行推論,而無需傳遞任何引數

const auto result = module.forward();

或者只是設定,然後部分傳遞輸入

// Set the second input ahead of time.
module.set_input(input_value_1, 1);

// Execute the method, providing the first input at call time.
const auto result = module.forward(input_value_0);

注意: 預先設定的輸入儲存在 Module 中,並且可以多次重複使用於下一次執行。

如果您不再需要輸入,請將它們設定為預設建構的 EValue,不要忘記清除或重設輸入

module.set_input(runtime::EValue(), 1);

設定輸出

只有類型為 Tensor 的輸出可以在執行階段設定,並且在模型匯出時不得進行記憶體規劃。 記憶體規劃的張量會在模型匯出期間預先配置,並且無法替換。

若要設定特定方法的輸出張量

module.set_output("forward", output_tensor, output_index);
  • output_tensor 是一個 EValue,包含您要設定為輸出的張量。

  • output_index 是要設定的輸出之從零開始的索引。

注意: 確保您設定的輸出張量符合該方法預期的形狀和資料類型。

您可以跳過 forward() 的方法名稱,以及第一個輸出的索引

module.set_output(output_tensor);

注意: 預先設定的輸出儲存在 Module 中,並且可以多次重複使用於下一次執行,就像輸入一樣。

結果和錯誤類型

大多數 ExecuTorch API 都會傳回 ResultError 類型

  • Error 是一個包含有效錯誤碼的 C++ 列舉。 預設值為 Error::Ok,表示成功。

  • Result 可以保存 Error(如果操作失敗),或者保存有效負載,例如封裝 TensorEValue(如果操作成功)。要檢查 Result 是否有效,請呼叫 ok()。要檢索 Error,請使用 error();要取得資料,請使用 get() 或解引用運算符(dereference operators),例如 *->

對模組進行效能分析

使用 ExecuTorch Dump 來追蹤模型執行。建立一個 ETDumpGen 實例,並將其傳遞給 Module 建構函式。執行一個方法後,將 ETDump 資料儲存到檔案中,以供進一步分析。

#include <fstream>
#include <memory>

#include <executorch/extension/module/module.h>
#include <executorch/devtools/etdump/etdump_flatcc.h>

using namespace ::executorch::extension;

Module module("/path/to/model.pte", Module::LoadMode::MmapUseMlock, std::make_unique<ETDumpGen>());

// Execute a method, e.g., module.forward(...); or module.execute("my_method", ...);

if (auto* etdump = dynamic_cast<ETDumpGen*>(module.event_tracer())) {
  const auto trace = etdump->get_etdump_data();

  if (trace.buf && trace.size > 0) {
    std::unique_ptr<void, decltype(&free)> guard(trace.buf, free);
    std::ofstream file("/path/to/trace.etdump", std::ios::binary);

    if (file) {
      file.write(static_cast<const char*>(trace.buf), trace.size);
    }
  }
}

結論

Module API 提供了一個簡化的介面,用於在 C++ 中運行 ExecuTorch 模型,非常類似於 PyTorch 的 eager 模式體驗。透過抽象化較低層級 runtime API 的複雜性,開發人員可以專注於模型執行,而無需擔心底層細節。

文件

存取 PyTorch 的完整開發人員文件

檢視文件

教學

取得初學者和進階開發人員的深入教學課程

檢視教學課程

資源

尋找開發資源並獲得問題解答

檢視資源