RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5]

痛定思痛。 2023-01-17 08:50 381阅读 0赞

文章目录

    1. 问题引入
    1. 运行报错
    1. 代码
    1. 分析原因
  • 5.解决办法
    1. 完整代码
    1. 参考文献

1. 问题引入

今天在使用pytorch训练一个模型的,数据集的读取是使用pytorch自带的函数来进行读取和预处理的,网络使用的是自定义的CNN,然后在运行的时候出现了如标题所示的这种小错误。

2. 运行报错

如下所示:

  1. RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5], but got 2-dimensional input of size [32, 784] instead

3. 代码

首先是我自己自定义的CNN网络如下所示:

  1. class MNIST_Model(nn.Module):
  2. def __init__(self, n_in):
  3. super(MNIST_Model, self).__init__()
  4. self.conv1 = nn.Sequential(
  5. nn.Conv2d(in_channels=n_in,
  6. out_channels=32,
  7. kernel_size=(5, 5),
  8. padding=2,
  9. stride=1),
  10. )
  11. self.maxp1 = nn.MaxPool2d(
  12. kernel_size=(2, 2))
  13. self.conv2 = nn.Sequential(
  14. nn.Conv2d(in_channels=32,
  15. out_channels=64,
  16. kernel_size=(5, 5),
  17. padding=0,
  18. stride=1),
  19. )
  20. self.maxp2 = nn.MaxPool2d(kernel_size=(2, 2))
  21. self.fc1 = nn.Sequential(
  22. nn.Linear(in_features=64 * 5 * 5, out_features=200) # Mnist
  23. )
  24. self.fc2 = nn.Sequential(
  25. nn.Linear(in_features=200, out_features=10),
  26. nn.ReLU()
  27. )
  28. def forward(self, x):
  29. x = self.conv1(x)
  30. x = self.maxp1(x)
  31. x = self.conv2(x)
  32. x = self.maxp2(x)
  33. x = x.contiguous().view(x.size(0), -1)
  34. x = self.fc1(x)
  35. x = self.fc2(x)
  36. return x

然后是在训练模型的代码

  1. #实例化网络,只考虑使用CPU
  2. model = model.MNIST_Model(1)
  3. net = model.to(device)
  4. #定义损失函数和优化器
  5. criterion = nn.CrossEntropyLoss()
  6. #momentum:动量因子有什么用处?
  7. optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum)
  8. #开始训练 先定义存储损失函数和准确率的数组
  9. losses = []
  10. acces = []
  11. #测试用
  12. eval_losses = []
  13. eval_acces = []
  14. for epoch in range(nums_epoches):
  15. #每次训练先清零
  16. train_loss = 0
  17. train_acc = 0
  18. #将模型设置为训练模式
  19. model.train()
  20. #动态学习率
  21. if epoch%5 == 0:
  22. optimizer.param_groups[0]['lr'] *= 0.1
  23. for img,label in train_loader:
  24. #前向传播,将图片数据传入模型中
  25. # out输出10维,分别是各数字的概率,即每个类别的得分
  26. out = model(img)
  27. #这里注意参数out是64*10,label是一维的64
  28. loss = criterion(out,label)
  29. #反向传播
  30. #optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
  31. optimizer.zero_grad()
  32. loss.backward()
  33. #这个方法会更新所有的参数,一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数
  34. optimizer.step()
  35. #记录误差
  36. train_loss += loss.item()
  37. #计算分类的准确率,找到概率最大的下标
  38. _,pred = out.max(1)
  39. num_correct = (pred == label).sum().item()#记录标签正确的个数
  40. acc = num_correct/img.shape[0]
  41. train_acc += acc
  42. losses.append(train_loss/len(train_loader))
  43. acces.append(train_acc/len(train_loader))
  44. eval_loss = 0
  45. eval_acc = 0
  46. model.eval()
  47. for img,label in test_loader:
  48. img = img.view(img.size(0),-1)
  49. out = model(img)
  50. loss = criterion(out,label)
  51. optimizer.zero_grad()
  52. loss.backward()
  53. optimizer.step()
  54. eval_loss += loss.item()
  55. _,pred = out.max(1)
  56. num_correct = (pred == label).sum().item()
  57. acc = num_correct/img.shape[0]
  58. eval_acc += acc
  59. eval_losses.append(eval_loss/len(test_loader))
  60. eval_acces.append(eval_acc/len(test_loader))
  61. print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'
  62. .format(epoch,train_loss/len(train_loader),train_acc/len(train_loader),
  63. eval_loss/len(test_loader),eval_acc/len(test_loader)))

4. 分析原因

定位出错位置

  1. Traceback (most recent call last):
  2. File "train.py", line 73, in <module>
  3. out = model(img)
  4. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
  5. result = self.forward(*input, **kwargs)
  6. File "/home/gzdx/wyf/PARAD/model.py", line 48, in forward
  7. x = self.conv1(x)
  8. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
  9. result = self.forward(*input, **kwargs)
  10. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/container.py", line 119, in forward
  11. input = module(input)
  12. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
  13. result = self.forward(*input, **kwargs)
  14. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/conv.py", line 399, in forward
  15. return self._conv_forward(input, self.weight, self.bias)
  16. File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/conv.py", line 396, in _conv_forward
  17. self.padding, self.dilation, self.groups)
  18. RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5], but got 2-dimensional input of size [32, 784] instead

