You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

仿TinyVGG的CNN模型各Epoch损失与准确率无变化的优化咨询

解决手写单词分类模型训练无进展问题

针对你训练时所有Epoch损失和准确率完全不变的问题,结合你的代码和场景,可从以下几个关键方向修改:


1. 修正分类器输入维度匹配问题

你模型中分类器的in_features=hidden_units*16*16是硬编码值,仅适用于初始尺寸为64×64的图像(经过两次2×2池化后特征图变为16×16)。如果你的输入图像尺寸不符,会导致特征维度不匹配,模型无法正常传递梯度,最终输出固定值。

修改方案:
先通过随机张量测试特征图尺寸,再动态设置分类器输入维度:

# 初始化模型后,用与你的输入同尺寸的随机张量测试
torch.manual_seed(42)
dummy_input = torch.randn(1, 3, 64, 64).to(device)  # 替换为你的图像实际尺寸(通道数, 高, 宽)
with torch.inference_mode():
    # 仅运行特征提取部分,获取输出形状
    feat_map = model_2.block_2(model_2.block_1(dummy_input))
print(f"特征图形状: {feat_map.shape}")
in_features = feat_map.numel() // feat_map.shape[0]  # 计算单样本特征总数量

# 重新替换分类器
model_2.classifier = nn.Sequential(
    nn.Flatten(),
    nn.Linear(in_features=in_features, out_features=len(class_names))
).to(device)

2. 移除重复的模型设备迁移

你的train_step和test_step函数中每次循环都调用model.to(device),这会重复迁移模型,可能导致参数状态异常。只需在模型初始化时执行一次设备迁移即可。

修改方案:
删除train_step和test_step中的model.to(device)行,保留初始化时的迁移:

# 初始化时已完成设备迁移,后续无需重复操作
model_2 = CUSTOMDATASETV2(input_shape=3, hidden_units=10, output_shape=len(class_names)).to(device)

3. 验证损失函数与输入的兼容性

如果使用nn.CrossEntropyLoss,它要求输入是未经过softmax的logits,且标签为类别索引(而非one-hot向量)。需确认两点:

  • 你的loss_fn确实是nn.CrossEntropyLoss()
  • 数据集标签是类别索引(如0=TRUE、1=FALSE、2=NONE),而非one-hot编码

若标签是one-hot格式,需在数据加载时转换:

# 在数据加载循环中添加标签转换
X, y = X.to(device), y.argmax(dim=1).to(device)  # 将one-hot转为索引

4. 提升模型容量

手写单词的特征复杂度较高,当前模型hidden_units=10过小,TinyVGG基础结构可能不足以拟合数据。

调整方案:

  • 增加隐藏单元数量,例如改为32或64:
model_2 = CUSTOMDATASETV2(input_shape=3, hidden_units=32, output_shape=len(class_names)).to(device)
  • 可选:在分类器中添加一层全连接层,增强拟合能力:
self.classifier = nn.Sequential(
    nn.Flatten(),
    nn.Linear(in_features=in_features, out_features=hidden_units*2),
    nn.ReLU(),
    nn.Linear(in_features=hidden_units*2, out_features=output_shape)
)

5. 检查数据预处理与数据集质量

训练无进展的常见根源是数据问题:

  • 图像归一化:将像素值缩放到0-1范围(除以255),可加速模型收敛:
# 在数据转换管道中添加归一化
transform = transforms.Compose([
    transforms.Resize((64, 64)),  # 统一图像尺寸
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])  # 或直接除以255
])
  • 数据集验证:确认训练集/测试集包含所有三类数据,无类别缺失或比例失衡;随机抽查样本,确保标签与图像匹配。

6. 初始化与梯度检查

  • 优化卷积层参数初始化,避免梯度消失:
# 在模型__init__方法末尾添加初始化逻辑
def __init__(self, input_shape: int, hidden_units: int, output_shape: int):
    super().__init__()
    # ... 原有结构定义 ...
    
    # 初始化卷积层参数
    for m in self.modules():
        if isinstance(m, nn.Conv2d):
            nn.init.kaiming_normal_(m.weight, mode='fan_out', nonlinearity='relu')
            if m.bias is not None:
                nn.init.constant_(m.bias, 0)
  • 训练时可打印梯度均值,确认梯度是否正常更新(不为0或NaN):
# 在train_step的loss.backward()后添加
for name, param in model.named_parameters():
    if param.grad is not None:
        print(f"{name} 梯度均值: {param.grad.mean().item()}")

内容的提问来源于stack exchange,提问作者Llana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:04:58