PyTorch训练共享分类器的VGG组合模型时报4维输入预期错误如何解决?
报错原因分析
该报错的核心是卷积层需要输入4维张量(格式为[批次大小, 通道数, 高度, 宽度]),但实际传入的是2维张量[128, 2048],具体触发点来自你代码里的3处致命错误:
- VGG16Classifier初始化逻辑错误:你定义的
VGG16Classifier的__init__参数为(num_classes=1,classifier = None,batch_norm=False),但实例化时传入了3个VGG16模型,导致参数对应完全错位,类内部依然会新建3个VGG16分支,你外部定义的model1/model2/model_star完全没有被用到。 - 自定义损失函数逻辑错误:
- 损失函数里调用了未定义的
self.loss_combo属性,属于笔误,应该是self.loss_star - 直接调用
model_star.weight、model1.weight是非法操作:VGG16类没有weight这个属性,模型权重分散在各个子模块中,直接取值会导致计算图异常,反向传播时出现路径错乱,把本该输入分类器的2维展平特征传回了卷积层,触发维度报错。
- 损失函数里调用了未定义的
- 训练函数变量名错误:你解压得到的数据集加载器变量是
loaders_star,但代码里多处写成loaders_s,同时epoch_accuracy["val"]也属于未定义变量,都会引发运行异常。
修复步骤
- 修正VGG16Classifier初始化逻辑,支持传入外部VGG16分支:
class VGG16Classifier(nn.Module): # 调整参数列表,接收三个外部VGG分支 def __init__(self, vgg_a, vgg_b, vgg_star, num_classes=1, classifier = None, batch_norm=False): super(VGG16Classifier, self).__init__() self._vgg_a = vgg_a self._vgg_b = vgg_b self._vgg_star = vgg_star self.classifier = classifier if (self.classifier is None): self.classifier = nn.Sequential( nn.Linear(2048, 2048), nn.ReLU(True), nn.Dropout(p=0.5), nn.Linear(2048, 512), nn.ReLU(True), nn.Dropout(p=0.5), nn.Linear(512, num_classes) ) def forward(self, x1,x2,x3): op1 = self._vgg_a(x1) op1 = torch.flatten(op1,1) op2 = self._vgg_b(x2) op2 = torch.flatten(op2,1) op3 = self._vgg_star(x3) op3 = torch.flatten(op3,1) x1 = self.classifier(op1) x2 = self.classifier(op2) x3 = self.classifier(op3) return x1,x2,x3
实例化代码调整为:
model1 = VGG16((1,32,32),batch_norm=True) model2 = VGG16((1,32,32),batch_norm=True) model_star = VGG16((1,32,32),batch_norm=True) model_combo = VGG16Classifier(model1,model2,model_star, num_classes=1)
- 修正自定义损失函数的逻辑错误:
class CombinedLoss(nn.Module): # 新增三个VGG分支的入参,避免调用全局变量 def __init__(self, loss_a, loss_b, loss_star, vgg1, vgg2, vgg_star, _lambda=1.0): super().__init__() self.loss_a = loss_a self.loss_b = loss_b self.loss_star = loss_star self.vgg1 = vgg1 self.vgg2 = vgg2 self.vgg_star = vgg_star self.register_buffer('_lambda',torch.tensor(float(_lambda),dtype=torch.float32)) # 工具方法:把模型所有参数展平为1维向量 def _flatten_params(self, model): return torch.cat([p.flatten() for p in model.parameters()]) def forward(self,y_hat,y): loss_cls = self.loss_a(y_hat[0],y[0]) + self.loss_b(y_hat[1],y[1]) + self.loss_star(y_hat[2],y[2]) # 计算参数正则项,修正原来的cdist用法错误 p1 = self._flatten_params(self.vgg1) p2 = self._flatten_params(self.vgg2) p_star = self._flatten_params(self.vgg_star) reg = self._lambda * torch.norm(p_star - (p1 + p2), p=2) ** 2 return loss_cls + reg
实例化损失函数时传入对应的模型:
# 示例用二分类交叉熵,可根据任务替换损失类型 criterion = CombinedLoss( loss_a=nn.BCEWithLogitsLoss(), loss_b=nn.BCEWithLogitsLoss(), loss_star=nn.BCEWithLogitsLoss(), vgg1=model1, vgg2=model2, vgg_star=model_star, _lambda=1.0 )
- 修正训练函数里的变量名:把所有
loaders_s替换为loaders_star,把未定义的epoch_accuracy["val"]替换为实际的验证精度变量,比如epoch_accuracy_star_val。
内容的提问来源于stack exchange,提问作者CasellaJr
相关产品推荐
相关产品推荐