可以看到这句提示,大致就是我们传入的数据输入到CNN网络,然后由于维度不同导致的。因为我们输入的是四维,但是得到的却是二维。

  1. File "train.py", line 73, in <module>
  2. out = model(img)

5.解决办法

对于这种问题网上给出了很多中不同的方案,这个哦个人也是参考我网上别人给出的一点想法然后自己修改了下,错误就解决了,如下所示:

  1. for i,data in enumerate(train_loader):
  2. #前向传播,将图片数据传入模型中
  3. # out输出10维,分别是各数字的概率,即每个类别的得分
  4. inputs, labels = data
  5. inputs,labels = data[0].to(device), data[1].to(device)
  6. # inputs torch.Size([32, 1, 28, 28])
  7. out = model(inputs)

解决办法也是很简单,就是将上面训练开始阶段将数据按照这种读取方式来赋值,然后在传入到model里面就不会出现上面那种错误了。

6. 完整代码

  1. import numpy as np
  2. import model
  3. import torch
  4. #导入PyTorch内置的mnist数据
  5. from torchvision.datasets import mnist
  6. #导入预处理模块
  7. from torchvision import transforms
  8. from torch.utils.data import DataLoader
  9. #导入神经网络工具
  10. import torch.nn as nn
  11. import torch.nn.functional as F
  12. import torch.optim as optim
  13. #定义后面要用到的超参数
  14. train_batch_size = 32
  15. test_batch_size = 32
  16. #学习率与训练次数
  17. learning_rate = 0.01
  18. nums_epoches = 50
  19. #优化器的时候使用的参数
  20. lr = 0.1
  21. momentum = 0.5
  22. #用compose来定意预处理函数
  23. transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
  24. #下载数据,在工程文件夹里新建一个data文件夹储存下载的数据
  25. train_dataset = mnist.MNIST('./data', train=True, transform=transform, target_transform=None, download=False)
  26. test_dataset = mnist.MNIST('./data', train=False, transform=transform, target_transform=None, download=False)
  27. #数据加载器,组合数据集和采样器,并在数据集上提供单进程或多进程迭代器
  28. train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True, num_workers=0)
  29. test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
  30. device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
  31. #实例化网络,只考虑使用CPU
  32. model = model.MNIST_Model(1)
  33. net = model.to(device)
  34. #定义损失函数和优化器
  35. criterion = nn.CrossEntropyLoss()
  36. #momentum:动量因子有什么用处?
  37. optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum)
  38. #开始训练 先定义存储损失函数和准确率的数组
  39. losses = []
  40. acces = []
  41. #测试用
  42. eval_losses = []
  43. eval_acces = []
  44. for epoch in range(nums_epoches):
  45. #每次训练先清零
  46. train_loss = 0
  47. train_acc = 0
  48. #将模型设置为训练模式
  49. model.train()
  50. #动态学习率
  51. if epoch%5 == 0:
  52. optimizer.param_groups[0]['lr'] *= 0.1
  53. for i,data in enumerate(train_loader):
  54. #前向传播,将图片数据传入模型中
  55. # out输出10维,分别是各数字的概率,即每个类别的得分
  56. inputs, labels = data
  57. inputs,labels = data[0].to(device), data[1].to(device)
  58. out = model(inputs)
  59. #这里注意参数out是64*10,label是一维的64
  60. loss = criterion(out,labels)
  61. #反向传播
  62. #optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
  63. optimizer.zero_grad()
  64. loss.backward()
  65. #这个方法会更新所有的参数,一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数
  66. optimizer.step()
  67. #记录误差
  68. train_loss += loss.item()
  69. #计算分类的准确率,找到概率最大的下标
  70. _,pred = out.max(1)
  71. num_correct = (pred == labels).sum().item() #记录标签正确的个数
  72. acc = num_correct/inputs.shape[0]
  73. train_acc += acc
  74. losses.append(train_loss/len(train_loader))
  75. acces.append(train_acc/len(train_loader))
  76. print('Finished Training')
  77. # 保存模型
  78. PATH = './model/mnist_net.pth'
  79. torch.save(net.state_dict(), PATH)
  80. eval_loss = 0
  81. eval_acc = 0
  82. model.eval()
  83. for i,data in enumerate(test_loader):
  84. inputs, labels = data
  85. inputs,labels = data[0].to(device), data[1].to(device)
  86. out = model(inputs)
  87. loss = criterion(out,labels)
  88. optimizer.zero_grad()
  89. loss.backward()
  90. optimizer.step()
  91. eval_loss += loss.item()
  92. _,pred = out.max(1)
  93. num_correct = (pred == labels).sum().item()
  94. acc = num_correct/inputs.shape[0]
  95. eval_acc += acc
  96. eval_losses.append(eval_loss/len(test_loader))
  97. eval_acces.append(eval_acc/len(test_loader))
  98. print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'
  99. .format(epoch,train_loss/len(train_loader),train_acc/len(train_loader),
  100. eval_loss/len(test_loader),eval_acc/len(test_loader)))

7. 参考文献

1.pytorch学习笔记—搭建CNN识别MNIST

2.使用Pytorch框架的CNN网络实现手写数字(MNIST)识别

发表评论

表情:
评论列表 (有 0 条评论,381人围观)

还没有评论,来说两句吧...

相关阅读

    相关 demension(dimensional)

    DellDimension4600重装了XP以后,连不上网了? 你的机器上的MODEM驱动和有关的软件装了么? 没有正确安装到本机的MODEM,和没有正确的安装有关的宽