PyTorch张量尺寸不匹配问题求助:padding方案无效
解决PyTorch训练MaqamCNN时的张量尺寸不匹配问题
问题背景
运行MaqamCNN训练代码时,触发RuntimeError,提示张量尺寸不匹配([1439994]与[1440000]),手动调用pad_to_max_length方法填充后问题依旧。
训练代码
import torch import torch.nn as nn import torch.optim as optim import torch.utils.data as data import dataset import model # Define hyperparameters batch_size = 2 learning_rate = 0.001 num_epochs = 10 # Load the dataset train_dataset = dataset.MaqamDataset(mode='train') # Find the maximum length of the input tensors max_length = 0 for i in range(len(train_dataset)): inputs, labels = train_dataset[i] if inputs.shape[0] > max_length: max_length = inputs.shape[0] # Pad all input tensors to the maximum length train_dataset.pad_to_max_length(1440000) train_loader = data.DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # Define the model device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") model = model.MaqamCNN().to(device) criterion = nn.CrossEntropyLoss() optimizer = optim.Adam(model.parameters(), lr=learning_rate) # Train the model for epoch in range(num_epochs): running_loss = 0.0 for i, data in enumerate(train_loader, 0): inputs, labels = data print(inputs.shape) inputs = inputs.unsqueeze(1).unsqueeze(3) optimizer.zero_grad() outputs = model(inputs) print("Outputs shape = ", outputs.shape) batch_size1 = outputs.size(0) padding_size = max_length - outputs.size(1) padding = torch.zeros(batch_size1, padding_size).to(device) padded_outputs = torch.cat((outputs, padding), dim=1) loss = criterion(padded_outputs, labels) loss.backward() optimizer.step() running_loss += loss.item() print('Epoch %d, loss: %.3f' % (epoch + 1, running_loss / len(train_loader))) # Save the model torch.save(model.state_dict(), 'maqam_cnn.pth')
报错信息
Traceback (most recent call last): File "C:\Users\omari\Documents\GitHub\Classifying_Maqams\model3\train.py", line 38, in <module> for i, data in enumerate(train_loader, 0): File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\dataloader.py", line 521, in __next__ data = self._next_data() File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\dataloader.py", line 561, in _next_data data = self._dataset_fetcher.fetch(index) # may raise StopIteration File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\_utils\fetch.py", line 47, in fetch return self.collate_fn(data) File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\_utils\collate.py", line 84, in default_collate return [default_collate(samples) for samples in transposed] File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\_utils\collate.py", line 84, in <listcomp> return [default_collate(samples) for samples in transposed] File "C:\Users\omari\anaconda3\lib\site-packages\torch\utils\data\_utils\collate.py", line 56, in default_collate return torch.stack(batch, 0, out=out) RuntimeError: stack expects each tensor to be equal size, but got [1439994] at entry 0 and [1440000] at entry 1
当前使用的pad_to_max_length方法
def pad_to_max_length(self, max_length): for i in range(len(self)): padded_data = F.pad(self.data[i][0], (0, max_length - len(self.data[i][0])), 'constant', 0) self.data[i] = (padded_data, self.data[i][1])
MaqamCNN模型代码
import torch.nn as nn class MaqamCNN(nn.Module): def __init__(self): super(MaqamCNN, self).__init__() self.conv1 = nn.Conv2d(1, 16, kernel_size=(5, 1), stride=(1, 1), padding=(2, 0)) self.bn1 = nn.BatchNorm2d(16) self.relu1 = nn.ReLU() self.pool1 = nn.MaxPool2d(kernel_size=(4, 1), stride=(4, 1)) self.conv2 = nn.Conv2d(16, 32, kernel_size=(5, 1), stride=(1, 1), padding=(2, 0)) self.bn2 = nn.BatchNorm2d(32) self.relu2 = nn.ReLU() self.pool2 = nn.MaxPool2d(kernel_size=(4, 1), stride=(4, 1)) self.fc1 = nn.Linear(32*90000, 128) self.bn3 = nn.BatchNorm1d(128) self.relu3 = nn.ReLU() self.dropout = nn.Dropout(p=0.5) self.fc2 = nn.Linear(128, 8) def forward(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu1(x) x = self.pool1(x) x = self.conv2(x) x = self.bn2(x) x = self.relu2(x) x = self.pool2(x) print(x.shape) batch_size = x.size(0) x = x.view(batch_size, -1) x = self.fc1(x) x = self.bn3(x) x = self.relu3(x) x = self.dropout(x) x = self.fc2(x) print("x shape = ", x.shape) return x
解决方案
1. 修复padding逻辑,确保所有样本尺寸统一
原pad_to_max_length方法未处理样本长度超过目标长度的情况,且可能存在遍历遗漏。修改后的方法先截断过长样本,再填充不足部分:
def pad_to_max_length(self, max_length): import torch.nn.functional as F for i in range(len(self)): data_tensor = self.data[i][0] # 截断长度超过max_length的样本 if len(data_tensor) > max_length: data_tensor = data_tensor[:max_length] # 填充长度不足的样本到max_length padded_data = F.pad(data_tensor, (0, max_length - len(data_tensor)), 'constant', 0) self.data[i] = (padded_data, self.data[i][1])
2. 更可靠的方案:在Dataset的__getitem__中处理padding
避免提前批量处理可能出现的遗漏,每次获取样本时实时处理尺寸:
import torch.nn.functional as F import torch.utils.data as data class MaqamDataset(data.Dataset): def __init__(self, mode='train', target_length=1440000): self.mode = mode self.target_length = target_length # 加载数据集的逻辑,比如读取self.data列表... def __getitem__(self, idx): inputs, labels = self.data[idx] # 统一处理截断和填充 if len(inputs) > self.target_length: inputs = inputs[:self.target_length] else: inputs = F.pad(inputs, (0, self.target_length - len(inputs)), 'constant', 0) return inputs, labels def __len__(self): return len(self.data)
3. 修正训练代码中的loss计算逻辑
模型最后一层输出是[batch_size, 8]的类别logits,符合CrossEntropyLoss的输入要求,不需要额外padding。删除错误的padding代码:
# 原错误代码段 # batch_size1 = outputs.size(0) # padding_size = max_length - outputs.size(1) # padding = torch.zeros(batch_size1, padding_size).to(device) # padded_outputs = torch.cat((outputs, padding), dim=1) # loss = criterion(padded_outputs, labels) # 修正后 loss = criterion(outputs, labels)
4. 统一目标长度参数
训练代码中先计算了max_length,但又手动传入1440000调用pad_to_max_length,容易导致参数不一致。建议直接使用固定目标长度,或确保计算的max_length与传入值一致。
内容的提问来源于stack exchange,提问作者Black Hat
相关产品推荐
相关产品推荐

