Jetson AGX Orin 上部署 Fun-ASR

3 阅读5分钟

在 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 的 torchaudio shim
  • 用 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 安装,固定 commit f9937385

部署架构总览

┌─────────────────────────────────────────────┐
│  应用层: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__.py
def load(filepath, *args, **kwargs):
    import soundfile as sf
    data, sr = sf.read(filepath, dtype="float32", always_2d=True)
    data = data.T  # [channels, samples]
    return torch.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-shim

python -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: cannot open shared object file: No such file or directory

原因

JetPack 6.x 系统级 cuDNN 是 9.x,但 NVIDIA 这个 PyTorch wheel 编译时链的是 cuDNN 8.x。

解决

在 conda 环境里单独装一套 cuDNN 8.9:

conda install -y cudnn=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 优先:

export LD_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.sh
export _OLD_LD_LIBRARY_PATH="${LD_LIBRARY_PATH}"
export LD_LIBRARY_PATH="/usr/local/cuda-12.6/lib64:${CONDA_PREFIX}/lib:${LD_LIBRARY_PATH}"
export _OLD_PYTHONPATH="${PYTHONPATH}"
export PYTHONPATH="/home/dog-8/workspace/Audio/asr:${PYTHONPATH}"

踩坑三:Qwen3 需要 transformers >= 4.51

现象

加载模型时:

ValueError: The checkpoint you are trying to load has model type `qwen3`
but Transformers does not recognize this architecture.

解决

把 transformers 从 4.45.0 升级到 >=4.51,<5

pip install "transformers>=4.51,<5"

同时 requirements.txt 中也相应锁定。


一键安装与模型下载

环境安装

bash scripts/install_jetson_deps.sh funasr-nano 3.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 激活/退出钩子

模型下载

bash scripts/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 个测试全部通过。

端到端验证

bash scripts/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. 离线文件识别

bash scripts/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 风格)

bash scripts/start_server.sh /home/dog-8/models/Fun-ASR-Nano-2512 0.0.0.0 8000

测试:

curl -X POST http://localhost:8000/v1/audio/transcriptions \
     -F file=@/home/dog-8/models/Fun-ASR-Nano-2512/example/zh.mp3 \
     -F language=中文

返回:

{"text":"开饭时间:早上九点至下午五点。"}

3. 实时麦克风识别

python src/realtime_mic.py \
    --model /home/dog-8/models/Fun-ASR-Nano-2512 \
    --language 中文 --chunk_duration 5

可复现性总结

为了让另一台相同 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

现在给新机器复现只需:

git clone <仓库> ~/workspace/Audio/asr
cd ~/workspace/Audio/asr
bash scripts/install_jetson_deps.sh funasr-nano 3.10
bash scripts/download_model.sh
conda activate funasr-nano
bash scripts/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