VGGT 推理 YAML 配置全解析:从单卡基线到多卡序列并行与 W8A8 量化
【免费下载链接】cann-recipes-embodied-ai本项目针对具身智能业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-embodied-ai
本篇技术指南以cann-recipes-embodied-ai仓库中 VGGT 模型在昇腾 NPU 上的推理适配为例,系统讲解其 YAML 配置文件体系。你将掌握config/*.yaml中每个参数的含义、默认值与约束关系,理解计算冗余消除、多卡序列并行、INT8 量化与内存数据格式四大优化类别的底层实现原理,并能够独立完成从单卡基线推理到 2/4/8 卡并行推理、再到 INT8 量化模型构建与推理的完整配置与启动流程。
一、配置体系总览
VGGT 的推理参数全部通过config/*.yaml文件管理,启动入口demo_infer.py使用--config参数指定配置文件(默认值为config/single.yaml)。这一机制由 demo_infer.py 中的parse_args()实现:读取 YAML 后,分别提取model_args、world_size,再经load_optimization_config解析optimization段,最终通过build_vggt_config组装为完整的推理配置对象(对应 utils.py 中的VGGTConfig数据结构)。
仓库预置了 5 套默认配置,覆盖单卡、多卡与量化三类典型场景:
| 配置文件 | 场景 | world_size | 序列并行 | 量化 |
|---|---|---|---|---|
| single.yaml | 单卡基线 | 1 | 关闭 | bf16 |
| sp2.yaml | 2 卡序列并行 | 2 | 开启(Ulysses=2, Ring=1) | bf16 |
| sp4.yaml | 4 卡序列并行 | 4 | 开启(Ulysses=2, Ring=2) | bf16 |
| sp8.yaml | 8 卡序列并行 | 8 | 开启(Ulysses=4, Ring=2) | bf16 |
| single_w8a8.yaml | 单卡 INT8 量化推理 | 1 | 关闭 | bf16 + W8A8 |
一个完整的配置文件由顶层元信息(model_name、world_size、master_port、entry_script)与两大配置段(model_args、optimization)组成。下面以 single.yaml 为基准逐段拆解。
二、model_args:模型与推理运行参数
model_args段控制模型权重、输入数据与推理过程的基本行为:
model_args: ckpt: "ckpt/model.pt" # 模型权重路径(必填) images-path: "examples/kitchen/images" # 输入图片目录(必填) enable-profiling: false # 是否开启性能剖析 profile-dir: "prof_sp" # 剖析结果输出目录 num-runs: 6 # 推理运行次数各参数要点:
- ckpt:模型权重文件路径,必填。标准模型对应 README.md 中通过 Hugging Face 下载的
model.pt;INT8 量化场景下则应指向生成的VGGT_model_W8A8.pt(见 single_w8a8.yaml)。 - images-path:输入图片目录,支持相对路径或绝对路径。
demo_infer.py中的_load_images_for_inference会递归收集目录下所有图片,经load_and_preprocess_images预处理后组成[1, N, 3, H, W]形状的批量张量。 - enable-profiling / profile-dir:性能剖析开关与输出目录。开启后由 demo_infer.py 中的
define_profiler创建 NPU+CPU 双活动剖析器,采用warmup=2, active=1的调度策略,多卡场景下结果按rank_{i}子目录分别落盘;关闭时使用空上下文管理器,零额外开销。 - num-runs:正式推理的次数。单卡路径下
_run_single_inference会先执行一次 warmup 再循环num_runs次;序列并行路径下_run_sp_inference_loop丢弃前 2 次结果(对应代码中step >= 2才记录日志),最终取剩余次数的平均值作为端到端推理耗时。
三、optimization:四大优化类别配置
optimization段是整个配置体系的核心,包含计算冗余消除、并行计算、量化、内存与数据格式四大类别:
optimization: # 计算冗余消除:通过缓存机制避免重复计算 computation-redundancy-elimination: rope-cache: true # 旋转编码缓存 dpt-pos-embed-cache: true # DPT 头位置编码缓存 cos-sin-dtype-optimization: true # Cos/Sin 数据类型优化 # 并行计算优化:利用多 NPU 并行,仅多卡场景生效 parallel-computation: enable: false # 并行计算总开关 ulysses-degree: 2 # Ulysses 序列并行度 ring-degree: 2 # Ring Attention 并行度 # 量化优化:降低数据精度以减少显存占用与计算开销 quantization: dtype: "bf16" # 模型数据类型:fp32 或 bf16 int8-w8a8: enable: false # INT8 量化开关 build: false # INT8 量化模型构建开关 # 内存与数据格式优化:提前转换数据格式,避免运行时转换开销 memory-and-data-format: conv-weight-layout-preconvert: true # 卷积核布局预转换3.1 计算冗余消除(Computation Redundancy Elimination)
| 参数 | 类型 | 说明 |
|---|---|---|
| rope-cache | bool | 旋转编码三层缓存;关闭时每次重新计算 |
| dpt-pos-embed-cache | bool | DPT 头位置编码缓存;关闭时不缓存 |
| cos-sin-dtype-optimization | bool | Cos/Sin 使用 bfloat16;关闭时使用 float64 |
rope-cache对应旋转编码的缓存机制,实现在 rope.py 的_compute_frequency_components中,代码注释明确其为"三层缓存":
- 基础频率缓存:以
(dim, seq_len, device, dtype)为 key 缓存 cos/sin 频率分量表(frequency_cache); - max 位置缓存:以
(height, width)为 key 缓存input_positions.max() + 1的序列长度(源码中即max_position_cache思路); - 2D 嵌入结果缓存:以
(height, width, batch_size, seq_len)为 key 缓存垂直/水平方向 embedding 后的 cos/sin 张量(cos_sin_cache)。
旋转编码的输入依赖 positions 变量,而 positions 与输入图片的宽高相关,因此对同样大小的图片可完全复用结果,避免每次前向都重新生成 cos/sin 与求最大值。
dpt-pos-embed-cache对应 DPT 头的位置编码缓存,实现在 dpt_head.py。位置编码结果取决于输入图片大小与 token 长度,因此以(W, H, x.shape)为 key 缓存_compute_pos_embed的结果;关闭时回退到_apply_pos_embed_original每次重新计算。
cos-sin-dtype-optimization对应 Cos/Sin 算子输入数据类型优化。原生实现中 omega 变量使用torch.double(float64),导致算子下发到 AI CPU 执行、性能低下;优化后改为 bfloat16,使算子可调度到 NPU 矢量/AICore 上执行。该开关通过 demo_infer.py 中的set_cos_sin_dtype_optimization_enabled全局生效,其详细替换逻辑记录在 vggt_optimization.md。
3.2 并行计算(Parallel Computation,仅多卡生效)
| 参数 | 类型 | 说明 |
|---|---|---|
| enable | bool | 启用序列并行;单卡场景必须为 false |
| ulysses-degree | int | Ulysses 并行度,必须满足ulysses-degree × ring-degree = world_size |
| ring-degree | int | Ring 并行度,必须满足ulysses-degree × ring-degree = world_size |
并行计算采用Ulysses + Ring Attention 混合序列并行方案:
- Ulysses 并行:将
num_heads(注意力头)维度切分到多卡,通过 all-to-all 通信实现 head 维度与序列维度的互换,使每个 rank 持有完整序列但只处理部分注意力头。约束num_attention_heads必须能被ulysses-degree整除。 - Ring 并行:将序列维度切分到多卡,利用 NPU FIA 算子返回的 LSE(log-sum-exp)信息支持分块注意力结果的数值稳定合并,并采用通信与计算 overlap 策略隐藏通信开销。
两个并行度的关系约束在源码层被强校验:demo_infer.py的setup_sequence_parallel_groups(demo_infer.py)会显式检查world_size != ulysses_degree * ring_degree并抛出ValueError,同时按ring_degree组创建 Ulysses 进程组、按ulysses_degree组创建 Ring 进程组,最终构造SPConfig(ulysses_degree, ring_degree, use_ring_overlap=True)传入模型。
序列并行的具体算子适配见 unified_sp_attention.py(以npu_fused_infer_attention_score为底层实现)与 attention.py:Frame Attention处理帧内短序列,保持使用 PyTorch SDPA;Global Attention处理跨帧长序列,切换到 NPU FIA 融合算子,二者通过is_global_attention标志分流。
多卡推理要求输入图片数量足够多(序列足够长)才能体现并行收益,配置并行场景时应结合输入规模评估。
3.3 量化(Quantization)
| 参数 | 类型 | 说明 |
|---|---|---|
| dtype | str | 模型数据类型:"fp32"(原始)或"bf16"(半精度) |
| int8-w8a8.enable | bool | 启用 INT8 量化推理(W8A8) |
| int8-w8a8.build | bool | 构建 INT8 量化模型,仅首次运行时使用 |
- dtype:模型整体数据精度。
fp32为原始精度,bf16显存减半。demo_infer.py的_load_model_with_sp与load_standard_model在加载权重后据此调用model.float()或model.bfloat16()。仓库实测(见 vggt_optimization.md):bf16 相比 fp32 获得 6.62% 性能收益,相机位姿任务精度从 0.919 降至 0.911,损失在 0.5% 以内。 - int8-w8a8.enable:INT8 量化推理开关。开启时模型加载走 W8A8 路径:激活使用动态 per-token 量化、权重使用静态 per-channel 量化。量化 Linear 层的实现见 vggt_linear.py:权重在
__init__时通过torch_npu.npu_dynamic_quant离线量化为 int8 并保存 per-channel scale,前向时对激活做 per-token 量化,再经npu_quant_matmul以 bf16 精度输出。 - int8-w8a8.build:量化模型构建开关。首次使用 INT8 时置为
true,demo_infer.py会先加载标准模型,调用build_and_save_w8a8_model生成量化模型并保存到当前路径(文件名VGGT_model_W8A8.pt)后直接返回。
值得注意的量化范围:当前实现仅对 VGGT 模型中in_features == 4096的 Linear 层进行 8bit 量化,其余 Linear 层通过set_ignore_quantize标记跳过(见 vggt_utils.py)。仓库实测:fp32 模型约 4.9GB,bf16 约 2.46GB,int8 约 2.16GB;INT8 相比 bf16 相机位姿精度从 0.911 降至 0.907,损失在 0.5% 以内(vggt_optimization.md)。
3.4 内存与数据格式(Memory and Data Format)
| 参数 | 类型 | 说明 |
|---|---|---|
| conv-weight-layout-preconvert | bool | 卷积核预转换为 Fractal_Z 格式;关闭时使用默认格式 |
NPU 上进行二维卷积前需要先通过 Transdata 算子将卷积核转为Fractal_Z(NZ)私有格式,推理过程中存在格式转换开销。该优化在模型加载完成后调用cast_model_weight(实现见 cast_weight.py,调用逻辑见 demo_infer.py)递归遍历所有nn.Conv2d模块,提前执行torch_npu.npu_format_cast(weight.data, 4)(格式 4 即 Fractal_Z)完成转换,从而将转换开销从推理热路径中剔除。
代码中有一处平台相关的前提条件:is_ascend_950()返回 True 时跳过该转换(注释说明 950 仅支持 ND 格式,无需 NZ 转换),因此该优化实际作用于 Atlas A2/A3 等目标环境。
四、顶层元信息与参数约束
4.1 顶层字段
model_name: "vggt" # 模型名称 world_size: 1 # 启动进程数 master_port: 29600 # torchrun 主节点端口 entry_script: "demo_infer.py" # 入口脚本- model_name / entry_script:
yaml_parse.sh校验与解析时的必填字段; - world_size:进程数,即 NPU 卡数,多卡时必须等于
ulysses-degree × ring-degree; - master_port:
torchrun启动时的分布式主节点端口,默认 29600。
配置文件校验逻辑见 yaml_parse.sh:vggt_validate_yaml会强制检查model_name、world_size、entry_script三个顶层键是否存在,并校验world_size为正整数,校验失败即中止启动。
4.2 量化参数关系
dtype与int8-w8a8.enable可以同时为 true(模型整体 BF16 + Linear 层 INT8),这也是 single_w8a8.yaml 采用的组合;int8-w8a8.build与int8-w8a8.enable不应同时为 true(build 用于生成模型,enable 用于使用模型)。
4.3 并行计算参数约束
- 必须满足
ulysses-degree × ring-degree = world_size; - 单卡场景(world_size=1)下,
parallel-computation.enable必须为false; num_attention_heads必须能被ulysses-degree整除。
4.4 合法配置示例速查表
| 场景 | world_size | parallel.enable | ulysses-degree | ring-degree | dtype | int8-w8a8.enable |
|---|---|---|---|---|---|---|
| 单卡推理 | 1 | false | 1 | 1 | bf16 | false |
| 单卡量化推理 | 1 | false | 1 | 1 | bf16 | true |
| 2 卡并行 | 2 | true | 2 | 1 | bf16 | false |
| 4 卡并行 | 4 | true | 2 | 2 | bf16 | false |
| 8 卡并行 | 8 | true | 4 | 2 | bf16 | false |
以上组合均与仓库预置配置文件一一对应,可直接套用。
五、多卡序列并行推理配置与启动
多卡推理通过 YAML 配置文件控制,关键参数如下:
| 参数 | 说明 |
|---|---|
world_size | NPU 卡数,必须等于ulysses-degree × ring-degree |
optimization.parallel-computation.enable | 是否启用序列并行,多卡推理设为true |
optimization.parallel-computation.ulysses-degree | Ulysses 并行度,num_attention_heads必须能被其整除 |
optimization.parallel-computation.ring-degree | Ring 并行度,约束ulysses-degree × ring-degree = world_size |
以 8 卡为例,对应 sp8.yaml:
optimization: parallel-computation: enable: true ulysses-degree: 4 ring-degree: 2 model_name: "vggt" world_size: 8 master_port: 29600 entry_script: "demo_infer.py"5.1 启动方式
方式一:Python 直接启动(仅单卡)
# 默认使用 single.yaml 配置(单卡推理) python demo_infer.py # 指定配置文件(单卡推理) python demo_infer.py --config config/single.yamldemo_infer.py的main()(demo_infer.py)依据enable_sp或环境变量中是否存在RANK/WORLD_SIZE自动分流到序列并行路径或单卡路径。
方式二:Shell 脚本启动(支持单卡与多卡)
# 单卡推理(默认使用 single.yaml) bash infer_test.sh # 多卡推理(2 卡并行,内部调用 torchrun) bash infer_test.sh sp2.yaml # 多卡推理(4 卡并行) bash infer_test.sh sp4.yaml # 多卡推理(8 卡并行) bash infer_test.sh sp8.yamlinfer_test.sh的执行流程为:source CANN 环境变量 → 加载 yaml_parse.sh 与 vggt_launch.sh →vggt_parse_config解析配置并导出WORLD_SIZE、MASTER_PORT、ENTRY_SCRIPT环境变量 →vggt_launch启动任务。
vggt_launch.sh的启动前会设置 NPU 优化环境变量与 HCCL 分布式通信配置:
# NPU 优化环境变量 export PYTORCH_NPU_ALLOC_CONF=${PYTORCH_NPU_ALLOC_CONF:-"expandable_segments:True"} export TASK_QUEUE_ENABLE=${TASK_QUEUE_ENABLE:-"2"} export CPU_AFFINITY_CONF=${CPU_AFFINITY_CONF:-"1"} export TOKENIZERS_PARALLELISM=${TOKENIZERS_PARALLELISM:-"false"} # HCCL 分布式通信配置 export HCCL_IF_IP=${LOCAL_HOST} export HCCL_IF_BASE_PORT=23456 export HCCL_CONNECT_TIMEOUT=1200 export HCCL_EXEC_TIMEOUT=1200随后按world_size通过torchrun --master_port=${MASTER_PORT} --nproc_per_node=${WORLD_SIZE}(torchrun 不可用时回退到python -m torch.distributed.run)拉起分布式推理。run_inference_with_sp中通过dist.init_process_group(backend='hccl')初始化 HCCL 通信后端,每个进程绑定npu:{local_rank}设备。
5.2 多卡推理执行流程
序列并行推理的完整链路(对应 demo_infer.py):固定随机种子 → 初始化分布式 → 依据 YAML 创建 Ulysses/Ring 进程组 → 按dtype加载模型(可选conv-weight-layout-preconvert)→ 加载并预处理图片 → warmup → 开启剖析(可选)→ 循环num_runs次推理并统计耗时 → 输出平均推理时间。
六、INT8 量化推理完整流程
INT8 量化推理分为"构建"与"使用"两个阶段:
步骤 1:生成 int8 量化模型
修改配置,将 build 置为 true(enable 保持 false):
optimization: quantization: int8-w8a8: enable: false build: true然后运行(yaml 文件名需替换为实际配置文件):
python demo_infer.py --config config/xxx.yamlint8 模型会生成在当前路径(文件名:VGGT_model_W8A8.pt)。此阶段quick_start会走标准模型加载路径,调用build_and_save_w8a8_model完成量化模型构建与落盘后直接返回。
步骤 2:使用 int8 量化模型推理
使用 single_w8a8.yaml 配置文件(ckpt指向生成的量化权重、int8-w8a8.enable: true):
python demo_infer.py --config config/single_w8a8.yaml七、性能剖析与结果输出
当enable-profiling: true时,推理过程通过 NPU Profiler 采集算子级性能数据(AIC 流水线利用率等指标),结果保存到profile-dir指定目录;多卡场景下每个 rank 的结果独立存放于profile-dir/rank_{i}子目录。剖析器采用 Level1 级别的PipeUtilization指标采集,兼顾信息量采集与开销控制。
推理耗时统计方面:单卡路径逐次打印每次推理耗时并输出平均值;序列并行路径仅 rank 0 打印,且丢弃前 2 次(warmup 后数据)取均值。仓库在 8 卡 Atlas 800I A2 上的参考数据(见 vggt_optimization.md):25 张输入图片时,逐步叠加 Cos/Sin 优化、旋转编码优化、DPT 头优化、Add+LayerNorm 融合、BF16 权重、私有格式提前转换后,单卡推理耗时由 1324.83ms 降至 1121.09ms;序列并行下 Ulysses=2/4/8 分别获得 1.75x/3.43x/6.47x 提升,Ring=2/4/8 分别获得 1.82x/3.48x/6.42x 提升。上述性能数据与测试环境强相关,实际部署时请以自身硬件与输入规模实测为准。
八、使用注意事项汇总
- 多卡配置必须满足
world_size = ulysses-degree × ring-degree; - 单卡场景(world_size=1)下
parallel-computation.enable必须为false; - 首次使用 INT8 量化时,需先设置
int8-w8a8.build: true构建量化模型,之后改为enable: true使用; build与enable不应同时为 true;- 性能剖析结果保存在
profile-dir目录; images-path支持相对路径或绝对路径;- 环境准备方面,本样例依赖 CANN 套件(当前为 CANN.8.5.0)、torch 2.7.1 与 torch_npu 2.7.1.post2,并需要从 VGGT 官方仓库以非覆盖模式复制网络结构代码(
vggt/dependency、vggt/heads、vggt/layers、vggt/utils等目录),完整步骤见 README.md; - 使用一站式平台的用户可直接运行
bash infer_platform_env_prepare.sh一键准备代码与权重,再以python demo_infer.py --config config/single.yaml完成单卡三维重建推理。
九、关联文档与进一步阅读
- vggt_optimization.md:本篇配置中四大优化类别的详细原理、代码替换示例与性能数据出处;
- vggt_accuracy_evaluation.md:VGGT 在相机位姿估计、点云重建、深度估计三个任务上的精度评测方法;
- demo_infer.py:YAML 配置的消费方,完整展示了单卡/序列并行/量化三条推理路径;
- config/:五套预置 YAML 配置,可直接作为自定义配置的模板;
- vggt/layers/rope.py 与 vggt/heads/dpt_head.py:缓存类优化的底层实现。
【免费下载链接】cann-recipes-embodied-ai本项目针对具身智能业务中的典型模型、加速算法,提供基于CANN平台的优化样例项目地址: https://gitcode.com/cann/cann-recipes-embodied-ai
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考