PyTorch自定义DNN调用torchsummary报通道不匹配错误
错误原因
- 直接触发RuntimeError的原因是通道数不匹配:定义的第一层Conv1d
in_channels=2,要求输入张量通道数为2,但传入torchsummary的输入size是(1,892)、(1,492),对应单通道输入,卷积层拿到的输入通道数和权重期望的通道数不一致。PyTorch中Conv1d的输入维度顺序为(batch_size, in_channels, signal_length),定义卷积层时的in_channels必须和输入张量的通道维度严格对齐。 - 模型前向传播存在逻辑错误:第四层卷积之后错误调用了
self.pool3,没有使用已经定义好的self.pool4,会导致输出维度计算偏差。 - 张量拼接语法错误:
torch.cat(x,y,1)的写法不符合API要求,torch.cat需要将待拼接的张量存入列表/元组作为第一个参数传入,当前写法会把y错误识别为dim参数,运行时会触发参数类型错误。 - 全连接层输入维度硬编码错误:
fc1的in_features=3200是随机预估值,没有和卷积池化后的展平维度对齐,运行时会触发全连接层维度不匹配错误。
修复方案
- 先对齐输入通道数:如果两个分支输入是单通道时序信号,将第一层Conv1d的
in_channels改为1;如果输入是2通道信号,将torchsummary调用时的输入size改为(2,892)、(2,492)即可。以下修复以单通道输入为例。 - 修正前向传播中池化层的调用错误,第四层卷积后统一调用
self.pool4。 - 修正torch.cat的调用写法,将待拼接张量放入列表后传入。
- 移除fc1层硬编码的in_features值,在模型初始化时通过构造哑张量自动计算卷积池化后的展平维度,无需手动计算,后续修改卷积参数、输入长度时会自动适配,不会出现维度不匹配问题。
修正后的完整模型代码如下:
import torch from torch import nn import torch.nn.functional as F class myDNN(nn.Module): def __init__(self, x_len=892, y_len=492): super(myDNN, self).__init__() # 卷积与池化层定义 self.conv1 = nn.Conv1d(in_channels=1, out_channels=8, kernel_size=7) self.pool1 = nn.MaxPool1d(kernel_size=2, stride=2) self.conv2 = nn.Conv1d(in_channels=8, out_channels=16, kernel_size=3) self.pool2 = nn.MaxPool1d(kernel_size=2, stride=2) self.conv3 = nn.Conv1d(in_channels=16, out_channels=32, kernel_size=3) self.pool3 = nn.MaxPool1d(kernel_size=2, stride=2) self.conv4 = nn.Conv1d(in_channels=32, out_channels=64, kernel_size=3) self.pool4 = nn.MaxPool1d(kernel_size=2, stride=2) self.conv5 = nn.Conv1d(in_channels=64, out_channels=128, kernel_size=3) self.pool5 = nn.MaxPool1d(kernel_size=2, stride=2) self.flatten = nn.Flatten() self.drop1 = nn.Dropout(p=0.5) # 自动计算全连接层输入维度 with torch.no_grad(): # 计算x分支卷积输出展平长度 dummy_x = torch.zeros(1, 1, x_len) dx = self.pool1(F.relu(self.conv1(dummy_x))) dx = self.pool2(F.relu(self.conv2(dx))) dx = self.pool3(F.relu(self.conv3(dx))) dx = self.pool4(F.relu(self.conv4(dx))) dx = self.pool5(F.relu(self.conv5(dx))) x_flat_len = self.flatten(dx).shape[1] # 计算y分支卷积输出展平长度 dummy_y = torch.zeros(1, 1, y_len) dy = self.pool1(F.relu(self.conv1(dummy_y))) dy = self.pool2(F.relu(self.conv2(dy))) dy = self.pool3(F.relu(self.conv3(dy))) dy = self.pool4(F.relu(self.conv4(dy))) dy = self.pool5(F.relu(self.conv5(dy))) y_flat_len = self.flatten(dy).shape[1] fc1_input_dim = x_flat_len + y_flat_len self.fc1 = nn.Linear(in_features=fc1_input_dim, out_features=50) self.drop2 = nn.Dropout(p=0.5) self.fc2 = nn.Linear(in_features=50, out_features=25) self.fc3 = nn.Linear(in_features=25, out_features=2) def forward(self, x, y): # x分支前向传播 x = F.relu(self.conv1(x)) x = self.pool1(x) x = F.relu(self.conv2(x)) x = self.pool2(x) x = F.relu(self.conv3(x)) x = self.pool3(x) x = F.relu(self.conv4(x)) x = self.pool4(x) x = F.relu(self.conv5(x)) x = self.pool5(x) # y分支前向传播 y = F.relu(self.conv1(y)) y = self.pool1(y) y = F.relu(self.conv2(y)) y = self.pool2(y) y = F.relu(self.conv3(y)) y = self.pool3(y) y = F.relu(self.conv4(y)) y = self.pool4(y) y = F.relu(self.conv5(y)) y = self.pool5(y) # 特征拼接 x = self.flatten(x) y = self.flatten(y) w = torch.cat([x, y], dim=1) # 全连接分类头 w = self.drop1(w) w = F.relu(self.fc1(w)) w = self.drop2(w) w = F.relu(self.fc2(w)) w = self.fc3(w) out = F.log_softmax(w, dim=1) return out
模型结构打印代码无需修改,直接运行即可:
model = myDNN(x_len=892, y_len=492) print(model) from torchsummary import summary if torch.cuda.is_available(): summary(model.cuda(), input_size = [(1,892),(1,492)]) else: summary(model, input_size = [(1,892),(1,492)])
自动计算全连接层输入维度的逻辑兼容后续的结构修改,只要调整卷积核大小、池化步长、输入信号长度,初始化时都会自动算出匹配的维度,不需要手动计算修改全连接层参数。
内容的提问来源于stack exchange,提问作者AleNekro97
相关产品推荐
相关产品推荐

