Jetson AGX Orin 上部署 Fun-ASR
在 Jetson AGX Orin 上部署 Fun-ASR-Nano-2512:踩坑、shim 与实时推理
目标:在 NVIDIA Jetson AGX Orin(JetPack 6.x / CUDA 12.x)上,用 Python 3.10 conda 环境把
Fun-ASR-Nano-2512部署到 GPU,并达到实时语音识别。最终成果:RTF ≈ 0.27,5.6 秒音频 1.5 秒出结果,支持离线文件、HTTP 服务、实时麦克风三种用法。
目录
- 背景与选型
- 硬件与软件环境
- 部署架构总览
- 踩坑一:torchaudio 与 Jetson PyTorch 的 C++ ABI 冲突
- 踩坑二:cuDNN 8 vs 9 与 CUBLAS 库路径顺序
- 踩坑三:Qwen3 需要 transformers >= 4.51
- 一键安装与模型下载
- 环境校验与端到端验证
- 性能测试
- 三种使用方式
- 可复现性总结
- 进一步优化方向
背景与选型
Fun-ASR-Nano-2512 是阿里巴巴通义实验室开源的端到端语音识别大模型,支持中/英/日及多方言、多口音,参数量 800M。它基于 FunASR 框架,音频编码器是 SenseVoiceEncoderSmall,LLM 是 Qwen3-0.6B。
在 Jetson 这类边缘设备上部署 LLM-ASR 模型,最大的挑战不是模型本身,而是PyTorch 生态在 ARM + JetPack 上的兼容性。官方 PyPI 的 aarch64 wheel 大多是 CPU 版,或者与 NVIDIA Jetson 专用 PyTorch 的 C++ ABI 不兼容。
因此本次部署没有走"pip install torch + pip install torchaudio"的常规路线,而是:
- 使用 NVIDIA 为 JetPack 6 编译的 PyTorch wheel
- 在项目内实现一个纯 Python 的
torchaudioshim - 用 conda 安装 cuDNN 8.9 解决 Jetson PyTorch 对
libcudnn.so.8的依赖 - 从源码安装 FunASR 并固定 commit
硬件与软件环境
| 项目 | 配置 |
|---|---|
| 设备 | NVIDIA Jetson AGX Orin 64GB |
| L4T | 36.4.4 |
| JetPack | 6.x |
| CUDA | 12.6 |
| Python | 3.10(conda 环境funasr-nano) |
| PyTorch | torch-2.4.0a0+07cecf4168.nv24.05 |
| transformers | 4.57.6 |
| funasr | 源码 editable 安装,固定 commitf9937385 |
部署架构总览
┌─────────────────────────────────────────────┐ │ 应用层:infer_file.py / asr_server.py │ │ / realtime_mic.py │ ├─────────────────────────────────────────────┤ │ 框架层:FunASR(源码 editable 安装) │ ├─────────────────────────────────────────────┤ │ 兼容层:torchaudio/ 纯 Python shim │ ├─────────────────────────────────────────────┤ │ 运行时:PyTorch Jetson wheel + conda cuDNN 8 │ ├─────────────────────────────────────────────┤ │ 系统层:JetPack 6.x / CUDA 12.6 / cuDNN 9.x │ └─────────────────────────────────────────────┘踩坑一:torchaudio 与 Jetson PyTorch 的 C++ ABI 冲突
现象
安装 PyPI 的torchaudio==2.4.0后,import 报错:
OSError:.../libtorchaudio.so:undefined symbol:_ZNK3c105Error4whatEv本质是 PyPI wheel 针对官方 PyTorch 编译,而 NVIDIA Jetson PyTorch 的 C++ ABI(尤其是c10::Error)与官方版不同。
解决思路
既然 funasr 对 torchaudio 的使用非常有限,何苦非要装那个带 C++ 扩展的 wheel?
我检查了 funasr 实际用到的接口:
torchaudio.load:音频文件读取torchaudio.transforms.Resample:重采样torchaudio.compliance.kaldi.fbank:Kaldi 风格滤波器组torchaudio.functional.create_dct/istft:少量符号
这些都是纯 Python 可实现的。
实现 torchaudio shim
在项目根目录下新建torchaudio/包:
torchaudio/ ├── __init__.py # load() 用 soundfile 实现,预加载子模块 ├── compliance/ │ ├── __init__.py │ └── kaldi.py # 从 torchaudio 源码拷贝的纯 Python fbank ├── functional/ │ └── __init__.py # resample / create_dct / istft ├── transforms/ │ └── __init__.py # Resample 纯 PyTorch 实现 └── sox_effects/ └── __init__.py # 占位关键代码片段:
# torchaudio/__init__.pydefload(filepath,*args,**kwargs):importsoundfileassf data,sr=sf.read(filepath,dtype="float32",always_2d=True)data=data.T# [channels, samples]returntorch.from_numpy(data),sr# torchaudio/functional/__init__.py# _get_sinc_resample_kernel / _apply_sinc_resample_kernel# 直接从 torchaudio 源码搬运,去掉对 libtorchaudio.so 的依赖然后让PYTHONPATH把项目根目录放在最前面,funasr 内部import torchaudio就会自动走到这个 shim。
效果
python-c"import torchaudio; print(torchaudio.__version__)"# 2.4.0-jetson-shimpython-c"import torchaudio; print(torchaudio.__file__)"# /home/dog-8/workspace/Audio/asr/torchaudio/__init__.py不再报 ABI 错误,fbank、resample、音频读取全部正常工作。
踩坑二:cuDNN 8 vs 9 与 CUBLAS 库路径顺序
现象 1:libcudnn.so.8 找不到
Jetson PyTorch wheel 启动时报:
ImportError:libcudnn.so.8:cannotopensharedobjectfile:No suchfileordirectory原因
JetPack 6.x 系统级 cuDNN 是 9.x,但 NVIDIA 这个 PyTorch wheel 编译时链的是 cuDNN 8.x。
解决
在 conda 环境里单独装一套 cuDNN 8.9:
condainstall-ycudnn=8.9.2.26然后把$CONDA_PREFIX/lib加到LD_LIBRARY_PATH。
现象 2:CUBLAS_STATUS_ALLOC_FAILED
解决 cuDNN 后,torch 能 import 了,但一跑 CUDA matmul 就报错:
RuntimeError:CUDA error:CUBLAS_STATUS_ALLOC_FAILED when calling `cublasCreate(handle)`原因
conda 的 cuDNN 包里也带了libcublas.so.12,但版本比系统 CUDA 12.6 的旧。如果 conda lib 排在系统 CUDA 前面,cublas 初始化就会失败。
解决
LD_LIBRARY_PATH必须让系统 CUDA 优先:
exportLD_LIBRARY_PATH="/usr/local/cuda-12.6/lib64:${CONDA_PREFIX}/lib:${LD_LIBRARY_PATH}"而不是反过来。
我把这个设置写进了 conda activate 钩子,每次激活环境自动生效:
# $CONDA_PREFIX/etc/conda/activate.d/funasr-nano-env.shexport_OLD_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"exportLD_LIBRARY_PATH="/usr/local/cuda-12.6/lib64:${CONDA_PREFIX}/lib:${LD_LIBRARY_PATH}"export_OLD_PYTHONPATH="${PYTHONPATH}"exportPYTHONPATH="/home/dog-8/workspace/Audio/asr:${PYTHONPATH}"踩坑三:Qwen3 需要 transformers >= 4.51
现象
加载模型时:
ValueError:The checkpoint you are trying to load has modeltype`qwen3` but Transformers doesnotrecognize this architecture.解决
把 transformers 从4.45.0升级到>=4.51,<5:
pipinstall"transformers>=4.51,<5"同时 requirements.txt 中也相应锁定。
一键安装与模型下载
环境安装
bashscripts/install_jetson_deps.sh funasr-nano3.10这个脚本现在做了这些事:
- 检查 aarch64 平台
- 自动检测 conda base 和 CUDA 路径
- 创建 conda 环境
- 下载并安装 Jetson PyTorch 2.4.0
- 安装 conda cuDNN 8.9
- 安装 requirements.txt 依赖
- 从
FunASR/子目录或 GitHub 源码安装 FunASR(editable) - 固定 FunASR 到验证通过的 commit
- 降级 numpy 到 1.x
- 写入 conda 激活/退出钩子
模型下载
bashscripts/download_model.sh优先从 ModelScope 下载FunAudioLLM/Fun-ASR-Nano-2512,失败则 fallback 到 HuggingFace。
环境校验与端到端验证
环境校验
conda activate funasr-nano python scripts/check_env.py输出示例:
[1/7] 平台架构检查 ✅ 平台: aarch64 [2/7] conda 环境检查 ✅ conda 环境: funasr-nano [3/7] PyTorch GPU 检查 ✅ torch version: 2.4.0a0+07cecf4168.nv24.05 ✅ CUDA available: True ✅ CUDA version: 12.2 ✅ GPU: Orin ✅ CUDA matmul 测试通过 [5/7] torchaudio shim 检查 ✅ torchaudio 路径: /home/dog-8/workspace/Audio/asr/torchaudio ✅ torchaudio 版本: 2.4.0-jetson-shim ✅ fbank 输出 shape: torch.Size([98, 80]) [6/7] FunASR 源码安装检查 ✅ funasr path: /home/dog-8/workspace/Audio/asr/FunASR/funasr/__init__.py ✅ funasr 确实从项目内源码加载 [7/7] 模型目录检查 ✅ 模型目录完整: /home/dog-8/models/Fun-ASR-Nano-2512torchaudio shim 单元测试
python tests/test_torchaudio_shim.py5 个测试全部通过。
端到端验证
bashscripts/verify_deployment.sh会依次跑:环境校验 → shim 测试 → 离线推理 → HTTP 服务 curl 测试。
🎉 端到端验证全部通过性能测试
在 Jetson AGX Orin 64GB 上,使用example/zh.mp3(5.6 秒中文音频):
| 指标 | 数值 |
|---|---|
| 模型冷加载 | 约 36 秒 |
| 推理耗时 | 约 1.5 秒 |
| RTF | 0.27~0.30 |
| 识别结果 | 开饭时间早上九点至下午五点 |
RTF < 1.0 即视为实时,0.27 意味着处理速度是音频播放速度的约 3.7 倍,边缘场景完全够用。
三种使用方式
1. 离线文件识别
bashscripts/test_offline.sh\/home/dog-8/models/Fun-ASR-Nano-2512\/home/dog-8/models/Fun-ASR-Nano-2512/example/zh.mp32. HTTP 服务(OpenAI 风格)
bashscripts/start_server.sh /home/dog-8/models/Fun-ASR-Nano-25120.0.0.08000测试:
curl-XPOST http://localhost:8000/v1/audio/transcriptions\-Ffile=@/home/dog-8/models/Fun-ASR-Nano-2512/example/zh.mp3\-Flanguage=中文返回:
{"text":"开饭时间:早上九点至下午五点。"}3. 实时麦克风识别
python src/realtime_mic.py\--model/home/dog-8/models/Fun-ASR-Nano-2512\--language中文--chunk_duration5可复现性总结
为了让另一台相同 JetPack 版本的 Jetson AGX Orin 也能一键复现,我做了这些改造:
| 改造点 | 说明 |
|---|---|
| 自动检测 conda base | conda info --base,不再写死${HOME}/miniconda3 |
| 自动检测 CUDA 路径 | 优先/usr/local/cuda,fallback/usr/local/cuda-* |
| FunASR 源码自动获取 | 子目录存在则直接用,否则自动 clone |
| FunASR commit 固定 | f9937385,避免未来源码更新破坏兼容性 |
| 模型自动下载 | scripts/download_model.sh,ModelScope + HuggingFace 双源 |
| 环境自动配置 | conda activate 钩子自动设置 LD_LIBRARY_PATH 和 PYTHONPATH |
| 完整校验链 | check_env.py+test_torchaudio_shim.py+verify_deployment.sh |
现在给新机器复现只需:
gitclone<仓库>~/workspace/Audio/asrcd~/workspace/Audio/asrbashscripts/install_jetson_deps.sh funasr-nano3.10bashscripts/download_model.sh conda activate funasr-nanobashscripts/verify_deployment.sh进一步优化方向
当前 RTF 0.27 已经满足实时,但想更低延迟或更高吞吐,可以优先考虑:
LLM 解码加速
- 用 vLLM 或 llama.cpp 替换 Qwen3-0.6B 的自回归解码
- 这是当前耗时最大头,收益最高
Audio encoder TensorRT / ONNX 化
- SenseVoiceEncoderSmall 做 TensorRT 推理
- 收益次之,但对长音频效果明显
服务化优化
- 用 gunicorn / uvicorn 替换 Flask 开发服务器
- 加推理队列和批处理,提升并发吞吐
模型量化
- LLM 用 INT8/INT4,audio encoder 用 FP16
- 在 Orin 上可降低显存占用并提速
结语
在 Jetson 上部署现代 LLM-ASR 模型,最大的工作量往往不是模型推理本身,而是让 PyTorch 生态在 ARM + JetPack 上跑起来。通过源码安装 FunASR、用纯 Python shim 替代 torchaudio、正确配置 cuDNN/cublas 库路径,最终实现了稳定可复现的 GPU 实时语音识别。
如果你也在做类似的事情,希望这篇笔记能帮你少踩几个坑。
项目结构参考:
. ├── FunASR/ # FunASR 源码 ├── requirements.txt ├── scripts/ │ ├── install_jetson_deps.sh │ ├── download_model.sh │ ├── env.sh │ ├── check_env.py │ ├── verify_deployment.sh │ ├── start_server.sh │ └── test_offline.sh ├── src/ │ ├── infer_file.py │ ├── asr_server.py │ └── realtime_mic.py ├── tests/ │ └── test_torchaudio_shim.py └── torchaudio/ # Jetson 兼容 shim