pytorch学习第三课-全连接网络2-MNIST分类

完成了简单的全连接网络之后,我们是用pytorch进行MNIST手写数字的分类问题,这次的网络相对复杂一下,输入输出和hidden layer都更多,表达能力更强

首先是下载MINIST的数据集:

import torch
import torch.nn as nn
from torchvision import datasets, transforms
import torch.nn.functional as F
import matplotlib.pyplot as plt
import numpy as np
from torch.autograd import Variable
import os

transform=transforms.Compose([transforms.ToTensor(),
							 transforms.Normalize((0.5,),(0.5,))])


#下载训练集和验证集
training_datasets=datasets.MNIST(root='./data',train=True,download=True,transform=transform)
validation_datasets=datasets.MNIST(root='./data',train=False,download=True,transform=transform)

training_loader=datsets.MNIST(datasets=training_datasets,batch_size=100,shuffle=True)
validation_loader=datsets.MNIST(datasets=validation_datasets,batch_size=100,shuffle=False)

这里注意,一定是transforms.Normalize((0.5,),(0.5,)),不是transforms.Normalize((0.5),(0.5)),一个逗号之差,数据类型会不是 tuple,然后就会报错 “IndexError: too many indices for tensor of dimension 0”

然后我们可以看一下training_loader里面的图片都长什么样子:

def im_convert(tensor):
	image=tensor.clone().detach().numpy()
	image=image.transpose(1,2,0) # 从 N*W*H,转成W*H*N
	image=image*np.array(0.5,)+np.array(0.5) #这步是transform Normalize的反向过程
	image=image.clip(0,1)
	image=image.squeeze()
	return image

dataiter=iter(training_loader)
images,labels=dataiter.next() 
fig=plt.figure(figsize=(25,4))

# 展示20幅图
for idx in range(20):
	ax=fig.add_subplot(2,10,idx+1)
	plt.imshow(im_convert(images[idx]))
	ax.set_title(labels[idx].item())

在这里插入图片描述

然后是神经网络的结构,全连接网络,有两个隐藏层

class Classifier(nn.Module):
	def __init__(self,input_size,h1,h2,output_Size):
		super().__init__()
		self.linear1=nn.Linear(input_size,h1)
		self.linear2=nn.Linear(h1,h2)
		self.linear3=nn.Linear(h2,output_size)
	def forward(self,x):
		pred1=F.relu(self.linear1(x))
		pred2=F.relu(self.linear1(pred1))
		pred=self.linear1(pred2) 
		#最后一层这里的不用softmax的原因是,后面我们会用 CrossEntropyLoss,里面就包括了softmax log 等操作,直接return 线性层的输出就够了
		return pred


use_gpu=torch.cuda.is_avaliable() #检查gpu是否可用

model=Classifier(28*28,125,65,10)
criterion=nn.CrossEntropyLoss()
optimizer=torch.optim.Adam(model.parameters(),lr=0.01)

if use_gpu:
	#将数据放在cuda上,才能用GPU运算
    model=model.cuda()
    criterion=criterion.cuda()
 
epoch=12
losses=[]

val_losses=[]
val_acces=[]

for i in range(epoch):
	running_loss=0
	dataiter=iter(training_loader)
	for j in range(len(dataiter)):

	#for steps,(inputs,labels) in enumerate(training_loader): 也是一样的,都是从training_loader里取training data
		inputs,labels=dataiter.next()
		inputs=inputs.view(inputs.shape[0],-1)
		#将输入变成 batchsize*input_size的样子
		
		if use_gpu:
			inputs=inputs.cuda()
			labels=labels.cuda()
		y_pred=model.forward(inputs)
		
		loss=criterion(y_pred,labels)
		optimizer.zero_grad()
		loss.backward()
		optimizer.step()
		running_loss+=loss.item()
	#每一个epoch都记录一下 loss
	running_loss=running_loss/inputs.shape[0]
	losses.append(running_loss/len(dataiter))
	
	val_running_loss=0.0
	val_running_acc=0.0
	
	val_dataiter=iter(validation_loader)
	
	for j in range(len(val_dataiter)):
		inputs,labels=val_dataiter.next()
		inputs=inputs.view(inputs.shape[0],-1)
		#将输入变成 batchsize*input_size的样子
		
		if use_gpu:
			inputs=inputs.cuda()
			labels=labels.cuda()
		y_pred=model.forward(inputs)
		loss=criterion(y_pred,labels)
		#validation 不需要进行反向传播,但是可以进行准确度的计算
		_,preds=torch.max(y_pred,1)
		val_running_acc+=torch.sum(preds=labels.data)
		val_running_loss+=loss.item()
	
	val_running_acc=val_running_acc/inputs.shape[0]
	val_running_loss=val_running_loss/inputs.shape[0]
	
	val_losses.append(val_running_loss/len(val_dataiter))	
	val_acces.append(val_running_acc/len(val_dataiter))

	plt.close()
    plt.plot(losses,label='training_loss')
    plt.plot(val_losses,label='validation_loss')
    plt.legend()
	
	#保存每一个epoch 的model
	dir='./deep_nn_checkpoint'
    PATH=os.path.join(dir,'model'+str(i)+'.pth')
    torch.save(model.state_dict(), PATH)

在这里插入图片描述
分割结束后,我们可以进行测试:
首先,我们可以选择中间的训练结果,也不是最后一个,因为训练的时候,我们将每一个epoch的model都存了下来,所以可以直接加载

dir='./deep_nn_checkpoint'
PATH=os.path.join(dir,'model'+str(5)+'.pth')
model.load_state_dict(torch.load(PATH))
model.eval()

然后我们找到一张数字图像,然后进行识别:
在这里插入图片描述
一张白底黑色的图片,所以对于这个图片,需要将其转化为我们训练时的格式:

from PIL import Image
img=Image.open('deep_nn_test_image.jpg')
img=PIL.ImageOps.invert(img) #将图片反色,变成黑底白字
img=Image.Convert('1') #转成单通道图片

transform=transforms.Compose([transforms.Resize([28,28]),
							  transforms.ToTensor(),
							  transforms.Normalize((0.5,),(0.5,))])
img=transform(img)

inputs= img.view(img.shape[0],-1)

pred=model.forward(inputs)
_,preds=torch.max(pred,1)
print(preds)

输出结果为 5,识别正确

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值