Files
VoxCPM-use/docs/finetune.md
2025-12-11 00:12:18 +08:00

12 KiB
Raw Permalink Blame History

VoxCPM 微调指南

本指南介绍了如何使用全量微调Full Fine-tuning和 LoRA 微调两种方式对 VoxCPM 模型进行微调。

🎓 SFT (监督微调)

全量微调会更新所有模型参数。适用于:

  • 📊 大型、专业的数据集
  • 🔄 需要显著改变模型行为的场景

LoRA 微调

LoRA (Low-Rank Adaptation) 是一种参数高效的微调方法,它:

  • 🎯 仅训练少量额外参数
  • 💾 显著降低显存需求和训练时间
  • 🔀 支持多个 LoRA 适配器热插拔

目录


快速开始WebUI

对于喜欢图形界面的用户,我们提供了 lora_ft_webui.py —— 一个用于训练和推理的综合 WebUI

启动 WebUI

python lora_ft_webui.py

然后在浏览器中打开 http://localhost:7860

功能特点

  • 🚀 训练标签页:通过直观的界面配置并启动 LoRA 训练

    • 设置训练参数学习率、Batch Size、LoRA Rank 等)
    • 实时监控训练进度
    • 从现有断点恢复训练
  • 🎵 推理标签页:使用训练好的模型生成音频

    • 从 LoRA 检查点配置自动加载基座模型
    • 带自动 ASR参考文本识别的声音克隆
    • 在多个 LoRA 模型间热切换
    • 无参考音频的零样本 TTS

数据准备

训练数据应准备为 JSONL 清单文件,每行一个样本:

{"audio": "path/to/audio1.wav", "text": "音频1的文本内容。"}
{"audio": "path/to/audio2.wav", "text": "音频2的文本内容。"}
{"audio": "path/to/audio3.wav", "text": "可选的时长字段。", "duration": 3.5}
{"audio": "path/to/audio4.wav", "text": "多数据集训练可选的 dataset_id。", "dataset_id": 1}

必填字段

字段 描述
audio 音频文件路径(绝对或相对路径)
text 对应的文本内容

可选字段

字段 描述
duration 音频时长(秒),用于加速样本过滤
dataset_id 多数据集训练的数据集 ID默认0

要求

  • 音频格式WAV
  • 采样率VoxCPM-0.5B 为 16kHzVoxCPM1.5 为 44.1kHz
  • 文本:与音频内容匹配的文本

查看 examples/train_data_example.jsonl 获取完整示例。


全量微调

全量微调更新所有模型参数。适用于大数据集或需要显著改变模型行为的情况。

配置

创建 conf/voxcpm_v1.5/voxcpm_finetune_all.yaml

pretrained_path: /path/to/VoxCPM1.5/
train_manifest: /path/to/train.jsonl
val_manifest: ""

sample_rate: 44100
batch_size: 16
grad_accum_steps: 1
num_workers: 2
num_iters: 2000
log_interval: 10
valid_interval: 1000
save_interval: 1000

learning_rate: 0.00001   # 全量微调使用较小的学习率
weight_decay: 0.01
warmup_steps: 100
max_steps: 2000
max_batch_tokens: 8192

save_path: /path/to/checkpoints/finetune_all
tensorboard: /path/to/logs/finetune_all

lambdas:
  loss/diff: 1.0
  loss/stop: 1.0

训练

# 单 GPU
python scripts/train_voxcpm_finetune.py --config_path conf/voxcpm_v1.5/voxcpm_finetune_all.yaml

# 多 GPU
CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 \
    scripts/train_voxcpm_finetune.py --config_path conf/voxcpm_v1.5/voxcpm_finetune_all.yaml

检查点结构

全量微调保存完整的模型目录,可以直接加载:

checkpoints/finetune_all/
└── step_0002000/
    ├── model.safetensors     # 模型权重 (不含 audio_vae)
    ├── config.json            # 模型配置
    ├── audiovae.pth           # Audio VAE 权重
    ├── tokenizer.json         # Tokenizer
    ├── tokenizer_config.json
    ├── special_tokens_map.json
    ├── optimizer.pth
    └── scheduler.pth

LoRA 微调

LoRA (Low-Rank Adaptation) 是一种参数高效的微调方法,仅训练少量额外参数,显著降低显存需求。

配置

创建 conf/voxcpm_v1.5/voxcpm_finetune_lora.yaml

pretrained_path: /path/to/VoxCPM1.5/
train_manifest: /path/to/train.jsonl
val_manifest: ""

