LoRA 微调和全量微调:VibeVoice 仓库只给了哪一种

2026-08-18

想把一个 ASR 模型调到自己那堆行话上,通常的第一个动作是去仓库里翻训练脚本,然后在「上 LoRA 还是全量」之间做个决定。VibeVoice 这边,这个决定其实不需要你做——仓库把它替你做完了,你需要判断的是它划下的这条边界会不会咬到你。

仓库把边界划在哪

docs/vibevoice-asr.md 的 Finetuning 一节只有一句话,写明支持 LoRA(Low-Rank Adaptation)微调,并把读者指向 finetuning-asr/README.md。仓库根 README 的 VibeVoice-ASR 板块里,Finetuning 那条链接指的也是同一个文件。

再看目录:整个仓库里带训练性质的 Python 脚本只有 finetuning-asr/lora_finetune.py 一个,同目录下另有 inference_lora.pyREADME.md 和一个 toy_dataset/全量微调的脚本、配置或说明,我们在仓库里没有找到——不是「不推荐」,是压根没有对应文件可读。

所以这篇不会去比「LoRA 和全量微调谁更划算」:一方有白纸黑字的代码,另一方在这个仓库里连一句描述都没有,没有依据的维度不比。能比的只有一件事——仓库给的这条路线,在数据、可训练范围、产物这三处各自要求你付出什么

另外把家族分清楚:finetuning-asr/ 下的脚本从头到尾针对的是 ASR 这一支,模型参数默认值是 microsoft/VibeVoice-ASR。TTS、Realtime 那几个模型的微调说明,我们在仓库里没有找到。

第一处:依赖不在 pyproject 里

finetuning-asr/README.md 的 Requirements 节写的是两步:

# Install vibevoice first
pip install -e .

pip install peft

第二行值得单独说一句。pyproject.tomldependencies 列表里有 torchtransformersacceleratelibrosa 这些,peft 不在里面optional-dependencies 里也只有一个 streamingtts 分组。也就是说装完主包并不会带上 peft,而 lora_finetune.py 顶部直接 from peft import LoraConfig, get_peft_model, ...。漏了第二行,脚本在 import 阶段就走不下去。

第二处:数据长什么样

这条路线对数据形态的要求写得相当具体。README 的 Data Format 节说明音频文件与同名 JSON 标注放在同一个目录里,0.mp30.json,依次类推。

JSON 的结构在 README 与 VibeVoiceASRDataset 的 docstring 里各写了一份,字段一致:

字段说明
audio_path音频文件名,_load_samples 用它拼出实际路径
audio_duration音频时长(秒)
segments分段列表,每段含 speakertextstartend
customized_context可选,领域术语或上下文句子

真正决定行为的是 _load_samples():它 glob("*.json") 遍历目录,以 JSON 为驱动,JSON 里没有 audio_path、或者按这个名字找不到音频文件,都只是打一条 warning 然后 continue。这意味着你少放几个音频不会报错中断,只会安静地少训几条——__init__ 末尾那句 Loaded {len(self.samples)} samples 是你唯一能对上数的地方。--max_audio_length 传了值的话,超过这个秒数的样本也会被跳过(audio_duration 缺失时按无穷大处理,也就是照样跳过)。

customized_context 这个字段和推理时的 hotwords 是同一条通路:__getitem__ 把列表用换行拼成一个字符串,作为 context_info 传给 processor;--use_customized_context 可以关掉它。README 表格里这一项写的是 True,这是仓库当前代码里的默认值,随版本可能变动。

还有一处别踩:README 明确写了 toy_dataset/ 里是 VibeVoice TTS 合成的音频,只作演示用,「不是一份完整的微调数据集」,并提示你换成真实录音与准确转写、按数据规模与领域调整学习率、epoch 与 LoRA rank。拿它当基线去判断效果是自己骗自己。

第三处:训练目标不是纯文本

