Ascend-SACT/FunASR_VAD-SenseVoiceSmall-CAMPPlus
模型介绍文件和版本Pull Requests讨论分析
下载使用量0

FunASR VAD + SenseVoice-Small + CAM++ 模型服务化部署与性能验证实践

1. 背景

本文档介绍基于 FunASR 框架,将 FSMN VAD + SenseVoice-Small + CAM++ 三个本地模型组合服务化部署为 OpenAI 兼容 HTTP API,并基于官方 AISHELL-1 test 数据集完成 SenseVoice-Small 精度复现的实践过程。

本实践服务接口:

POST /v1/audio/transcriptions

评测目标:

  1. 验证三个模型服务化部署后可以通过 HTTP API 调用
  2. 基于官方 AISHELL-1 test 数据集复现 SenseVoice-Small 精度

模型信息:

模型ModelScope 地址作用
FSMN VADhttps://modelscope.cn/models/iic/speech_fsmn_vad_zh-cn-16k-common-pytorch语音活动检测,将长音频切分为有效语音片段
SenseVoice-Smallhttps://modelscope.cn/models/iic/SenseVoiceSmall多语种语音识别、情绪/事件富文本识别
CAM++https://modelscope.cn/models/iic/speech_campplus_sv_zh-cn_16k-common说话人识别/说话人标记

2. 服务化部署

2.1 硬件环境

  • 设备信息:Atlas 800T A2,Ascend 910B3

2.2 软件环境

项目版本 / 规格
操作系统 / 架构Ubuntu 22.04.5 LTS / aarch64
驱动 / 固件25.2.0 / 7.0.3.220
CANN8.5.1
Python3.11.14
torch / torch_npu2.9.0+cpu / 2.9.0.post1+gitee7ba04

2.3 安装依赖

在项目目录执行:

python -m pip install -r requirements.txt

requirements.txt:

fastapi
uvicorn
python-multipart
funasr
modelscope
torch
torch-npu
soundfile
librosa
pytest
httpx

2.4 启动服务

所有模型路径和推理参数均通过命令行参数传入。以下示例使用占位符表示本地模型目录,请按实际部署路径替换。

python -m funasr_openai_service.main \
  --host 0.0.0.0 \
  --port 8000 \
  --asr-model <MODEL_ROOT>/SenseVoiceSmall \
  --vad-model <MODEL_ROOT>/speech_fsmn_vad_zh-cn-16k-common-pytorch \
  --spk-model <MODEL_ROOT>/speech_campplus_sv_zh-cn_16k-common \
  --device npu:0 \
  --batch-size-s 60 \
  --merge-vad true \
  --merge-length-s 15 \
  --max-single-segment-time 30000 \
  --max-upload-size-mb 100 \
  --lazy-load false

2.5 启动参数说明

参数默认值说明
--host0.0.0.0服务监听地址
--port8000服务监听端口
--asr-modelSenseVoice-Small 本地模型目录SenseVoice-Small 模型路径
--vad-modelFSMN VAD 本地模型目录FSMN VAD 模型路径
--spk-modelCAM++ 本地模型目录CAM++ 模型路径
--devicenpu:0推理设备
--batch-size-s60传给 FunASR generate() 的动态 batch 参数,单位为秒。表示内部一次 batch 推理中累计音频时长的目标规模或上限约为 60 秒;它不是 HTTP 请求数量,也不会把多个 API 请求合并成 batch。
--merge-vadtrue传给 FunASR generate() 的 VAD 片段合并开关。开启后,FunASR 会尝试合并相邻 VAD 语音片段,减少过碎切分,使 ASR 获得更完整上下文。
--merge-length-s15传给 FunASR generate() 的 VAD 合并目标长度,单位秒,仅在 --merge-vad true 时有意义。表示合并后的语音片段目标长度约为 15 秒。
--max-single-segment-time30000传给 FunASR AutoModel 的 vad_kwargs 参数,单位毫秒。表示 VAD 单个语音片段允许的最大时长,30000 即 30 秒,用于避免 VAD 输出过长片段。
--max-upload-size-mb100上传音频文件大小上限,单位 MiB
--lazy-loadfalse是否延迟加载 FunASR 模型。默认 false,服务启动阶段即加载模型;设置为 true 时,模型会在第一次转写请求中加载。

