HuggingFace中from_config与from_pretrained的差异及等效实现方法
测试所用代码如下:
num_labels = 3 if task.startswith("mnli") else 1 if task=="stsb" else 2 preconfig = DistilBertConfig(n_layers=6) model1 = AutoModelForSequenceClassification.from_config(preconfig) model2 = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=num_labels)
修改官方文本分类示例代码,目标是通过from_config方法测试DistilBERT的Transformer层深度对模型效果的影响。已知标准DistilBERT共6层Transformer结构,和原论文中“学生模型从教师模型每两层抽取一层完成初始化”的描述一致,计划测试更多不同层数配置的模型效果。
对照测试设置:参照DistilBertConfig文档说明,设置n_layers=6通过from_config初始化得到model1,同时通过from_pretrained加载对应模型检查点、设置匹配任务的num_labels得到model2,在SST-2数据集上测试两个模型的准确率,结果存在显著差异:
model1准确率仅为0.8073model2准确率达到0.901
核心疑问:
- 造成该效果差异的核心原因是什么?是否
model1仅为随机初始化未加载预训练权重? - 是否存在方法可以让同结构配置下两种方法初始化的模型表现一致?
核心原因
你的判断完全正确:from_config 仅会根据传入的配置对象搭建模型结构,所有权重都是随机初始化的,完全不会加载任何预训练参数,这就是10%精度差距的根本来源。
两个接口的设计目标完全不同:
from_config:只负责结构实例化,不涉及任何权重加载逻辑。哪怕你把n_layers设成和预训练模型完全一致的6,它生成的模型也是从头随机初始化的,在下游任务上微调相当于从零训练,SST-2二分类任务上随机初始化模型训几轮达到0.8左右的准确率是完全正常的水平。from_pretrained:会先匹配checkpoint对应的默认配置搭建结构,再加载checkpoint中存储的大规模语料预训练权重,你传入的num_labels这类自定义参数只会覆盖对应配置项,分类头因维度不匹配会随机初始化,但底层Transformer编码器的全部权重都是预训练好的,只需要少量微调就能达到很高的精度,也就是你测到的0.901的结果。
实现效果对齐、自定义层数测试的正确方法
如果要验证6层配置下两种初始化方式的效果一致,只需要在from_config实例化模型后,手动加载预训练权重即可,结构完全匹配时加载后精度和from_pretrained生成的模型没有区别:
num_labels = 3 if task.startswith("mnli") else 1 if task=="stsb" else 2 preconfig = DistilBertConfig(n_layers=6, num_labels=num_labels) model1 = AutoModelForSequenceClassification.from_config(preconfig) # 加载预训练权重 ref_model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=num_labels) model1.load_state_dict(ref_model.state_dict())
如果你要测试不同Transformer层数对模型效果的影响,不要直接用from_config生成随机初始化模型——这样得到的精度差是“是否用预训练权重”带来的,和层数无关。正确的做法是加载完整预训练模型后,手动裁剪Transformer层,保留对应层的预训练权重:
target_layer_num = 4 # 替换为你要测试的层数 model = AutoModelForSequenceClassification.from_pretrained(model_checkpoint, num_labels=num_labels) # 按需求选取对应层,比如取前N层,或者参考DistilBERT原论文逻辑隔层抽取 model.distilbert.transformer.layer = model.distilbert.transformer.layer[:target_layer_num] # 同步更新配置,避免后续保存、推理报错 model.config.n_layers = target_layer_num
用这种方式得到的不同层数模型,保留了对应层的预训练参数,测试得到的精度变化才是层数调整带来的真实影响。
内容的提问来源于stack exchange,提问作者strnlz

