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 服务、实时麦克风三种用法。


目录

  1. 背景与选型
  2. 硬件与软件环境
  3. 部署架构总览
  4. 踩坑一:torchaudio 与 Jetson PyTorch 的 C++ ABI 冲突
  5. 踩坑二:cuDNN 8 vs 9 与 CUBLAS 库路径顺序
  6. 踩坑三:Qwen3 需要 transformers >= 4.51
  7. 一键安装与模型下载
  8. 环境校验与端到端验证
  9. 性能测试
  10. 三种使用方式
  11. 可复现性总结
  12. 进一步优化方向

背景与选型

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
L4T36.4.4
JetPack6.x
CUDA12.6
Python3.10(conda 环境funasr-nano
PyTorchtorch-2.4.0a0+07cecf4168.nv24.05
transformers4.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

这个脚本现在做了这些事:

  1. 检查 aarch64 平台
  2. 自动检测 conda base 和 CUDA 路径
  3. 创建 conda 环境
  4. 下载并安装 Jetson PyTorch 2.4.0
  5. 安装 conda cuDNN 8.9
  6. 安装 requirements.txt 依赖
  7. FunASR/子目录或 GitHub 源码安装 FunASR(editable)
  8. 固定 FunASR 到验证通过的 commit
  9. 降级 numpy 到 1.x
  10. 写入 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-2512

torchaudio shim 单元测试

python tests/test_torchaudio_shim.py

5 个测试全部通过。

端到端验证

bashscripts/verify_deployment.sh

会依次跑:环境校验 → shim 测试 → 离线推理 → HTTP 服务 curl 测试。

🎉 端到端验证全部通过

性能测试

在 Jetson AGX Orin 64GB 上,使用example/zh.mp3(5.6 秒中文音频):

指标数值
模型冷加载约 36 秒
推理耗时约 1.5 秒
RTF0.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.mp3

2. 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 baseconda 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 已经满足实时,但想更低延迟或更高吞吐,可以优先考虑:

  1. LLM 解码加速

    • 用 vLLM 或 llama.cpp 替换 Qwen3-0.6B 的自回归解码
    • 这是当前耗时最大头,收益最高
  2. Audio encoder TensorRT / ONNX 化

    • SenseVoiceEncoderSmall 做 TensorRT 推理
    • 收益次之,但对长音频效果明显
  3. 服务化优化

    • 用 gunicorn / uvicorn 替换 Flask 开发服务器
    • 加推理队列和批处理,提升并发吞吐
  4. 模型量化

    • 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