DiffVC 是论文《Diffusion-Based Voice Conversion with Fast Maximum Likelihood Sampling Scheme》(ICLR 2022 Oral)的官方实现,代码在 huawei-noah/Speech-Backbones 仓库的 DiffVC 子目录下,MIT 授权。它做的是 any-to-any 一次性语音转换:给一段源语音,再给一段几秒钟的目标说话人参考音频,直接把音色换过去,源说话人和目标说话人都不需要出现在训练集里。结构上分两级——一个 846 万参数的“平均音色”编码器把 mel 谱压成剥离个人音色的中间表示,再由一个 1.178 亿参数的二维 U-Net 扩散解码器在目标说话人条件下反扩散重建 mel,最后交给 HiFi-GAN 出波形。DiffVC 本体合计约 1.26 亿参数,fp32 权重约 0.5GB,推理时 notebook 会用 generator.nparams 把这个数直接打出来。
这个模型真正稀缺的资源不是显存,是耐心。10 秒音频、n_timesteps=30、mode='ml' 的一次转换峰值显存也就 2GB 上下,30 秒长句 3~4GB——U-Net 把 80×T 的 mel 当成一张二维图去卷,显存基本随片长线性涨,唯一会 OOM 的场景是你一口气塞进去几分钟的整段录音。麻烦全在环境:仓库里那份 requirements.txt 钉死了 torch==1.7.1、torchaudio==0.5.1、librosa==0.6.0、numpy==1.19.0,其中 torchaudio 0.5.1 根本不是 torch 1.7.1 的配对版本,librosa 0.6 在今天的 numba/numpy 上装都装不上。更要命的是 torch 1.7.1 的 cu110 wheel 只编到 sm_80,RTX 3090/A10/A6000(sm_86)、RTX 4090(sm_89)、RTX 5090(sm_120)、H100/H200(sm_90)全都会甩出 no kernel image is available 或架构不兼容告警。
那还值不值得现在部署 DiffVC?看你在意什么。后来的扩散语音转换基本都从它身上长出来:AAAI 2024 的 DDDM-VC 在致谢里明写扩散部分的代码取自 DiffVC,但它的授权是 CC BY-NC-SA 4.0,商用免谈;风头更劲的 Seed-VC 是 GPL-3.0,而且仓库已经变成 Public archive 不再更新。DiffVC 这边,本体、HiFi-GAN、说话人编码器三块在 THIRD_PARTY_NOTICE 里逐条列明全是 MIT,Speech-Backbones 仓库至今没有归档。要做基线复现、要改架构、要拿去商用,它依然是最省事的那个起点——前提是你肯花一小时把 2022 年的依赖翻新一遍。
01 —
权重清单:DiffVC 不是一个文件,是四个
跑通一次转换要同时装好转换模型、平均音色编码器、声码器和说话人编码器,缺一个都出不了声
| 版本 | 参数量 | 显存 | 上下文 | 说明 |
|---|---|---|---|---|
| Diff-LibriTTS(vc_libritts_wodyn.pt) | 126M(编码器 8.46M + 扩散解码器 117.8M) | fp32 权重 ~0.5GB;10 秒句子 30 步推理峰值 ~2GB | 22.05kHz · 80 mel · n_fft 1024 · hop 256 · n_timesteps=30 | 官方默认权重,LibriTTS 约 1100 位说话人训练,any-to-any 首选。文件名里的 wodyn 是论文条件方式消融中胜出的那一档:说话人 embedding 加上加噪后的目标 mel,不喂整条扩散轨迹。 |
| Diff-VCTK | 126M,与 LibriTTS 版同结构 | fp32 权重 ~0.5GB,推理占用同上 | 22.05kHz · 80 mel · hop 256 | VCTK 109 位说话人训练,其中 99 位在论文里被留作 unseen 测试集。录音棚干声、英式口音场景更贴;论文的条件方式消融里 wodyn 在 VCTK 上把说话人相似度推到 46.7%。 |
| 平均音色编码器 enc.pt(FwdDiffusion) | 8.46M(MelEncoder 6.84M + PostNet 1.62M) | fp32 ~34MB | 6 层 Transformer,channels 192、filters 768、2 头、相对位置窗口 4 | 训练解码器之前必须先有它。要么下官方 LibriTTS 版丢进 logs_enc/,要么自己跑 Montreal Forced Aligner 出 TextGrid、用 get_avg_mels.ipynb 造平均音色 mel 再跑 train_enc.py。train_dec.py 里 Adam 只挂在 model.decoder.parameters() 上,编码器全程冻结。 |
| HiFi-GAN universal_v1 声码器 | ~14M | fp32 ~56MB | 22.05kHz 输出;mel 滤波器组 fmin=0、fmax=8000 | DiffVC 只产 mel,波形完全靠它,取自 jik876/hifi-gan 的通用权重,MIT 授权。注意 mel basis 的 fmax 卡在 8kHz——8kHz 以上的齿音细节本来就不在建模范围内,别指望它还原。 |
| GE2E 说话人编码器 checkpts/spk_encoder/pretrained.pt | ~1.4M(3 层 LSTM,hidden 256,输出 256 维 embedding) | fp32 ~6MB | 16kHz · 40 mel · 25ms 窗 / 10ms 步 · 1.6 秒 partial | 唯一随仓库直接下发、不用去 Google Drive 拉的权重,来自 Real-Time-Voice-Cloning。它跑的是另一套前端:webrtcvad 切静音、归一化到 -30 dBFS、重采样到 16kHz——和 DiffVC 主体的 22.05kHz 前端是两条独立管线,改采样率时两边都要动。 |
02 —
GPU 选型:对 CUDA 架构比对显存更要紧
DiffVC 全程 fp32,选卡前先把计算能力和你打算用的 torch 版本对齐
先试听效果,或批量转换几百上千条 10 秒以内的语音
Tesla V100 32GB$0.188/卡·时
全表最便宜的一张卡,还给到 32GB;sm_70 正好落在 torch 1.7.1+cu110 官方 wheel 的架构列表里,是少数几张照抄 requirements.txt 也能直接跑起来的卡。
按官方默认复现解码器训练(batch_size=32、train_frames=128、全程 fp32)
RTX 3090 24GB$0.193/卡·时
Adam 只优化 1.178 亿参数的解码器,权重加梯度加一阶二阶动量固定占约 1.9GB,剩下全是激活;24GB 刚好吃下默认配置,注意 sm_86 需要把 torch 升到 1.8+/cu111 以上。
整段 3 分钟以上录音一次性转换不切片,或把 batch_size 拉到 64 重训
RTX A6000 48GB$0.817/卡·时
U-Net 显存随 mel 帧数线性上涨,48GB 的余量让你不必写切片和拼接逻辑,顺带把片段边界的音色漂移问题一起省掉。
翻新到 torch 2.x,把 30 步反扩散做成常驻批量服务
RTX 4090 24GB$0.540/卡·时
论文在 GPU 上给出 ML-30 的 RTF 约 0.5、ML-6 约 0.1,换到 Ada 架构上只会更好;24GB 足够让 DiffVC、HiFi-GAN、说话人编码器同时常驻再开并发。
03 —
四步在 NexGPU 上把 DiffVC 跑起来
从开机到听见第一段转换音频,卡上的时间不超过二十分钟
- 01
开一台带 CUDA 的实例,拉代码
在 console.nexgpu.net 选卡,先试水就用 Tesla V100 32GB($0.188/卡·时),镜像从 2000+ 预置里挑现成的 PyTorch。按秒计费、无最低消费、不用申请配额,SSH/Jupyter/Web 终端都通。DiffVC 的官方入口本来就是一个 notebook,直接用 Jupyter 最顺手。注意仓库是整个 Speech-Backbones,DiffVC 只是其中一个子目录,同级还有 Grad-TTS 和 SPIRAL。
git clone https://github.com/huawei-noah/Speech-Backbones.git && cd Speech-Backbones/DiffVC - 02
别照抄 requirements.txt
那份依赖是 2022 年钉死的:torch==1.7.1 配 torchaudio==0.5.1(这两个版本本身就对不上),librosa==0.6.0、numpy==1.19.0 在今天装都装不上。装当前版本,然后只改两处调用:inference.ipynb 里的 mel_basis = librosa_mel_fn(22050, 1024, 80, 0, 8000) 在 librosa 0.10+ 必须改成关键字写法 librosa.filters.mel(sr=22050, n_fft=1024, n_mels=80, fmin=0, fmax=8000);librosa.core.load 与 librosa.core.stft 换成 librosa.load 与 librosa.stft。模型代码本身是纯 PyTorch 加 einops,在 torch 2.x 上零改动。
pip install torch torchaudio einops 'librosa>=0.10' numpy scipy webrtcvad tgt tqdm - 03
补齐两个 checkpoint,第三个仓库自带
checkpts/spk_encoder/pretrained.pt 随仓库下发,不用管。要下的是 checkpts/vc/ 下的转换模型(LibriTTS 版 Drive ID 18Xbme0CTVo58p2vOHoTQm8PBGW7oEjAy,VCTK 版 12s9RPmwp9suleMkBCVetD8pub7wsDAy4)和 checkpts/vocoder/ 下的 HiFi-GAN 通用声码器(Drive ID 10khlrM645pTbQ4rc2aNEYPba8RFDBkW-)。声码器那份解开后要让 checkpts/vocoder/ 里同时有 config.json 和 generator 两个文件,notebook 是按这两个名字读的。想自己重训解码器的话,编码器权重 Drive ID 是 1JdoC5hh7k6Nz_oTcumH0nXNEib-GDbSq,放进 logs_enc/。
pip install gdown && mkdir -p checkpts/vc checkpts/vocoder && gdown 18Xbme0CTVo58p2vOHoTQm8PBGW7oEjAy -O checkpts/vc/vc_libritts_wodyn.pt - 04
跑一次转换,然后修掉 notebook 里那行 bug
推理是两次前向:DiffVC 出 mel,HiFi-GAN 出波形,源音频和参考音频各走一遍 get_mel,参考音频还要多走一遍 get_embed 拿 256 维说话人向量。跑通之后一定要回头看转换那个 cell——mel_synth_np 和 mel_source_np 两行取的都是 mel_,后一行本该是 mel_source。结果就是紧接着的 mel_spectral_subtraction 拿合成 mel 去减它自己,那步底噪抑制完全空转。把它改成 mel_source.cpu().detach().squeeze().numpy() 再听一遍,沙沙声会明显收敛。
mel_encoded, mel_ = generator.forward(mel_source, mel_source_lengths, mel_target, mel_target_lengths, embed_target, n_timesteps=30, mode='ml')
算笔账:两小时转完 1000 句,和一周复现官方训练
先说便宜的一头。论文在 GPU 上给出 ML-30 的 RTF 约 0.5,也就是 10 秒音频大约占 5 秒 GPU 时间;1000 条 10 秒语音的纯转换约 5000 秒,加上 mel 与 speaker embedding 预处理、模型加载,按 2 小时算——Tesla V100 32GB 是 2 × $0.188 = $0.376。 再说重的一头。train_dec.py 默认 epochs=110、batch_size=32、learning_rate=1e-4,在 RTX 3090 24GB 上按 72 小时(3 天)估:72 × $0.193 = $13.90。数据是大头:论文说训练用了约 1100 位说话人,而 LibriTTS 的 train-clean-100 加 train-clean-360 正好 1151 位、约 245 小时;重采样到 22.05kHz 的 wavs 约 39GB,预先算好的 mel(80 × T 的 float32)约 24GB,speaker embeds 可以忽略,合计约 65GB。按 $0.414/GB·月 存一周是 65 × 0.414 × 7/30 ≈ $6.28。 还有一笔最容易被忽略的。train_dec.py 里 save_every=1,每个 epoch 都会 torch.save 一份完整 state_dict,一份约 0.5GB,110 个 epoch 就是 55GB,一周存储 55 × 0.414 × 7/30 ≈ $5.31。一周总账 $13.90 + $6.28 + $5.31 ≈ $25.49,训练算力只占五成半。这也正是 NexGPU 计费上要提醒的一点:实例一停,算力立刻停止计费,但存储卷会一直计到你销毁为止——训练跑完记得只留最后几个 checkpoint,把数据卷清掉再走。
04 —