其中 --batch-size-s、--merge-vad、--merge-length-s、--max-single-segment-time 均由当前服务解析后透传给 FunASR 框架处理。服务代码不自行实现 VAD 切分、片段合并或内部 batch 组织逻辑。

2.6 健康检查

curl http://127.0.0.1:8000/health

返回示例:

{
  "status": "ok",
  "model_id": "sensevoice-small-vad-campp",
  "settings": {
    "asr_model": "<MODEL_ROOT>/SenseVoiceSmall",
    "vad_model": "<MODEL_ROOT>/speech_fsmn_vad_zh-cn-16k-common-pytorch",
    "spk_model": "<MODEL_ROOT>/speech_campplus_sv_zh-cn_16k-common",
    "device": "npu:0"
  },
  "transcriber": {
    "loaded": true,
    "device": "npu:0",
    "npu": {
      "requested": true,
      "available": true,
      "count": 8
    },
    "load_error": null
  }
}

2.7 模型列表接口

curl http://127.0.0.1:8000/v1/models

返回:

{
  "object": "list",
  "data": [
    {
      "id": "sensevoice-small-vad-campp",
      "object": "model",
      "created": 0,
      "owned_by": "local"
    }
  ]
}

2.8 OpenAI 兼容转写接口

接口:

POST /v1/audio/transcriptions

请求类型:

multipart/form-data

请求参数:

参数必填默认值当前行为
file是无上传音频文件
language否auto传给 FunASR 作为语言提示
response_format否json支持 json、text、srt、vtt、verbose_json
timestamp_granularities[]否无仅 verbose_json 支持;当前支持 segment,word 明确返回 400

调用示例:

curl http://127.0.0.1:8000/v1/audio/transcriptions \
  -F language=auto \
  -F response_format=verbose_json \
  -F "timestamp_granularities[]=segment" \
  -F file=@<AUDIO_FILE>

3. 代码适配

3.1 目录结构

当前服务代码结构:

.
├── README.md
├── requirements.txt
└── funasr_openai_service
    ├── __init__.py
    ├── main.py
    ├── config.py
    ├── api.py
    ├── transcriber.py
    ├── formatter.py
    ├── run_result.py
    ├── benchmark.py
    ├── evaluation.py
    ├── datasets.py
    └── model_profiles.py

核心模块职责:

文件说明
config.py启动参数、模型路径、设备、上传大小等配置
main.pyCLI 参数解析与 Uvicorn 启动入口
api.pyFastAPI 路由与 OpenAI 兼容接口
transcriber.pyFunASR AutoModel 封装、模型加载、NPU 探测、推理调用
formatter.pySenseVoice 标签清理、OpenAI 响应格式转换、SRT/VTT 生成
run_result.py单次推理结构化指标
benchmark.pyHTTP / service-sdk / funasr-direct 三种模式的评测 CLI
evaluation.pyCER/WER、评测汇总、官方精度基线对比、manifest 读取
datasets.pyAISHELL-1 / AISHELL-4 manifest 构建
model_profiles.py三模型组件画像和官方公开精度基线

3.2 整体架构

官方 FunASR OpenAI API 示例流程:

FastAPI 接收上传文件 → 写临时文件 → AutoModel.generate → 返回 OpenAI 风格响应

当前适配后流程:

启动参数解析
  → FastAPI 服务启动
  → 默认加载 FunASR AutoModel
  → /health、/v1/models、/v1/model_profiles 可用
  → 转写请求
  → 接收上传文件并写入临时文件
  → 使用 VAD + SenseVoice-Small + CAM++ 推理
  → 清理 SenseVoice 富文本标签
  → 转换为 OpenAI json/text/srt/vtt/verbose_json 响应
  → 删除临时上传文件

3.3 FunASR 推理实现

核心推理参数:

model.generate(
    input=str(audio_path),
    cache={},
    language=language or "auto",
    use_itn=True,
    batch_size_s=settings.batch_size_s,
    merge_vad=settings.merge_vad,
    merge_length_s=settings.merge_length_s,
)

关键说明:

参数作用
use_itn=True将数字、日期、时间等转换为书面形式;适合服务输出,但可能影响官方 CER 对齐
batch_size_sFunASR 内部按音频时长控制动态 batch,不等于 HTTP 请求级 batch
merge_vad / merge_length_s控制 VAD 分段合并
spk_modelCAM++ 说话人模型,用于输出 speaker 字段

