Loading...

文章背景图

SenseVoice:多语言语音理解大模型(ASR+情感+音频事件)部署指南

2026-09-30
2
- 字
- 分钟
|

SenseVoice:多语言语音理解大模型(ASR+情感+音频事件)部署指南

SenseVoice 是阿里巴巴达摩院 FunAudioLLM 团队开源的音频基础模型,论文见 arXiv:2407.04051。它把四类语音理解能力整合进同一个 checkpoint:语音识别(ASR)、语种识别(LID)、语音情感识别(SER)与声学事件分类/检测(AEC/AED)。更广泛的研究版本采用超过 40 万小时数据训练并覆盖 50 多种语言;当前公开发布的 SenseVoiceSmall 权重支持中文、粤语、英文、日文和韩文五种语言的 ASR 与语种识别,并在转写文本中同时输出情感标签与音频事件标签,做到"一句话结果同时给出说了什么、是什么情绪、现场有什么声音事件"。

这种"识别加理解"一体化设计的价值在于:传统流水线往往要先跑 ASR、再分别跑情感分类与事件检测,模型之间格式不一致、延迟叠加;SenseVoice 把三类标签训练进同一 checkpoint,一次前向就能同时输出文本、情感与事件,既省链路又减少模块间误差累积。研究版本采用超过 40 万小时数据并覆盖 50 多种语言,但公开的 SenseVoiceSmall 权重只承诺中、粤、英、日、韩五语种,README 中的 benchmark 对比也只对应所列任务与语种,选型时不要把研究版的语言覆盖范围当作已发布权重的能力。

一、项目官方信息

项目 信息
GitHub 仓库 QwenAudio/SenseVoice
官方主页 funasr.com
模型仓库 ModelScope 模型卡 与 Hugging Face 模型卡
在线体验 ModelScope Studio 与 Hugging Face Space
开源协议 仓库源码 MIT;模型权重单独授权(FunASR 模型开源协议)
支持语言 中文、粤语、英文、日文、韩文
配套工具链 funasr ≥ 1.3.26(当前部署路径建议 funasr==1.4.14)

二、官方图片

SenseVoice 架构与能力示意(本站封面):

SenseVoice

三、核心功能与能力边界

  • 富文本识别:在输出转写文本的同时附带情感标签与音频事件标签。情感识别在测试数据上达到甚至超过目前最佳情感识别模型;事件检测支持音乐、掌声、笑声、哭声、咳嗽、喷嚏等常见人机交互事件。
  • 高效推理:SenseVoiceSmall 采用非自回归端到端框架,延迟很低。在官方 benchmark 中,参数量与 Whisper-Small 相当的情况下,推理速度比 Whisper-Small 快 5 倍以上,比 Whisper-Large 快 15 倍。
  • 中文与粤语优势:在 AISHELL-1、AISHELL-2、Wenetspeech、LibriSpeech、Common Voice 等开源基准上与 Whisper 对比,中文和粤语识别效果有明显优势。
  • 事件检测的边界:尽管只在语音数据上训练,模型仍可单独用作事件检测,在 ESC-50 环境音分类上与 BEATS、PANN 对比取得不错结果;但受训练数据与方式限制,其事件分类效果与专业事件检测模型相比仍有差距。
  • 微调定制:提供便捷的微调脚本与策略,方便修复业务长尾样本。
  • 服务部署:完整服务链路支持多并发请求,客户端语言覆盖 Python、C++、HTML、Java 与 C#。
  • 能力边界:说话人分离是 FunASR 组合独立 FSMN-VAD 与 CAM++ 的 pipeline 能力,并非 SenseVoiceSmall checkpoint 本身的输出;需要联合转写、时间戳与匿名说话人标注时,应使用 FunASR 生态接入的 OpenMOSS/MOSS-Transcribe-Diarize,离线输出三者合一,不必业务侧自己拼装多模型。

四、环境要求与安装

pip install -r requirements.txt

