系统环境:Windows 10/11 x86_64
SDK 版本:QAIRT 2.35 / 2.40 / 2.42
Python:3.10(本地编译)+ 3.11(云编译)
写在前面
在 Windows 上用 QAIRT SDK 做 LLM 模型的本地编译,是一段需要耐心的旅程。
QAIRT SDK 主要面向 Linux 开发,Windows 支持属于"能用但处处是坑"的状态:Python 版本绑定、NumPy ABI 断裂、ONNX 模块缺失、临时目录爆满、控制台乱码……每一个都可能让你卡上半天。
QAIRT 工作流概览:从 Host 到 Target
从在"主机(Host Machine)"上拥有一个训练好的 AI 模型,到在"目标设备(Target Device)"上得到一个可运行的模型,中间需要经历多个阶段。QAIRT 的核心作用正是帮你准备目标设备上所需的正确文件,同时为每种后端和处理器提供运行时解释器(runtime interpreter),将模型指令转换为可在目标硬件上执行的代码。
理解这条链路有助于定位问题:编译阶段的报错大多发生在 Host Machine 侧(即本文重点讨论的环境搭建问题),而运行时异常则往往与 Target Device 上的处理器后端和 firmware 版本相关。
本文汇总了项目实战中遇到的7 个环境兼容性问题和1 个 SDK 版本特定 Bug,按搭建阶段逐一拆解根因和解决方案。如果你正在(或即将)在 Windows 上搭建 QAIRT 编译环境,希望这篇文章能帮你省下反复排查的时间。
快速排查速查表
遇到报错?先对号入座,直接跳到对应章节。
| 报错关键词 | 问题 | 章节 |
|---|---|---|
.pyd模块找不到 / ABI 不兼容 | Python 版本不对 | 第一阶段 · 问题 1 |
numpy相关 ImportError | NumPy 2.x ABI 不兼容 | 第一阶段 · 问题 2 |
cannot import name 'mapping' from 'onnx' | ONNX 1.17 移除模块 | 第二阶段 · 问题 3 |
No module named 'islpy' | SDK 引用未安装依赖 | 第二阶段 · 问题 4 |
No space left on device(但 D 盘有空间) | 临时目录在 C 盘 | 第三阶段 · 问题 5 |
| 控制台输出乱码 / 进度条异常 | GBK 编码问题 | 第三阶段 · 问题 6 |
QnnBackend_validateOpConfig failed 3110/rms_norm | QAIRT 2.35 的 FP16 Bug | 第四阶段 |
环境全景:推荐配置总览
在逐个踩坑之前,先看一眼最终推荐的环境架构。QAIRT 的工作流天然分成两条线,需要两个独立的虚拟环境:
┌─────────────────────────────────────────────────────┐ │ QAIRT 工作流双环境 │ ├──────────────────────┬──────────────────────────────┤ │ 云编译环境 (3.11) │ 本地编译环境 (3.10) │ ├──────────────────────┼──────────────────────────────┤ │ Python 3.11 │ Python 3.10 │ │ qai_hub_models │ qairt (SDK .pyd) │ │ AI Hub API 客户端 │ qairt.convert() │ │ 模型导出 / 上传 │ qairt.compile() │ │ │ onnx 处理 / 编码适配 │ └──────────────────────┴──────────────────────────────┘| 虚拟环境 | Python 版本 | 核心用途 |
|---|---|---|
D:\venv\py3.11 | 3.11 | qai_hub_models导出、AI Hub 云编译 |
D:\venv\py3.10 | 3.10 | qairt.convert()、qairt.compile()本地编译 |
为什么要两个环境?QAIRT SDK 的
.pyd原生扩展是针对 Python 3.10 编译的,而qai_hub_models及 AI Hub 工具链要求 Python 3.11。两者 C 扩展 ABI 不兼容,无法共存于同一个 venv。
一、Python 环境准备
问题 1:QAIRT SDK 的.pyd模块要求 Python 3.10
现象
在 Python 3.11 环境中执行import qairt报错,提示找不到.pyd模块或 ABI 不兼容。
根因
QAIRT SDK(2.35–2.42)附带的.pyd原生扩展模块是针对Python 3.10编译的。Python 的 C 扩展 ABI 在次版本之间不兼容——3.10 编译的.pyd无法在 3.11 解释器中加载,这是 CPython 的设计,不是 QAIRT 的问题。
解决方案
维护两个独立的虚拟环境,各司其职:
# 云编译 venv(Python 3.11)— 用于 qai_hub_models + AI Hub APIC:\Python311\python.exe-m venv"D:\venv\py3.11"# 本地编译 venv(Python 3.10)— 用于 QAIRT SDK 本地工具C:\Python310\python.exe-m venv"D:\venv\py3.10"后续所有本地编译操作都在py3.10环境中执行,云编译相关操作在py3.11中执行。
问题 2:NumPy 2.x ABI 不兼容
现象
在 Python 3.10 环境中导入 QAIRT 模块时报numpy相关错误,通常表现为ImportError或段错误。
根因
QAIRT SDK 的.pyd模块链接到 NumPy 1.x 的 C ABI。NumPy 2.0(2024 年中发布)引入了不向后兼容的 ABI 变更,导致针对 1.x 编译的原生扩展在 2.x 环境下无法正常工作。
如果你用pip install qairt或直接安装 SDK 时没有锁定 NumPy 版本,pip 很可能会拉取最新的 NumPy 2.x,从而触发这个问题。
解决方案
在本地编译 venv 中固定 NumPy 版本:
D:\venv\py3.10\Scripts\activate pip install numpy==1.26.4
1.26.4是 NumPy 1.x 系列的最后一个稳定版本,也是与 QAIRT SDK 兼容性最好的版本。
二、依赖兼容性修复
问题 3:onnx.mapping模块缺失
现象
ImportError: cannot import name 'mapping' from 'onnx'根因
ONNX 1.17 版本移除了onnx.mapping模块(该模块此前已被标记为废弃),但 QAIRT SDK 内部代码仍然from onnx import mapping或from onnx.mapping import TENSOR_TYPE_MAP。这是一个典型的上游依赖版本演进与下游 SDK 未同步更新导致的断裂。
解决方案
在 venv 的 onnx 包目录中创建兼容性 shim 文件,手动补回TENSOR_TYPE_MAP:
# 文件路径:D:\venv\py3.10\Lib\site-packages\onnx\mapping.py# QAIRT SDK 兼容性 shim — onnx 1.17 移除了 onnx.mappingfromonnximportTensorProto TENSOR_TYPE_MAP={int(TensorProto.FLOAT):"float32",int(TensorProto.UINT8):"uint8",int(TensorProto.INT8):"int8",int(TensorProto.UINT16):"uint16",int(TensorProto.INT16):"int16",int(TensorProto.INT32):"int32",int(TensorProto.INT64):"int64",int(TensorProto.BOOL):"bool",int(TensorProto.FLOAT16):"float16",int(TensorProto.DOUBLE):"float64",int(TensorProto.UINT32):"uint32",int(TensorProto.UINT64):"uint64",}这个 shim 只提供 QAIRT SDK 实际用到的TENSOR_TYPE_MAP常量,不涉及其他已移除的 API,因此是安全的。
问题 4:ImportError: islpy
现象
ImportError: No module named 'islpy'根因
QAIRT SDK 的 MHA→SHA(Multi-Head Attention → Single-Head Attention)转换模块在顶层import islpy(Integer Set Library for Python,一个用于多面体编译的库)。但对于预量化模型的编译流程,这个转换功能根本不会被执行到——SDK 只是在模块导入时做了存在性检查。
islpy在 Windows 上没有预编译 wheel,从源码编译需要 LLVM 等重型依赖,成本极高。好消息是:我们不需要真正安装它。
解决方案
创建一个空的 stub 模块,满足导入检查即可:
# 创建 islpy 包目录和空的 __init__.pyNew-Item-Path"D:\venv\py3.10\Lib\site-packages\islpy\__init__.py"-ItemType File-Force文件内容可以为空。QAIRT SDK 只是在模块导入时检查islpy是否存在,实际执行路径中不会调用它的任何功能。
注意:如果你确实需要使用 MHA→SHA 转换(例如对非预量化模型做注意力优化),则不能用 stub,需要在 Linux 环境中完成该步骤。
三、编译运行阶段
问题 5:ONNX 拆分时磁盘空间不足
现象
ONNX 模型拆分过程中报IOError: No space left on device,但检查 D 盘发现空间充足。
根因
Windows 默认将临时文件写入%TEMP%,通常指向C:\Users\<user>\AppData\Local\Temp。如果你的 C 盘是容量有限的 SSD(常见 100–200 GB),7B 模型的 ONNX 拆分过程会产生大量中间文件——每个 split 的 ONNX 加上数据文件可达数 GB,很容易在编译过程中填满临时目录。
这个问题的迷惑性在于:报错信息不会告诉你是哪个盘满了,你第一反应往往是去看数据盘(D 盘),发现空间充足后一头雾水。
解决方案
在运行编译脚本前,将临时目录重定向到大容量磁盘:
# 重定向系统临时目录$env:TEMP ="D:\tmp"$env:TMP ="D:\tmp"mkdir"D:\tmp"-Force如果 QAIRT SDK 版本支持专用临时目录变量,也可以单独设置:
$env:QAIRT_TMP_DIR ="D:\tmp"建议:将上述设置写入编译脚本的开头,避免每次手动执行。同时定期清理
D:\tmp,因为异常中断的编译可能留下大量孤儿临时文件。
问题 6:控制台 GBK 编码导致乱码
现象
运行 AI Hub 客户端或 QAIRT 工具时,状态输出中的 Unicode 字符(如进度条█、勾选标记✓、特殊符号)显示为乱码或问号。
根因
Windows 中文版控制台默认使用 GBK 编码(代码页 936),无法正确显示 QAIRT 工具输出中的 UTF-8 Unicode 字符。虽然不影响功能,但会让日志变得难以阅读,进度条完全不可用。
解决方案
在运行工具前设置 UTF-8 编码:
# 切换控制台代码页为 UTF-8chcp 65001# 确保 Python 标准输出使用 UTF-8$env:PYTHONIOENCODING ="utf-8"如果使用 Windows Terminal,也可以在设置中将默认配置文件的编码改为 UTF-8,一劳永逸。
四、SDK 版本特定 Bug:RmsNorm 编译失败
问题 7:QAIRT 2.35 的--float_bitwidth 16导致 RmsNorm 编译失败
现象
使用 QAIRT 2.35 的qairt-converter转换预量化 ONNX 模型时指定--float_bitwidth 16,后续qnn-context-binary-generator编译报错:
QnnBackend_validateOpConfig failed 3110 Failed to validate op rms_norm_2 with error 0xc26根因
这是 QAIRT 2.35 converter 的一个确认 Bug——--float_bitwidth 16本应只影响未量化的操作(将 FP32 降级为 FP16),但它错误地修改了已量化张量的数据类型。
具体来说,RmsNorm 操作中原本使用UFIXED_POINT_16(int16 定点)编码的张量被错误地改为FLOAT_16,产生了 HTP 后端不支持的 FP16 + INT16 混合精度配置,导致后端校验失败。
修复历史
这个 Bug 在后续版本中经历了多次修复,RmsNorm 相关的问题直到 2.44 才基本收敛:
| QAIRT 版本 | Issue 编号 | 修复内容 |
|---|---|---|
| 2.38 / 2.39 | {145723} | 修复--float_bitwidth错误更新非量化张量的数据类型 |
| 2.40 | {149931} | 为 RMS Norm 新增 2 种模式映射 |
| 2.42 / 2.43 | {154731} | 修复 RMSNorm gamma 有多个消费者时编码丢失 |
| 2.44 | {164079} | 修复 16-bit 浮点精度下的数据类型推断问题 |
解决方案
- 在 QAIRT 2.35 上:使用
--float_bitwidth 32替代。HTP 后端在执行时会内部自动将 FP32 转换为 FP16,因此无性能损失,只是中间 DLC 文件稍大。
qairt-converter\--input_networkmodel.onnx\--output_pathmodel.dlc\--float_bitwidth32\--quantization_overridesmodel.encodings- 在 QAIRT 2.38+:已修复,可以正常使用
--float_bitwidth 16。
汽车平台注意事项:在汽车平台(PPA)上,设备 DSP firmware 可能锁定在特定 QAIRT 版本(如 2.35)。如果无法升级 firmware,
--float_bitwidth 32是唯一可行方案。在项目启动前,务必确认目标设备的 firmware 版本与 SDK 版本的对应关系。
五、其他实用配置
HuggingFace 离线模式
国内环境访问 HuggingFace Hub 经常不稳定,下载模型时容易超时。启用离线模式可以避免运行时反复尝试网络连接:
$env:HF_HUB_OFFLINE ="1"前提是相关模型文件已经缓存在本地(~/.cache/huggingface)。
增加虚拟内存
7B 模型的 ONNX 处理(拆分、编码适配)峰值内存约 40 GB。如果物理内存不足,Windows 会频繁换页导致编译极慢,甚至 OOM。建议将虚拟内存设置为 40 GB 或更高:
Windows 设置 → 系统 → 关于 → 高级系统设置 → 性能 → 设置 → 高级 → 虚拟内存 → 更改
断点续传下载
预量化模型约 15 GB,国内下载中断是常态。使用 curl 的-C -参数可以自动从上次中断的位置继续:
curl.exe-C--L-o model.zip"https://qaihub-public-assets.s3.us-west-2.amazonaws.com/..."六、一键环境初始化脚本
将上述核心步骤整合为一个 PowerShell 脚本,新建环境时一键执行:
# setup_qairt_venv.ps1# 用法:.\setup_qairt_venv.ps1 -VenvPath "D:\venv\py3.10"param([string]$VenvPath="D:\venv\py3.10",[string]$PythonPath="C:\Python310\python.exe")# 1. 创建虚拟环境&$PythonPath-m venv$VenvPath$pip=Join-Path$VenvPath"Scripts\pip.exe"# 2. 安装固定版本依赖&$pipinstall numpy==1.26.4 &$pipinstall onnx==1.17.0 onnxscript==0.6.2 onnx-graphsurgeon==0.5.8 &$pipinstall transformers==4.46.3 pyyaml packaging aenum paramiko jsonschema pydantic# 3. 创建 onnx.mapping 兼容性 shim$sitePackages=Join-Path$VenvPath"Lib\site-packages"$mappingPy=Join-Path$sitePackages"onnx\mapping.py"@" from onnx import TensorProto TENSOR_TYPE_MAP = { int(TensorProto.FLOAT): "float32", int(TensorProto.UINT8): "uint8", int(TensorProto.INT8): "int8", int(TensorProto.UINT16): "uint16", int(TensorProto.INT16): "int16", int(TensorProto.INT32): "int32", int(TensorProto.INT64): "int64", int(TensorProto.BOOL): "bool", int(TensorProto.FLOAT16): "float16", int(TensorProto.DOUBLE): "float64", int(TensorProto.UINT32): "uint32", int(TensorProto.UINT64): "uint64", } "@|Out-File-FilePath$mappingPy-Encoding utf8# 4. 创建 islpy 空 stub$islpyInit=Join-Path$sitePackages"islpy\__init__.py"New-Item-Path$islpyInit-ItemType File-Force|Out-NullWrite-Host"QAIRT venv 初始化完成:$VenvPath"-ForegroundColor Green七、推荐的 Python 3.10 venv 依赖清单
numpy==1.26.4 onnx==1.17.0 onnxscript==0.6.2 onnx-graphsurgeon==0.5.8 transformers==4.46.3 pyyaml packaging aenum paramiko jsonschema pydantic加上手动创建的onnx/mapping.pyshim 和islpy/__init__.pystub。
八、总结与建议
| # | 问题 | 根因 | 解决方案 | 阶段 |
|---|---|---|---|---|
| 1 | .pyd模块加载失败 | SDK 绑定 Python 3.10 | 独立 3.10 venv | 环境准备 |
| 2 | NumPy 错误 | NumPy 2.x ABI 不兼容 | 固定numpy==1.26.4 | 环境准备 |
| 3 | onnx.mapping缺失 | ONNX 1.17 移除该模块 | 创建兼容性 shim | 依赖兼容 |
| 4 | islpy缺失 | SDK 引用未安装的依赖 | 创建空 stub 模块 | 依赖兼容 |
| 5 | 磁盘空间不足 | %TEMP%在小容量 C 盘 | 重定向到 D 盘 | 编译运行 |
| 6 | 控制台乱码 | GBK 编码 vs Unicode 输出 | chcp 65001+PYTHONIOENCODING=utf-8 | 编译运行 |
| 7 | RmsNorm 编译失败 (3110) | QAIRT 2.35 的--float_bitwidth 16bug | 改用--float_bitwidth 32或升级 SDK | 版本 Bug |
问题 1–6 是环境搭建阶段的兼容性问题,问题 7 是 SDK 版本特定的 bug。它们都不涉及 QAIRT SDK 的核心推理功能,但会在模型准备阶段消耗大量时间。
最后几条建议:
- 版本锁定是第一原则——Python、NumPy、ONNX、QAIRT SDK 全部锁定具体版本,不要用
latest。环境能跑通后,用pip freeze > requirements.txt留档。 - 优先在 Linux 上做本地编译——如果项目允许,WSL2 或原生 Linux 能避开本文 90% 的 Windows 特定问题。只有当工具链必须在 Windows 上运行时,才走本文的路线。
- 汽车项目提前确认 firmware 版本——PPA 设备的 DSP firmware 升级成本高,SDK 版本选择往往被 firmware 锁定,项目启动前就要对齐。
- 临时目录和虚拟内存提前配置——不要等编译跑到一半报磁盘满或 OOM 才处理,7B 模型编译一次动辄数十分钟,重来的成本很高。
希望这篇踩坑实录能让你的 QAIRT 环境搭建之路顺畅一些。如果遇到文中未覆盖的问题,欢迎在评论区补充。