最近从tensorflow转战pytorch,今天又遇到了了一个大坑:RuntimeError: mat1 and mat2 shapes cannot be multiplied,网上的结果大都模模糊糊模棱两可,我在认真分析网络结构的实现模式以后终于弄懂了这个问题。
这次采用的数据集是CIFAR10,大概130M。有50000张训练图以及10000张测试图、每张图尺寸32*32,所有图分为十类,非常适合作为分类目标的数据集。

文章目录

  • 1. 导入CIFAR10数据集
  • 2.理解图像尺寸与VGG16网络结构的关系
    • 终极详解:RuntimeError: mat1 and mat2 shapes cannot be multiplied 问题
  • 3.训练过程
    • 训练结果

1. 导入CIFAR10数据集

注意我这里batch_size设为1,下面要用

import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torch import nn,optim,device
from torch.utils.tensorboard import SummaryWriter
device=device("cuda")train_transform = transforms.Compose([transforms.ToTensor(),# 归一化transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])valid_transform=transforms.Compose([transforms.ToTensor(),# 归一化transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])])
train_dataset =torchvision.datasets.CIFAR10(root=r'D:\AAA\PYTHON\pythonproject\jupyter\data\CIFAR10',train=True,transform=train_transform,download=False)
valid_dataset =torchvision.datasets.CIFAR10(root=r'D:\AAA\PYTHON\pythonproject\jupyter\data\CIFAR10',train=False,transform=valid_transform,download=False)batch_size=1
train_loader =DataLoader(train_dataset,batch_size=batch_size, shuffle=True,num_workers=0)
valid_loader =DataLoader(valid_dataset,batch_size=batch_size, shuffle=True,num_workers=0)
print('train_dataset',len(train_dataset))  #50000
print('valid_dataset',len(valid_dataset))  #10000

2.理解图像尺寸与VGG16网络结构的关系

首先,这个问题是出现在模型对象输入时候的,原因是模型在进入全连接层时候的一对tensor的shape不能够相乘,要解决这个问题就必须搞清楚输入图像尺寸在网络结构里每一层的输入输出细节,还是从这两张最经典的vgg16图解说起:

图一的D列的每一行描述了我们要用的vgg16每一层的卷积核尺寸以及输出通道,例如conv3-64就是这一层卷积的卷积核尺寸是(3*3),输出通道数是64


图二描述了默认情况下以224 X 224为尺寸的图形传入图像的vgg16每层操作的输出尺寸以及通道数,例如112 X 112 X 128,此层的输出尺寸是112 X 112,输出通道数是128。我们的32 X 32尺寸的数据集的过程是图二中用红笔批注的那些,注意当图像进入池化层时tensor尺寸已经被卷积为1 X 1了,相当于没有池化,所以别的博主可能会省略不写。
综上,我们可以把vgg16手动搭建出来:

from torch import nn
class vgg16_net(nn.Module):def __init__(self):super(vgg16_net,self).__init__()# 卷积层self.features=nn.Sequential(# block1nn.Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(),nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),# block2nn.Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),# block3nn.Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),# block4nn.Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False),# block5nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)),nn.ReLU(inplace=True),nn.MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)      )# 平均池化self.avgpool=nn.AdaptiveAvgPool2d(output_size=(1, 1))# 全连接层self.classifier=nn.Sequential(nn.Linear(in_features=1*1*512, out_features=512, bias=True),nn.ReLU(inplace=True),nn.Dropout(p=0.4, inplace=False),nn.Linear(in_features=512, out_features=256, bias=True),nn.ReLU(inplace=True),nn.Dropout(p=0.4, inplace=False),nn.Linear(in_features=256, out_features=10, bias=True))def forward(self,input):input=self.features(input)input=self.avgpool(input)# input=input.view(-1,512)input=self.classifier(input)return inputmodel=vgg16_net()
model=model.to(device) #调用GPU
print(model)

此时的模型结构为:

vgg16_net((features): Sequential((0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(1): ReLU(inplace=True)(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(3): ReLU(inplace=True)(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(6): ReLU(inplace=True)(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(8): ReLU(inplace=True)(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(11): ReLU(inplace=True)(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(13): ReLU(inplace=True)(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(15): ReLU(inplace=True)(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(18): ReLU(inplace=True)(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(20): ReLU(inplace=True)(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(22): ReLU(inplace=True)(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(25): ReLU(inplace=True)(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(27): ReLU(inplace=True)(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))(29): ReLU(inplace=True)(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False))(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))(classifier): Sequential((0): Linear(in_features=512, out_features=512, bias=True)(1): ReLU(inplace=True)(2): Dropout(p=0.4, inplace=False)(3): Linear(in_features=512, out_features=256, bias=True)(4): ReLU(inplace=True)(5): Dropout(p=0.4, inplace=False)(6): Linear(in_features=256, out_features=10, bias=True))
)

终极详解:RuntimeError: mat1 and mat2 shapes cannot be multiplied 问题

添加一小个测试板块看看

from torch import ones
input=ones((batch_size,3,32,32))
input=input.to(device)  #调用GPU
output=model(input)

报错:

我尝试了很多数据终于找到了这个(512 X 1 and 512 X 512)的组成规律:

相当于
and左边=(卷积层最后的输出通道数*batch_size*池化尺寸 X 池化尺寸)
and右边=(第一个全连接层的输入尺寸 X 第一个全连接层的输出尺寸)
其中
batch_size就是操作数据集DataLoader时候的自定义的batch_size,我的值为1
第一个全连接层的输入尺寸=池化尺寸*池化尺寸*卷积层最后的输出通道数

定睛一看会发现,and左右两边构成的等式,至少要满足池化尺寸==第一个全连接层的输入尺寸才能相乘,而这两个值没有逻辑关系。再定睛一看,又发现等式两边只有batch_size是自定义的,其他值都是网络结构固定的可以视为常数,所以我们只用把and左边的式子全部展开,然后把batch_size放在X的左边,把池化尺寸*池化尺寸*卷积层最后的输出通道数放在X的右边,这样不就满足前行乘后列永远是恒等的常数相乘了。此时
and左边=(batch_size X 池化尺寸*池化尺寸*卷积层最后的输出通道数)
and右边=(池化尺寸*池化尺寸*卷积层最后的输出通道数 X 第一个全连接层的输出尺寸)
就解决问题了
代码中,在forward方法里,在avgpool平均池化模块之后,在全连接classifier模块之前添上

input=input.view(-1,512)

在我的代码中,只用把那句注释取消了就行。
详解一下view函数:-1为计算后的自动填充值,在上面的分析中知道,这个值就是batch_size,而512是网络模型的常数值,所以换成这样也是对的:

input=input.view(batch_size,512)

3.训练过程

训练过程并未优化,但总体框架大至如此

import time
import torch
# 损失函数
loss_fn=nn.CrossEntropyLoss()
# 优化器
lr=0.01#每n次epoch更新一次学习率
step_size=2
# momentum(float)-动量因子
optimizer=optim.SGD(model.parameters(),lr=lr,momentum=0.8,weight_decay=0.001)
schedule=optim.lr_scheduler.StepLR(optimizer,step_size=step_size,gamma=0.5,last_epoch=-1)train_step=0
vali_step=0
writer=SummaryWriter('./logs')
epoch=5for i in range(1,epoch+1):starttime=time.time()train_acc=0
# -----------------------------训练过程------------------------------for data in train_loader:img,tar=dataimg=img.to(device)tar=tar.to(device)outputs=model(img)train_loss=loss_fn(outputs,tar)# print(outputs.argmax(1),tar)train_acc+=sum(outputs.argmax(1)==tar)/batch_size# 优化器优化模型optimizer.zero_grad()train_loss.backward()optimizer.step()train_step+=1if train_step%5000==0:print("train_step",train_step)vali_loss=0vali_acc=0
# -----------------------------验证过程------------------------------with torch.no_grad():for vali_data in valid_loader:img,tar=vali_dataimg=img.to(device)tar=tar.to(device)outputs=model(img)vali_loss+=loss_fn(outputs,tar) vali_acc+=sum(outputs.argmax(1)==tar)/batch_sizevali_step+=1if vali_step%2000==0:print("vali_step",vali_step)endtime=time.time()spendtime=endtime-starttimeave_train_acc=train_acc/(len(train_loader))ave_vali_loss=vali_loss/(len(valid_loader))ave_vali_acc=vali_acc/(len(valid_loader))# 训练次数:每一个epoch就是所有train的图跑一遍:1968*3/batch_size,每次batch_size张图print("Epoch {}/{} : train_step={}, vali_step={}, spendtime={}s".format(i,epoch,train_step,vali_step,spendtime))print("ave_train_acc={}, ave_vali_acc={}".format(ave_train_acc,ave_vali_acc))print("train_loss={}, ave_vali_loss={} \n".format(train_loss,ave_vali_loss))# tensorboard --logdir=logswith SummaryWriter('./logs/ave_train_acc') as writer:writer.add_scalar('Acc', ave_train_acc, i)with SummaryWriter('./logs/ave_vali_acc') as writer:writer.add_scalar('Acc', ave_vali_acc, i)with SummaryWriter('./logs/train_loss') as writer:writer.add_scalar('Loss', train_loss, i)with SummaryWriter('./logs/ave_vali_loss') as writer:writer.add_scalar('Loss', ave_vali_loss, i)writer.close()

训练结果

训练结果还是很拉的,等优化好了再更新

Pytorch vgg16 实现CIFAR10数据集分类 以及RuntimeError: mat1 and mat2 shapes cannot be multiplied终极详解相关推荐

  1. RuntimeError: mat1 and mat2 shapes cannot be multiplied (1024x1 and 1024x3)

    RuntimeError: mat1 and mat2 shapes cannot be multiplied (1024x1 and 1024x3) 前言:在学习pytorch 搭建神经网络的时候, ...

  2. 解决:RuntimeError: mat1 and mat2 shapes cannot be multiplied (8x256 and 8x256)维度不匹配问题

    在设计网络是,前面几层是去噪网络,后边几层是分类网络,因为之前没有接触过分类任务,对全连接层输入维度不太理解,出现错误RuntimeError: mat1 and mat2 shapes cannot ...

  3. RuntimeError: mat1 and mat2 shapes cannot be multiplied (32x7 and 784x1024) 报错解决

    RuntimeError: mat1 and mat2 shapes cannot be multiplied (32x7 and 784x1024) 运行pytorch时,出现以下报错: 错误代码: ...

  4. RuntimeError: mat1 and mat2 shapes cannot be multiplied

    RuntimeError: mat1 and mat2 shapes cannot be multiplied RuntimeError: mat1 and mat2 shapes cannot be ...

  5. RuntimeError: mat1 and mat2 shapes cannot be multiplied (3584x7 and 25088x4096)

    RuntimeError: mat1 and mat2 shapes cannot be multiplied (3584x7 and 25088x4096) 使用VGG19提取图像特征时出现该问题 ...

  6. RuntimeError mat1 and mat2 shapes cannot be multiplied

    详细显示如下 x = self.fc(x) File "D:\Python36\lib\site-packages\torch\nn\modules\module.py", lin ...

  7. RuntimeError: mat1 and mat2 shapes cannot be multiplied (5760x6 and 128x4)

    在使用pytorch框架定义子类网络结构时,有时可能会出现mat1和mat2的形状不匹配的这种问题.如下,定义了一个7层的cnn网络: class CNN(nn.Module):def __init_ ...

  8. RuntimeError: mat1 and mat2 shapes cannot be multiplied (250x7 and 9x256) pytorch报错

    在利用pytorch搭建神经网络模型的时候,遇到这个错误通常表示矩阵乘法操作的维度不匹配.具体地说,根据错误信息,mat1是一个250x7的矩阵,而mat2是一个9x256的矩阵,它们的维度无法相乘. ...

  9. pytorch报错:RuntimeError: mat1 and mat2 shapes cannot be multiplied (64x2500 and 3020x1600)

    相信同学们在刚接触深度学习的时候老会遇到类似的问题: 这个其实就是卷积层到全连接层之间的参数数量不对应的问题 卷积层的的输出结果是64*2500的矩阵,那么全连接层的第一个第一层的就应该是:2500* ...

最新文章

  1. 手工纸盒子_不锈钢水槽如何选购,拉伸水槽与手工槽制造工艺有何区别
  2. 4.成本核算相关步骤的财务处理
  3. python PyQt5 adjustSize()(根据内容自适应大小)
  4. java 字符串 数组互转
  5. Angular multiple binding debug
  6. 第一个Django应用程序_part1
  7. 监视和检测Java应用程序中的内存泄漏
  8. promise async await
  9. python怎么把数据存在本地_将Python中的数据存储到系统本地的简单方法
  10. HDU 1087 Super Jumping! Jumping! Jumping!(DP)
  11. Module build failed: Error: Couldn't find preset react relative to directory
  12. 漫画:不止于存储的智能云相册
  13. SQL Server 2008R2密钥
  14. nodejs--模块化、模块作用域、导出数据的几种方式、包、包管理、自定义包、模块加载机制
  15. grpc生成pb.go文件报错github.com/gogo/protobuf/gogoproto/gogo.proto: File not found.
  16. CAD2015 C#二次开发 字体变形
  17. 开发电商系统用什么开发语言呢
  18. 31. Git与Github
  19. 【显著目标检测论文】Pyramid Feature Attention Network for Saliency detection
  20. 帝国cms用自定义反馈做在线报名等系统

热门文章

  1. 前后端项目如何实现完美的OSS文件上传
  2. 常用个人邮箱之用户体验分析
  3. 求历年奥斯卡获奖动画影片
  4. Android清空画布
  5. 微型计算机的先驱,DLSS加持的星际战斗你不要来爽一下?《先驱者》全系GPU评测...
  6. 专访丨PingCAP创始人CTO黄东旭:开源是基础软件成功的唯一道路
  7. 转载的在北京程序员如何做到月入2万???
  8. 计算机名称是pc是什么意思,pc是什么意思
  9. 真正不需要网关的智能门锁——NBIoT智能门锁
  10. 深入剖析 iOS 编译 Clang / LLVM