PyTorch AttributeError排查:并行CNN+Transformer情感分类模型报错
错误原因
出现AttributeError: 'NoneType' object has no attribute 'size'的核心原因是torchsummary不支持模型返回多个输出张量。你的模型forward方法返回了output_logits和output_softmax两个结果,但torchsummary默认只能处理返回单个张量的模型,在追踪模型结构时会因无法解析多输出产生None值,进而触发该错误。
另外先确认卷积模块输出维度与全连接层输入维度的匹配性:单个卷积块输出flatten后为64*1*8=512,两个卷积块总维度是512*2=1024,加上Transformer的40维嵌入,总维度1024+40=1064,你的全连接层nn.Linear(512*2+40,num_emotions)维度设置是正确的。
解决方法
方法1:临时修改forward适配torchsummary
运行summary前,临时让模型只返回一个输出张量:
def forward(self,x): # 原forward逻辑保持不变 conv2d_embedding1 = self.conv2Dblock1(x) conv2d_embedding1 = torch.flatten(conv2d_embedding1, start_dim=1) conv2d_embedding2 = self.conv2Dblock2(x) conv2d_embedding2 = torch.flatten(conv2d_embedding2, start_dim=1) x_maxpool = self.transformer_maxpool(x) x_maxpool_reduced = torch.squeeze(x_maxpool,1) x = x_maxpool_reduced.permute(2,0,1) transformer_output = self.transformer_encoder(x) transformer_embedding = torch.mean(transformer_output, dim=0) complete_embedding = torch.cat([conv2d_embedding1, conv2d_embedding2,transformer_embedding], dim=1) output_logits = self.fc1_linear(complete_embedding) output_softmax = self.softmax_out(output_logits) # 临时只返回一个张量 return output_logits
完成summary查看后,再改回原forward方法返回两个值即可。
方法2:改用torchinfo替代torchsummary
torchinfo对多输出模型的支持更完善,安装后直接使用:
from torchinfo import summary device = 'cuda' model = parallel_all_you_want(len(emotion_labels)).to(device) summary(model, input_size=(1,40,282)) # 原生支持多输出模型的结构查看
方法3:排查forward中是否存在None张量(可选)
可以在forward中添加打印语句,确认所有中间张量都不为None:
def forward(self,x): print("Input shape:", x.shape) conv2d_embedding1 = self.conv2Dblock1(x) print("Conv1 output shape:", conv2d_embedding1.shape) conv2d_embedding1 = torch.flatten(conv2d_embedding1, start_dim=1) print("Conv1 flattened shape:", conv2d_embedding1.shape) conv2d_embedding2 = self.conv2Dblock2(x) print("Conv2 output shape:", conv2d_embedding2.shape) conv2d_embedding2 = torch.flatten(conv2d_embedding2, start_dim=1) print("Conv2 flattened shape:", conv2d_embedding2.shape) x_maxpool = self.transformer_maxpool(x) print("Maxpool shape:", x_maxpool.shape) x_maxpool_reduced = torch.squeeze(x_maxpool,1) print("Squeezed shape:", x_maxpool_reduced.shape) x = x_maxpool_reduced.permute(2,0,1) print("Transformer input shape:", x.shape) transformer_output = self.transformer_encoder(x) print("Transformer output shape:", transformer_output.shape) transformer_embedding = torch.mean(transformer_output, dim=0) print("Transformer embedding shape:", transformer_embedding.shape) complete_embedding = torch.cat([conv2d_embedding1, conv2d_embedding2,transformer_embedding], dim=1) print("Complete embedding shape:", complete_embedding.shape) output_logits = self.fc1_linear(complete_embedding) print("Logits shape:", output_logits.shape) output_softmax = self.softmax_out(output_logits) print("Softmax shape:", output_softmax.shape) return output_logits, output_softmax
通过打印结果可以快速确认是否有张量意外变为None。
额外提示
你的Transformer模块输入维度处理是正确的:输入经过MaxPool2d后维度变为(batch,1,40,70),squeeze后得到(batch,40,70),permute为(70,batch,40),完全符合TransformerEncoder要求的(seq_len, batch_size, d_model)格式。
内容的提问来源于stack exchange,提问作者Arianna

