上次帮一个做法律问答的朋友调模型,他一开始直接全参微调,数据量不大,训了一整晚,验证集准确率反而掉了两个点。后来我帮他把 embedding 层和前 10 层 Transformer Block 全部冻住,只留下最后 4 层加输出头去训练,第二天早上指标回来了,还上涨了不少。这个经历让我意识到,很多人对“微调模型指定层参数”这件事没有概念,以为微调就是整盘接受、从头改到尾,但真正高效的场景里,指定层微调往往才是那根最该拔的杠杆。
这篇内容不局限于某个特定框架,我会把微调模型指定层参数的原理、实操代码、选层经验和避坑方法都讲清楚,覆盖 PyTorch 原生流程、HuggingFace Trainer 和 LLaMA-Factory 这类常用大模型微调工具。适合正在做大模型微调、迁移学习,或者被显存和算力卡住的朋友,读完至少你能自己动手实现“只训某些层,其余层全部冻结”。
1. 为什么会想“只微调某些层”:三种典型场景
1.1 领域迁移时最怕的“学新忘旧”
预训练模型本质上是一个在超大语料上长大的“通才”,它肚子里装了很多通用语法、常识推理和世界知识。当我们把它迁移到某个具体领域,比如法律、医疗、金融,真正需要它改变的是“表达方式和判断偏好”,而不是重新认识世界。全参微调相当于让这个通才把所有知识全部重写一遍,数据量不够时,轻则过拟合,重则灾难性遗忘——原来会做通用对话的能力被冲淡,新领域又没学好。
我自己做过一个对比实验:同一份财报问答数据集,全参微调和只调最后 6 层加 LayerNorm,在测试集上的得分几乎持平,但后者的训练时间只有前者的三分之一,过拟合程度也更低。原因不复杂,底层和中层编码的通用语言结构,你要它们改变反而容易破坏已有特征表达,冻结它们就是给模型“圈了一块重建区”,只允许它在靠近输出端的地方调整决策逻辑。
1.2 显存不够?冻结层是成本最低的减负方案之一
很多人的第一反应是上 LoRA 或在有限算力下硬扛全参微调。但如果你已经有现成的全参微调管线,只是想快速把模型改造成某个领域版本,冻结大部分层是一个几乎零成本、不需要引入额外依赖的思路。
算一笔账可能会改变你的认知。以 7B 参数的模型为例,用 AdamW 优化器全参微调时,除了模型本身的 FP16/BF16 权重,还要在显存里维护 FP32 的主权重副本、一阶动量、二阶动量。每参数字节数大概是:2 字节权重(BF16)+ 4 字节 FP32 主权重 + 4 字节动量 + 4 字节方差,也就是约 14 字节。7B 参数算下来光优化器状态和主权重副本就要接近 98GB 显存。如果你冻结 80% 的参数,这部分开销直接降到原来的 20% 左右,对单卡微调来说这是质的差别。
另外,分布式训练里优化器状态的同步通信量也会大幅下降。所以很多人在显存不够时第一反应是换更小模型,其实先冻结层往往能省下更多的资源开销。
1.3 指定层微调在微调技术谱系里的位置
现在说到大模型微调,大家讨论最多的三个词是提示工程、RAG 检索、模型微调。很多初学者会混淆:提示词不改变权重,RAG 用外部检索补充知识,而模型微调是把领域规律写进权重里。指定层微调就处在“全参微调”和“参数高效微调”之间。
全参微调更新所有参数,数据量和算力要求最高;LoRA、Adapter 这类参数高效微调只更新额外加的少量参数,但需要引入新依赖和额外的合并逻辑;指定层微调则是一种“次全参”方案——权重主体还是原来的结构,只是冻结一部分参数、保留另一部分更新。它比 LoRA 更容易调试,因为你能精确控制模型里哪些模块被改变,也更容易解释最终效果的差异来源。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 层参数微调的原理:先弄清参数在哪、怎么控制更新
2.1 Transformer 模型的参数分布与命名习惯
你要指定层,首先得知道层在代码里长什么样。以常见的 LLaMA 结构为例,用 HuggingFace Transformers 加载后,用 model.named_parameters() 打印出来的参数名大致是这个形态:
text复制model.embed_tokens.weight
model.layers.0.input_layernorm.weight
model.layers.0.self_attn.q_proj.weight
model.layers.0.self_attn.k_proj.weight
model.layers.0.self_attn.v_proj.weight
model.layers.0.self_attn.o_proj.weight
model.layers.0.mlp.gate_proj.weight
model.layers.0.mlp.up_proj.weight
model.layers.0.mlp.down_proj.weight
model.layers.0.post_attention_layernorm.weight
model.layers.1.input_layernorm.weight
...
model.norm.weight
lm_head.weight
BERT 类模型结构有些不同,但核心规律一致:
text复制bert.embeddings.word_embeddings.weight
bert.embeddings.positio
