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

463 lines
12 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# VoxCPM 微调指南
本指南介绍了如何使用全量微调Full Fine-tuning和 LoRA 微调两种方式对 VoxCPM 模型进行微调。
### 🎓 SFT (监督微调)
全量微调会更新所有模型参数。适用于:
- 📊 大型、专业的数据集
- 🔄 需要显著改变模型行为的场景
### ⚡ LoRA 微调
LoRA (Low-Rank Adaptation) 是一种参数高效的微调方法,它:
- 🎯 仅训练少量额外参数
- 💾 显著降低显存需求和训练时间
- 🔀 支持多个 LoRA 适配器热插拔
## 目录
- [快速开始WebUI](#快速开始webui)
- [数据准备](#数据准备)
- [全量微调](#全量微调)
- [LoRA 微调](#lora-微调)
- [推理](#推理)
- [LoRA 热插拔](#lora-热插拔)
- [常见问题](#常见问题)
---
## 快速开始WebUI
对于喜欢图形界面的用户,我们提供了 `lora_ft_webui.py` —— 一个用于训练和推理的综合 WebUI
### 启动 WebUI
```bash
python lora_ft_webui.py
```
然后在浏览器中打开 `http://localhost:7860`
### 功能特点
- **🚀 训练标签页**:通过直观的界面配置并启动 LoRA 训练
- 设置训练参数学习率、Batch Size、LoRA Rank 等)
- 实时监控训练进度
- 从现有断点恢复训练
- **🎵 推理标签页**:使用训练好的模型生成音频
- 从 LoRA 检查点配置自动加载基座模型
- 带自动 ASR参考文本识别的声音克隆
- 在多个 LoRA 模型间热切换
- 无参考音频的零样本 TTS
## 数据准备
训练数据应准备为 JSONL 清单文件,每行一个样本:
```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`
```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
```
### 训练
```bash
# 单 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`
```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/2``r` |
| `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`。
### 训练
```bash
# 单 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` 包含:
```json
{
"base_model": "/path/to/VoxCPM1.5/",
"lora_config": {
"enable_lm": true,
"enable_dit": true,
"r": 32,
"alpha": 16,
...
}
}
```
`base_model` 字段包含:
- 本地路径 (默认):当 `distribute: false` 或未设置时
- HuggingFace ID`distribute: true` 时 (例如 `"openbmb/VoxCPM1.5"`)
这允许在没有原始训练配置文件的情况下加载 LoRA 检查点。
---
## 推理
### 全量微调推理
检查点目录是一个完整的模型,直接加载:
```bash
python scripts/test_voxcpm_ft_infer.py \
--ckpt_dir /path/to/checkpoints/finetune_all/step_0002000 \
--text "你好,这是微调后的模型。" \
--output output.wav
```
带声音克隆:
```bash
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` 读取):
```bash
python scripts/test_voxcpm_lora_infer.py \
--lora_ckpt /path/to/checkpoints/finetune_lora/step_0002000 \
--text "你好,这是 LoRA 微调的结果。" \
--output lora_output.wav
```
带声音克隆:
```bash
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
```
覆盖基座模型路径 (可选)
```bash
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 参考
```python
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`(由训练脚本保存),你可以自动加载所有内容:
```python
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,
)
```
或者直接使用测试脚本:
```bash
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/2``alpha = 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.json``audiovae.pth`
- LoRA检查点目录应包含
- `lora_weights.safetensors` (或 `lora_weights.ckpt`) - LoRA 权重
- `lora_config.json` - LoRA 配置和基座模型路径