使用 XNNPACK 后端构建和运行 ExecuTorch¶
以下教程将让您熟悉如何利用 ExecuTorch XNNPACK Delegate 通过 CPU 硬件加速 ML 模型。它将介绍如何将模型导出和序列化为二进制文件,以 XNNPACK Delegate Backend 为目标,并在支持的目标平台上运行模型。要快速入门,请使用 ExecuTorch 存储库中的脚本,其中包含有关导出和生成二进制文件的说明,以获取一些演示流程的示例模型。
在本教程中,您将学习如何导出 XNNPACK 降低的模型并在目标平台上运行它
将模型降低到 XNNPACK¶
import torch
import torchvision.models as models
from torch.export import export, ExportedProgram
from torchvision.models.mobilenetv2 import MobileNet_V2_Weights
from executorch.backends.xnnpack.partition.xnnpack_partitioner import XnnpackPartitioner
from executorch.exir import EdgeProgramManager, ExecutorchProgramManager, to_edge_transform_and_lower
from executorch.exir.backend.backend_api import to_backend
mobilenet_v2 = models.mobilenetv2.mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT).eval()
sample_inputs = (torch.randn(1, 3, 224, 224), )
exported_program: ExportedProgram = export(mobilenet_v2, sample_inputs)
edge: EdgeProgramManager = to_edge_transform_and_lower(
exported_program,
partitioner=[XnnpackPartitioner()],
)
我们将使用从 TorchVision 库下载的 MobileNetV2 预训练模型来介绍此示例。降低模型的流程在导出模型后开始。我们使用 .分区程序标识适合 XNNPACK 后端委托使用的子图。之后,将使用 XNNPACK Delegate flatbuffer 模式对标识的子图进行序列化,并且每个子图都将替换为对 XNNPACK Delegate 的调用。to_edge
to_backend
XnnpackPartitioner
>>> print(edge.exported_program().graph_module)
GraphModule(
(lowered_module_0): LoweredBackendModule()
(lowered_module_1): LoweredBackendModule()
)
def forward(self, b_features_0_1_num_batches_tracked, ..., x):
lowered_module_0 = self.lowered_module_0
lowered_module_1 = self.lowered_module_1
executorch_call_delegate_1 = torch.ops.higher_order.executorch_call_delegate(lowered_module_1, x); lowered_module_1 = x = None
getitem_53 = executorch_call_delegate_1[0]; executorch_call_delegate_1 = None
aten_view_copy_default = executorch_exir_dialects_edge__ops_aten_view_copy_default(getitem_53, [1, 1280]); getitem_53 = None
aten_clone_default = executorch_exir_dialects_edge__ops_aten_clone_default(aten_view_copy_default); aten_view_copy_default = None
executorch_call_delegate = torch.ops.higher_order.executorch_call_delegate(lowered_module_0, aten_clone_default); lowered_module_0 = aten_clone_default = None
getitem_52 = executorch_call_delegate[0]; executorch_call_delegate = None
return (getitem_52,)
在降低以上内容后,我们打印图形,以显示为调用 XNNPACK 委托而插入的新节点。委托给 XNNPACK 的子图是每个调用站点的第一个参数。可以观察到,大多数块和块都能够委托给 XNNPACK。我们还可以看到无法降低到 XNNPACK 委托的运算符,例如 和 。convolution-relu-add
linear
clone
view_copy
exec_prog = edge.to_executorch()
with open("xnnpack_mobilenetv2.pte", "wb") as file:
exec_prog.write_to_file(file)
在简化到 XNNPACK 程序后,我们可以为 executorch 准备它并将模型保存为文件。 是一种二进制格式,用于存储序列化的 ExecuTorch 图形。.pte
.pte
将量化模型降低到 XNNPACK¶
XNNPACK 委托还可以执行对称量化模型。要了解量化流程并了解如何量化模型,请参阅 自定义量化 注释。在本教程中,我们将利用方便地添加到文件夹中的 python 帮助程序函数。quantize()
executorch/executorch/examples
from torch.export import export_for_training
from executorch.exir import EdgeCompileConfig, to_edge_transform_and_lower
mobilenet_v2 = models.mobilenetv2.mobilenet_v2(weights=MobileNet_V2_Weights.DEFAULT).eval()
sample_inputs = (torch.randn(1, 3, 224, 224), )
mobilenet_v2 = export_for_training(mobilenet_v2, sample_inputs).module() # 2-stage export for quantization path
from torch.ao.quantization.quantize_pt2e import convert_pt2e, prepare_pt2e
from torch.ao.quantization.quantizer.xnnpack_quantizer import (
get_symmetric_quantization_config,
XNNPACKQuantizer,
)
def quantize(model, example_inputs):
"""This is the official recommended flow for quantization in pytorch 2.0 export"""
print(f"Original model: {model}")
quantizer = XNNPACKQuantizer()
# if we set is_per_channel to True, we also need to add out_variant of quantize_per_channel/dequantize_per_channel
operator_config = get_symmetric_quantization_config(is_per_channel=False)
quantizer.set_global(operator_config)
m = prepare_pt2e(model, quantizer)
# calibration
m(*example_inputs)
m = convert_pt2e(m)
print(f"Quantized model: {m}")
# make sure we can export to flat buffer
return m
quantized_mobilenetv2 = quantize(mobilenet_v2, sample_inputs)
量化需要两个阶段的导出。首先,我们使用 API 捕获模型,然后再将其提供给 utility function。执行量化步骤后,我们现在可以利用 XNNPACK 委托来降低量化导出的模型图。从这里开始,该过程与将非量化模型降低到 XNNPACK 的过程相同。export_for_training
quantize
# Continued from earlier...
edge = to_edge_transform_and_lower(
export(quantized_mobilenetv2, sample_inputs),
compile_config=EdgeCompileConfig(_check_ir_validity=False),
partitioner=[XnnpackPartitioner()]
)
exec_prog = edge.to_executorch()
with open("qs8_xnnpack_mobilenetv2.pte", "wb") as file:
exec_prog.write_to_file(file)
使用脚本降低aot_compiler.py
¶
我们还提供了一个脚本来快速降低和导出一些示例模型。您可以运行该脚本来生成降低的 fp32 和量化模型。此脚本仅用于方便起见,并执行与前两部分中列出的步骤相同的所有步骤。
python -m examples.xnnpack.aot_compiler --model_name="mv2" --quantize --delegate
请注意,在上面的示例中,
指定要使用的模型
-—model_name
标志控制是否应量化模型
-—quantize
该标志控制我们是否尝试将图形的某些部分降低到 XNNPACK 委托。
-—delegate
生成的模型文件将根据提供的参数进行命名。[model_name]_xnnpack_[qs8/fp32].pte
使用 CMake 运行 XNNPACK 模型¶
导出 XNNPACK 委托模型后,我们现在可以尝试使用 CMake 通过示例输入运行它。我们可以构建和使用 xnn_executor_runner,它是 ExecuTorch 运行时和 XNNPACK 后端的示例包装器。我们首先从配置 CMake 构建开始,如下所示:
# cd to the root of executorch repo
cd executorch
# Get a clean cmake-out directory
rm -rf cmake-out
mkdir cmake-out
# Configure cmake
cmake \
-DCMAKE_INSTALL_PREFIX=cmake-out \
-DCMAKE_BUILD_TYPE=Release \
-DEXECUTORCH_BUILD_EXTENSION_DATA_LOADER=ON \
-DEXECUTORCH_BUILD_EXTENSION_MODULE=ON \
-DEXECUTORCH_BUILD_EXTENSION_TENSOR=ON \
-DEXECUTORCH_BUILD_XNNPACK=ON \
-DEXECUTORCH_ENABLE_LOGGING=ON \
-DPYTHON_EXECUTABLE=python \
-Bcmake-out .
然后,您可以使用
cmake --build cmake-out -j9 --target install --config Release
现在您应该能够找到构建的可执行文件,您可以使用您生成的模型运行该可执行文件./cmake-out/backends/xnnpack/xnn_executor_runner
./cmake-out/backends/xnnpack/xnn_executor_runner --model_path=./mv2_xnnpack_fp32.pte
# or to run the quantized variant
./cmake-out/backends/xnnpack/xnn_executor_runner --model_path=./mv2_xnnpack_q8.pte