SenseVoiceSmall 示例与 FunASR 组合说话人分离路径需要 funasr>=1.3.26;如果之前装过旧版,请先执行 pip install -U "funasr>=1.3.26" 再运行 demo。当前部署路径建议安装 funasr==1.4.14,即可使用 Python 推理、OpenAI 兼容服务与容器工作流。GPU 推理按 PyTorch/CUDA 常规要求准备;无 GPU 场景可走 llama.cpp/GGUF 单二进制路线。

五、部署步骤

1. Python 推理(funasr AutoModel)

长录音必须先分段再送入编码器,下面用 FSMN-VAD 分段:

from funasr import AutoModel
from funasr.utils.postprocess_utils import rich_transcription_postprocess

model_dir = "iic/SenseVoiceSmall"

model = AutoModel(
    model=model_dir,
    trust_remote_code=True,
    remote_code="./model.py",
    vad_model="fsmn-vad",
    vad_kwargs={"max_single_segment_time": 30000},
    device="cuda:0",
)

# en
res = model.generate(
    input=f"{model.model_path}/example/en.mp3",
    cache={},
    language="auto",  # "zh", "en", "yue", "ja", "ko", "nospeech"
    use_itn=True,
    batch_size_s=60,
    merge_vad=True,
    merge_length_s=15,
)
text = rich_transcription_postprocess(res[0]["text"])
print(text)

关键参数说明:model_dir 是模型名或本地路径;trust_remote_code=True 时从 remote_code 指定的 model.py 加载模型实现(支持绝对/相对路径与网络 URL),设为 False 则用 funasr 内部集成版本,改当前目录的 model.py 不生效;vad_model 开启 VAD 把长音频切短,此时耗时是 VAD 加识别的链路耗时;vad_kwargs.max_single_segment_time 为 VAD 最大切分时长(毫秒);use_itn 控制输出是否带标点与逆文本正则化;batch_size_s 是动态 batch 的总音频时长(秒);merge_vad 配合 merge_length_s 把 VAD 碎片合并;ban_emo_unk 禁用 emo_unk 标签后所有句子都会被赋予情感标签。

注意:使用 remote_code="./model.py" 时,升级 funasr 包不会同步更新本地 model.py,需同时更新仓库源码;当前时间戳格式为 timestamp=[[开始毫秒, 结束毫秒], ...],与 words 一一对应,旧版三元组不兼容 VAD 聚合。

2. 不使用 VAD 的长音频推理

把一小时波形一次性传给 model.generate 会使编码器内存远大于音频文件本身。业务不能接受 VAD 时,用有界内存参考脚本:ffmpeg 解码,默认 30 秒窗口、2 秒重叠调用 SenseVoice,且不配置 VAD:

python long_audio_no_vad.py meeting.mp3 \
  --output meeting.txt \
  --window-seconds 30 \
  --overlap-seconds 2

合并文本只删除相邻窗口边界完全相同的重复文字;meeting.chunks.jsonl 保留每个窗口的原始输出与窗口偏移,不匹配内容不会被静默丢弃,传 --no-dedupe 可连完全匹配去重也关闭。窗口偏移是输入窗口边界而非逐词时间戳;固定切点可能影响边界附近识别,业务允许按内容分段时仍推荐 VAD pipeline。

3. 短音频批量推理

输入均为 30 秒以下短音频时,可去掉 VAD 并设 batch_size 提升效率:

model = AutoModel(model=model_dir, trust_remote_code=True, device="cuda:0")

res = model.generate(
    input=f"{model.model_path}/example/en.mp3",
    cache={},
    language="auto",
    use_itn=True,
    batch_size=64,
)

4. 直接推理(绕过 funasr pipeline)

from model import SenseVoiceSmall
from funasr.utils.postprocess_utils import rich_transcription_postprocess

model_dir = "iic/SenseVoiceSmall"
m, kwargs = SenseVoiceSmall.from_pretrained(model=model_dir, device="cuda:0")
m.eval()

