为何小数据集上微调MLP后测试精度与预训练模型一致?
问题:MLP微调后性能无变化的原因及代码修正
我基于6k样本训练了一个简单MLP模型,测试集精度达96.80%,保存权重为model_weights.pth。随后用50个样本(finetune_loader)微调模型,但微调后测试集精度与预训练时完全一致,输出概率也无变化。相关代码如下:
模型定义
class MLP(nn.Module): def __init__(self,input_dim=92, hidden_dim = 150, num_classes=2): super().__init__() self.input_dim = input_dim self.num_classes = num_classes self.hidden_dim = hidden_dim #self.softmax = nn.Softmax(dim=1) self.layers = nn.Sequential( nn.Linear(self.input_dim, self.hidden_dim), nn.ReLU(), nn.Linear(self.hidden_dim, self.hidden_dim), nn.ReLU(), nn.Linear(self.hidden_dim, self.hidden_dim), nn.ReLU(), nn.Linear(self.hidden_dim, self.num_classes), ) def forward(self, x): x = self.layers(x) return x
预训练超参数与模型初始化
num_epoch = 300 # 200e3//len(train_loader) learning_rate = 1e-3 batch_size = 64 device = torch.device("cuda") SEED = 42 torch.manual_seed(42) model = MLP(input_dim=input_dim, hidden_dim=hidden_dim, num_classes=num_classes).to(device) optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate, weight_decay=1e-4) criterion = nn.CrossEntropyLoss()
微调代码
model_finetune = MLP() model_finetune.load_state_dict(torch.load('model_weights.pth')) model_finetune.to(device) model_finetune.train() # train the network for t in tqdm(range(num_epoch)): for i, data in enumerate(finetune_loader, 0): #def closure(): # Get and prepare inputs inputs, targets = data inputs, targets = inputs.float(), targets.long() inputs, targets = inputs.to(device), targets.to(device) # Zero the gradients optimizer.zero_grad() # Perform forward pass outputs = model_finetune(inputs) # Compute loss loss = criterion(outputs, targets) # Perform backward pass loss.backward() #return loss optimizer.step() # a model_finetune.eval() with torch.no_grad(): outputs2 = model_finetune(test_data) #predicted_labels = outputs.squeeze().tolist() _, preds = torch.max(outputs2, 1) prediction_test = np.array(preds.cpu()) accuracy_test_finetune = accuracy_score(y_test, prediction_test) accuracy_test_finetune Output: 0.9680851063829787
核心问题:优化器绑定对象错误
你的微调代码存在致命错误:使用的optimizer是预训练时绑定原model参数的优化器,而非微调模型model_finetune的参数。这意味着optimizer.step()更新的是原模型的权重,而非你加载的微调模型,导致model_finetune的权重完全没被修改,性能自然和预训练时一致。
修正方案
1. 重新初始化优化器,绑定微调模型参数
在微调部分,必须为model_finetune单独创建优化器,且建议使用更小的学习率(避免破坏预训练的有效权重):
model_finetune = MLP() model_finetune.load_state_dict(torch.load('model_weights.pth')) model_finetune.to(device) model_finetune.train() # 关键:为微调模型重新创建优化器 optimizer = torch.optim.Adam(model_finetune.parameters(), lr=1e-4, weight_decay=1e-4) criterion = nn.CrossEntropyLoss() # 若预训练时已定义,可复用,但建议显式声明避免混淆 # train the network for t in tqdm(range(num_epoch)): running_loss = 0.0 for i, data in enumerate(finetune_loader, 0): inputs, targets = data inputs, targets = inputs.float(), targets.long() inputs, targets = inputs.to(device), targets.to(device) optimizer.zero_grad() # 清空当前模型的梯度 outputs = model_finetune(inputs) loss = criterion(outputs, targets) loss.backward() # 计算微调模型的梯度 optimizer.step() # 更新微调模型的权重 running_loss += loss.item() # 打印损失确认训练进程 print(f"Epoch {t+1}, Loss: {running_loss/len(finetune_loader):.4f}")
2. 额外注意事项
- 学习率设置:微调时学习率通常比预训练小1-2个数量级(比如从1e-3改为1e-4),防止预训练学到的特征被破坏。
- 数据验证:确认
finetune_loader加载的50个样本标签正确、数据格式与预训练一致,且已转移到指定设备(GPU)。 - 训练状态验证:通过打印每轮损失值,观察损失是否下降,确认训练确实在更新模型权重。
内容的提问来源于stack exchange,提问作者S.EB
相关产品推荐
相关产品推荐

