ToTensor作用
- 将输入转化为Tensor
- 将图片的变量顺序变为(channal,height,width),规范图片格式
- 将像素取值范围规范到(0,1),归一化
DataLoader作用
-
乱序 shuffle
-
将数据采样为小批次 batch_size
-
num_workers 实现多图片同时读取
- 设置批次处理函数 collate_fn
加载数据集并显示图片
import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
#torchvison加载内置数据集
import torchvision
from torchvision.transforms import ToTensor #transforms里是一些处理图片的方法
#数据集都在torchvision的datasets里
#设定缓存地址和下载的是train还是test数据,不填就全下载
#download=True时代码会自动检测相应目录下是否有文件
train_dataset = torchvision.datasets.MNIST('data',train=True,download=True,transform=ToTensor())
test_dataset = torchvision.datasets.MNIST('data',train =False,download=True,transform=ToTensor())
#DataLoader类来进行对dataset封装:
#1.乱序 shuffle
#2.将数据采样为小批次 batch_size
#3.num_workers 实现多图片同时读取
#4.设置批次处理函数 collate_fn
train_dataloader = torch.utils.data.DataLoader(train_dataset,batch_size = 64,shuffle = True)
test_dataloader = torch.utils.data.DataLoader(test_dataset,batch_size = 64)
#查看数据,iter是生成器,next返回一个批次的数据,包括image和labels
imgs,labels = next(iter(train_dataloader))
#64是批次有多少图片,1是通道,黑白,然后是高宽
print(imgs.shape)
#figsize,规定图片规格,这里是10张横的图片
plt.figure(figsize=(10,1))
#切片前十张
#for表示i<10,取前十张,img表示取的是imgs里的图片
for i,img in enumerate(imgs[:10]):
npimg = img.numpy()#imgshitensor,要转换为numpy
npimg = np.squeeze(npimg) #因为绘图时不能有1维,所以去掉
plt.subplot(1,10,i+1)
plt.imshow(npimg)
plt.axis('off')
plt.show()
print(labels[:10]) #显示图片与编号一致
MNIST多分类模型创建
神经网络学习笔记(一):全连接层的作用是什么?_Dr Xplorer的博客-CSDN博客_神经网络全连接层作用
nn.Linear层是全连接层
NumPy学习笔记(四)—— argmax()函数_ac不知深的博客-CSDN博客_argmax
import torch
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from torch import nn
#torchvison加载内置数据集
import torchvision
from torchvision.transforms import ToTensor #transforms里是一些处理图片的方法
#数据集都在torchvision的datasets里
#设定缓存地址和下载的是train还是test数据,不填就全下载
#download=True时代码会自动检测相应目录下是否有文件
train_dataset = torchvision.datasets.MNIST('data',train=True,download=True,transform=ToTensor())
test_dataset = torchvision.datasets.MNIST('data',train =False,download=True,transform=ToTensor())
#DataLoader类来进行对dataset封装:
#1.乱序 shuffle
#2.将数据采样为小批次 batch_size
#3.num_workers 实现多图片同时读取
#4.设置批次处理函数 collate_fn
train_dataloader = torch.utils.data.DataLoader(train_dataset,batch_size = 64,shuffle = True)
test_dataloader = torch.utils.data.DataLoader(test_dataset,batch_size = 64)
#查看数据,iter是生成器,next返回一个批次的数据,包括image和labels
imgs,labels = next(iter(train_dataloader))
#64是批次有多少图片,1是通道,黑白,然后是高宽。(1,28,28)
print(imgs.shape)
#figsize,规定图片规格,这里是10张横的图片
# plt.figure(figsize=(10,1))
# #切片前十张
# #for表示i<10,取前十张,img表示取的是imgs里的图片
# for i,img in enumerate(imgs[:10]):
# npimg = img.numpy()#imgshitensor,要转换为numpy
# npimg = np.squeeze(npimg) #因为绘图时不能有1维,所以去掉
# plt.subplot(1,10,i+1)
# plt.imshow(npimg)
# plt.axis('off')
#plt.show()
#print(labels[:10]) #显示图片与编号一致
#创建多层感知器模型
# 全连接层,对全部输入加权求和,要求输入数据为一维
#nn.Linear() #输入都是(batch,features),features必须是一维
class model(nn.Module):
def __init__(self):
super(model, self).__init__()
self.linear_1 = nn.Linear(28*28,120) #linear输入为一维,所以将所有像素展开为一维,即通道*高*宽,1*28*28
self.linear_2 = nn.Linear(120, 84)
self.linear_3 = nn.Linear(84, 10) #因为要输出十个,从0到9
def forward(self,input):
#因为输入的是图片,有通道,高宽,所以先对输入进行展平
x = input.view(-1,1*28*28) #-1是batch维,随batch变化,后面则是后三维相乘
#此时x已展开,可以连接linear层了
x = torch.relu(self.linear_1(x))
x = torch.relu(self.linear_2(x))
logits = self.linear_3(x) #softmax分类在损失函数中计算,所以不用激活
return logits #logits一般被称为未激活的输出。因为分类问题的损失函数需要的输入是未激活的
#初始化模型,使模型在当前可用设备上使用.标准写法
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model = model().to(device)
#损失函数
loss_fn = torch.nn.CrossEntropyLoss()
#优化
opt = torch.optim.SGD(model.parameters(),lr=0.001)
#编写通用训练函数代码
def train(dataloader,model,loss_fn,optimizer):
size = len(dataloader.dataset) #获得当前数据的总样本数
num_batches = len(dataloader) #批次数:如全部数据为100,batch=16,则7次可全部训练一遍,7就是批次数
train_loss,correct = 0,0 #train_loss所有批次的损失和,correct为累加的预测正确的样本数
for x,y in dataloader: #注意:x,y都是一个批次的值
x,y = x.to(device),y.to(device)
pred = model(x)
loss = loss_fn(pred,y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
with torch.no_grad():#argmax(axis),这里axis=1,即按行看,返回最大元素的位置
correct += (pred.argmax(1) == y).type(torch.float).sum().item()#计算预测对了多少个样本。地0维是batch,所以用1
train_loss += loss.item()
#计算正确率和每个样本的平均损失值
correct /=size
train_loss /=num_batches
return correct,train_loss
#编写通用测试函数代码
def ttest(test_dataloader,model,loss_fn): #注意名字不要取成test,不然会自动运行pytest
size = len(test_dataloader.dataset) #获得当前数据的总样本数
num_batches = len(test_dataloader) #批次数
test_loss,correct = 0,0 #train_loss所有批次的损失和,correct为累加的预测正确的样本数
with torch.no_grad(): #测试流程不需要跟踪梯度
for x,y in test_dataloader: #注意:x,y都是一个批次的值
x,y = x.to(device),y.to(device)
pred = model(x)
loss = loss_fn(pred,y)
correct += (pred.argmax(1) == y).type(torch.float).sum().item()
test_loss += loss.item()
correct /=size
test_loss /=num_batches
return correct,test_loss
# #每一个epoch代表将全部数据集训练一遍
# epoches = 50
# #创建4个空列表,记录每个epoch的平均损失和正确率
# train_loss = []
# train_correct = []
# test_loss = []
# test_correct = []
#
# for epoch in range(epoches):
# epoch_correct,epoch_loss = train(train_dataloader,model,loss_fn,opt)
# epoch_test_correct,epoch_test_loss = ttest(test_dataloader, model, loss_fn)
# #记录训练情况
# test_loss.append(epoch_test_loss)
# train_loss.append(epoch_loss)
# test_correct.append(epoch_test_correct)
# train_correct.append(epoch_correct)
#
# #打印模板,用的字符串格式化.注意双引号是中文双引号
# template = ("epoch:{:2d},train_loss:{:.5f},train_correct:{:.1f},test_loss:{:.5f},test_correct:{:.1f}")
# #注意这里输出的是当前循环的loss和correct,不是存入列表的train_loss
# print(template.format(epoch,epoch_loss,epoch_correct*100,epoch_test_loss,epoch_test_correct*100))
# print('Done')
#可创建一个通用的fit训练函数
def fit(epoches,train_dataloader,test_dataloader,model,loss_fn,opt):
train_loss = []
train_correct = []
test_loss = []
test_correct = []
for epoch in range(epoches):
epoch_correct, epoch_loss = train(train_dataloader, model, loss_fn, opt)
epoch_test_correct, epoch_test_loss = ttest(test_dataloader, model, loss_fn)
# 记录训练情况
test_loss.append(epoch_test_loss)
train_loss.append(epoch_loss)
test_correct.append(epoch_test_correct)
train_correct.append(epoch_correct)
# 打印模板,用的字符串格式化.注意双引号是中文双引号
template = ("epoch:{:2d},train_loss:{:.5f},train_correct:{:.1f},test_loss:{:.5f},test_correct:{:.1f}")
# 注意这里输出的是当前循环的loss和correct,不是存入列表的train_loss
print(template.format(epoch, epoch_loss, epoch_correct * 100, epoch_test_loss,
epoch_test_correct * 100))
print('Done')
return train_loss,train_correct,test_loss,test_correct
#直接调用fit函数
train_loss,train_correct,test_loss,test_correct = fit(100,train_dataloader,test_dataloader,model,loss_fn,opt)
#也可绘图
plt.plot(range(100),train_loss,label='train_loss')
plt.plot(range(100),test_loss,label='test_loss')
plt.legend()
plt.show()