res = m.inference(
    data_in=f"{kwargs['model_path']}/example/en.mp3",
    language="auto",
    use_itn=False,
    ban_emo_unk=False,
    **kwargs,
)
text = rich_transcription_postprocess(res[0][0]["text"])
print(text)

5. ONNX 与 Libtorch 导出

ONNX 路线(先 pip3 install -U funasr funasr-onnx):

from pathlib import Path
from funasr_onnx import SenseVoiceSmall
from funasr_onnx.utils.postprocess_utils import rich_transcription_postprocess

model_dir = "iic/SenseVoiceSmall"
model = SenseVoiceSmall(model_dir, batch_size=10, quantize=True)
wav_or_scp = ["{}/.cache/modelscope/hub/{}/example/en.mp3".format(Path.home(), model_dir)]
res = model(wav_or_scp, language="auto", use_itn=True)
print([rich_transcription_postprocess(i) for i in res])

Libtorch 路线把 funasr_onnx 换成 funasr_torch,构造时传 device="cuda:0";两种导出的模型都落在原模型目录中。

6. CPU/边缘:llama.cpp / GGUF 单二进制

类似 Whisper 的 whisper.cpp,但在中文与粤语场景下更适合 SenseVoice;运行时内置 FSMN-VAD,无需 Python:

bash runtime/llama.cpp/download-funasr-model.sh sensevoice ./gguf
llama-funasr-sensevoice -m ./gguf/sensevoice-small-f16.gguf --vad ./gguf/fsmn-vad.gguf -a audio.wav

预编译二进制见 Releases,GGUF 权重见 Hugging Face。

7. FastAPI 与 Docker 部署

FastAPI 直接起服务:

export SENSEVOICE_DEVICE=cuda:0
fastapi run --port 50000

Docker 本地构建与运行:

docker build -t sensevoice .
# GPU(默认)
docker run --rm --gpus all -p 50000:50000 -v sensevoice-models:/models sensevoice
# 仅 CPU
docker run --rm -e SENSEVOICE_DEVICE=cpu -p 50000:50000 -v sensevoice-models:/models sensevoice

容器健康后访问 http://127.0.0.1:50000/docs 查看自动生成的接口文档。FastAPI 路线通过环境变量 SENSEVOICE_DEVICE 选择 cuda:0 或 cpu,端口默认 50000;Docker 运行时把模型目录挂载到容器内 /models,首次启动会下载权重到该卷,之后重启直接复用。注意:构建工作流也发布 ghcr.io/qwenaudio/sensevoice,但该容器包当前为 private,匿名拉取返回 HTTP 401;在容器包页面转 Public 之前请用上面的本地构建。

六、微调

1. 训练环境

git clone https://github.com/modelscope/FunASR.git && cd FunASR
pip3 install -e ./

2. 数据准备

训练数据为 JSONL,每行一个样本,字段包括:key(唯一 ID)、source(音频路径)、source_len(fbank 帧数)、target(标注文本)、target_len(文本长度)、text_language(语种标签)、emo_target(情感标签)、event_target(事件标签)、with_or_wo_itn(是否含标点与逆文本正则化)。

可用 sensevoice2jsonl 从 train_wav.scp、train_text.txt、train_text_language.txt、train_emo_target.txt、train_event_target.txt 五个文件生成:

sensevoice2jsonl \
++scp_file_list='["../../../data/list/train_wav.scp", "../../../data/list/train_text.txt", "../../../data/list/train_text_language.txt", "../../../data/list/train_emo.txt", "../../../data/list/train_event.txt"]' \
++data_type_list='["source", "target", "text_language", "emo_target", "event_target"]' \
++jsonl_file_out="../../../data/list/train.jsonl"