当前服务化请求是单文件请求,不会把多个 HTTP 请求自动合并为 batch。--direct-batch-size 只用于 benchmark.py --mode funasr-direct,不影响当前 HTTP API。

3.4 OpenAI 响应格式适配

当前支持:

response_format返回类型
json{"text": "..."}
text纯文本
srtSubRip 字幕
vttWebVTT 字幕
verbose_jsonOpenAI 风格结构化 JSON

verbose_json 示例:

{
  "task": "transcribe",
  "language": "auto",
  "duration": 5.622,
  "text": "开饭时间早上9点至下午5点。",
  "segments": [
    {
      "id": 0,
      "seek": 0,
      "start": 0.42,
      "end": 5.6,
      "text": "开饭时间早上9点至下午5点。",
      "tokens": [],
      "temperature": 0.0,
      "avg_logprob": 0.0,
      "compression_ratio": 0.0,
      "no_speech_prob": 0.0,
      "speaker": "speaker_0"
    }
  ]
}

格式化规则:

规则说明
SenseVoice 标签清理删除 `<
时间单位转换FunASR 毫秒时间戳转为秒
说话人字段spk: 0 转为 speaker_0
timestamp fallback无 sentence_info 时合并 timestamp 范围,避免重复整段文本

4. 精度评测

4.1 AISHELL-1 数据集

本实践使用 AISHELL-1 的 test split 进行 SenseVoice-Small 精度复现。

ModelScope 数据集地址:

https://www.modelscope.cn/datasets/OmniData/AISHELL-1

当前用于官方精度对齐的是 AISHELL-1 的 test split,不包含 train 和 dev。

数据统计:

指标数值
样本数7176
总时长36108.919s
总时长10.03h
平均单条时长5.032s
中位数4.743s
最短1.859s
最长14.700s
P958.153s

时长分布:

区间数量
< 3s378
3s - 5s3616
5s - 10s3111
>= 10s71

4.2 生成 AISHELL-1 manifest

python -m funasr_openai_service.datasets \
  aishell1 \
  --root <AISHELL1_ROOT> \
  --split test \
  --output <AISHELL1_TEST_MANIFEST>

manifest 格式:

{"id":"BAC009S0764W0121","audio":"wav/test/S0764/BAC009S0764W0121.wav","text":"参考文本","language":"zh"}

4.3 评测指标

指标含义方向
CERCharacter Error Rate,字符错误率,中文 ASR 主指标越低越好
WERWord Error Rate,词错误率,英文/空格分词语言更适合越低越好

中文 AISHELL-1 主要看 CER。WER 因中文参考文本通常无空格,数值可解释性较弱。

4.4 SenseVoice-Small 精度复现

为对齐官方 SenseVoice-Small 在 AISHELL-1 上的精度,使用 funasr-direct 模式测试 SenseVoice-Small ASR 本体。

关键配置:

配置值
模式funasr-direct
模型SenseVoice-Small
VAD关闭
CAM++关闭
use_itnFalse
batch50
数据集AISHELL-1 test 全量 7176 条

完整测试命令:

python -u -m funasr_openai_service.benchmark \
  --manifest <AISHELL1_TEST_MANIFEST> \
  --mode funasr-direct \
  --official-dataset aishell1_test \
  --warmup 1 \
  --device npu:0 \
  --direct-batch-size 50 \
  --progress-every 500 \
  --progress-interval-s 60 \
  --output <AISHELL1_BATCH50_REPORT> \
  --quiet

全量结果:

指标当前结果
样本数7176
CER3.0115%
官方 AISHELL-1 CER2.96%
CER 差值+0.0515%

结果说明:

  1. 当前 direct ASR 评测已经基本对齐官方 AISHELL-1 精度

5. 总结

本实践完成了 FSMN VAD、SenseVoice-Small 和 CAM++ 三个本地模型的服务化封装,并通过 OpenAI 兼容的 POST /v1/audio/transcriptions 接口对外提供转写能力。

在精度复现方面,使用 AISHELL-1 test 全量 7176 条样本、funasr-direct 模式、关闭 VAD 和 CAM++、direct_batch_size=50 的配置,SenseVoice-Small 得到 3.0115% CER,与官方 2.96% 基线差值为 +0.0515%,整体与官方公开结果基本对齐。