导出 LLM¶
无需手动编写代码调用 torch.export()、ExecuTorch 的各种降低 (lowering) API,甚至无需与 TorchAO quantize_ API 交互进行量化,我们提供了一开箱即用的体验,可以高效地将一系列支持的模型导出到 ExecuTorch。
先决条件¶
LLM 导出功能需要 pytorch_tokenizers
包。如果您遇到 ModuleNotFoundError: No module named 'pytorch_tokenizers'
错误,请从 ExecutorTorch 源代码安装它。
pip install -e ./extension/llm/tokenizers/
支持的模型¶
截至本篇文档,支持的 LLM 列表包括以下模型:
Llama 2/3/3.1/3.2
Qwen 2.5/3
Phi 3.5/4-mini
SmolLM2
支持的 LLM 的最新列表可以在代码 此处 找到。
export_llm API¶
export_llm
是 ExecuTorch 用于 LLM 的高级导出 API。在本教程中,我们将重点使用此 API 导出 Llama 3.2 1B。 export_llm
的参数可以通过 CLI 参数或 YAML 配置文件指定,其字段在 LlmConfig
中定义。要调用 export_llm
,
python -m executorch.examples.extension.llm.export.export_llm
--config <path-to-config-yaml>
+base.<additional-CLI-overrides>
基本导出¶
要执行 Llama3.2 的基本导出,我们首先需要下载检查点文件(consolidated.00.pth
)和参数文件(params.json
)。您可以在 Llama 网站 或 Hugging Face 上找到它们。
然后,我们将 model_class
、checkpoint
(检查点文件路径)和 params
(参数文件路径)指定为参数。此外,稍后当我们使用运行器 API 运行导出的 .pte 文件时,运行器需要了解此模型的 bos 和 eos id,以便知道何时终止。这些可以通过 .pte 中的 bos 和 eos 获取方法来暴露,我们可以通过在 metadata
参数中指定 bos 和 eos id 来添加它们。这些 token 的值通常可以在 HuggingFace 上找到的模型的 tokenizer_config.json
中找到。
# path/to/config.yaml
base:
model_class: llama3_2
checkpoint: path/to/consolidated.00.pth
params: path/to/params.json
metadata: '{"get_bos_id":128000, "get_eos_ids":[128009, 128001]}'
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
我们只需要为 Llama 模型系列手动指定检查点路径,因为它是我们最优化的模型,并且我们有更高级的优化,例如 SpinQuant,这些优化需要自定义检查点。
对于其他支持的 LLM,检查点将自动从 HuggingFace 下载,并且参数文件可以在 executorch/examples/models
下的相应目录中找到,例如 executorch/examples/models/qwen3/config/0_6b_config.json
。
导出设置¶
ExportConfig 包含导出 .pte
的设置,例如 max_seq_length
(提示的最大长度)和 max_context_length
(模型的内存/缓存的最大长度)。
添加优化¶
export_llm
在导出前、导出过程中以及降低过程中对模型进行各种优化。量化和委托给加速器后端是主要的优化,将在接下来的两个部分中介绍。所有其他优化都可以在 ModelConfig
中找到。我们将继续添加一些优化。
# path/to/config.yaml
base:
model_class: llama3_2
checkpoint: path/to/consolidated.00.pth
params: path/to/params.json
metadata: '{"get_bos_id":128000, "get_eos_ids":[128009, 128001]}'
model:
use_kv_cache: True
use_sdpa_with_kv_cache: True
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
use_kv_cache
和 use_sdpa_with_kv_cache
推荐用于导出任何 LLM,而其他选项则视情况而定。例如:
use_shared_embedding
可用于具有绑定输入/输出嵌入层的模型,前提是您使用 TorchAO 低精度操作进行量化(quantization.qmode: torchao:8da(\d+)w
或quantization.qmode: torchao:fpa(\d+)w
),更多信息请参见 此处。use_attention_sink
用于通过在达到最大上下文长度时从 KV 缓存的开头移除内容来扩展生成。quantize_kv_cache
以 int8 量化 KV 缓存。local_global_attention
实现 Local-Global Attention,使特定的注意力层使用更小的局部滑动窗口 KV 缓存。
量化¶
量化选项由 QuantizationConfig
定义。ExecuTorch 通过两种方式进行量化:
TorchAO (XNNPACK)¶
TorchAO 在源代码级别进行量化,将 Linear 模块替换为 QuantizedLinear 模块。**要在 XNNPACK 后端上进行量化,请遵循此量化路径。** 量化模式定义在 此处。
常用的有:
8da4w
:表示 int8 动态激活 + int4 权重量化。int8
:int8 仅权重量化。
组大小通过以下方式指定:
group_size
:8、32、64 等。
对于 Arm CPU,还有 低精度内核,用于 int8 动态激活 + int[1-8] 权重量化。请注意,这不应与 XNNPACK 一起使用,并且根据我们的实验,对于等效的 8da4w
,性能有时可能更好。要使用它们,请将 qmode
指定为以下任一项:
torchao:8da(\d+)w
:int8 动态激活 + int[1-8] 权重,例如torchao:8da5w
。torchao:fpa(\d+)w
:仅 int[1-8] 权重,例如torchao:fpa4w
。
要量化嵌入层,请指定 embedding_quantize: <bitwidth>,<groupsize>
(这里的 bitwidth
必须是 2、4 或 8),或者对于低精度内核,请使用 embedding_quantize: torchao:<bitwidth>,<groupsize>
(bitwidth
可以是 1-8)。
# path/to/config.yaml
base:
model_class: llama3_2
checkpoint: path/to/consolidated.00.pth
params: path/to/params.json
metadata: '{"get_bos_id":128000, "get_eos_ids":[128009, 128001]}'
model:
use_kv_cache: True
use_sdpa_withp_kv_cache: True
quantization:
embedding_quantize: 4,32
qmode: 8da4w
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
pt2e (QNN, CoreML, 和 Vulkan)¶
pt2e 在导出后的图级别进行量化,替换节点并注入量化/反量化节点。**要在非 CPU 后端(QNN、CoreML、Vulkan)上进行量化,请遵循此量化路径。** 有关 pt2e 的更多信息,请阅读 此处,以及 ExecuTorch 如何使用 pt2e 的信息 此处。
CoreML 和 Vulkan 对 export_llm 的支持目前仍处于实验阶段且有限。有关 QNN 导出的更多信息,请阅读 在 Android (Qualcomm) 上运行。
后端支持¶
后端选项由 BackendConfig
定义。每个后端都有自己的后端配置选项。以下是一个将 LLM 降低到 XNNPACK 以实现 CPU 加速的示例:
# path/to/config.yaml
base:
model_class: llama3_2
checkpoint: path/to/consolidated.00.pth
params: path/to/params.json
metadata: '{"get_bos_id":128000, "get_eos_ids":[128009, 128001]}'
model:
use_kv_cache: True
use_sdpa_withp_kv_cache: True
quantization:
embedding_quantize: 4,32
qmode: 8da4w
backend:
xnnpack:
enabled: True
extended_ops: True # Expand the selection of ops delegated to XNNPACK.
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
性能分析和调试¶
要查看哪些算子被委托给后端,哪些没有,请指定 verbose: True
。
# path/to/config.yaml
...
debug:
verbose: True
...
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
在日志中,将有一个表格列出图中所有算子,以及哪些被委托,哪些未被委托。
这是一个例子:
点击查看委托详情
总委托子图数:368
委托节点数:2588
非委托节点数:2513
op_type |
# in_delegated_graphs |
# in_non_delegated_graphs |
|
---|---|---|---|
0 |
_assert_scalar |
0 |
167 |
1 |
_local_scalar_dense |
0 |
123 |
2 |
add |
0 |
31 |
3 |
aten__to_copy_default |
0 |
44 |
4 |
aten_add_tensor |
418 |
44 |
5 |
aten_alias_copy_default |
0 |
52 |
… |
|||
15 |
aten_linear_default |
183 |
0 |
18 |
aten_mul_tensor |
445 |
0 |
20 |
aten_pow_tensor_scalar |
157 |
0 |
22 |
aten_rsqrt_default |
157 |
0 |
27 |
aten_view_copy_default |
0 |
126 |
31 |
getitem |
366 |
628 |
… |
|||
41 |
torchao_quantize_affine_default |
183 |
0 |
42 |
Total |
2588 |
2513 |
为了进行进一步的性能分析,您可以选择使用 ExecuTorch 开发者工具 来执行诸如将单个算子性能追溯到源代码、查看内存规划以及调试中间激活等操作。要生成 ETRecord 以将 .pte
程序链接回源代码,您可以使用:
# path/to/config.yaml
...
debug:
generate_etrecord: True
...
# export_llm
python -m extension.llm.export.export_llm \
--config path/to/config.yaml
其他调试和性能分析选项可以在 DebugConfig 中找到。
一些示例选项:
profile_memory
:用于生成 chrome trace 格式的激活内存配置文件。它允许您可视化模型不同中间张量在模型执行过程中的生命周期、它们的生命周期如何重叠、这些张量来自哪里以及它们如何影响模型的内存占用。有关内存配置文件的更多详细信息,请单击 此处。profile_path
:用于生成 export_llm 各组件的时间配置文件。这些组件包括torch.export
、量化、to_edge
、通过 to_backend API 的委托等。此选项会生成一个 .html 文件,以火焰图/冰柱图格式提供时间配置文件。这有助于了解export_llm
的哪个部分花费的时间最多。对开发者和 ExecuTorch 的贡献者来说非常有价值。有关火焰图的更多信息,您可以查看 https://www.parca.dev/docs/icicle-graph-anatomy/
要了解更多关于 ExecuTorch 开发者工具的信息,请参阅 ExecuTorch 开发者工具简介。