原帖植物病害 CNN 的卷积结果展平后有 119072 个特征,而分类头写成 Linear(800,300):
RuntimeError: mat1 and mat2 shapes cannot be multiplied (32x119072 and 800x300)
两个矩阵内维已经说明冲突位置
32x119072 中的 32 是样本数,800x300 是第一层 Linear 权重转置参与运算时的形状。不能把 batch_size 改成 800 来对齐;要决定卷积特征是全部保留,还是有意池化到 800 维。
32 是 batch 数,119072 是每张图片实际展开后的特征数;800 是 Linear 期待的输入数。应在 Flatten 前确认特征图,再决定保留哪种模型设计。
把检查放到 self.fc_model(x) 前:
print("josh050608")
print("feature map:", x.shape)
print("flattened:", x.flatten(1).shape)
print("linear weight:", self.fc_model[1].weight.shape)
如果希望保留所有空间位置,把第一层 Linear 的 in_features 改为测得的每样本特征数,并在创建优化器前完成。原报错对应 119072,但不要把它套到另一输入分辨率。该方案会明显增大参数与内存,需要符合训练预算。
如果原本希望固定为 32×5×5=800,可以在卷积后显式加入自适应池化,保留原 Linear:
# __init__ 中添加:
self.pool_to_head = nn.AdaptiveAvgPool2d((5, 5))
# forward 中卷积后、fc_model 前执行:
x = self.pool_to_head(x)
x = self.fc_model(x)
这段需已有 from torch import nn。它改变空间汇聚方式,应重新训练,不能当成与保留全部特征等价。两种方案任选其一。
原模型末层还有 Softmax;若使用 CrossEntropyLoss,移除它,让分类头直接输出 38 类 logits。验证输出为 [N,38]、N 与 imgs 相同,普通 batch 和尾批均能计算损失并反向。
两种设计的参数规模相差很大
若直接使用 Linear(119072,300),仅权重就有 35,721,600 个元素;Linear(800,300) 为 240,000 个,两者内存与拟合能力不同。应按任务选择,不要仅为消除报错建立一个巨大分类头。
下面合成网络展示自适应池化方案,保留 32×5×5=800,再输出原题的 38 类。CPU 可运行,不下载病害图片:
import torch
from torch import nn
class PlantClassifier(nn.Module):
def __init__(self):
super().__init__()
self.features = nn.Sequential(nn.Conv2d(3, 16, 3), nn.ReLU(), nn.MaxPool2d(2),
nn.Conv2d(16, 32, 5), nn.ReLU(), nn.MaxPool2d(2))
self.pool = nn.AdaptiveAvgPool2d((5, 5))
self.head = nn.Sequential(nn.Flatten(), nn.Linear(800, 300), nn.ReLU(), nn.Linear(300, 38))
def forward(self, x):
return self.head(self.pool(self.features(x)))
model = PlantClassifier()
for count in (2, 1):
images = torch.randn(count, 3, 64, 64)
labels = torch.arange(count, dtype=torch.long)
model.zero_grad()
logits = model(images)
assert logits.shape == (count, 38)
loss = nn.CrossEntropyLoss()(logits, labels)
loss.backward()
assert model.head[1].weight.grad is not None
print("batch/output:", count, logits.shape)
这是有意改变特征汇聚的模型,需要重新训练。若选择保留全部特征,固定真实输入分辨率、测量展平宽度,并在创建优化器前完成 head 替换;不要在每次 forward 里新建 Linear,否则优化器可能拿不到新参数。
最后移除与 CrossEntropyLoss 重复的 Softmax,检查真实标签范围 0–37、数据集类别映射及尾批。尺寸匹配、有限 loss 和非空梯度一起通过,才能说明分类接口已经连通。
参考:原始求助帖;技术依据:Linear(2.5)、AdaptiveAvgPool2d(2.5)、CrossEntropyLoss(2.5)。