PyTorch模型torch.cat维度错误及形状不匹配问题修复请求
多模态模型训练随机报错的修复方案
问题背景
训练多模态模型时,错误会在不同epoch随机触发,无固定规律:有时执行到第50个epoch才报错,有时第16个epoch就触发。
初始报错信息
0it [00:00, ?it/s]/usr/local/lib/python3.8/dist-packages/torch/nn/functional.py:1960: UserWarning: nn.functional.sigmoid is deprecated. Use torch.sigmoid instead. warnings.warn("nn.functional.sigmoid is deprecated. Use torch.sigmoid instead.") 185it [00:07, 23.88it/s] Traceback (most recent call last): File "/content/drive/MyDrive/train.py", line 241, in <module> train() File "/content/drive/MyDrive/train.py", line 98, in train text_aligned_match, image_aligned_match, pred_similarity_match = similarity_module(fixed_text, matched_image) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/content/drive/MyDrive/model.py", line 106, in forward text_encoding, image_encoding = self.encoding(text, image) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/content/drive/MyDrive/model.py", line 70, in forward text_encoding = self.shared_text_encoding(text) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/content/drive/MyDrive/model.py", line 33, in forward x_out = torch.cat(x_out, 1) IndexError: Dimension out of range (expected to be in range of [-1, 0], but got 1)
修改后的新报错
将x_out = torch.cat(x_out, 1)改为x_out = torch.cat(x_out, dim=0)后,出现维度不匹配错误:
0it [00:01, ?it/s] Traceback (most recent call last): File "/content/drive/MyDrive/train.py", line 241, in <module> train() File "/content/drive/MyDrive/train.py", line 98, in train text_aligned_match, image_aligned_match, pred_similarity_match = similarity_module(fixed_text, matched_image) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/content/drive/MyDrive/model.py", line 106, in forward text_encoding, image_encoding = self.encoding(text, image) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/content/drive/MyDrive/model.py", line 71, in forward text_shared = self.shared_text_linear(text_encoding) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/container.py", line 139, in forward input = module(input) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/module.py", line 1130, in _call_impl return forward_call(*input, **kwargs) File "/usr/local/lib/python3.8/dist-packages/torch/nn/modules/linear.py", line 114, in forward return F.linear(input, self.weight, self.bias) RuntimeError: mat1 and mat2 shapes cannot be multiplied (132x32 and 128x64)
报错原因分析
- 随机维度错误原因:
FastCNN中使用module(x).squeeze()时,若当前批次的batch_size=1,张量会被压缩成1维(形状从(1,32)变为(32,)),此时执行torch.cat(x_out, 1)会因张量只有0维而报错,这就是错误随机触发的根源——仅当遇到batch_size=1的批次时触发。 - 修改后维度不匹配原因:改为
dim=0拼接后,4个形状为(bs,32)的张量会被拼接成(bs*4,32),但后续shared_text_linear的第一层是nn.Linear(128,64),要求输入特征维度为128,导致矩阵乘法维度不匹配。
修复方案
- 固定张量维度:将
squeeze()改为squeeze(-1),仅去除最后一个维度,确保即使batch_size=1,张量仍保持2维((1,32))。 - 恢复正确拼接维度:保持
torch.cat(x_out, dim=1),将4个(bs,32)的张量在特征维度拼接为(bs,128),与后续线性层输入维度匹配。 - 修复废弃API警告:将
nn.functional.sigmoid(skl)替换为torch.sigmoid(skl),消除deprecated警告。
完整修正代码
import math import random from random import random, seed import torch import torch.nn as nn from torch.distributions import Normal, Independent from torch.nn.functional import softplus seed(825) class FastCNN(nn.Module): # a CNN-based altertative approach of bert for text encoding def __init__(self, channel=32, kernel_size=(1, 2, 4, 8)): super(FastCNN, self).__init__() self.fast_cnn = nn.ModuleList() for kernel in kernel_size: self.fast_cnn.append( nn.Sequential( nn.Conv1d(200, channel, kernel_size=kernel), nn.BatchNorm1d(channel), nn.ReLU(), nn.AdaptiveMaxPool1d(1) ) ) def forward(self, x): x = x.permute(0, 2, 1) x_out = [] for module in self.fast_cnn: # 修改:使用squeeze(-1)仅去除最后一个维度,避免batch_size=1时维度丢失 x_out.append(module(x).squeeze(-1)) # 修改:明确指定dim=1,在特征维度拼接 x_out = torch.cat(x_out, dim=1) return x_out class EncodingPart(nn.Module): def __init__( self, cnn_channel=32, cnn_kernel_size=(1, 2, 4, 8), shared_image_dim=128, shared_text_dim=128 ): super(EncodingPart, self).__init__() self.shared_text_encoding = FastCNN( channel=cnn_channel, kernel_size=cnn_kernel_size ) self.shared_text_linear = nn.Sequential( nn.Linear(128, 64), nn.BatchNorm1d(64), nn.ReLU(), nn.Dropout(), nn.Linear(64, shared_text_dim), nn.BatchNorm1d(shared_text_dim), nn.ReLU() ) self.shared_image = nn.Sequential( nn.Linear(512, 256), nn.BatchNorm1d(256), nn.ReLU(), nn.Dropout(), nn.Linear(256, shared_image_dim), nn.BatchNorm1d(shared_image_dim), nn.ReLU() ) def forward(self, text, image): text_encoding = self.shared_text_encoding(text) text_shared = self.shared_text_linear(text_encoding) image_shared = self.shared_image(image) return text_shared, image_shared class SimilarityModule(nn.Module): def __init__(self, shared_dim=128, sim_dim=64): super(SimilarityModule, self).__init__() self.encoding = EncodingPart() self.text_aligner = nn.Sequential( nn.Linear(shared_dim, shared_dim), nn.BatchNorm1d(shared_dim), nn.ReLU(), nn.Linear(shared_dim, sim_dim), nn.BatchNorm1d(sim_dim), nn.ReLU() ) self.image_aligner = nn.Sequential( nn.Linear(shared_dim, shared_dim), nn.BatchNorm1d(shared_dim), nn.ReLU(), nn.Linear(shared_dim, sim_dim), nn.BatchNorm1d(sim_dim), nn.ReLU() ) self.sim_classifier_dim = sim_dim * 2 self.sim_classifier = nn.Sequential( nn.BatchNorm1d(self.sim_classifier_dim), nn.Linear(self.sim_classifier_dim, 64), nn.BatchNorm1d(64), nn.ReLU(), nn.Linear(64, 2) ) def forward(self, text, image): text_encoding, image_encoding = self.encoding(text, image) text_aligned = self.text_aligner(text_encoding) image_aligned = self.image_aligner(image_encoding) sim_feature = torch.cat([text_aligned, image_aligned], 1) pred_similarity = self.sim_classifier(sim_feature) return text_aligned, image_aligned, pred_similarity class Encoder(nn.Module): def __init__(self, z_dim=2): super(Encoder, self).__init__() self.z_dim = z_dim # Vanilla MLP self.net = nn.Sequential( nn.Linear(64, 64), nn.ReLU(True), nn.Linear(64, z_dim * 2), ) def forward(self, x): # x = x.view(x.size(0), -1) # Flatten the input params = self.net(x) mu, sigma = params[:, :self.z_dim], params[:, self.z_dim:] sigma = softplus(sigma) + 1e-7 return Independent(Normal(loc=mu, scale=sigma), 1) class AmbiguityLearning(nn.Module): def __init__(self): super(AmbiguityLearning, self).__init__() self.encoding = EncodingPart() self.encoder_text = Encoder() self.encoder_image = Encoder() def forward(self, text_encoding, image_encoding): # text_encoding, image_encoding = self.encoding(text, image) p_z1_given_text = self.encoder_text(text_encoding) p_z2_given_image = self.encoder_image(image_encoding) z1 = p_z1_given_text.rsample() z2 = p_z2_given_image.rsample() kl_1_2 = p_z1_given_text.log_prob(z1) - p_z2_given_image.log_prob(z1) kl_2_1 = p_z2_given_image.log_prob(z2) - p_z1_given_text.log_prob(z2) skl = (kl_1_2 + kl_2_1)/ 2. # 修改:替换废弃的nn.functional.sigmoid为torch.sigmoid skl = torch.sigmoid(skl) return skl class UnimodalDetection(nn.Module): def __init__(self, shared_dim=128, prime_dim = 16): super(UnimodalDetection, self).__init__() self.text_uni = nn.Sequential( nn.Linear(shared_dim, shared_dim), nn.BatchNorm1d(shared_dim), nn.ReLU(), nn.Linear(shared_dim, prime_dim), nn.BatchNorm1d(prime_dim), nn.ReLU() ) self.image_uni = nn.Sequential( nn.Linear(shared_dim, shared_dim), nn.BatchNorm1d(shared_dim), nn.ReLU(), nn.Linear(shared_dim, prime_dim), nn.BatchNorm1d(prime_dim), nn.ReLU() ) def forward(self, text_encoding, image_encoding): text_prime = self.text_uni(text_encoding) image_prime = self.image_uni(image_encoding) return text_prime, image_prime class CrossModule4Batch(nn.Module): def __init__(self, text_in_dim=64, image_in_dim=64, corre_out_dim=64): super(CrossModule4Batch, self).__init__() self.softmax = nn.Softmax(-1) self.corre_dim = 64 self.pooling = nn.AdaptiveMaxPool1d(1) self.c_specific_2 = nn.Sequential( nn.Linear(self.corre_dim, corre_out_dim), nn.BatchNorm1d(corre_out_dim), nn.ReLU() ) def forward(self, text, image): text_in = text.unsqueeze(2) image_in = image.unsqueeze(1) corre_dim = text.shape[1] similarity = torch.matmul(text_in, image_in) / math.sqrt(corre_dim) correlation = self.softmax(similarity) correlation_p = self.pooling(correlation).squeeze() correlation_out = self.c_specific_2(correlation_p) return correlation_out class DetectionModule(nn.Module): def __init__(self, feature_dim=64+16+16, h_dim=64): super(DetectionModule, self).__init__() self.encoding = EncodingPart() self.ambiguity_module = AmbiguityLearning() self.uni_repre = UnimodalDetection() self.cross_module = CrossModule4Batch() self.classifier_corre = nn.Sequential( nn.Linear(feature_dim, h_dim), nn.BatchNorm1d(h_dim), nn.ReLU(), # nn.Dropout(), nn.Linear(h_dim, h_dim), nn.BatchNorm1d(h_dim), nn.ReLU(), # nn.Dropout(), nn.Linear(h_dim, 2) ) def forward(self, text_raw, image_raw, text, image): # text_encoding, image_encoding = self.encoding_module(text, image) skl = self.ambiguity_module(text, image) text_prime, image_prime = self.encoding(text_raw, image_raw) text_prime, image_prime = self.uni_repre(text_prime, image_prime) correlation = self.cross_module(text, image) weight_uni = (1-skl).unsqueeze(1) weight_corre = skl.unsqueeze(1) text_final = weight_uni * text_prime img_final = weight_uni * image_prime corre_final = weight_corre * correlation final_corre = torch.cat([text_final, img_final, corre_final], 1) pre_label = self.classifier_corre(final_corre) return pre_label
内容的提问来源于stack exchange,提问作者MARY m
相关产品推荐
相关产品推荐