sample_rate: 44100
batch_size: 16
grad_accum_steps: 1
num_workers: 2
num_iters: 2000
log_interval: 10
valid_interval: 1000
save_interval: 1000

learning_rate: 0.0001    # LoRA 可以使用较大的学习率
weight_decay: 0.01
warmup_steps: 100
max_steps: 2000
max_batch_tokens: 8192

save_path: /path/to/checkpoints/finetune_lora
tensorboard: /path/to/logs/finetune_lora

lambdas:
  loss/diff: 1.0
  loss/stop: 1.0

# LoRA 配置
lora:
  enable_lm: true        # 对语言模型应用 LoRA
  enable_dit: true       # 对 Diffusion Transformer 应用 LoRA
  enable_proj: false     # 对投影层应用 LoRA (可选)
  
  r: 32                  # LoRA rank (越高容量越大)
  alpha: 16              # LoRA alpha, scaling = alpha / r
  dropout: 0.0
  
  # 目标模块
  target_modules_lm: ["q_proj", "v_proj", "k_proj", "o_proj"]
  target_modules_dit: ["q_proj", "v_proj", "k_proj", "o_proj"]

# 分发选项 (可选)
# hf_model_id: "openbmb/VoxCPM1.5"  # HuggingFace ID
# distribute: true                   # 如果为 true在 lora_config.json 中保存 hf_model_id

LoRA 参数

参数 描述 推荐值
enable_lm 对 LM (语言模型) 应用 LoRA true
enable_dit 对 DiT (扩散模型) 应用 LoRA true (声音克隆必须)
r LoRA rank (越高容量越大) 16-64
alpha 缩放因子, scaling = alpha / r 通常 r/2r
target_modules_* 添加 LoRA 的层名称 attention layers

分发选项 (可选)

参数 描述 默认值
hf_model_id HuggingFace 模型 ID (例如 openbmb/VoxCPM1.5) ""
distribute 如果为 true,将 hf_model_id 作为 base_model 保存到检查点;否则保存本地 pretrained_path false

注意:如果 distribute: true,则必须提供 hf_model_id

训练

# 单 GPU
python scripts/train_voxcpm_finetune.py --config_path conf/voxcpm_v1.5/voxcpm_finetune_lora.yaml

# 多 GPU
CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun --nproc_per_node=4 \
    scripts/train_voxcpm_finetune.py --config_path conf/voxcpm_v1.5/voxcpm_finetune_lora.yaml

检查点结构

LoRA 训练保存 LoRA 参数和配置:

checkpoints/finetune_lora/
└── step_0002000/
    ├── lora_weights.safetensors    # 仅含 lora_A, lora_B 参数
    ├── lora_config.json            # LoRA 配置 + 基座模型路径
    ├── optimizer.pth
    └── scheduler.pth

lora_config.json 包含:

{
  "base_model": "/path/to/VoxCPM1.5/",
  "lora_config": {
    "enable_lm": true,
    "enable_dit": true,
    "r": 32,
    "alpha": 16,
    ...
  }
}

base_model 字段包含:

  • 本地路径 (默认):当 distribute: false 或未设置时
  • HuggingFace IDdistribute: true 时 (例如 "openbmb/VoxCPM1.5")

这允许在没有原始训练配置文件的情况下加载 LoRA 检查点。


推理

全量微调推理

检查点目录是一个完整的模型,直接加载:

python scripts/test_voxcpm_ft_infer.py \
    --ckpt_dir /path/to/checkpoints/finetune_all/step_0002000 \
    --text "你好,这是微调后的模型。" \
    --output output.wav

带声音克隆:

python scripts/test_voxcpm_ft_infer.py \
    --ckpt_dir /path/to/checkpoints/finetune_all/step_0002000 \
    --text "这是声音克隆的结果。" \
    --prompt_audio /path/to/reference.wav \
    --prompt_text "参考音频的文本内容" \
    --output cloned_output.wav

LoRA 推理

LoRA 推理只需要检查点目录(基座模型路径和 LoRA 配置从 lora_config.json 读取):

python scripts/test_voxcpm_lora_infer.py \
    --lora_ckpt /path/to/checkpoints/finetune_lora/step_0002000 \
    --text "你好,这是 LoRA 微调的结果。" \
    --output lora_output.wav

带声音克隆:

python scripts/test_voxcpm_lora_infer.py \
    --lora_ckpt /path/to/checkpoints/finetune_lora/step_0002000 \
    --text "这是带 LoRA 的声音克隆。" \
    --prompt_audio /path/to/reference.wav \
    --prompt_text "参考音频的文本内容" \
    --output cloned_output.wav

