目录
一、tensorboard的使用
通过调用add_image()方法和add_scalar()方法对数据进行可视化处理
# -*- coding:utf-8 -*-
from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image
writer=SummaryWriter("log")
image_path="data/val/bees/44105569_16720a960c.jpg"
img_PIL=Image.open(image_path)
img_array=np.array(img_PIL)
print(type(img_array))
print(img_array.shape)
writer.add_image("train",img_array,1,dataformats="HWC")
#y=5x
for i in range(100):
writer.add_scalar("y=5x",5*i,i)
writer.close()
运行结果:
二、Transforms的使用
transforms.py文件是一个工具箱,里边的类比如totensor、resize是工具模板。
使用工具 需要创建具体的工具,比如tool=transforms.ToTensor(),transforms.ToTensor()是将图片转化为tensor数据类型。然后使用工具输入输出,比如result=tool(input)。
transforms.ToTensor()具体使用代码
# -*- coding:utf-8 -*-
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
# python的用法 -> tensor的数据类型
# 通过transforms.ToTensor去看两个问题
# 绝对路径: F:\JetBrains\learn_pytorch\data\train\ants_image\0013035.jpg
# 相对路径: data/train/ants_image/0013035.jpg
img_path="data/train/ants_image/0013035.jpg"
img=Image.open(img_path)
#print(img)
writer=SummaryWriter("logs")
# 1.transforms该如何使用
tensor_trans=transforms.ToTensor()
tensor_img=tensor_trans(img)
#print(tensor_img)
writer.add_image("Tensor_img",tensor_img)
writer.close()
# 2.为什么我们需要tensor数据类型
# tensor数据类型是包装了反向神经网络所需要的理论基础的一些参数 在神经网络中需要转化为tensor型进行训练
# 所以transforms和tensor是必不可少的
transforms.Resize()是改变图片的规格大小
from PIL import Image
from torchvision import transforms
img_path="data/train/ants_image/0013035.jpg"
img=Image.open(img_path)
#Resize
print(img.size)
trans_resize=transforms.Resize((512,512))
img_resize=trans_resize(img)
print(img_resize.size)
本例中图片有(768,512)变换为(512,512)
Compose()用法:Compose()中的参数需要是一个列表,Python中,列表的形式表示为[数据1,数据2,…],在Compose中,数据需要是transforms类型。所以得到,Compose([transforms参数1,transforms参数2,…])。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer=SummaryWriter("logs")
#Tensor
trans_tensor=transforms.ToTensor()
img_path="data/train/ants_image/0013035.jpg"
img=Image.open(img_path)
# Compose - resize - 2
trans_resize_2=transforms.Resize(512)
# PIL -> PIL -> tensor
trans_compose=transforms.Compose([trans_resize_2,trans_tensor])
img_resize_2=trans_compose(img)
writer.add_image("Resize",img_resize_2,1)
writer.close()
在本例中,trans_compose()将img先通过Resize()变换图片规格大小,在通过tensor()转换为tensor数据类型。
transforms.RandomCrop()是随机裁剪(将Image类型的图片随机裁剪)
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer=SummaryWriter("logs")
#Tensor
trans_tensor=transforms.ToTensor()
img_path="data/train/ants_image/0013035.jpg"
img=Image.open(img_path)
# RandomCrop
trans_random=transforms.RandomCrop(512)
trans_compose_2=transforms.Compose([trans_random,trans_tensor])
for i in range(10):
img_crop=trans_compose_2(img)
writer.add_image("RandomCrop",img_crop,i)
writer.close()
三、torchvision中数据集的使用
(以CIFAR10数据集为例)
import torchvision
from torch.utils.tensorboard import SummaryWriter
dataset_transform = torchvision.transforms.Compose([torchvision.transforms.ToTensor()])
# 参数train 若等于True则数据集为训练集 若等于False则数据集为测试集
train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True)
test_set = torchvision.datasets.CIFAR10(root="./dattaset", train=False, transform=dataset_transform, download=True)
# print(test_set[0])
# print(test_set.classes)
# img,target=test_set[0]
# print(img)
# print(target)
# print(test_set.classes[target])
# img.show()
# print(test_set[0])
writer = SummaryWriter("p10")
for i in range(10):
img,target=test_set[i]
writer.add_image("test",img,i)
writer.close()
四、DataLoader的使用
通俗点说,就是通过特定的方式从数据集中取数据
import torchvision
#准备测试数据集
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor())
# DataLoader的使用以及参数含义
# 参数dataset为要使用的数据集 参数batch_size为每次选取图片数
# 参数shuffle为确定多轮选取的图片以及顺序是否一致 True为每次选取的图片是不一致的 False为每次选取的图片是一致的
# 参数drop_last为当所选的图片数小于batch_size时,True为舍去,False为不舍去
test_loader=DataLoader(dataset=test_data,batch_size=64,shuffle=False,num_workers=0,drop_last=False)
#测试数据集中第一张图片及target
img,target=test_data[0]
print(img.shape)
print(target)
# tensorboard 图像的使用
writer=SummaryWriter("dataloader")
for epoch in range(2):
step=0
for data in test_loader:
imgs,targets=data
# print(imgs.shape)
# print(targets)
writer.add_images("Epoch: {}".format(epoch),imgs,step)
step=step+1
writer.close()
五、神经网络的基本骨架torch.nn.Module的使用
神经网络的基本模型(模板) torch.nn.Module
nn为神经网络(neural network)的缩写
继承Module类要重写__init__()方法和forward()方法
# -*- coding:utf-8 -*-
import torch
from torch import nn
class Yuxi(nn.Module):
def __init__(self):
super().__init__()
def forward(self,input):
output=input+1
return output
x=torch.tensor(1.0)
yx=Yuxi()
output=yx(x)
print(output)
测试Module类:创建Yuxi类并继承Module类对数据tensor(1.0)进行操作加一并输出
六、卷积操作
通过使用torch.nn.functional.conv2d()对二维图片进行卷积操作
# -*- coding:utf-8 -*-
# 测试卷积操作 torch.nn.functional
import torch
import torch.nn.functional as F
# 输入图像
input=torch.tensor([[1,2,0,3,1],
[0,1,2,3,1],
[1,2,1,0,0],
[5,2,3,1,1],
[2,1,0,1,1]])
# 卷积核
kernel=torch.tensor([[1,2,1],
[0,1,0],
[2,1,0]])
print("reshape之前:")
print(input.shape)
print(kernel.shape)
# 由于conv2d()函数的输入与卷积核的参数必须是四维输入
# 于是利用torch.reshape()函数把输入与卷积核进行reshape将其转化为四维
input=torch.reshape(input,(1,1,5,5))
kernel=torch.reshape(kernel,(1,1,3,3))
print("reshape之后:")
print(input.shape)
print(kernel.shape)
# conv2d()方法的参数
# stride的作用是控制卷积核移动步数 若stride的数值为n则在进行卷积操作过程中卷积核每次移动n步
# padding的作用是对图像边缘进行填充(一般情况下填充为0) 若padding的数值为n则对图像矩阵上下左右各插入n行或者n列
# 卷积后的输出
# 当stride为1的时候
output1=F.conv2d(input,kernel,stride=1)
print("stride为1:")
print(output1)
# 当stride为2的时候
output2=F.conv2d(input,kernel,stride=2)
print("stride为2:")
print(output2)
# 当padding为1时,原来的图像被填充为7x7的图像,进行卷积操作后输出变为5x5
output3=F.conv2d(input,kernel,stride=1,padding=1)
print(output3)
当padding为1时,原来的图像被填充为7x7的图像,进行卷积操作后输出变为5x5
七、神经网络
1.卷积层(Convolution Layers)
# -*- coding:utf-8 -*-
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download="True")
dataloader=DataLoader(dataset,batch_size=64)
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.conv1=Conv2d(in_channels=3,out_channels=6,kernel_size=3,stride=1,padding=0)
def forward(self,x):
x=self.conv1(x)
return x
yx=Yuxi()
print(yx)
writer=SummaryWriter("./logs")
step=0
for data in dataloader:
imgs,targets=data
output=yx(imgs)
print(imgs.shape)
print(output.shape)
# torch.Size([64, 3, 32, 32])
writer.add_images("input",imgs,step)
# torch.Size([64, 6, 30, 30]) -> [xxx,3,30,30]
output=torch.reshape(output,(-1,3,30,30))
writer.add_images("output",output,step)
step=step+1
writer.close()
2.最大池化
池化层(Pooling layers)
最大池化的目的(作用):保留输入的特征,并把数据量减小,提高训练速度
例如,1080p的视频,经过最大池化之后变为720p的视频,保留了视频特征,数据量变小(文件变小)
如图,输入图像5x5经过3x3的池化核之后,在ceil_model为true的情况下,输出变为2x2,在ceil_model为false的情况下,输入变为1x1(ceil_model为true时,为向上取整保留,ceil_model为false时,为向下取整不保留)
# -*- coding:utf-8 -*-
import torch
from torch import nn
from torch.nn import MaxPool2d
#输入图像
input=torch.tensor([[1,2,0,3,1],
[0,1,2,3,1],
[1,2,1,0,0],
[5,2,3,1,1],
[2,1,0,1,1]],dtype=torch.float32)
input=torch.reshape(input,(-1,1,5,5))
print(input.shape)
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=False)
def forward(self,input):
output=self.maxpool1(input)
return output
yx=Yuxi()
output=yx(input)
print(output)
当参数ceil_model为true时
当参数ceil_model为false时
代码实例 对图像进行池化处理 图像变模糊(通过tensorboard查看图像变化)
# -*- coding:utf-8 -*-
import torch
import torchvision.datasets
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,download=True,
transform=torchvision.transforms.ToTensor())
dataloader=DataLoader(dataset,batch_size=64)
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.maxpool1=MaxPool2d(kernel_size=3,ceil_mode=True)
def forward(self,input):
output=self.maxpool1(input)
return output
yx=Yuxi()
writer=SummaryWriter("logs_maxpool")
step=0
for data in dataloader:
imgs,targets=data
writer.add_images("input",imgs,step)
output=yx(imgs)
writer.add_images("output",output,step)
step=step+1
writer.close()
池化处理前后对比
3.非线性激活(Non-linear Activations)
非线性变换的主要目的就是给网络当中去引入一些非线性的特征,因为非线性越多的话才能训练出符合各种曲线或者说是符合各种特征的一个模型,如果都是直愣愣的话,那模型的泛化能力就不够好。
代码实现(nn.ReLU)
# -*- coding:utf-8 -*-
import torch
from torch import nn
from torch.nn import ReLU
input=torch.tensor([[1,-0.5],
[-1,3]])
input=torch.reshape(input,(-1,1,2,2))
print(input.shape)
#测试非线性激活
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.relu=ReLU(inplace=False)
def forward(self,input):
output=self.relu(input)
return output
yx=Yuxi()
output=yx(input)
print(output)
运行结果
例如,我们选择nn.Sigmoid()方法进行非线性激活,然后通过tensorboard显示图像感受非线性激活的处理。
# -*- coding:utf-8 -*-
import torch
import torchvision.datasets
from torch import nn
from torch.nn import ReLU, Sigmoid
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
input=torch.tensor([[1,-0.5],
[-1,3]])
input=torch.reshape(input,(-1,1,2,2))
print(input.shape)
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),download=True)
dataloader=DataLoader(dataset,batch_size=64)
#测试非线性激活
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.relu=ReLU(inplace=False)
self.sigmoid=Sigmoid()
def forward(self,input):
output=self.sigmoid(input)
return output
yx=Yuxi()
writer=SummaryWriter("./logs_sigmoid")
step=0
for data in dataloader:
imgs,targets=data
writer.add_images("input",imgs,step)
output=yx(imgs)
writer.add_images("output",output,step)
step=step+1
writer.close()
非线性激活前后对比
4.线性层(Linear Layers)
# -*- coding:utf-8 -*-
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=True)
dataloader=DataLoader(dataset,batch_size=64)
#测试线性层
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.linear1=Linear(196608,10)
def forward(self,input):
output=self.linear1(input)
return output
yx=Yuxi()
for data in dataloader:
imgs,targets=data
print(imgs.shape)
# 把tensor数据展开成一行
output=torch.flatten(imgs)
print(output.shape)
output=yx(output)
print(output.shape)
运行结果
5.搭建小实战网络模型以及torch.nn.Sequential的使用
搭建一个对CIFAR10数据集进行简单分类的网络
CIFAR10的模型结构:
代码实现(未使用Sequential时)
# -*- coding:utf-8 -*-
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear
# 搭建CIFAR10网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.conv1=Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2)
self.maxpool1=MaxPool2d(kernel_size=2)
self.conv2=Conv2d(32,32,5,1,2)
self.maxpool2=MaxPool2d(2)
self.conv3=Conv2d(32,64,5,1,2)
self.maxpool3=MaxPool2d(2)
self.flatten=Flatten()
self.linear1=Linear(1024,64)
self.linear2=Linear(64,10)
def forward(self,x):
x=self.conv1(x)
x=self.maxpool1(x)
x=self.conv2(x)
x=self.maxpool2(x)
x=self.conv3(x)
x=self.maxpool3(x)
x=self.flatten(x)
x=self.linear1(x)
x=self.linear2(x)
return x
yx=Yuxi()
print(yx)
input=torch.ones((64,3,32,32))
output=yx(input)
print(output.shape)
运行结果
使用Sequential后(代码会简洁很多)
# -*- coding:utf-8 -*-
import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter
# 搭建CIFAR10网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=Sequential(
Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
MaxPool2d(kernel_size=2),
Conv2d(32, 32, 5, 1, 2),
MaxPool2d(2),
Conv2d(32, 64, 5, 1, 2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
yx=Yuxi()
print(yx)
input=torch.ones((64,3,32,32))
output=yx(input)
print(output.shape)
writer=SummaryWriter("./logs_seq")
writer.add_graph(yx,input)
writer.close()
运行结果
tensorboard中通过writer.add_graph()生成的可视化图像
八、损失函数与反向传播
Loss Functions
作用:
1.计算实际输出和目标输出之间的差距
2.为我们更新输出提供一定的依据(反向传播)
# -*- coding:utf-8 -*-
#测试Loss
import torch
from torch import nn
inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5],dtype=torch.float32)
inputs=torch.reshape(inputs,(1,1,1,3))
targets=torch.reshape(targets,(1,1,1,3))
# L1Loss() 计算实际输出与目标之间的差距
# 参数reduction为mean时计算差的绝对值的平均数 为sum时计算差的绝对值的和
loss=nn.L1Loss(reduction="mean")
result=loss(inputs,targets)
print(result)
# MSELoss() 计算实际输出与目标之间的差距(平均方差)
loss_mse=nn.MSELoss()
result_mse=loss_mse(inputs,targets)
print(result_mse)
# CrossEntropyLoss() 计算实际输出与目标之间的差距
x=torch.tensor([0.1,0.2,0.3])
y=torch.tensor([1])
x=torch.reshape(x,(1,3))
loss_cross=nn.CrossEntropyLoss()
result_cross=loss_cross(x,y)
print(result_cross)
运行结果
在网络模型中使用nn.CrossEntropyLoss(),并使用backward()进行反向传播
# -*- coding:utf-8 -*-
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Sequential, Flatten, Linear
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=True)
dataloader=DataLoader(dataset,batch_size=1)
# 测试在网络模型中使用损失函数Loss Functions
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=Sequential(
Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
MaxPool2d(kernel_size=2),
Conv2d(32, 32, 5, 1, 2),
MaxPool2d(2),
Conv2d(32, 64, 5, 1, 2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
yx=Yuxi()
loss=nn.CrossEntropyLoss()
for data in dataloader:
imgs,targets=data
outputs=yx(imgs)
result_loss=loss(outputs,targets)
result_loss.backward()
print(result_loss)
九、优化器
优化器根据梯度调整参数,以降低误差。
# -*- coding:utf-8 -*-
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Sequential, Flatten, Linear
from torch.utils.data import DataLoader
dataset=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=True)
dataloader=DataLoader(dataset,batch_size=1)
# 测试在网络模型中使用损失函数Loss Functions
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=Sequential(
Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
MaxPool2d(kernel_size=2),
Conv2d(32, 32, 5, 1, 2),
MaxPool2d(2),
Conv2d(32, 64, 5, 1, 2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
yx=Yuxi()
# 定义损失函数
loss=nn.CrossEntropyLoss()
# 定义优化器
optim=torch.optim.SGD(yx.parameters(),lr=0.01)
# 多轮训练
for epoch in range(20):
running_loss=0.0
for data in dataloader:
imgs,targets=data
outputs=yx(imgs)
# 计算实际输出与目标的差距
result_loss=loss(outputs,targets)
# 将网络中每个参数的梯度调为0
optim.zero_grad()
# 使用反向传播得到每个参数的梯度
result_loss.backward()
# 调用优化器进行调优
optim.step()
# 累加 输出与目标的差 的和
running_loss=running_loss+result_loss
print(running_loss)
运行结果
十、pytorch提供的现有网络模型
1.现有网络模型的使用以及修改
修改网络模型有两种方式:添加层 或者直接修改某一层
# -*- coding:utf-8 -*-
import torchvision
from torch import nn
# 加载pytorch提供的现有的网络模型
vgg16_false=torchvision.models.vgg16(pretrained=False)
vgg16_true=torchvision.models.vgg16(pretrained=True)
train_data=torchvision.datasets.CIFAR10("./dataset",train=True,transform=torchvision.transforms.ToTensor(),
download=True)
# 修改加载的网络模型
# 显示vgg16的网络结构
print(vgg16_true)
# 在已有的网络模型中添加一层
vgg16_true.classifier.add_module("add_linear",nn.Linear(1000,10))
print(vgg16_true)
# 显示vgg16的网络模型结构
print(vgg16_false)
# 修改已有的网络模型的某一层
vgg16_false.classifier[6]=nn.Linear(4096,10)
print(vgg16_false)
2.模型的保存与加载
模型的保存:
# -*- coding:utf-8 -*-
# model_save.py
import torchvision
import torch
from torch import nn
# 加载vgg16未训练的模型
vgg16=torchvision.models.vgg16(pretrained=False)
# 保存方式1,模型结构+模型参数
torch.save(vgg16,"vgg16_method1.pth")
# 保存方式2,模型参数(官方推荐)
torch.save(vgg16.state_dict(),"vgg16_method2.pth")
# 自定义的网络模型的保存
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.conv1=nn.Conv2d(3,64,3)
def forward(self,x):
x=self.conv1(x)
return x
yx=Yuxi()
torch.save(yx,"Yuxi_method1.pth")
模型的加载:
# -*- coding:utf-8 -*-
# model_load.py
import torch
import torchvision
from torch import nn
from model_save import *
# 方式1 保存方式1->加载模型
model=torch.load("vgg16_method1.pth")
# print(model)
# 方式2 保存方式2->加载模型
vgg16=torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
# model=torch.load("vgg16_method2.pth")
# print(vgg16)
# 自定义的网络模型的加载
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi,self).__init__()
self.conv1=nn.Conv2d(3,64,3)
def forward(self,x):
x=self.conv1(x)
return x
model=torch.load("Yuxi_method1.pth")
print(model)
十一、完整的模型训练套路
1.argmax()函数的使用:寻找最大值
# -*- coding:utf-8 -*-
import torch
outputs=torch.tensor([[0.1,0.2],
[0.05,0.4]])
# 函数argmax()参数为0时从上往下看找最大值,参数为1时从左往右看找最大值
print(outputs.argmax(0))
print(outputs.argmax(1))
outputs=torch.tensor([[0.1,0.2],
[0.3,0.4]])
preds=outputs.argmax(1)
targets=torch.tensor([0,1])
# 得到对应位置是否相等
print(preds==targets)
# 得到对应位置相等的个数
print((preds==targets).sum().item())
2.对数据集CIFAR10进行分类(10分类)问题的模型训练
model.py
# -*- coding:utf-8 -*-
import torch
from torch import nn
# 搭建神经网络
# 搭建CIFAR10网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
if __name__ == '__main__':
yx=Yuxi()
input=torch.ones((64,3,32,32))
output=yx(input)
print(output.shape)
train.py
# -*- coding:utf-8 -*-
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
from model import *
# 准备数据集
train_data=torchvision.datasets.CIFAR10("./dataset",train=True,transform=torchvision.transforms.ToTensor(),
download=True)
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=False)
# length 长度
train_data_size=len(train_data)
test_data_size=len(test_data)
# 如果train_data_size=10,则输出训练数据集长度为:10
print("训练数据集长度为:{}".format(train_data_size))
print("测试数据集长度为:{}".format(test_data_size))
# 利用 DataLoader 来加载数据集
train_dataloader=DataLoader(train_data,batch_size=64)
test_dataloader=DataLoader(test_data,batch_size=64)
# 创建网络模型
yx=Yuxi()
# 损失函数
loss_fn=nn.CrossEntropyLoss()
# 优化器
learning_rate=1e-2
optimizer=torch.optim.SGD(yx.parameters(),lr=learning_rate)
# 设置训练网络的一些参数
# 记录训练的次数
total_train_step=0
# 记录测试的次数
total_test_step=0
# 训练的轮数
epoch=10
# 添加tensorboard
writer=SummaryWriter("./logs_train")
# 训练
for i in range(epoch):
print("--------第{}轮训练开始--------".format(i+1))
#训练步骤开始
yx.train()
for data in train_dataloader:
imgs,targets=data
outputs=yx(imgs)
# 计算损失值
loss=loss_fn(outputs,targets)
# 优化器模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step=total_train_step+1
if total_train_step%100==0:
print("训练次数: {}, loss: {}".format(total_train_step,loss.item()))
writer.add_scalar("train_loss",loss.item(),total_train_step)
# 测试步骤开始
yx.eval()
total_test_loss=0
total_accuracy=0
with torch.no_grad():
for data in test_dataloader:
imgs,targets=data
outputs=yx(imgs)
loss=loss_fn(outputs,targets)
total_test_loss=total_test_loss+loss.item()
accuracy=(outputs.argmax(1)==targets).sum()
total_accuracy=total_accuracy+accuracy
print("整体测试集上的Loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss",total_test_loss,total_test_step)
writer.add_scalar("test_accuracy",total_accuracy/test_data_size,total_test_step)
total_test_step=total_test_step+1
# 模型保存方式1
torch.save(yx,"yx_{}.pth".format(i+1))
# 模型保存方式2(官方推荐)
# torch.save(yx.state_dict(),"yx_{}.pth".format(i+1))
print("模型已保存")
writer.close()
运行结果:
tensorboard图像处理
十一、利用GPU训练
1.使用GPU的第一种方式
if torch.cuda.is_available():
yx=yx.cuda()
if torch.cuda.is_available():
loss_fn=loss_fn.cuda()
if torch.cuda.is_available():
imgs=imgs.cuda()
targets=targets.cuda()
对网络模型、数据(输入、标注)以及损失函数调用.cuda()在返回给它自己就可以了
train_gpu_1.py
# -*- coding:utf-8 -*-
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
#from model import *
# 准备数据集
train_data=torchvision.datasets.CIFAR10("./dataset",train=True,transform=torchvision.transforms.ToTensor(),
download=True)
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=False)
# length 长度
train_data_size=len(train_data)
test_data_size=len(test_data)
# 如果train_data_size=10,则输出训练数据集长度为:10
print("训练数据集长度为:{}".format(train_data_size))
print("测试数据集长度为:{}".format(test_data_size))
# 利用 DataLoader 来加载数据集
train_dataloader=DataLoader(train_data,batch_size=64)
test_dataloader=DataLoader(test_data,batch_size=64)
# 创建网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
yx=Yuxi()
if torch.cuda.is_available():
yx=yx.cuda()
# 损失函数
loss_fn=nn.CrossEntropyLoss()
if torch.cuda.is_available():
loss_fn=loss_fn.cuda()
# 优化器
learning_rate=1e-2
optimizer=torch.optim.SGD(yx.parameters(),lr=learning_rate)
# 设置训练网络的一些参数
# 记录训练的次数
total_train_step=0
# 记录测试的次数
total_test_step=0
# 训练的轮数
epoch=10
# 添加tensorboard
writer=SummaryWriter("./logs_train")
# 训练
for i in range(epoch):
print("--------第{}轮训练开始--------".format(i+1))
#训练步骤开始
yx.train()
for data in train_dataloader:
imgs,targets=data
if torch.cuda.is_available():
imgs=imgs.cuda()
targets=targets.cuda()
outputs=yx(imgs)
# 计算损失值
loss=loss_fn(outputs,targets)
# 优化器模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step=total_train_step+1
if total_train_step%100==0:
print("训练次数: {}, loss: {}".format(total_train_step,loss.item()))
writer.add_scalar("train_loss",loss.item(),total_train_step)
# 测试步骤开始
yx.eval()
total_test_loss=0
total_accuracy=0
with torch.no_grad():
for data in test_dataloader:
imgs,targets=data
if torch.cuda.is_available():
imgs = imgs.cuda()
targets = targets.cuda()
outputs=yx(imgs)
loss=loss_fn(outputs,targets)
total_test_loss=total_test_loss+loss.item()
accuracy=(outputs.argmax(1)==targets).sum()
total_accuracy=total_accuracy+accuracy
print("整体测试集上的Loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss",total_test_loss,total_test_step)
writer.add_scalar("test_accuracy",total_accuracy/test_data_size,total_test_step)
total_test_step=total_test_step+1
# 模型保存方式1
torch.save(yx,"yx_{}.pth".format(i+1))
# 模型保存方式2(官方推荐)
# torch.save(yx.state_dict(),"yx_{}.pth".format(i+1))
print("模型已保存")
writer.close()
2.使用GPU的第二种方式
# 定义训练使用的设备
# 若cuda可用则使用gpu 不可用则使用cpu
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
yx=yx.to(device)
loss_fn=loss_fn.to(device)
imgs=imgs.to(device)
targets=targets.to(device)
对网络模型、数据(输入、标注)以及损失函数调用.to(device)在返回给它自己就可以了
train_gpu_2.py
# -*- coding:utf-8 -*-
import time
import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
# 定义训练使用的设备
# 若cuda可用则使用gpu 不可用则使用cpu
device=torch.device("cuda" if torch.cuda.is_available() else "cpu")
#from model import *
# 准备数据集
train_data=torchvision.datasets.CIFAR10("./dataset",train=True,transform=torchvision.transforms.ToTensor(),
download=True)
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
download=False)
# length 长度
train_data_size=len(train_data)
test_data_size=len(test_data)
# 如果train_data_size=10,则输出训练数据集长度为:10
print("训练数据集长度为:{}".format(train_data_size))
print("测试数据集长度为:{}".format(test_data_size))
# 利用 DataLoader 来加载数据集
train_dataloader=DataLoader(train_data,batch_size=64)
test_dataloader=DataLoader(test_data,batch_size=64)
# 创建网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
yx=Yuxi()
yx=yx.to(device)
# 损失函数
loss_fn=nn.CrossEntropyLoss()
loss_fn=loss_fn.to(device)
# 优化器
learning_rate=1e-2
optimizer=torch.optim.SGD(yx.parameters(),lr=learning_rate)
# 设置训练网络的一些参数
# 记录训练的次数
total_train_step=0
# 记录测试的次数
total_test_step=0
# 训练的轮数
epoch=10
# 添加tensorboard
writer=SummaryWriter("./logs_train")
# 训练
start_time=time.time()
for i in range(epoch):
print("--------第{}轮训练开始--------".format(i+1))
#训练步骤开始
yx.train()
for data in train_dataloader:
imgs,targets=data
imgs=imgs.to(device)
targets=targets.to(device)
outputs=yx(imgs)
# 计算损失值
loss=loss_fn(outputs,targets)
# 优化器模型
optimizer.zero_grad()
loss.backward()
optimizer.step()
total_train_step=total_train_step+1
if total_train_step%100==0:
end_time=time.time()
print(end_time-start_time)
print("训练次数: {}, loss: {}".format(total_train_step,loss.item()))
writer.add_scalar("train_loss",loss.item(),total_train_step)
# 测试步骤开始
yx.eval()
total_test_loss=0
total_accuracy=0
with torch.no_grad():
for data in test_dataloader:
imgs,targets=data
imgs = imgs.to(device)
targets = targets.to(device)
outputs=yx(imgs)
loss=loss_fn(outputs,targets)
total_test_loss=total_test_loss+loss.item()
accuracy=(outputs.argmax(1)==targets).sum()
total_accuracy=total_accuracy+accuracy
print("整体测试集上的Loss:{}".format(total_test_loss))
print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
writer.add_scalar("test_loss",total_test_loss,total_test_step)
writer.add_scalar("test_accuracy",total_accuracy/test_data_size,total_test_step)
total_test_step=total_test_step+1
# 模型保存方式1
torch.save(yx,"yx_{}.pth".format(i+1))
# 模型保存方式2(官方推荐)
# torch.save(yx.state_dict(),"yx_{}.pth".format(i+1))
print("模型已保存")
writer.close()
十二、完整的模型验证(测试demo)套路
完整的模型验证实际上就是利用训练好的模型,然后给它提供输入。模型训练好了,验证过程实际上就是对外的一个实际应用。
test_model.py
# -*- coding:utf-8 -*-
import torch
import torchvision
from PIL import Image
from torch import nn
image_path="./imgs/img_4.png"
image=Image.open(image_path)
print(image)
image=image.convert('RGB')
transform=torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
torchvision.transforms.ToTensor()])
image=transform(image)
print(image.shape)
# 搭建神经网络
# 搭建CIFAR10网络模型
class Yuxi(nn.Module):
def __init__(self):
super(Yuxi, self).__init__()
self.model1=nn.Sequential(
nn.Conv2d(in_channels=3,out_channels=32,kernel_size=5,stride=1,padding=2),
nn.MaxPool2d(kernel_size=2),
nn.Conv2d(32, 32, 5, 1, 2),
nn.MaxPool2d(2),
nn.Conv2d(32, 64, 5, 1, 2),
nn.MaxPool2d(2),
nn.Flatten(),
nn.Linear(1024, 64),
nn.Linear(64, 10)
)
def forward(self,x):
x=self.model1(x)
return x
# 加载训练好的网络模型
model=torch.load("yx_30.pth",map_location=torch.device('cpu'))
print(model)
image=torch.reshape(image,(1,3,32,32))
model.eval()
with torch.no_grad():
output=model(image)
print(output.argmax(1))
CIFAR10数据集中的10分类:
当图片为这个飞机时
预测结果:(结果准确)
当图片是这个狗时
预测结果:(结果准确)
这里加载的是事先使用cpu训练好的第30轮的网络模型,准确率可达66%