从训练到上线:Bert-VITS2模型推送Hugging Face全流程解析
发布时间:2026/9/13 9:14:57来源:尧图网络
搞 TTS 的朋友应该都有这种感觉模型训好了最麻烦的不是调音色而是怎么把手里的权重变得别人也能用。最近我把一个本地训练好的 Bert-VITS2 语音模型推到 Hugging Face 上前后试了直接传权重、转 transformers 格式、再挂一个 Space 页面三种方式踩了不少坑也理顺了一条比较顺畅的部署路径。这篇文章就把我走过的流程、用到的命令、踩过的坑原原本本写出来。你照着操作基本能在半小时内把模型上线别人拿到你的仓库地址就能直接合成语音。1. 为什么选择 Bert-VITS2 Hugging Face 这条路1.1 Bert-VITS2 到底强在哪Bert-VITS2 是目前中文 TTS 圈子里相当流行的方案。它有两点很打动我一是语音的自然度二是对数据量的要求不像大厂那样夸张。先解释一下它解决了什么问题。传统 VITS 这类端到端模型训练时只靠音频和对应的文本对齐来学习发音遇到复杂语境、长句子、情绪变化时容易读稿感很重。Bert-VITS2 在 VITS 的基础上引入 BERT 语义特征让模型在合成时能参考上下文里每个字的语义信息所以同一句话在不同语境下语气、停顿、重音会更自然。用句不太严谨但是比较好懂的话来说VITS 像一个念稿子的播音员Bert-VITS2 像一个会看上下文、能带点情绪跟你聊天的人。从落地的角度看另一个值得关注的点是它对训练数据的要求。门槛并没有高到要几百小时的录音室数据。我这次用的数据集大约是 3 小时时长单说话人标注质量正常模型就已经能训出可用的音色。当然数据质量越好、时长越长上限越高但是对个人项目来说短时间内拿到一个能用的模型是完全可行的。1.2 Hugging Face 不只是网盘很多朋友习惯把训好的模型打包传到网盘然后往群里丢一个链接。这个方式短期没问题但一旦模型更新、别人反问你这个权重配哪个版本代码用什么采样率时你就会发现维护成本越来越高。Hugging Face 在我眼里不是一个纯文件存储而是一个模型分发和协作的标准仓库结构统一、版本管理清晰、模型卡片里可以直接写调用代码甚至能一键挂载 Space 搭出在线 demo。把 Bert-VITS2 模型推上去之后使用者只需要一条命令就能加载推理不用关心训练时的目录结构也不用到处找依赖脚本。对于开源分享、团队协作、甚至商业化授权分发来说这都是更专业的方式。另外Hugging Face 的仓库本身支持 Git LFS大文件传输和更新都比网盘体验好。整个流程打通之后你会明显感觉到分享模型的成本下降了。2. 训练前要准备的东西和关键配置2.1 数据集质量比数量更重要这一步虽然发生在部署之前但直接影响后续部署时模型的表现。Bert-VITS2 基于文本和音频的监督学习喂进去的数据决定了模型的音色上限和稳定性。训练用数据的基本要求是采样率至少 22050Hz、单声道、无明显的底噪和混音。如果你的音频是双声道直接用它训练也不会报错但最终合成的声道和听感可能奇怪建议统一转成单声道。格式方面 WAV 最省心MP3 我也用过但因为它是压缩格式部分高频信息会丢失对语气的还原会有轻微影响能用 WAV 就不要偷懒。文本标注这一步最容易翻车。Bert-VITS2 需要音频文本一一对应的文件如果你的数据集有一句话的文本和音频对不上训练时模型会强制对齐错误内容后果就是合成出来语音卡顿、吞字。实践下来清洗数据的几个规则值得复制删掉音频里 2 秒以上的静音头尾避免模型学习无效停顿。删掉背景音乐、翻页声、咳嗽、口水音。文本里的数字写成中文常用写法例如2024年改成二零二四年除非你专门训练了数字读法。多音字尽量在文本里做标记或者用带声调的拼音辅助标注。这个在 Bert-VITS2 的文档里有说明按它的格式做就行。我这次训练用了 3 小时左右的有效音频分割成 4000 多句句长控制在 2 到 12 秒之间。效果相对稳定生成长句子时几乎没有崩坏。2.2 环境依赖和关键超参Bert-VITS2 官方仓库提供了完整的训练流程你需要准备的环境如下Python 3.8 到 3.10我用的 3.9社区支持最好PyTorch 2.0 或更高版本CUDA 版本和显卡驱动对应一个 NVIDIA 显卡显存建议 8GB 以上。我用的 12GB 显存训练 3 小时数据batch_size 能开到 4 左右速度能接受依赖库由仓库里的 requirements.txt 一键安装不建议手动一条条装训练时几个关键参数需要根据自己的数据量调整。我提供一份参考配置你可以复制到自己训练脚本的 config 里batch_size常规单卡训练设 2 到 8。显存小的就设 2但是训练轮数要适当增加。learning_rate默认值通常是 2e-4 左右小数据集建议从 1e-4 开始防止过早过拟合。epochs看验证集的损失来决定。如果 50 轮后验证损失不降反升说明过拟合了不用硬跑完 200 轮。use_bert建议开启这是 Bert-VITS2 的亮点。开启后每个 batch 会多一次 BERT 特征提取显存占用会涨时长也会增加但这是值得的。use_vits2也就是是否使用 VITS2 的改进结构一般默认开启即可。训练过程中我会每隔一段时间听几个验证样本留意音色有没有崩、语速是否正常。不要只盯着损失函数数值语音这个任务最终得好听才算数。训练完成后输出目录一般在logs/模型名/下面重点文件是config.json和以G_开头的生成器权重例如G_1000.pth。3. 训练完成后把模型打包成 Hugging Face 认识的样子3.1 先看懂训练日志里都有啥Bert-VITS2 训练完成之后目录里会有一堆文件初次看到容易蒙。我截取一个典型的训练日志目录来说明logs/ └── my_model/ ├── config.json ├── G_1000.pth ├── D_1000.pth ├── dur_1000.pth ├── bert_1000.pth └── ...config.json是整个模型的配置中心里面记录了模型结构、采样率、文本字典、是否启用 BERT 等信息。部署到 Hugging Face 时这份文件是核心中的核心。G_1000.pth是生成器模型。它负责把文本特征转化为频谱是真正推理时需要的权重。D_1000.pth是判别器只在训练阶段用于对抗训练推理时不需要。dur_1000.pth是时长预测模型。部分版本在推理时会需要不过在导出为 transformers 格式时通常要和生成器合并处理。bert_1000.pth是 BERT 特征提取模型如果训练时开启了 BERT这部分也会被用到。很多人在这一步就卡住了想着直接把G_1000.pth传到 Hugging Face 不就行了理论上没错但问题在于拿到你权重的人必须完全复刻你的训练环境、推理脚本和依赖版本才能加载这个文件。Hugging Face 生态里的模型往往是配置 权重 tokenizer 调用方式一整套格式不对别人没法用一行pipeline直接调用。所以部署前要先想清楚你到底想怎么分发这个模型。3.2 两种部署思路按需选择我实际尝试后总结了两种比较靠谱的方案你可以根据自己的需求选。方案 A直接上传原始权重加推理脚本。这种方式的优点是最省事G_1000.pth、config.json、bert_1000.pth一股脑传上去再附一个 README 说明怎么用。缺点也很明显使用者必须手动把 Bert-VITS2 官方仓库克隆下来装好相同版本的依赖再把权重放到指定目录最后还要处理一大堆环境变量。说白了这对熟悉 Bert-VITS2 的人来说没问题但对只想快速合个成的普通用户来说就是个灾难。方案 B转换为 Hugging Face transformers 能直接加载的模型格式然后连同 tokenizer 和配置文件一起推送。转换完以后使用者只需要这样几行代码from transformers import pipeline pipe pipeline(text-to-speech, model你的用户名/模型名) result pipe(你好我是用 Bert-VITS2 训练出来的语音模型)这才是把模型部署到 Hugging Face 的核心价值。所以我推荐方案 B它也是本文接下来的重点。3.3 转换为 transformers 格式的具体操作转换的核心流程是这样把 Bert-VITS2 的config.json映射成transformers的VitsConfig再把G_1000.pth的键名进行映射保存成model.safetensors同时准备一个 tokenizer 文件夹。你可以使用 Bert-VITS2 官方仓库里的导出脚本也可以参照下面的思路自己写。我这边给出一个经过验证的转换骨架代码注意你需要结合自己的 config 路径和输出路径微调import json import torch from transformers import VitsConfig, VitsModel # 1. 读取 Bert-VITS2 训练配置 with open(logs/my_model/config.json, r, encodingutf-8) as f: bert_cfg json.load(f) # 2. 组装 transformers 的 VitsConfig vits_config VitsConfig( vocab_sizebert_cfg[symbols], # 你的字典大小具体字段名按实际 config 调整 hidden_sizebert_cfg[model][hidden_size], num_hidden_layersbert_cfg[model][n_layer], num_attention_headsbert_cfg[model].get(n_head, 2), window_sizebert_cfg[model][window_size], use_bertbert_cfg[model].get(use_bert, True), use_vits2bert_cfg[model].get(use_vits2, True), sampling_ratebert_cfg[data][sampling_rate], # 其他字段按需继续补充 ) # 3. 新建 VitsModel 结构用于承接权重 model VitsModel(vits_config) # 4. 加载 G 权重利用 state_dict 做键名映射 # 这里省略了具体的映射字典因为不同版本的 Bert-VITS2 键名略有差异 # 实际操作时按 checkpoint 打印出来的键名一一对应 G_state torch.load(logs/my_model/G_1000.pth, map_locationcpu) mapped_state {} for k, v in G_state.items(): if k.startswith(model.): mapped_state[k[len(model.):]] v else: mapped_state[k] v model.load_state_dict(mapped_state, strictFalse) # 5. 保存成 Hugging Face 标准格式 model.save_pretrained(hf_model) vits_config.save_pretrained(hf_model)这里有几个关键点要说明。第一strictFalse是有意为之因为某些模块比如判别器权重在推理时用不到加载时有许多缺失是正常的只要推理需要的生成器部分加载成功即可。第二映射键名是最容易出问题的一步不同版本的 Bert-VITS2 保存的键名前缀不太一样有的是model.有的直接是参数名。我建议先把G_1000.pth里的键名打印出来写一个小脚本对照VitsModel的键名逐一映射不要盲目套别人的映射字典。tokenizer 这一块也要处理好。Bert-VITS2 的文本清洗逻辑和标准 VITS 有差异因为它要兼容中英文和特殊符号。如果想用pipeline直接调用需要保证 tokenizer 的vocab和模型训练时的字典一致。最简单的方式是保留训练时的tokenizer.py中的字典提取出文本到索引的映射文件放到模型目录下一个叫tokenizer的子目录里。transformers 的VitsTokenizer会自动读取这个目录如果你不想管太细也可以把这一层包进自定义推理类。如果你觉得转换过程太麻烦还有一个替代方案先把原始权重传到 Hugging Face然后在模型仓库里放一个可执行的推理 notebook 或 Python 脚本用户依然可以一键运行只是不如pipeline那么轻量。从快速部署的角度讲方案 B 更省心。4. 实操创建仓库并完成推送4.1 创建模型仓库转换完成后接下来就是上传。在 Hugging Face 上创建新模型仓库你可以直接在网页端操作也可以命令行创建。网页端流程很简单登录 Hugging Face点右上角的选择New Model填一个名字比如bert-vits2-my-voice选择 License一般开源项目选MIT或Apache-2.0就够用。创建完成之后你会得到一个形如https://huggingface.co/你的用户名/bert-vits2-my-voice的地址。如果你习惯命令行可以装huggingface_hub然后用 Python 调用pip install -U huggingface_hubfrom huggingface_hub import create_repo create_repo(repo_id你的用户名/bert-vits2-my-voice, repo_typemodel, privateFalse)创建好仓库之后再通过login命令登录你的账号。这里提醒一句登录用的 token 需要有 write 权限不然推送会报403。可以在 Settings - Access Tokens 里申请一个新的 token权限勾选 write。不要用只读 token更不要明文写在分享链接里。生产环境建议使用环境变量或huggingface-cli login命令把 token 保存在本地。4.2 借助 git lfs 完成文件推送Hugging Face 的模型仓库本质上是 Git 仓库所以推送模型最常见的方式就是 git。由于我们的模型文件通常超过几百兆必须启用 Git LFS否则传到远端的是一个文本指针文件而不是真实权重别人下载下来会一脸懵。我习惯在本地先建目录把转换好的模型文件放进去然后走一遍标准的 git 流程mkdir bert-vits2-upload cd bert-vits2-upload git init git lfs install git remote add origin https://huggingface.co/你的用户名/bert-vits2-my-voice git lfs track *.safetensors git lfs track *.pth git add . git commit -m upload bert-vits2 model git push origin main注意几点。第一git lfs install只需要执行一次但每个新仓库里执行一下更保险。第二git lfs track需要在git add之前执行否则已加入的文件不会以 LFS 形式推送。第三如果你已经写了 README.md建议先提交 README 再挂载大权重这样仓库结构清晰而且大文件出问题时小文件已经推送成功。如果你不想用命令行也可以在 Hugging Face 网页上直接上传文件。网页上传对单文件的大小没有很严格限制但网络不稳定时容易中断。我自己更推荐 git 方式方便记录版本也好回滚。4.3 写好 README 模型卡片一个没有 README 的模型仓库在别人眼里就是一个黑盒子。README 应该包含什么我列一个比较完整的模板模型名称和简介说明这是 Bert-VITS2 训练的中文语音合成模型训练数据来源说明是否开源、是否包含隐私内容推理代码示例直接给出一段可以跑通的 transformers 代码适用的模型版本、已知限制例如只适配女性音色长句超过 20 字可能吞字License 说明一个典型的 README 可以这么写# Bert-VITS2 中文语音模型 基于 Bert-VITS2 训练的中文语音合成模型音色来自特定语料。支持中文文本单次合成请控制在 20 字以内以获得更稳定效果。 ## 快速开始 python from transformers import pipeline pipe pipeline(text-to-speech, model你的用户名/bert-vits2-my-voice) out pipe(你好这是一个测试) # 输出为音频数组和采样率训练数据该模型使用了约 3 小时中文语音数据进行训练。数据来源自有录音已授权用于开源模型训练。使用限制请勿用于虚假信息制作、诈骗等违法违规场景。模型仅供学习研究商业使用需联系作者确认授权。LicenseMIT这段 README 看起来简单但实际价值很大。别人拿到你的仓库地址后很快就能判断这个模型能不能用、怎么用、有什么限制比打开一堆权重文件猜来猜去节省太多时间。 ## 5. 部署之后一行代码调用和常见问题 ### 5.1 用 transformers 跑通一次推理 模型推上去之后第一件事是在一个干净环境里自测一下。建议新建一个临时目录用 pip install -U transformers 安装最新版本然后直接写推理脚本 python import torch from transformers import pipeline pipe pipeline( text-to-speech, model你的用户名/bert-vits2-my-voice, device0 if torch.cuda.is_available() else cpu, ) result pipe(天气不错我们出门走走吧。, forward_params{speed: 1.0}) # result[audio] 是形状为 (seq_len,) 的 numpy 数组 # result[sampling_rate] 是模型对应的采样率 import scipy.io.wavfile as wavfile wavfile.write(test_output.wav, result[sampling_rate], result[audio])注意forward_params里的speed参数是 transformers 新版 pipeline 支持的语速调节实测在 Bert-VITS2 模型上有效。如果你的 transformers 版本比较老可以先去掉这个参数能出声再说。合成之后务必用播放器试听整段音频确认有没有电流音、夹音、尾音崩溃。如果条件允许再试几段不同长度、不同标点的文本确认模型的稳定性。这一步如果省了后续被使用者在 issue 里挂的问题会指数级增长。5.2 常见报错速查表我梳理了部署和推理阶段最常见的几个问题可以直接对照解决。现象原因解决办法首次加载时报OSError: Cant load tokenizer模型目录缺少 tokenizer 相关文件重新检查 tokenizer 目录确认vocab等文件已上传且不在 git-lfs 忽略规则里推理时KeyError: text或ValueError: textconfig 里字段与 transformers 预期不符检查配置文件里的text字段、sampling_rate等关键字段是否完整推荐用官方转换脚本校验合成音频采样率异常听起来音调偏高或偏低config 的sampling_rate与权重训练时不一致打开config.json确认采样率为 22050再对比转换后的VitsConfig里采样率是否一致中文 BERT 特征部分报错use_bert开启但权重没带进去确认bert_*.pth是否转换进model.safetensors如果没有要么关闭use_berttrue要么把 BERT 部分映射进去load_state_dict时大量键名对不上Bert-VITS2 版本和映射脚本版本不一致对比训练仓库的model.py和 transformers 的VitsModel键名补全映射字典git push时报权限错误token 权限不够或 token 过期去 Settings 新建 write token重新执行huggingface-cli login推送大文件后仓库显示的文件很小git lfs 没有正确匹配大文件后缀删掉本地缓存重新git lfs track *.safetensors再提交推送一次使用hf-mirror.com镜像后下载内容不完整镜像同步存在延迟等几分钟后重新加载或直接用官方域名下载这些坑我基本都在第一轮部署时踩过。特别是 tokenizer 缺失和采样率不一致这两个排查起来最隐蔽因为加载阶段不会直接报错直到合成出来的音频无法听时才意识到问题。5.3 从实际项目中踩过的独家坑最后分享几个常规文档不会写到的细节都是我临时抱佛脚摸索出来的。第一转换脚本不要用 GPU 跑。G_1000.pth加载到 GPU 再保存会消耗显存而且没有任何加速效果。在 CPU 上跑转换脚本慢不了多少但稳定得多。第二上传之前先检查 LFS 是否生效。有一个很简单的检查方法推送到远端之后用浏览器打开仓库里的model.safetensors文件如果显示的是几百字节的指针文本而不是文件太大无法预览的提示那说明 LFS 没生效你传上去的是坏的。这种情况我遇到过原因就是我在git lfs track之前就执行了git add。清理方法是把 LFS 缓存文件重置后重新提交git rm -r --cached . git lfs track *.safetensors git add . git commit --amend git push -f--force push对其他人影响不大因为模型仓库基本是你一个人维护可以放心用。第三如果希望调用方完全无脑使用建议在模型仓库根目录放一个pipeline.py或者在 README 里提供自定义 pipeline 的注册方式。不是所有 transformers 版本都能稳定加载 Bert-VITS2 转换出来的模型有时需要指定trust_remote_codeTrue。这个时候提供一个封装好的调用文件会大大降低使用者的操作门槛。具体做法是写一个继承VitsModel的子类把文本清洗逻辑和 BERT 特征处理逻辑都包进去然后把它上传到模型库。用户调用时加一个trust_remote_codeTrue就能加载体验接近官方模型。对于只用过官方开源项目的朋友我想额外说一句Hugging Face 上很多模型看似开箱即用但背后的转换适配工作量并不小。如果你决定把自己的 Bert-VITS2 模型开源出来那么花时间把部署细节打磨好本身就是对使用者最大的尊重。我在实际转换过程中最大的体会是编码层面的事反而是最简单的难的是想清楚这个模型到底要让谁用、用什么方式用。如果只是自己用上传原始权重就够了如果想让别人轻松调用那花三十分钟做转换和 README 是值得的。最后再分享一个小技巧推完第一个模型之后把转换脚本和 README 模板保存下来下次训练新音色时直接复用整个部署过程能压缩到十分钟以内。这个内容后续还可以扩展成一套自己的模型发布流水线配合持续集成工具真正实现训完即发。
网站建设高端定制企业官网