运行时集成¶
本节介绍配置和自定义 ExecuTorch 运行时的选项。虽然预构建的包旨在提供“开箱即用”的体验,但在生产环境中进行发货时,通常需要额外的配置。ExecuTorch 提供了编译时门控功能(例如日志记录)、自定义系统集成以及仅包含运行特定模型所需的算子(选择性构建)的能力。
日志记录¶
ExecuTorch 运行时代码包含各种级别的日志记录语句,以帮助集成和调试。日志记录的包含由构建时的 EXECUTORCH_ENABLE_LOGGING
和 EXECUTORCH_LOG_LEVEL
CMake 选项控制。将这些作为编译时配置公开,允许在不使用时排除所有与日志相关的代码,这对于资源受限的系统至关重要。
在主机平台上,日志默认发送到 STDOUT 和 STDERR,在 Android 和 iOS 上会重定向到特定于操作系统的日志。有关日志路由的更多信息,请参阅下面的 平台抽象层。
要配置从源文件构建时的日志级别,请将 EXECUTORCH_ENABLE_LOGGING
指定为开启或关闭,并将 EXECUTORCH_LOG_LEVEL
指定为 debug、info、error 或 fatal 之一。日志在调试构建中默认启用,在发布构建中默认禁用。日志级别默认为 info。
有关更多信息,请参阅 从源文件构建。
cmake -b cmake-out -DEXECUTORCH_ENABLE_LOGGING=ON -DEXECUTORCH_LOG_LEVEL=DEBUG ...
平台抽象层 (PAL)¶
ExecuTorch 平台抽象层(简称 PAL)是一个粘合层,负责提供与特定宿主系统的集成。这包括日志路由、时间戳和中止处理。ExecuTorch 为符合 POSIX 标准的目标以及 Android 和 iOS 提供了默认实现,并包含在适当的扩展中。
对于不符合 POSIX 标准的系统,提供了一个最小的无操作 PAL 实现。用户需要覆盖相关的 PAL 方法才能启用日志记录、时间戳和中止。可以通过使用 -DEXECUTORCH_PAL_DEFAULT=minimal
进行构建来选择最小 PAL。
覆盖 PAL¶
通常会覆盖默认的 PAL 实现,以将日志路由到用户指定的目的地,或在嵌入式系统上提供 PAL 功能。PAL 可以使用运行时 API 或在链接时覆盖。除非您特别需要链接时覆盖,否则首选运行时 API。
运行时 PAL 注册¶
要注册自定义 PAL 实现,请执行以下步骤:
在您的应用程序的某个
.c
或.cpp
文件中包含executorch/runtime/platform/platform.h
。创建 PalImpl 结构体的一个实例。
将一个或多个字段设置为自定义 PAL 函数实现。将字段留空以使用默认平台实现。
PalImpl 结构体为此目的提供了一个 create 方法。
调用
executorch::platform::register_pal(pal_impl)
来注册实现。这可以从全局构造函数完成,如下面的示例所示。
以下是来自 pybindings.cpp 的一个完整示例,其中日志被重定向到 Python notebook 环境中正确显示。
namespace {
void emit_log_message(
et_timestamp_t timestamp,
et_pal_log_level_t level,
const char* filename,
ET_UNUSED const char* function,
size_t line,
const char* message,
ET_UNUSED size_t length) {
std::cerr << "[" << filename << ":" << line << "] " << message << std::endl;
}
runtime::PalImpl build_pal() {
return runtime::PalImpl::create(emit_log_message, __FILE__);
}
// Update PAL to redirect logs.
ET_UNUSED bool registration_result = runtime::register_pal(build_pal());
}
弱符号覆盖¶
ExecuTorch 还提供了一种通过弱符号在链接时覆盖 PAL 的方法。此方法主要用于向后兼容。
要覆盖一个或多个 PAL 方法,请执行以下步骤:
在您的应用程序的某个
.c
或.cpp
文件中包含executorch/runtime/platform/platform.h
。定义一个或多个
et_pal_*()
函数的实现。
默认的 PAL 函数是弱符号,因此提供自己的强符号定义可以在链接时覆盖它们。为确保您的定义优先,您可能需要确保强定义在链接顺序中先于弱定义。
有关 PAL 函数签名,请参阅 runtime/platform/platform.h,有关参考 POSIX 实现,请参阅 runtime/platform/default/posix.cpp。
内核库¶
在导出过程中,模型被分解为一系列算子,每个算子提供一些基本计算。两个张量相加是一个算子,卷积也是。每个算子都需要一个相应的算子内核来在目标硬件上执行计算。ExecuTorch 后端是实现此目的的首选方式,但并非所有后端都支持所有算子。
为了处理这种情况,ExecuTorch 提供了两个实现——*可移植*和*优化*的内核库。可移植内核库以平台无关的方式提供对所有算子的完全支持。优化库带有额外的系统要求,但能够利用多线程和向量化代码来获得更高的性能。可以在单个构建中同时使用这两种内核库,从而在可用时使用优化库,并以可移植库作为回退。
使用移动设备预构建包时,内核库的选择对用户来说是透明的。但是,在从源文件构建时,尤其是在嵌入式系统上,这一点很重要。在移动设备上,优先使用可用的优化算子。有关更多信息,请参阅 ExecuTorch 内核库概述。