各 scp 文件左边都是数据唯一 ID,需一一对应;语种标签支持 <|zh|>、<|en|>、<|yue|>、<|ja|>、<|ko|>;情感标签支持 <|HAPPY|>、<|SAD|>、<|ANGRY|>、<|NEUTRAL|>、<|FEARFUL|>、<|DISGUSTED|>、<|SURPRISED|>;事件标签支持 <|BGM|>、<|Speech|>、<|Applause|>、<|Laughter|>、<|Cry|>、<|Sneeze|>、<|Breath|>、<|Cough|>。若缺少语种/情感/事件标注文件,可加 ++model_dir='iic/SenseVoiceSmall' 让脚本自动用 SenseVoice 打标。

3. 启动训练

先把 finetune.sh 里的 train_tool 改成你安装的 funasr 路径下 funasr/bin/train_ds.py 绝对路径,然后:

bash finetune.sh

WebUI 体验直接运行 python webui.py。

七、性能评测要点

  • 多语言 ASR:在 AISHELL-1、AISHELL-2、Wenetspeech、LibriSpeech、Common Voice 上与 Whisper 对比,中文与粤语优势明显。
  • 情感识别:由于目前缺乏被广泛认可的情感识别测试指标与方法,团队在多个测试集的多种指标上评测,并与近年 Benchmark 结果全面对比;所选测试集同时包含中、英文以及表演、影视剧、自然对话等多种风格数据,在不做目标数据微调的前提下达到甚至超过最佳模型。复现零训练 CASIA 或 RAVDESS 结果时应使用仓库内 SER 评测契约脚本,直接读取 SenseVoice 原始情感标签并同时输出 UA 和 WA,不要从富文本转写结果里用字符串切分推断情感标签。SenseVoice-Large 模型几乎在所有数据上达到最佳,Small 也在多数数据集上超越其他开源模型。
  • 事件检测:尽管只在语音数据上训练,模型仍可单独用作事件检测;在环境音分类 ESC-50 上与业内广泛使用的 BEATS、PANN 对比取得不错结果,但受训练数据与方式限制,与专业事件检测模型相比仍有一定差距。
  • 推理效率:非自回归端到端架构下,参数量与 Whisper-Small 相当,推理速度比 Whisper-Small 快 5 倍以上、比 Whisper-Large 快 15 倍。

八、最新动态与输出标签

  • 当前部署路径:安装 funasr==1.4.14 即可使用 SenseVoice 的 Python、OpenAI 兼容服务与容器工作流。
  • 长音频无需 VAD:long_audio_no_vad.py 使用有界重叠窗口并保留原始 chunk 输出,小时级录音不必一次送入模型占用无界显存。
  • 一体化说话人标注:FunASR 生态已接入 OpenMOSS/MOSS-Transcribe-Diarize,离线输出转写、时间戳和匿名说话人标签,业务侧无需手工拼 VAD 与说话人模型。
  • 输出标签格式:富文本转写结果中,语种以 <|zh|>、<|en|>、<|yue|>、<|ja|>、<|ko|>、<|nospeech|> 标注;情感以 <|HAPPY|>、<|SAD|>、<|ANGRY|>、<|NEUTRAL|>、<|FEARFUL|>、<|DISGUSTED|>、<|SURPRISED|> 标注;事件以 <|BGM|>、<|Speech|>、<|Applause|>、<|Laughter|>、<|Cry|>、<|Sneeze|>、<|Breath|>、<|Cough|> 标注。rich_transcription_postprocess 负责把这些标签整理成可读文本,业务代码应从 words 字段读取文字,而不是自己解析原始字符串。

九、优秀三方工作

  • Triton(GPU):Triton 加 TensorRT,fp32 在 V100 上加速比达 526,fp16 支持中。
  • sherpa-onnx:支持 C++、C、Python、C#、Go、Swift、Kotlin、Java、JavaScript、Dart 十种语言,并可在 iOS、Android、树莓派上运行。
  • Orca:通过 sherpa-onnx 集成 SenseVoice 做 macOS/Linux/Windows 本地离线识别,已合并入主干。
  • SenseVoice.cpp:基于 GGML 的纯 C/C++ 推理,支持 3/4/5/8 位量化,无第三方依赖。
  • 流式 SenseVoice:分块推理加截断注意力实现伪流式,支持 CTC 前缀束搜索与热词增强。
  • OmniSenseVoice:轻量化推理库,支持 batch。
  • 神经网络热词:ModelScope 上的 SenseVoiceSmall_hotword 模型,基于 CPPN 的神经网络热词增强。

