使用 C++ 中的模块扩展运行 ExecuTorch 模型¶
在 在 C++ 中运行 ExecuTorch 模型教程中,我们探讨了用于运行导出模型的较低级别 ExecuTorch API。虽然这些 API 提供零开销、极大的灵活性和控制力,但它们对于常规使用来说可能很冗长和复杂。为了简化这一点并类似于 PyTorch 在 Python 中的 Eager 模式,我们在常规 ExecuTorch 运行时 API 上引入了模块外观 API。模块 API 提供相同的灵活性,但默认使用常用组件,如 和 ,隐藏了最复杂的细节。DataLoader
MemoryAllocator
例¶
让我们看看如何使用 API 运行从 导出到 ExecuTorch 教程生成的模型:SimpleConv
Module
#include <executorch/extension/module/module.h>
using namespace ::torch::executor;
// Create a Module.
Module module("/path/to/model.pte");
// Wrap the input data with a Tensor.
float input[1 * 3 * 256 * 256];
Tensor::SizesType sizes[] = {1, 3, 256, 256};
TensorImpl tensor(ScalarType::Float, std::size(sizes), sizes, input);
// Perform an inference.
const auto result = module.forward({EValue(Tensor(&tensor))});
// Check for success or failure.
if (result.ok()) {
// Retrieve the output data.
const auto output = result->at(0).toTensor().const_data_ptr<float>();
}
现在,代码归结为创建 a 并调用它,无需额外设置。让我们仔细看看这些 API 和其他 API,以更好地了解内部工作原理。Module
forward()
Module
蜜蜂属¶
创建模块¶
创建对象是一项速度非常快的操作,不涉及大量的处理时间或内存分配。a 和 a 的实际加载在第一次推理中懒惰地发生,除非使用专用 API 明确请求。Module
Program
Method
Module module("/path/to/model.pte");
强制加载方法¶
要随时强制加载 (以及底层的 ExecuTorch ),请使用以下函数:Module
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"));
注意:在加载 any 之前自动加载。如果前面的 attemp 之一成功,则用于加载它们的后续尝试将不起作用。Program
Method
查询元数据¶
获取 Module 包含的一组函数名称:method_names()
const auto method_names = module.method_names();
if (method_names.ok()) {
assert(method_names.count("forward"));
}
注意:第一次调用时将尝试强制加载。method_names()
Program
通过 function 返回的 struct 内省有关特定方法的杂项元数据:MethodMeta
method_meta()
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 = 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", {EValue(Tensor(&tensor))});
标准方法名称也可以简化为:forward()
const auto result = module.forward({EValue(Tensor(&tensor))});
注意:or 会尝试强制加载 和 第一次调用时。因此,第一次推理将比后续推理花费更多的时间,因为它会延迟加载模型并准备执行,除非之前使用相应的函数显式加载了 or。execute()
forward()
Program
Method
Program
Method
结果和错误类型¶
大多数 ExecuTorch API(包括上述 API)都返回 or 类型。让我们了解一下这些是什么:Result
Error
分析模块¶
使用 ExecuTorch Dump 跟踪模型执行情况。创建类的实例并将其传递给构造函数。执行方法后,将 保存到文件中以供进一步分析。如果需要,您可以在单个跟踪中捕获多个执行。ETDumpGen
Module
ETDump
#include <fstream>
#include <memory>
#include <executorch/extension/module/module.h>
#include <executorch/sdk/etdump/etdump_flatcc.h>
using namespace ::torch::executor;
Module module("/path/to/model.pte", Module::MlockConfig::UseMlock, 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);
}
}
}