RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5]
文章目录
- 问题引入
- 运行报错
- 代码
- 分析原因
- 5.解决办法
- 完整代码
- 参考文献
1. 问题引入
今天在使用pytorch训练一个模型的,数据集的读取是使用pytorch自带的函数来进行读取和预处理的,网络使用的是自定义的CNN,然后在运行的时候出现了如标题所示的这种小错误。
2. 运行报错
如下所示:
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网络如下所示:
class MNIST_Model(nn.Module):
def __init__(self, n_in):
super(MNIST_Model, self).__init__()
self.conv1 = nn.Sequential(
nn.Conv2d(in_channels=n_in,
out_channels=32,
kernel_size=(5, 5),
padding=2,
stride=1),
)
self.maxp1 = nn.MaxPool2d(
kernel_size=(2, 2))
self.conv2 = nn.Sequential(
nn.Conv2d(in_channels=32,
out_channels=64,
kernel_size=(5, 5),
padding=0,
stride=1),
)
self.maxp2 = nn.MaxPool2d(kernel_size=(2, 2))
self.fc1 = nn.Sequential(
nn.Linear(in_features=64 * 5 * 5, out_features=200) # Mnist
)
self.fc2 = nn.Sequential(
nn.Linear(in_features=200, out_features=10),
nn.ReLU()
)
def forward(self, x):
x = self.conv1(x)
x = self.maxp1(x)
x = self.conv2(x)
x = self.maxp2(x)
x = x.contiguous().view(x.size(0), -1)
x = self.fc1(x)
x = self.fc2(x)
return x
然后是在训练模型的代码
#实例化网络,只考虑使用CPU
model = model.MNIST_Model(1)
net = model.to(device)
#定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#momentum:动量因子有什么用处?
optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum)
#开始训练 先定义存储损失函数和准确率的数组
losses = []
acces = []
#测试用
eval_losses = []
eval_acces = []
for epoch in range(nums_epoches):
#每次训练先清零
train_loss = 0
train_acc = 0
#将模型设置为训练模式
model.train()
#动态学习率
if epoch%5 == 0:
optimizer.param_groups[0]['lr'] *= 0.1
for img,label in train_loader:
#前向传播,将图片数据传入模型中
# out输出10维,分别是各数字的概率,即每个类别的得分
out = model(img)
#这里注意参数out是64*10,label是一维的64
loss = criterion(out,label)
#反向传播
#optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
optimizer.zero_grad()
loss.backward()
#这个方法会更新所有的参数,一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数
optimizer.step()
#记录误差
train_loss += loss.item()
#计算分类的准确率,找到概率最大的下标
_,pred = out.max(1)
num_correct = (pred == label).sum().item()#记录标签正确的个数
acc = num_correct/img.shape[0]
train_acc += acc
losses.append(train_loss/len(train_loader))
acces.append(train_acc/len(train_loader))
eval_loss = 0
eval_acc = 0
model.eval()
for img,label in test_loader:
img = img.view(img.size(0),-1)
out = model(img)
loss = criterion(out,label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
eval_loss += loss.item()
_,pred = out.max(1)
num_correct = (pred == label).sum().item()
acc = num_correct/img.shape[0]
eval_acc += acc
eval_losses.append(eval_loss/len(test_loader))
eval_acces.append(eval_acc/len(test_loader))
print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'
.format(epoch,train_loss/len(train_loader),train_acc/len(train_loader),
eval_loss/len(test_loader),eval_acc/len(test_loader)))
4. 分析原因
定位出错位置
Traceback (most recent call last):
File "train.py", line 73, in <module>
out = model(img)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
result = self.forward(*input, **kwargs)
File "/home/gzdx/wyf/PARAD/model.py", line 48, in forward
x = self.conv1(x)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
result = self.forward(*input, **kwargs)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/container.py", line 119, in forward
input = module(input)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/module.py", line 889, in _call_impl
result = self.forward(*input, **kwargs)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/conv.py", line 399, in forward
return self._conv_forward(input, self.weight, self.bias)
File "/home/gzdx/anaconda3/envs/Torch/lib/python3.7/site-packages/torch/nn/modules/conv.py", line 396, in _conv_forward
self.padding, self.dilation, self.groups)
RuntimeError: Expected 4-dimensional input for 4-dimensional weight [32, 1, 5, 5], but got 2-dimensional input of size [32, 784] instead
可以看到这句提示,大致就是我们传入的数据输入到CNN网络,然后由于维度不同导致的。因为我们输入的是四维,但是得到的却是二维。
File "train.py", line 73, in <module>
out = model(img)
5.解决办法
对于这种问题网上给出了很多中不同的方案,这个哦个人也是参考我网上别人给出的一点想法然后自己修改了下,错误就解决了,如下所示:
for i,data in enumerate(train_loader):
#前向传播,将图片数据传入模型中
# out输出10维,分别是各数字的概率,即每个类别的得分
inputs, labels = data
inputs,labels = data[0].to(device), data[1].to(device)
# inputs torch.Size([32, 1, 28, 28])
out = model(inputs)
解决办法也是很简单,就是将上面训练开始阶段将数据按照这种读取方式来赋值,然后在传入到model里面就不会出现上面那种错误了。
6. 完整代码
import numpy as np
import model
import torch
#导入PyTorch内置的mnist数据
from torchvision.datasets import mnist
#导入预处理模块
from torchvision import transforms
from torch.utils.data import DataLoader
#导入神经网络工具
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
#定义后面要用到的超参数
train_batch_size = 32
test_batch_size = 32
#学习率与训练次数
learning_rate = 0.01
nums_epoches = 50
#优化器的时候使用的参数
lr = 0.1
momentum = 0.5
#用compose来定意预处理函数
transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize([0.5],[0.5])])
#下载数据,在工程文件夹里新建一个data文件夹储存下载的数据
train_dataset = mnist.MNIST('./data', train=True, transform=transform, target_transform=None, download=False)
test_dataset = mnist.MNIST('./data', train=False, transform=transform, target_transform=None, download=False)
#数据加载器,组合数据集和采样器,并在数据集上提供单进程或多进程迭代器
train_loader = DataLoader(train_dataset, batch_size=train_batch_size, shuffle=True, num_workers=0)
test_loader = DataLoader(test_dataset, batch_size=test_batch_size, shuffle=False)
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
#实例化网络,只考虑使用CPU
model = model.MNIST_Model(1)
net = model.to(device)
#定义损失函数和优化器
criterion = nn.CrossEntropyLoss()
#momentum:动量因子有什么用处?
optimizer = optim.SGD(model.parameters(),lr=lr,momentum=momentum)
#开始训练 先定义存储损失函数和准确率的数组
losses = []
acces = []
#测试用
eval_losses = []
eval_acces = []
for epoch in range(nums_epoches):
#每次训练先清零
train_loss = 0
train_acc = 0
#将模型设置为训练模式
model.train()
#动态学习率
if epoch%5 == 0:
optimizer.param_groups[0]['lr'] *= 0.1
for i,data in enumerate(train_loader):
#前向传播,将图片数据传入模型中
# out输出10维,分别是各数字的概率,即每个类别的得分
inputs, labels = data
inputs,labels = data[0].to(device), data[1].to(device)
out = model(inputs)
#这里注意参数out是64*10,label是一维的64
loss = criterion(out,labels)
#反向传播
#optimizer.zero_grad()意思是把梯度置零,也就是把loss关于weight的导数变成0
optimizer.zero_grad()
loss.backward()
#这个方法会更新所有的参数,一旦梯度被如backward()之类的函数计算好后,我们就可以调用这个函数
optimizer.step()
#记录误差
train_loss += loss.item()
#计算分类的准确率,找到概率最大的下标
_,pred = out.max(1)
num_correct = (pred == labels).sum().item() #记录标签正确的个数
acc = num_correct/inputs.shape[0]
train_acc += acc
losses.append(train_loss/len(train_loader))
acces.append(train_acc/len(train_loader))
print('Finished Training')
# 保存模型
PATH = './model/mnist_net.pth'
torch.save(net.state_dict(), PATH)
eval_loss = 0
eval_acc = 0
model.eval()
for i,data in enumerate(test_loader):
inputs, labels = data
inputs,labels = data[0].to(device), data[1].to(device)
out = model(inputs)
loss = criterion(out,labels)
optimizer.zero_grad()
loss.backward()
optimizer.step()
eval_loss += loss.item()
_,pred = out.max(1)
num_correct = (pred == labels).sum().item()
acc = num_correct/inputs.shape[0]
eval_acc += acc
eval_losses.append(eval_loss/len(test_loader))
eval_acces.append(eval_acc/len(test_loader))
print('epoch:{},Train Loss:{:.4f},Train Acc:{:.4f},Test Loss:{:.4f},Test Acc:{:.4f}'
.format(epoch,train_loss/len(train_loader),train_acc/len(train_loader),
eval_loss/len(test_loader),eval_acc/len(test_loader)))
7. 参考文献
1.pytorch学习笔记—搭建CNN识别MNIST
2.使用Pytorch框架的CNN网络实现手写数字(MNIST)识别
还没有评论,来说两句吧...