九之二、仓库结构与训练数据格式要点

仓库根目录下,model.py 是 remote_code 模式加载的模型实现,demo2.py 演示直接从 words 字段读取文字,long_audio_no_vad.py 是无 VAD 长音频参考脚本,webui.py 启动 Gradio 风格界面,finetune.sh 是微调入口,benchmarks/ser/ 下是情感评测契约脚本。训练 JSONL 的每个字段含义为:key 数据唯一 ID;source 音频文件路径;source_len 音频 fbank 帧数;target 标注文本;target_len 标注文本长度;text_language 语种标签;emo_target 情感标签;event_target 事件标签;with_or_wo_itn 标注文本是否含标点与逆文本正则化。五个 scp 文件左边的 ID 必须一一对应,可用 sensevoice2jsonl 一键合并;缺少语种/情感/事件标注时,加 ++model_dir 让 SenseVoice 自动打标。启动训练前记得把 finetune.sh 里的 train_tool 改成 funasr/bin/train_ds.py 的绝对路径,否则训练入口找不到脚本。

十、常见问题 FAQ

Q:情感标签能从转写文本里用字符串切分得到吗? A:不建议。官方 SER 评测契约要求直接读取 SenseVoice 原始情感标签;从富文本转写结果切字符串推断会带来误差,复现 CASIA/RAVDESS 结果时务必用官方脚本。

Q:一小时录音直接喂模型为什么 OOM? A:长音频必须先分段。VAD pipeline 用 FSMN-VAD 切句;不能用 VAD 时用 long_audio_no_vad.py 做 30 秒窗口加 2 秒重叠,避免整段录音进编码器。

Q:为什么升级 funasr 后行为没变? A:用了 remote_code="./model.py" 时,本地 model.py 不会随包升级而更新,需同时更新仓库源码。

Q:说话人是谁能识别出来吗? A:SenseVoiceSmall 本身不输出说话人身份;说话人分离靠 FunASR 组合 FSMN-VAD 加 CAM++,且编号只在同一段录音内有效。需要匿名说话人标注用 MOSS-Transcribe-Diarize。

Q:Docker 镜像为什么拉不下来? A:ghcr.io/qwenaudio/sensevoice 当前为 private,匿名拉取返回 401;请在仓库根目录 docker build -t sensevoice . 本地构建。

Q:模型权重能商用吗? A:根据维护者对 FunASR 模型开源协议 v1.1 的澄清,遵守模型协议(含 2.2 节署名与模型名称要求)时允许商业使用官方 SenseVoiceSmall 权重,第 3 节是责任与风险免责而非额外的"禁止商用"限制,微调后的衍生权重可保持私有;第三方转换版本需另行核对条款。

Q:language="auto" 和显式指定语言有什么区别? A:auto 让模型自动识别语种,支持 zh、en、yue、ja、ko 与 nospeech 几类;已知语种的业务显式指定可减少误判。use_itn=True 时输出带标点与逆文本正则化(数字、日期、货币等规整为口语写法),直接推理示例中 use_itn=False 则输出原始文本。

Q:ONNX 导出后和 Python 版结果一致吗? A:ONNX 路线用 funasr-onnx,构造时 quantize=True 做量化、batch_size=10,导出物落在原模型目录;Libtorch 路线用 funasr-torch 并指定 device="cuda:0"。两者都是为端侧或服务化准备的导出形态,精度与 PyTorch 原版会有轻微量化差异,对结果敏感的场景建议先做评测。

十一、跳转链接

评论交流

文章目录