ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

FunASR vs Whisper,5分钟搞定Paraformer中文语音识别本地部署指南

FunASR vs Whisper,5分钟搞定Paraformer中文语音识别本地部署指南 我第一次跑达摩院开源的语音识别模型时完全没有标题里这种轻松感。装完依赖、拉完模型、调完代码半天时间就这么没了最后卡在音频格式上报错一度怀疑是不是自己环境有问题。等到把整个链路彻底理顺才发现如果环境干净、模型已经就位从装好 FunASR 到拿到第一句转写文本5 分钟确实够用。这篇就把我整理出的本地部署最短路径完整拆开讲覆盖 Paraformer 模型选型、环境准备、核心代码、服务化改造以及我在本地部署和后续使用中反复踩过的高频报错和排查思路。如果你也需要一套可离线、可定制的中文语音识别方案或者想把它作为本地大模型应用的语音入口这篇文章能帮你省掉大半天的试错时间。FunASR 是达摩院开源的语音识别工具包Paraformer 是它主推的非自回归端到端模型两者配合起来在中文识别场景下性价比很高。文章不会只给能跑的代码还会把每一步背后的选择和取舍讲清楚方便你根据自己机器的情况做调整。1. 为什么是 Paraformer 和 FunASR这套组合解决了什么痛点1.1 本地部署语音识别到底图什么在讲技术之前先聊一个实际问题你的语音识别需求真的需要上云吗很多人一开始习惯直接用在线 API本地部署这件事往往是被逼出来的。最常见的三种场景一是音频里包含客户信息或内部讨论内容数据不能出内网二是调用量一大按次计费的成本会变得非常可观三是网络链路不稳定实时性要求高的场景根本不敢把识别结果交给远程接口。把模型放到本地之后音频文件直接在机器上处理不经过任何外部服务隐私问题从架构上就解决了。一次性的硬件投入换来的是一次性买断的免费调用同时本地 GPU 推理不存在公网波动延迟可控。再加上模型可以自己换、参数可以自己调这是在线 API 很难提供的灵活性。当然本地部署也有它的代价环境维护要自己来模型更新要自己管性能调优要自己折腾。这篇文章的价值就在于把代价压缩到最低。1.2 Paraformer 和 Whisper 怎么选别只盯着准确率很多人的第一反应是直接用 OpenAI 的 Whisper毕竟名气大、多语言支持好。但在纯中文场景下Paraformer 有它独特的优势。最核心的一点是它的非自回归架构Whisper 这类自回归模型生成文本时是一个 token 一个 token 往外蹦的速度受限于串行过程Paraformer 通过引入预测器机制实现了音频与文本的并行对齐输出整体推理速度快一个量级。用大白话说自回归模型像是人逐字誊写一句话非自回归模型则是看完整句话后直接整体默写出来。在同样长度的中文音频上后者的延迟体感要低非常多。在工程配套上Paraformer 的模型体系也更完整。官方仓库提供了 ASR 主模型、VAD 语音活动检测模型、标点恢复模型三个模型可以串成一条流水线先用 VAD 切出有效语音段再把每一段丢给 ASR 识别最后用标点模型恢复标点和数字格式。这套组合在长音频、多人对话场景下非常实用而 Whisper 往往需要自己额外处理分段逻辑。下面这个表格是我在本地实测时比较关心的几个维度数据来自个人测试环境仅供参考对比项Paraformer-zhWhisper large-v3中文识别准确率高日常对话表现稳定高但在口语化文本上偶尔有幻觉推理速度快非自回归并行输出较慢自回归逐 token 生成显存占用模型体积约 1GB 以内模型权重超过 3GB标点/数字恢复有专门配套模型自带但可控性弱热词定制支持可动态传入热词表不支持主要通过 prompt 引导社区生态ModelScope 模型仓库完善Hugging Face 生态丰富如果你只处理英文或者需要覆盖几十种语言Whisper 仍然是很强的选择。但如果是中文为主、追求响应速度和可控性Paraformer-zh 会更顺手。1.3 FunASR 不只是模型封装它其实是一套工具链真正让 Paraformer 变得好用的功臣是 FunASR。它不是简单地把模型包了一层 Python API而是把模型管理、推理、服务化都做了进去。你不需要手动去 ModelScope 翻模型文件再写加载逻辑只要指定模型名字FunASR 会自动处理下载和缓存。更关键的是它内置了完整的推理流程。比如你在初始化 AutoModel 时同时指定了 vad_model 和 punc_model调用 generate 时它会自动完成VAD 切段 - ASR 识别 - 标点恢复的串联你拿到的就是带标点的完整文本。这个设计对工程来说太重要了直接省掉了一条流水线的开发量。此外 FunASR 还提供了命令行工具和服务端启动能力下面会分别演示。对于只想快速验证效果的人来说这些入口都非常友好。2. 部署前三件套硬件、Python 环境、模型下载一个都不能漏2.1 没有 GPU 能不能跑能但你要接受一个前提先说结论CPU 完全可以跑尤其是短音频。Paraformer-zh 模型用 CPU 处理一条几秒钟的音频停顿感是能接受的但如果是几分钟的长音频或者需要高并发CPU 就非常吃力了。我的建议是先用 CPU 把整个流程跑通确认功能没问题再上 GPU 优化性能。这样环境复杂度低排查问题也更容易。GPU 方面显存需求其实没有想象中大。Paraformer-zh 主模型加上 VAD 和标点模型用 FP32 精度跑起来大约需要 2-3GB 显存如果换成半精度会更低。现在市面上主流显卡基本都能满足。显存不足时的降低策略在后面排错部分会专门展开。有一点必须提前说清楚PyTorch 的 CUDA 版本和显卡驱动必须匹配。很多人在这一步翻车后面安装环节我会单独强调。2.2 用 conda 建独立环境避免污染系统 Python我强烈建议用 conda 创建一个专用环境来部署 FunASR。原因很现实FunASR 依赖 PyTorch、ModelScope、torchaudio 这一整套重组件如果直接装进系统 Python很可能和你现有的深度学习环境产生版本冲突。conda 环境之间互相隔离出问题直接删掉重建成本很低。conda create -n funasr_env python3.9 -y conda activate funasr_envPython 版本我建议 3.9 或 3.10这两个版本兼容性最稳。3.11 以上部分依赖的预编译包可能还没跟上3.8 以下则太老没必要给自己找麻烦。2.3 提前用 ModelScope 把模型拉下来别等运行时卡住FunASR 的模型存储在 ModelScope 上。AutoModel 在加载模型时如果本地没有缓存会即时去下载。问题是模型文件体积不小如果在运行时才开始下载不仅慢而且一旦网络波动中断还容易留下不完整的缓存目录下次加载继续报错。更稳妥的做法是先用 ModelScope 的 SDK 把模型下载到本地缓存目录再让 FunASR 去读取。pip install modelscope python -c from modelscope import snapshot_download snapshot_download(iic/speech_paraformer-large_asr_nat-zh-cn-16k-common-vocab8404-pytorch) snapshot_download(iic/speech_fsmn_vad_zh-cn-16k-common-pytorch) snapshot_download(iic/punc_ct-transformer_zh-cn-common-vocab272727-pytorch) 这里解释一下手动下载的意义第一下载过程独立出来进度可视化失败可以单独重试第二模型文件会落到 ModelScope 的缓存目录后面 FunASR 运行时直接命中缓存不用再等第三你还能提前确认硬盘空间是否足够。这三个模型加起来大约 2GB 左右需要留意磁盘剩余空间。这里我还要多提一句不要用git clone的方式去拉模型仓库尤其不要用 git lfs。ModelScope 大文件走的是专门的分发链路git 方式在模型文件多的时候非常容易中断而且中断后的续传逻辑也不好使。用 SDK 的 snapshot_download 是最省心的。2.4 ffmpeg经常被忽略但几乎必装的辅助依赖FunASR 在读取音频时依赖 ffmpeg 作为后端解码器。如果你只传 wav 格式的文件可能还好说一旦输入是 mp3、m4a、aac 或者采样率不是 16k 的音频就会自动调 ffmpeg 做重采样和解码。没有装 ffmpeg运行时会直接报错。# Ubuntu/Debian sudo apt update sudo apt install ffmpeg -y # macOS brew install ffmpegWindows 用户需要到 ffmpeg 官网下载可执行文件解压后把 bin 目录加到系统 PATH 环境变量里。装完后在终端敲ffmpeg -version能正常输出版本信息说明环境就绪。这个环节花不了两分钟但能避免一个非常典型的启动报错。3. 从零跑通识别五分钟的实操链路和最简代码3.1 第一步安装 funasr 包在激活的 conda 环境里安装即可pip install funasr这里要特别强调一个顺序问题如果这台机器还没装过 PyTorch建议先去 PyTorch 官网按你的 CUDA 版本选择对应的安装命令先把 torch 装好再回来安装 funasr。因为 funasr 的执行依赖里包含 torch如果让它自动装它拉取的往往是 CPU 版或者和你 CUDA 不匹配的版本。先装 torch 再装 funasr 的好处是pip 检测到 torch 已存在且满足版本要求就不会重复拉取环境更干净也避免后面的 CUDA 不可用问题。安装完验证一下关键包python -c import torch, funasr; print(torch:, torch.__version__); print(cuda available:, torch.cuda.is_available())如果输出cuda available: False而你确认显卡驱动正常那就是刚才说的 torch 版本问题先不要继续往下走回头把 CUDA 版本的 torch 装好再说。3.2 第二步准备一条测试音频准备音频这件事比看起来更容易踩坑。我这里给你一条最标准的转换命令把任意输入音频统一转成 16kHz 采样率、单声道、16bit PCM wav 格式ffmpeg -i input.mp3 -ar 16000 -ac 1 -sample_fmt s16 out.wav-ar 16000设置采样率为 16k-ac 1转为单声道-sample_fmt s16设定位深。为什么要统一到这个格式因为 Paraformer 是使用 16k 音频训练的模型内部对输入有固定的采样率预期。你直接丢一个 44.1kHz 的音频进去FunASR 虽然会自动重采样但这个自动过程偶尔会有边界问题效果也没有预先转好来得好。我自己实际使用中凡是把音频先归一化到 16k 单声道再送入模型识别稳定性和出字率都会好不少。这个习惯建议从一开始就养成。3.3 第三步写第一段 Python 代码环境就绪后用 AutoModel 加载三个模型并识别音频核心代码不超过十行from funasr import AutoModel model AutoModel( modelparaformer-zh, model_revisionv2.0.4, vad_modelfsmn-vad, vad_model_revisionv2.0.4, punc_modelct-punc, punc_model_revisionv2.0.4, devicecuda:0 if __import__(torch).cuda.is_available() else cpu ) result model.generate(inputout.wav) text result[0][text] print(识别结果, text)参数说明model指定主识别模型paraformer-zh是 FunASR 内置的别名会自动映射到 ModelScope 上对应的模型仓库。model_revision是模型版本号建议固定避免后续默认版本更新带来行为变化。vad_model和punc_model分别指定语音活动检测模型和标点恢复模型。device根据 torch 是否可用 CUDA 自动选择设备。generate返回的是一个列表列表每个元素对应一个音频输入。元素里的text字段就是最终文本。如果同时设置了return_raw_text或return_time_stamp返回内容会更丰富后面调参部分会讲到。3.4 第四步用命令行快速验证如果不想写 Python 代码FunASR 也提供了 CLI 入口。不同版本命令名可能不同运行前先用 --help 确认一下funasr-auto --model paraformer-zh --input_file ./out.wav我见过老版本用--audio_file新版本改成--input_file的情况。所以最稳妥的做法是先执行funasr-auto --help看清当前版本支持的参数名。CLI 适合快速验证模型是否正常工作等确认无误后还是建议回到 Python API 去做工程集成可控性更强。3.5 关于5 分钟的诚实说明看到这里你应该能明白5 分钟是个有一定前提的说法。当你已经完成 conda 环境创建、torch 安装、模型下载之后从pip install funasr到跑通指令这中间的耗时确实可以控制在 5 分钟以内。第一次部署的人会把时间花在模型下载和 torch 版本问题上这不代表教程不靠谱只是时间分布不同。我的实际操作习惯是先花 20 分钟把环境和模型准备好然后强制要求自己在 5 分钟内把代码跑通。如果跑不通就说明遗漏了某个环境细节回头一项项检查。4. 从 Demo 到服务把识别能力真正接进项目4.1 模型加载只做一次别每条音频都 load 一遍很多第一次用 AutoModel 的人会踩进一个性能陷阱在每次调用识别时都执行一次AutoModel(...)。这个操作背后是真实的模型文件读取和内存加载一次也就罢了每条音频都 load性能会差到不可接受。正确的做法是在服务进程启动时加载一次模型之后不断复用。模型本身在推理时是线程安全的多个请求共享同一个模型实例没有问题from funasr import AutoModel # 全局只初始化一次 _model AutoModel( modelparaformer-zh, vad_modelfsmn-vad, punc_modelct-punc, devicecuda:0 ) def transcribe(file_path): result _model.generate(inputfile_path) return result[0][text]如果你是在编写 HTTP 接口处理并发请求可以用 threading.Lock 控制并发或者直接依赖 FunASR 服务端内置的并发能力后面会讲到。4.2 用内置服务端把模型发布成 HTTP/WebSocket 接口FunASR 提供了服务化部署能力安装额外依赖后可以一键启动pip install funasr[server] funasr-server --host 0.0.0.0 --port 10095不同版本参数有差异用之前先跑一下funasr-server --help看参数名。默认情况下它会加载一组预置模型提供离线文件识别和流式识别的接口。前端可以通过 HTTP 或 WebSocket 对接这样就实现了一个标准的本地语音识别微服务。服务化的好处是解耦音频处理的逻辑不用侵入你的主项目任何语言只要能发 HTTP 请求就能调用识别能力。对于团队协作来说部署一次服务大家都通过接口访问非常方便。我自己在实际项目中更常用的是先写好 Python 服务层再通过 HTTP 暴露这样可以在接口里自定义热词、音频预处理等业务逻辑比直接用一键服务更灵活。4.3 批量处理场景一边读磁盘一边识别如果你面对的是几百个音频文件的批量转写任务建议用下面的方式先把所有音频统一转成 16k 单声道 wav避免中途格式报错。逐个调用model.generate结果先写到内存列表全部完成后统一写入 JSONL 或 CSV。出错时单独记录文件路径不要中断整个流程。批量处理时要更关注推理速度。如果用的是 CPU可以考虑调小单次处理的音频长度配合 VAD 切段后的并发处理如果用的是 GPU则尽量把显存用满避免一次只处理一条短音频造成显存浪费。4.4 离线识别还是流式识别场景决定选型FunASR 同时支持离线全量识别和流式识别。两种模式对应完全不同的需求离线识别对完整音频一次性处理准确率高支持标点恢复和热词适合会议记录、音频转写、视频字幕。流式识别边说话边出结果延迟低适合实时字幕、语音助手、实时客服质检。Paraformer 是离线模型如果要流式识别需要换成 FunASR 提供的流式模型例如paraformer-streaming相关模型。判断依据很简单如果你的场景允许说完再出结果就用离线如果是对话过程就要实时反馈只能走流式。这里我建议你把离线识别作为主力方案因为它的准确率、配套模型和工程成熟度都更高。流式模型可以用在一些对延迟极度敏感的特定场景不要盲目求新。5. 本地部署高频报错与排查现象、根因、解决方式5.1 模型下载卡住或报连接超时现象运行代码后长时间停在下载阶段进度条不动或者报出类似Connection error、Read timed out的错误。排查链路先确认是不是网络到 ModelScope 的连接不稳定再检查本地磁盘空间是否不足。很多时候是这个模型文件的缓存目录权限不对导致写入失败后反复重试。解决方式杀掉进程后把缓存目录里不完整的模型文件删掉重新用snapshot_download拉取。缓存目录一般在用户目录下的.cache/modelscope/hub删掉对应模型 id 的目录即可。如果反复失败考虑设置 modelscope 的下载重试次数或者换个网络环境再试。这一步没什么捷径模型文件就是需要完整下载到本地。建议你利用时间窗口提前在这个环节做好备份后续重装环境可以直接拷贝模型目录节省时间。5.2 torch 的 CUDA 版本和显卡驱动不匹配现象torch.cuda.is_available()返回 False或者加载模型时报警告推理一直在 CPU 上跑。排查链路在终端输入nvidia-smi查看当前驱动支持的 CUDA 版本然后在 Python 里执行import torch; print(torch.__version__)看 torch 的编译版本。两者如果不匹配就会出现明明有显卡但用不上的情况。解决方式最稳妥的做法是去 PyTorch 官网选择和你 CUDA 驱动版本匹配的安装命令。比如你驱动支持 CUDA 12.1就选 cu121 对应的安装命令先卸载掉现有 torch 再重装pip uninstall torch torchaudio -y pip install torch torchaudio --index-url https://download.pytorch.org/whl/cu121不需要把 CUDA Toolkit 本身装到系统里torch 是自带 CUDA 运行时的只需要显卡驱动支持即可。5.3 报错找不到 ffmpeg现象报错信息形如FileNotFoundError: [Errno 2] No such file or directory: ffmpeg。排查链路先在终端敲ffmpeg -version如果提示 command not found说明系统根本没装。如果装过了还是找不到排查是不是没加到 PATH。解决方式按照前面提到的系统对应安装方式装好 ffmpeg。这一步真的没什么技术含量但掉进去的人非常多。另外如果你是在 Windows 上运行装好 ffmpeg 后需要重新打开终端让 PATH 环境变量生效。5.4 显存不足或推理速度过慢现象GPU 模式下报CUDA out of memory或者 CPU 模式下处理一段 10 分钟音频耗时让人无法接受。排查链路先确认当前显存占用。用nvidia-smi查看显卡实时显存如果其他进程已经占了大半就说明不是模型问题而是资源争抢。如果 CPU 推理太慢先检查是不是没走 GPU再看音频是否过长。解决方式关闭其他占用显存的进程尤其是图形界面程序。加载模型时指定dtypefloat16使用半精度显存占用能下降约一半。长音频先交给 VAD 模型切段再逐段识别。FunASR 的内置流水线本身会做这事但如果你的音频只有一个长音段切分效果有限可以考虑调节 VAD 参数。确实无法满足性能要求再考虑增加硬件资源。使用 VAD 模型切段后其实每段的有效音频长度都很短CPU 处理也能接受。很多人的长音频识别卡顿问题不在模型性能而在于没有正确切段。5.5 模型路径、缓存目录权限、中文路径问题现象加载模型时报Can not find model或Permission deniedWindows 下报路径解析错误。排查链路先是确认模型 id 拼写是否正确再检查缓存目录能否读写。如果项目路径中包含中文或特殊字符部分版本的依赖库在路径解析上会有兼容问题。解决方式将模型 id 替换为完整的 ModelScope 仓库路径必要时直接指定本地模型目录给缓存目录添加当前用户的可写权限项目代码和音频文件一律使用英文路径避免中文目录名带来的编码问题。我之前在 Windows 上碰到过一种奇怪现象代码在 D 盘某个中文目录下运行模型加载和推理都正常但偶尔输出文件时会出现 UnicodeEncodeError。排查了很久才发现是路径编码的问题把输出路径改成英文后才稳定。这个经验分享出来希望大家处理 Windows 部署时留意。5.6 输出全是空文本或个别字被吞现象识别流程正常结束但text字段是空字符串或者某些关键词频繁识别错。排查链路先确认输入音频确实有语音内容可以用播放器听一遍或看波形。再检查是不是音频增益太低Paraformer 在极低音量下会把静音段全部切掉导致 VAD 认为没有有效语音。解决方式用 ffmpeg 对音频做增益处理或者调低 VAD 的静音检测阈值。对于特定词频繁识别错的情况使用热词功能进行纠偏下节详细讲。6. 把识别准确率再往上顶一截热词、参数和工程细节6.1 热词 hotword针对人名、地名和专有名词的神器Paraformer 支持动态热词这个功能对中文识别非常实用。默认词表之外的专有名词比如你公司产品名、客户人名、行业术语经常会被识别成同音字。通过热词可以在不改动模型的情况下大幅提升这些词的命中率。使用方式是在generate时传入hotword参数result model.generate( inputaudio.wav, hotword通义千问 百炼 灵码 函数计算 阿里云 )多个热词用空格分隔。热词的原理是在解码阶段对这些词对应的候选路径做加权让模型更倾向于输出这些词。效果上可以理解为一种软约束不需要重新训练。我这里分享一个实用经验热词不是越多越好。热词列表过长反而可能干扰正常识别把原来对的词带偏。一般控制在几十个以内优先放那些出现频率高、系统容易听错的词。如果想动态管理可以在服务层做一个热词配置接口根据不同的业务场景切换热词集合识别效果会灵活很多。6.2 打开时间戳、原始文本和结构化输出model.generate默认返回经过标点和数字格式化的最终文本。但集成到业务系统时你可能还需要以下信息result model.generate( inputaudio.wav, return_time_stampTrue, return_raw_textTrue ) print(result)return_raw_text返回还没有经过标点和数字格式化的原始文本。return_time_stamp返回每个句子或每个字的时间戳可用于字幕对齐、会议纪要和可视化呈现。sentence_timestamp在部分版本中用于区分字级别和句级别的时间戳粒度具体看版本文档。时间戳的精度足够满足大多数业务需求。比如做字幕时拿句级别时间戳对齐视频分割就行。如果要做字级别对齐Paraformer 的time_stamp输出还提供了每个字的起止时间实际效果非常干净。输出字段里可能还会看到emo之类的键那是情感分析模型的接口预留一般场景用不到忽略即可。6.3 输入音频质量预处理比换模型更有效模型对输入音频的敏感度很多人会低估。实际使用中我发现识别效果不稳定七成问题出在音频预处理环节而不是模型本身。我的固定流程是统一转为 16kHz、单声道、16bit wav。检测音频峰值如果整体音量过低做一次增益。如果音频中有明显底噪做轻量降噪比如用 sox 的noisered。包含多条分段的音频先按业务逻辑切分再逐段识别不要交给模型自己处理。这套流程做下来单条音频的识别准确率能提升一截更重要的是不同文件之间的效果稳定性明显变好。工程上稳定往往比某一条特别准更有价值。6.4 把语音识别接进本地大模型一个很值得做的小工程最后聊一个我最近在折腾的方向把 FunASR 的识别结果作为输入接进本地部署的大模型做一个完整的语音交互链路。具体来说就是用 Paraformer 做语音转写把文字交给本地跑的 Ollama 或其他推理引擎再让大模型生成回复。这样在完全没有公网依赖的情况下你也能搭建一个语音输入 - 文字 - 推理 - 回复的本地语音助手。这个方向的意义在于它把两个本地部署能力打通了语音识别负责把非结构化的声音变成结构化的文本大模型负责处理这个文本。两者都是本地运行数据全程不出机器隐私性和可控性都很好。实际做的时候要注意把录音程序、FunASR 识别、大模型调用三个模块之间的数据流解耦。我现在的做法是录音程序把音频写入临时目录FunASR 轮询目录并转写写好的文本再转发给本地大模型服务。模块之间通过文件或消息队列通信互不阻塞这样任何一环出问题都不会导致整条链路崩溃。这个方向后续还能扩展的方向很多在识别结果上做热词定制针对特定业务话语把标点模型换成更适会议场景的分段策略在识别阶段加说话人分离让大模型知道哪句话是谁说的。每一步都有现成的模型或工具可以用但组合起来的价值远大于单点识别。根据我个人这段时间的体会最值得投入的还是把音频预处理和热词配置做扎实这两件事不需要改模型但收益是最直接的。每次给新业务接入识别能力时先花十分钟检查测试音频的采样率和音量比纠结换什么模型有效得多。还有一个小技巧把常用的模型目录完整备份一份下次换机器部署时直接本地指定路径加载连下载时间都省了。
返回列表