PyTorch模型输出形状不匹配求助:期望[64,1]却得到[64,64,1]
问题描述
运行batch size为64、DNA序列长度1000的神经网络模型,DNA序列采用独热编码(张量结构为(1000,4)),训练时触发以下警告:
UserWarning: Using a target size (torch.Size([64, 1])) that is different to the input size (torch.Size([64, 64, 1]))
期望模型输出形状为torch.Size([64,1]),但实际输出为torch.Size([64,64,1])。
模型代码如下:
class model_test(nn.Module): # deepcre model def __init__(self, seq_len: int =1000, kernel_size: int = 8, p = 0.25): # drop out value super().__init__() self.seq_len = seq_len # adjusting window size corresponding to sequence length window_size = int(seq_len*(8/3000)) # 8/3 =^ 2.6 # CNN module self.conv11 = Conv1d(4,64,kernel_size=(kernel_size),stride = 1,padding = 1) self.relu11 = ReLU() self.maxpool1 = MaxPool1d(kernel_size=window_size) self.Dropout1 = Dropout(p) self.fc1 =Linear(497,1) #batch_size_init*(seq_len//window_size) , 1) # 1000-2*1-1/2 def forward(self, x): """Forward pass.""" x = x.permute(0,2,1) x = self.conv11(x) x = self.relu11(x) x = self.maxpool1(x) x = self.Dropout1(x) x = self.fc1(x) return x
问题分析
输出维度不匹配的核心原因是全连接层的输入维度逻辑错误:
- 输入张量经过
permute(0,2,1)后,形状变为(64,4,1000)(batch_size=64,通道数4,序列长度1000) - 经过
Conv1d后,输出序列长度计算为(1000 -8 +2*1)//1 +1 = 995,形状变为(64,64,995) MaxPool1d使用window_size=2,池化后序列长度为995//2=497,形状变为(64,64,497)- 此时直接接入
Linear(497,1),PyTorch的Linear仅对最后一个维度做变换,输出形状变为(64,64,1),与目标(64,1)不匹配。
解决方法
方案1:全局池化压缩通道维度(推荐)
在Dropout后添加全局平均/最大池化,将通道维度的特征压缩为单值,再接入全连接层:
修改forward函数:
def forward(self, x): """Forward pass.""" x = x.permute(0,2,1) x = self.conv11(x) x = self.relu11(x) x = self.maxpool1(x) x = self.Dropout1(x) # 全局平均池化,将(64,64,497)转为(64,64) x = torch.mean(x, dim=2) # 也可使用全局最大池化:x = torch.max(x, dim=2)[0] x = self.fc1(x) return x
修改全连接层输入维度:
self.fc1 = Linear(64,1)
最终输出形状为(64,1),符合要求,且参数数量适中,避免过拟合。
方案2:展平维度后接入全连接层
将池化后的三维张量展平为二维,再用对应输入维度的全连接层输出单值:
修改forward函数:
def forward(self, x): """Forward pass.""" x = x.permute(0,2,1) x = self.conv11(x) x = self.relu11(x) x = self.maxpool1(x) x = self.Dropout1(x) # 展平通道与序列维度:(64,64,497) -> (64,64*497) x = x.flatten(start_dim=1) x = self.fc1(x) return x
修改全连接层输入维度:
self.fc1 = Linear(64*497,1)
此方法保留所有空间特征,但参数数量大幅增加,容易引发过拟合,需配合更强的正则化手段。
方案3:调整池化窗口至序列长度为1
修改池化窗口大小,让池化后序列长度变为1,再挤压通道维度:
修改__init__中的池化层:
self.maxpool1 = MaxPool1d(kernel_size=497) # 池化后序列长度为1
修改forward函数:
def forward(self, x): """Forward pass.""" x = x.permute(0,2,1) x = self.conv11(x) x = self.relu11(x) x = self.maxpool1(x) x = self.Dropout1(x) x = self.fc1(x) # 输出形状(64,64,1) x = torch.mean(x, dim=1) # 挤压通道维度至(64,1) return x
修改全连接层:
self.fc1 = Linear(1,1)
此方法逻辑繁琐,灵活性差,不推荐使用。
内容的提问来源于stack exchange,提问作者Jin_soo
相关产品推荐
相关产品推荐