覆盖基座模型路径 (可选)

python scripts/test_voxcpm_lora_infer.py \
    --lora_ckpt /path/to/checkpoints/finetune_lora/step_0002000 \
    --base_model /path/to/another/VoxCPM1.5 \
    --text "使用不同的基座模型。" \
    --output output.wav

LoRA 热插拔

LoRA 支持在推理时动态加载、卸载和切换,无需重新加载整个模型。

API 参考

from voxcpm.core import VoxCPM
from voxcpm.model.voxcpm import LoRAConfig

# 1. 加载带 LoRA 结构和权重的模型
lora_cfg = LoRAConfig(
    enable_lm=True, 
    enable_dit=True, 
    r=32, 
    alpha=16,
    target_modules_lm=["q_proj", "v_proj", "k_proj", "o_proj"],
    target_modules_dit=["q_proj", "v_proj", "k_proj", "o_proj"],
)
model = VoxCPM.from_pretrained(
    hf_model_id="openbmb/VoxCPM1.5",  # 或本地路径
    load_denoiser=False,              # 可选:禁用降噪器以加快加载
    optimize=True,                    # 启用 torch.compile 加速
    lora_config=lora_cfg,
    lora_weights_path="/path/to/lora_checkpoint",
)

# 2. 生成音频
audio = model.generate(
    text="你好,这是 LoRA 微调的结果。",
    prompt_wav_path="/path/to/reference.wav",  # 可选:用于声音克隆
    prompt_text="参考音频的文本内容",            # 可选:用于声音克隆
)

# 3. 禁用 LoRA (仅使用基座模型)
model.set_lora_enabled(False)

# 4. 重新启用 LoRA
model.set_lora_enabled(True)

# 5. 卸载 LoRA (重置权重为零)
model.unload_lora()

# 6. 热切换到另一个 LoRA
loaded, skipped = model.load_lora("/path/to/another_lora_checkpoint")
print(f"Loaded {len(loaded)} params, skipped {len(skipped)}")

# 7. 获取当前 LoRA 权重
lora_state = model.get_lora_state_dict()

简化用法 (从 lora_config.json 加载)

如果你的检查点包含 lora_config.json(由训练脚本保存),你可以自动加载所有内容:

import json
from voxcpm.core import VoxCPM
from voxcpm.model.voxcpm import LoRAConfig

# 从检查点加载配置
lora_ckpt_dir = "/path/to/checkpoints/finetune_lora/step_0002000"
with open(f"{lora_ckpt_dir}/lora_config.json") as f:
    lora_info = json.load(f)

base_model = lora_info["base_model"]
lora_cfg = LoRAConfig(**lora_info["lora_config"])

# 加载带 LoRA 的模型
model = VoxCPM.from_pretrained(
    hf_model_id=base_model,
    lora_config=lora_cfg,
    lora_weights_path=lora_ckpt_dir,
)

或者直接使用测试脚本:

python scripts/test_voxcpm_lora_infer.py \
    --lora_ckpt /path/to/checkpoints/finetune_lora/step_0002000 \
    --text "Hello world"

方法参考

方法 描述 torch.compile 兼容性
load_lora(path) 从文件加载 LoRA 权重
set_lora_enabled(bool) 启用/禁用 LoRA
unload_lora() 将 LoRA 权重重置为初始值
get_lora_state_dict() 获取当前 LoRA 权重
lora_enabled 属性:检查是否配置了 LoRA

常见问题 (FAQ)

1. 显存溢出 (OOM)

  • 增加 grad_accum_steps (梯度累积步数)
  • 减小 batch_size
  • 使用 LoRA 微调代替全量微调
  • 减小 max_batch_tokens 以过滤长样本

2. LoRA 效果不佳

  • 增加 r (LoRA rank)
  • 调整 alpha (尝试 alpha = r/2alpha = r)
  • 增加训练步数
  • 添加更多目标模块

3. 训练不收敛

  • 减小 learning_rate (学习率)
  • 增加 warmup_steps
  • 检查数据质量

4. LoRA 在推理时未生效

  • 检查检查点目录下是否存在 lora_config.json
  • 检查 load_lora() 返回值 - skipped_keys 应该为空
  • 确认调用了 set_lora_enabled(True)

5. 检查点加载错误

  • 全量微调:检查点目录应包含 model.safetensors (或 pytorch_model.bin)、config.jsonaudiovae.pth
  • LoRA检查点目录应包含
    • lora_weights.safetensors (或 lora_weights.ckpt) - LoRA 权重
    • lora_config.json - LoRA 配置和基座模型路径