这一点是 VibeVoice-ASR 微调和「随便找个 ASR 微调教程照做」差别最大的地方。_format_transcription() 把你 JSON 里的 segments 重新拼成模型要学的输出串,键名是首字母大写的 StartEndSpeakerContent,时间戳 round(..., 2),最后 json.dumps(..., ensure_ascii=False, separators=(',', ':')) 序列化成不带空格的紧凑 JSON。

也就是说,你的标注要负责的不只是「说了什么」,还有「谁在什么时候说的」,而且模型学的是一段结构化 JSON 文本__getitem__ 里把这段目标文本用 tokenizer.apply_chat_template 套上 assistant 角色再拼到输入后面,labels 前半段全填 -100,损失只落在这段回答上。

VibeVoiceASRDataCollator.__call__ 里那行注释也值得留意:processor 在推理/生成时用左 padding,训练这边用的是右 padding。它按三种长度基准把张量补齐——input_idsattention_masklabelsacoustic_input_maskmax_seq_lenspeech_tensors 按原始波形的 max_speech_lenspeech_masksmax_vae_len。你自己改 collator 时,这三条基准与各张量的对应关系是硬约束。

顺带一个读代码时会绊一下的地方:_format_transcription(self, segments, audio_duration) 收了 audio_duration 这个形参,但函数体里没有用到它;__getitem__ 调用时还为它准备了 data.get("audio_duration", len(speech) / 24000) 这样一个兜底。两处放在一起看就是:这个兜底目前不会影响生成的目标文本。仅此而已,不替作者解释为什么留着。

第四处:可训练的范围被钉死在语言模型侧

setup_model_for_training() 做了两件事。先按名字冻结:遍历 named_parameters(),凡名字里含 acoustic_tokenizersemantic_tokenizer 的一律 requires_grad = False,注释写的是「只想微调语言模型」。然后 get_peft_model(model, lora_config) 套上 LoRA,再调 print_trainable_parameters()

get_lora_config() 里,target_modules 形参默认 None,落到函数体里就是一份写死的列表:q_projk_projv_projo_projgate_projup_projdown_proj,注释标明这是 Qwen2 的注意力与 MLP 层。task_typeTaskType.CAUSAL_LMbias="none"

这里有个容易吃亏的点:README 说「脚本用的是 HuggingFace 的 TrainingArguments,所有标准选项都可用」,容易让人以为什么都能从命令行调。但 LoRA 侧只有 LoraArguments 这个 dataclass 暴露出来的 --lora_r--lora_alpha--lora_dropout 三个;train()get_lora_config()没有透传 target_modules,命令行里也没有对应参数。想换一组注入层,只能改 lora_finetune.py 的源码。

同一类「命令行说了不算」的还有一处:README 的参数表把 --gradient_checkpointing 记为 False,但 main()train(...) 时并没有把这个开关传下去,train() 签名里 gradient_checkpointing: bool = Truesetup_model_for_training() 据此调用 enable_input_require_grads()gradient_checkpointing_enable()。两处摆在一起就是不一致,我们只指出这一点,不推断它会带来什么后果。这两个值都是仓库当前文档与代码里的写法,随版本可能变动。

再补一条会咬 Windows 用户的:lora_finetune.pyinference_lora.py 加载模型时都把 attn_implementation="flash_attention_2" 写死在 from_pretrained 调用里,没有留命令行开关。环境里如果没有这个实现,改法只有一个——改源码。仓库里我们没有找到关于替换注意力实现的说明。

第五处:训完你手里拿到的是什么

README 的训练命令原样是这样(单卡那条):

torchrun --nproc_per_node=1 lora_finetune.py \
    --model_path microsoft/VibeVoice-ASR \
    --data_dir ./toy_dataset \
    --output_dir ./output \
    --num_train_epochs 3 \
    --per_device_train_batch_size 1 \
    --learning_rate 1e-4 \
    --bf16 \
    --report_to none

