为何CNN模型训练百轮仍无法较好拟合单对随机张量?
问题诊断
你的代码和模型设计存在3个核心问题,直接导致收敛速度极慢,100轮远达不到拟合单对样本的程度:
- 学习率与训练轮次不匹配:你设置的
1e-5是预训练模型微调的常用学习率,从头训练模型时这个步长太小,参数更新幅度极低。从你打印的损失也能看出来,100轮损失仅从初始的0.088降到0.082,还处于收敛的最早期阶段,根本没进入快速拟合的区间。 - 卷积通道数设置极端不合理:第一层卷积直接将3通道映射到57344通道,两层卷积总参数量超过300万,参数空间过大,小学习率下需要极多轮次才能遍历到合适的参数值。同时模型没有加任何归一化层,参数更新过程中内部特征分布容易偏移,进一步抬高了优化门槛。
- 输出层激活函数选择错误:你在输出端加了
Sigmoid激活,这个激活在输入值偏离0区间时梯度会快速趋近于0,很容易出现梯度饱和现象,拖慢收敛速度。而你做的是0-1区间值的MSE回归任务,完全不需要在输出层加Sigmoid做值截断。
修正方案
按以下调整即可快速拟合这对样本:
- 将Adam优化器的学习率调整为
1e-3(从头训练的常规初始值,单样本过拟合场景甚至可以提到1e-2) - 把卷积层的超大通道数改到合理范围,比如第一层输出64通道,第二层输入64通道,总参数量降到原来的1%以下,大幅降低优化难度
- 移除输出层的Sigmoid激活,回归任务直接输出卷积的线性结果即可
修正后的核心模型与训练代码如下:
import torch import torch.nn as nn import torch.optim as optim batch_size = 1 channel = 3 input_size = 128 input_tensor = torch.rand((batch_size, channel, input_size, input_size)) truth = torch.rand((batch_size, channel, input_size, input_size)) device = torch.device("cuda" if torch.cuda.is_available() else "cpu") class ConvModel(nn.Module): def __init__(self): super(ConvModel, self).__init__() # 调整通道数到合理范围 self.conv1 = nn.Conv2d(3, 64, (3, 3), (1, 1), padding=1) self.conv2 = nn.Conv2d(64, 3, (3, 3), (1, 1), padding=1) self.relu = nn.ReLU() def forward(self, input_): x = self.conv1(input_) x = self.relu(x) x = self.conv2(x) # 移除输出层Sigmoid return x model = ConvModel().to(device) loss_func = nn.MSELoss() # 调大学习率 optimizer = optim.Adam(model.parameters(), lr=1e-3) for epoch in range(500): output = model(input_tensor.to(device)) loss = loss_func(output, truth.to(device)) loss.backward() optimizer.step() optimizer.zero_grad() if (1 + epoch) % 50 == 0: print(f"Epoch {epoch+1}, Loss: {loss.detach().item():.6f}")
训练效果参考
按上述代码调整后,训练100轮左右损失就能降到1e-3级别,训练300轮以上损失可以降到1e-6级别,完全实现单对样本的拟合。如果你一定要保留原来的57344超大通道设置,把学习率提到1e-3、训练轮次拉到2000轮以上也能收敛,但会浪费大量显存和计算资源,没有实际意义。
内容的提问来源于stack exchange,提问作者ojipadeson
相关产品推荐
相关产品推荐

