内核库选择性构建¶
选择性构建是 ExecuTorch 上的一种构建模式,它使用模型元数据来指导 ExecuTorch 构建。此构建模式包含在 CMake 和 buck2 上都可用的构建工具 API。ExecuTorch 用户可以使用选择性构建 API 来构建具有最小二进制大小的 ExecuTorch 运行时二进制文件,方法是仅包含模型所需的运算符。
本文档旨在通过列出可用的 API、提供高层架构概述以及展示示例来帮助 ExecuTorch 用户更好地使用选择性构建。
预读: ExecuTorch 运行时概述, ExecuTorch 的高级架构和组件
设计原则¶
为什么选择性构建? 许多 ExecuTorch 用例受到二进制大小的限制。选择性构建可以在不影响目标模型支持的情况下减小 ExecuTorch 运行时的二进制大小。
我们选择什么? 我们的核心 ExecuTorch 库大约 50kB,没有操作符/内核或委托。如果我们链接诸如 ExecuTorch 内部可移植内核库之类的内核库,整个应用程序的二进制大小会激增,因为未使用的内核被注册到 ExecuTorch 运行时。选择性构建能够对内核库应用过滤器,以便仅链接实际使用的内核,从而减小应用程序的二进制大小。
我们如何选择? 选择性构建提供 API,允许用户传入操作符信息,从目标模型派生的操作符元数据。选择性构建工具将收集这些操作符信息并为所有链接的内核库构建过滤器。
高级架构¶
请注意,所有选择性构建工具都在构建时运行(与编译时或运行时区分开来)。因此,选择性构建工具只能访问来自用户输入或模型的静态数据。
基本流程如下
对于我们计划运行的每个模型,我们都会从中提取操作符信息,无论是手动还是通过 Python 工具。操作符信息将写入 yaml 文件并在构建时生成。
一个操作符信息聚合器将收集这些模型操作符信息并将它们合并到一个操作符信息 yaml 文件中。
一个内核解析器将接收链接的内核库以及合并的操作符信息 yaml 文件,然后决定将哪些内核注册到 ExecuTorch 运行时。
API¶
我们为 CMake 和 Buck2 公开构建宏,以允许用户指定操作符信息。
在 CMake 上
在 Buck2 上
这两个构建宏都接受以下输入
选择所有操作符¶
如果此输入设置为 true,则表示我们正在注册链接到应用程序的所有内核库中的所有内核。如果设置为 true,则实际上是关闭选择性构建模式。
从架构 yaml 选择操作符¶
上下文:每个内核库都设计为与其关联一个 yaml 文件。有关此 yaml 文件的更多信息,请参阅 内核库概述。此 API 允许用户直接传入内核库的架构 yaml,有效地允许列出要注册的库中的所有内核。
从操作符列表中选择根操作符¶
此 API 允许用户传入操作符名称列表。请注意,此 API 可以与上面的 API 结合使用,我们将从两个 API 输入的并集创建一个允许列表。
示例演练¶
Buck2 示例¶
让我们看一下以下构建
# Select a list of operators: defined in `ops`
et_operator_library(
name = "select_ops_in_list",
ops = [
"aten::add.out",
"aten::mm.out",
],
)
此目标生成包含这两个操作的操作信息的 yaml 文件。
除此之外,如果我们想从内核库中选择所有操作,我们可以执行以下操作
# Select all ops from a yaml file
et_operator_library(
name = "select_ops_from_yaml",
ops_schema_yaml_target = "//executorch/examples/portable/custom_ops:custom_ops.yaml",
)
然后在内核注册库中,我们可以执行以下操作
executorch_generated_lib(
name = "select_ops_lib",
custom_ops_yaml_target = "//executorch/examples/portable/custom_ops:custom_ops.yaml",
functions_yaml_target = "//executorch/kernels/portable:functions.yaml",
deps = [
"//executorch/examples/portable/custom_ops:custom_ops_1", # kernel library
"//executorch/examples/portable/custom_ops:custom_ops_2", # kernel library
"//executorch/kernels/portable:operators", # kernel library
":select_ops_from_yaml",
":select_ops_in_list",
],
)
请注意,我们允许从列表中添加 add.out、mm.out,以及来自模式 yaml (custom_ops.yaml
) 的那些。
CMake 示例¶
在 CMakeLists.txt 中,我们有以下逻辑
set(_kernel_lib)
if(SELECT_ALL_OPS)
gen_selected_ops("" "" "${SELECT_ALL_OPS}")
elseif(SELECT_OPS_LIST)
gen_selected_ops("" "${SELECT_OPS_LIST}" "")
elseif(SELECT_OPS_YAML)
set(_custom_ops_yaml ${EXECUTORCH_ROOT}/examples/portable/custom_ops/custom_ops.yaml)
gen_selected_ops("${_custom_ops_yaml}" "" "")
endif()
然后在调用 CMake 时,我们可以执行以下操作
cmake -D… -DSELECT_OPS_LIST="aten::add.out,aten::mm.out”
或者
cmake -D… -DSELECT_OPS_YAML=ON
从操作名称列表或内核库中的模式 yaml 中进行选择。