其中的 311e-4 是仓库示例里给的值,不是推荐配置,README 自己也让你按数据集调。以上命令原样抄自 finetuning-asr/README.md,未经实测,以仓库最新内容与 --help 的实际输出为准。

--output_dir 指向的目录,训完会被写进两样东西:trainer.save_model(training_args.output_dir) 存的是被 PEFT 包装过的模型(也就是 adapter 权重),processor.save_pretrained(training_args.output_dir) 把 processor 配置一并存进去。基座权重不在这里。

推理侧的用法与之对应,inference_lora.pyload_lora_model()from_pretrained 把基座 microsoft/VibeVoice-ASR load 起来(processor 那边还带了 language_model_pretrained_name="Qwen/Qwen2.5-7B"),再 PeftModel.from_pretrained(model, lora_path) 贴上 adapter。基座和 adapter 是两份东西,分发时得一起给。 脚本里 model.merge_and_unload() 那行是注释掉的;README 的 Merging LoRA Weights 节把它列为可选步骤,合并后 save_pretrained("./merged_model") 得到一份独立权重。

那么,怎么决定要不要走这条路

按上面几处倒推,判断顺序大致是这样:

  1. 你的标注里有没有 speaker 和时间戳? 没有的话,_format_transcription 需要的 start/end/speaker 就得先补出来,这往往比训练本身更费事。
  2. 你要动的是语言模型这一侧吗? 脚本冻结了两个 tokenizer、LoRA 只注入 Qwen2 的注意力与 MLP 层。如果你的问题出在音频前端,这条路线覆盖不到。
  3. 能不能接受改源码? target_modulesattn_implementation 都只能改代码。不能改的话,先想清楚。
  4. 产物形态能不能接受? 训练脚本没有传 eval_datasetTrainer 只拿到 train_dataset;评估、早停这类东西要你自己接。产物默认是 adapter,要独立权重得自己走一次 merge。

至于「全量微调会不会更合适」——这一点我们在 VibeVoice 仓库里没有找到任何依据,不比,也不推荐。

Windows 侧一句补充(通用做法,非该项目官方内容):README 里多卡那条命令写成 CUDA_VISIBLE_DEVICES=0,1,2,3 torchrun ...,这种把环境变量前置在命令前的写法是 POSIX shell 的语法,在 PowerShell 与 cmd 里不成立,需要按各自 shell 的方式先设好环境变量再执行。仓库里没有给 Windows 的对应说明,请结合自身环境评估。


本文依据 github.com/microsoft/VibeVoice 仓库与 Hugging Face 模型卡于 2026-08-18 的公开内容整理, 事实来自仓库内的文档与源码。我们没有下载权重、没有跑过推理、也没有做过训练, 因此不涉及显存占用、推理速度、识别准确率与音质的任何描述,也不与其它模型做比较或排名。 该项目持续更新,文中涉及的模块路径、配置字段与接口写法随版本变动,请以仓库最新内容为准。

需要说明的是:仓库 README 记载,2025-09-05 微软因发现有与既定意图不符的使用方式, 基于负责任 AI 原则从该仓库移除了 VibeVoice-TTS 代码; 当前 vibevoice/modular/modeling_vibevoice.py 首行注释标明其来自社区 fork, 且该模块未被 vibevoice/modular/__init__.py__all__ 导出。 本文只讲代码与架构,不构成 TTS 推理的可用性保证。

仓库 README 的风险与限制一节写明:该模型仅供研究与开发用途, 未经进一步测试与开发不建议用于商业或真实场景,并特别提示了合成语音被用于伪造与虚假信息的风险。 使用合成语音时应遵守所在司法辖区的法律法规,并在分享 AI 生成内容时主动披露。

本文对照的是同一项目内的两种用法,依据均为上述仓库内容,不对两种用法做优劣排名, 选型结论只在仓库文档写明的能力边界内成立。

安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。