目录
4.1 tansforms中两个函数的使用------Totensor与normalize
1. Resize-------将图片进行缩放,有两个参数或者单参数
2.Compose---------组合使用方法,同步进行resize和totensor
3. RandomCrop--------------对图片进行随机裁剪
五. 对Transforms的总结,及TensorBoard
9.0 卷积操作 ----- 其中stride是步数的意思,若为2则是横向或者纵向走两步
9.3------------对数据集进行最大池化操作-----------代码示例
9.4------------------------------非线性激活
11. 1----------------------------损失函数要注意输入与输出的参数
11.2----------------------------交叉损失函数
11.3----------------反向传播:backward( )
一.Dataset(数据集)代码
在真正的使用中,数据集的分类为
在一个大的文件中,分为image与label;image为真实的图片对象,label所存储的为每个图片对象所对应的txt文件
2.--------------------------------------------------------------------------------对应上面的image与label
import os
# 设置源目录和目标目录
source_dir = 'dataset/train/bees_image'
target_dir = 'dataset/train/bees_label'
# 如果目标目录不存在,则创建它
if not os.path.exists(target_dir):
os.makedirs(target_dir)
# 遍历源目录中的所有.jpg文件
for filename in os.listdir(source_dir):
if filename.endswith('.jpg'):
# 构建目标文件路径(替换.jpg为.txt)
target_file_path = os.path.join(target_dir, filename.replace('.jpg', '.txt'))
# 创建并写入.txt文件
with open(target_file_path, 'w') as f:
f.write('bees')
print("所有.txt文件已生成并放置在'ants_label'目录下。")
p7代码,新建一个脚本和dataset同目录,蚂蚁的相应地方改成ants就行了
二.Tensorboard
1.定义和作用
TensorBoard 是一个由 TensorFlow 提供的可视化工具,它允许用户在训练机器学习模型时可视化和分析模型的性能。TensorBoard 可以展示多种类型的数据,包括损失和准确率曲线、激活直方图、权重和偏差的分布、以及嵌入的可视化等
2.代码
logdir是事件文件夹所在的位置 logs是创建的文件夹
打开方式为 : tensorboard --logdir =logs --port6008
y轴是标量,x轴是迭代次数,也就是执行次数
3.在tensorboard下,传入打开图片,并利用numpy进行格式转换;
-----最终可以查看过程和输出图片的结果---
三.Transform
1.transform的结构与用法
-----------tensor的意思就是张量,也就是维度------------------
---将一个图片通过工具进行转换,以得到结果,其中totensor是转换为tensor类型
2.代码实例
3.为什么要使用tensor数据类型
没有为什么,在深度学习中就是必须要用
四.Transforms的使用
python中__call__的用法
符号__下划线所表示的是内置函数;其作用是不需要再通过.来调用函数,可以直接在类名中传入参数
4.1 tansforms中两个函数的使用------Totensor与normalize
1.转换数据类型
2.规范化
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter
from PIL import Image
writer = SummaryWriter("logs")
img = Image.open("DataSet/train/ants/0013035.jpg")
print(img)
# ToTensor---------1.转换为tensor数据类型
trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image("ToTensor", img_tensor) #名称,图片对象
# Normalize-------2.将图片进行规范化
print(img_tensor[0][0][0]) # 选择第一个图像的第一个通道的第一个像素值 [0]->[0]->[0]
trans_norm = transforms.Normalize([0.5,0.5,0.5], [0.5,0.5,0.5]) # 两个长度为三的数组,分别表示三个通道的平均值和标准差
img_norm= trans_norm(img_tensor)
print(img_norm[0][0][0])
writer.add_image("Normalize", img_norm,1) #后面的数字是迭代次数,也就是第几步
writer.close()
归一化是为了消除奇异值,及样本数据中与其他数据相比特别大或特别小的数据,可以加快训练速度
4.2 transforms其余函数的使用
1. Resize-------将图片进行缩放,有两个参数或者单参数
Risize输入两个参数时,输出图片的高和宽的像素点数量会按照你设定的值进行输出。而只输入一个参数时,代表的时你最短的那个边输出的像素点数量
代码实例
# Resize----------3.1改变图片大小,等比缩放
print(img.size)
trans_resize = transforms.Resize((512,512)) # 注意是两个括号!!
#img PIL --> resize --> img_resize PIL
img_resize = trans_resize(img)
#img_resize PIL --> totensor --> img_resize tensor
img_resize = trans_totensor(img_resize)
writer.add_image("Resize", img_resize, 0)
print(img_resize)
2.Compose---------组合使用方法,同步进行resize和totensor
代码实例
# Compose------------3.2 另一种resize的方法
trans_resize_2 = transforms.Resize(512) #单参数形式
# PIL -> PIL --> tensor
trans_compose = transforms.Compose([trans_resize_2, trans_totensor]) #传入的参数是列表的形式,首先进行缩放,再进行数据转换
img_resize_2 = trans_compose(img)
writer.add_image("Resize", img_resize_2, 1)
3. RandomCrop--------------对图片进行随机裁剪
代码示例
# RandomCrop-------------4.随机裁剪
trans_random = transforms.RandomCrop(123)
trans_compose_2 = transforms.Compose([trans_random, trans_totensor])
for i in range(10):
img_crop = trans_compose_2(img) # 将图片传入进行随机裁剪
writer.add_image("RandomCrop", img_crop, i) # 总共有10个图片
五. 对Transforms的总结,及TensorBoard
1.transforms和tensorboard是两种不同的工具,分别用于图像预处理和模型训练过程的可视化;所以请分清两者的作用------> 图像等数据经过transforms中的函数后,在tensorboard中进行可视化展示
2.tansforms学习技巧-----------如何学习其中的函数
注意所定义的数据所返回的类型
六.torchvision中的数据集使用
torchvision是torch库的一个扩展,专门用于支持计算机视觉任务
1.代码示例---------步骤
-------------数据集的下载可以用迅雷,具体操作看p14------------------------
import torchvision
# 为了在tensorboard中显示,使用tansforms将图片转换为tensor类型
from torch.utils.tensorboard import SummaryWriter
dataset_transform = torchvision.transforms.Compose([
torchvision.transforms.ToTensor() #将其类型转换
])
# 定义训练数据集 存放路径 是否为训练数据集 对图片进行transform中的函数使用 是否下载
train_set = torchvision.datasets.CIFAR10(root="./dataset", train=True, transform=dataset_transform, download=True)
# 测试数据集
test_set = torchvision.datasets.CIFAR10(root="./dataset", train=False, transform=dataset_transform, download=True)
img, target = test_set[0] #返回 ->>图像的信息,种类的下标!!!!!!!!!!!!!!!!!!!!!!!!!
# print(test_set[0])
# print(test_set.classes) # 打印测试数据集中图片的种类
# print(img)
# print(target)
# print(test_set.classes[target])
writer = SummaryWriter("p14")
for i in range(10):
img, target = test_set[i]
writer.add_image("test_set", img, i)
七.DataLoader的定义及使用
注意在dataloader中,imgs, targets与writer.add_images的写法!!!
代码示例
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())
# 从测试数据集中加载 传入数据集 从中提取数量 打乱顺序 线程/多线程 删除最后一步所有图像
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True, num_workers=0, drop_last=True)
# 测试数据集中第一张图片及target !!!!!!!!!!!!!!!
img, target = test_data[0]
print(img.shape)
print(target)
writer = SummaryWriter("dataloader")
step = 0 #迭代次数
for data in test_loader:
imgs, targets = data #将遍历到的图片信息等赋值
writer.add_images("test_data_drop_last", imgs, step)
step = step+1
writer.close()
八. 神经网络的基本骨架-nn.Module的使用
1.在定义的神经网络模版中-----进行输入与输出的过程
2.代码示例
import torch
from torch import nn #引用神经网络
#创建一个神经网络模版
class Tudui(nn.Module):
def __int__(self):
super().__init__() #引用父类的特殊方法
def forward(self, input): #传入一个输入
output = input + 1
return output
#创建一个真实的神经网络
tudui = Tudui()
x = torch.tensor(1.0)
output = tudui(x) #在神经网络中进行输入,再输出
print(output)
九. 神经网络中神经结构的使用
9.0 卷积操作 ----- 其中stride是步数的意思,若为2则是横向或者纵向走两步
其中conv是卷积的意思
9.0 代码示例
import torch
# 引入神经网络中的所有函数方法,简写为F
import torch.nn.functional as F
#输入图像 --------------注意tensor中只能传入一个参数,所以这里外面还有个中括号
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]])
#上面所定义的输入图像和卷积核只有宽高,没有通道数等参数
#重写输入图像-----在卷积函数中需要输入图像和卷积核的通道数等信息
input = torch.reshape(input, (1, 1, 5, 5)) #后面的参数分别为(batchsize, 通道数,宽,高)
kernel = torch.reshape(kernel, (1, 1, 3, 3))
print(input.shape)
print(kernel.shape)
#输入图像 卷积核 步数
output = F.conv2d(input, kernel, stride=1)
print(output)
#在卷积函数中还有一个参数-------padding-------为几就会将输入图像往外扩展几个大小
output3 = F.conv2d(input, kernel, stride=1, padding=1)
print(output3)
9.1 神经网络---卷积层
conv2d卷积函数---2d图像(前五个参数必须知道!重要)
channel(通道数):当outchannel为2时,需要两个卷积核,输出结果也为两个
代码示例
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
data_set = torchvision.datasets.CIFAR10("./DataSet", train=False, transform=torchvision.transforms.ToTensor(), download=True)
data_loader = DataLoader(data_set, batch_size=64)
class Tudui(nn.Module):
def __int__(self):
super(Tudui, self).__int__()
#定义一个自身的函数--卷积-----> 用2d卷积层来进行赋值
self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
def forward(self, x):
#传入x这个参数,利用自身定义的函数来进行卷积操作
x = self.conv1(x)
return x
#创建实例
tudui = Tudui()
writer = SummaryWriter("logs")
step = 0
for data in data_loader:
imgs, targets = data
output = tudui(imgs) #!!!!!!!将参数imgs图片信息,传入所创建的神经网络中,利用forward函数进行自定义的卷积
print(imgs.shape)
print(output.shape)
# torch.Size([64, 3, 32, 32]) #输出图像集合的信息,batchsize......
writer.add_image("input", imgs, step)
# 要将torch.Size([64, 3, 32, 32]) ->> [xxx, 3, 30 , 30]
output = torch.reshape(output, (-1, 3, 30, 30))
writer.add_images("output", imgs, step)
step = step + 1
writer.close()
9.3 神经网络-----池化层
池化层的步长默认是卷积核的大小
ceil_mode-------------------floor地板,ceil天花板(也就是上下取整)
dilation指的是卷积核元素之间的间距----在卷积中,就是空洞卷积
padding指的是输入图像,对输入图像的周围添加方块数,其内的值一般为0
9.3.1---------------最大池化操作
通过池化核选取输入图像中所对应的最大值
池化的作用:
将原始图片进行池化,以便运行加快方便
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], #datatype 数据类型
[2, 1, 0, 1, 1]], dtype=torch.float32)
input = torch.reshape(input, (-1, 1, 5, 5))
print(input.shape)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__() #默认为false,即取地板,下限
self.maxpool = MaxPool2d(kernel_size=3, ceil_mode=False)
def forward(self, input):
output = self.maxpool(input) #将输入图像传入,进行最大池化层操作
return output
tudui = Tudui()
output = tudui(input) #对神经网络传入输入图像
9.3------------对数据集进行最大池化操作-----------代码示例
import torch
import torchvision
from torch import nn
from torch.nn import MaxPool2d
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
data_set = torchvision.datasets.CIFAR10("./DataSet", train=False, download=True, transform=torchvision.transforms.ToTensor())
data_loader = DataLoader(data_set, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__() #默认为false,即取地板,下限
self.maxpool = MaxPool2d(kernel_size=3, ceil_mode=False)
def forward(self, input):
output = self.maxpool(input) #将输入图像传入,进行最大池化层操作
return output
tudui = Tudui()
writer = SummaryWriter("logs")
step = 0
for data in data_loader:
imgs, targets = data
writer.add_images("input", imgs, step)
output = tudui(imgs)
writer.add_images("output", output, step)
step += 1
writer.close()
9.4------------------------------非线性激活
非线性激活-------两个函数(ReLu与Sigmoid)作用是就是为了非线性的存在
ReLu函数中的参数---inplace,其本意是替换的意思
代码示例
import torch
import torchvision
from torch import nn
from torch.nn import ReLU
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)
data_set = torchvision.datasets.CIFAR10("./DataSet", train=False, transform=torchvision.transforms.ToTensor(), download=True)
data_loader = DataLoader(data_set, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.rule = ReLU()
def forward(self, input):
output = self.rule(input)
return output
tudui = Tudui()
writer = SummaryWriter("new_logs")
step = 0
for data in data_loader:
imgs, targets = data
writer.add_images("input", imgs, step)
output = tudui(imgs) #因为使用数据集,所以这里传入输入图像
writer.add_images("output", output, step)
step += 1
writer.close()
9.5 神经网络的其他层
其他的所有层请看torch官网中的官方文档
正则化层 Normalization Layers
ReCurrent Layers
Transformer层 Transformer Layers
线性层 Linear Layers Layers
Dropout Layers
Sparse
线性层-----------------示例代码(将图像变成一行的形式)
import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader
data_set = torchvision.datasets.CIFAR10("./DataSet", train=False, transform=torchvision.transforms.ToTensor(), download=True)
data_loader = DataLoader(data_set, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.linear = Linear(196608, 10)
def forward(self):
output = self.linear(input)
return output
tudui = Tudui()
for data in data_loader:
imgs, targets = data
print(imgs.shape)
output = torch.reshape(imgs, (1, 1, 1, -1))
#将输入展成一维的形式,也就是一行
output = torch.flatten(output)
output = tudui(output)
print(output.shape)
十. 神经网络搭建实战---利用Sequential
代码示例
import torch
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Conv3d, Flatten, Linear
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
#通过Sequntial来自定义一个model来进行对数据的训练
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2), #此处的padding(增加图片周围格子数)是通过公式计算得来的
MaxPool2d(2), #池化核的大小为2
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(), #一个平铺操作
Linear(1024, 64), # 线性层,一个图片中的1024变为64
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
tudui = Tudui()
input = torch.ones((64, 3, 32, 32)) # ones就是很多个1,对数据进行1的填充
output = tudui(input)
print(output.shape)
十一. 损失函数与反向传播
11. 1----------------------------损失函数要注意输入与输出的参数
绝对值损失函数 : L1Loss
平方差损失函数: MSELoss
import torch
# 输入的数据
from torch.nn import L1Loss
inputs = torch.tensor([1, 2, 3], datype=torch.float32 )
# 目标数据
targets = torch.t([1, 2, 5], datype=torch.float32)
#!!!!!!!!因为 L1Loss 函数需要的参数有batchsize,所以需要进行reshape
inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))
# 计算损失大小
loss = L1Loss(reduction= 'sum') # 如果不写该参数,则计算方式默认为平均值形式
result = loss(inputs, targets) #传入输入数据与目标数据
print(result)
11.2----------------------------交叉损失函数
#CrossEntropy Loss 交叉损失函数
# 这里三个参数分别代表预测的 人,狗,猫 三种结果的概率
x = torch.tensor([0.1, 0.2, 0.3]) # 得分结果,也就是真实值
y = torch.tensor([1]) # 1为三个类的下标,此为狗
x = torch.reshape(x, (1, 3)) # 交叉损失函数的参数需要batchsize 与 类别----类别为3
loss_cross = nn.CrossEntropyLoss()
result = loss_cross(x, y)
在神经网络中使用交叉损失函数,计算损失值大小
import torch
import torchvision
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Conv3d, Flatten, Linear
from torch.utils.data import DataLoader
data_set = torchvision.datasets.CIFAR10("./DataSet", train=False, transform=torchvision.transforms.ToTensor(), download=True)
data_loader = DataLoader(data_set, batch_size=64)
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
#通过Sequntial来自定义一个model来进行对数据的训练
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2), #此处的padding(增加图片周围格子数)是通过公式计算得来的
MaxPool2d(2), #池化核的大小为2
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(), #一个平铺操作
Linear(1024, 64), # 线性层,一个图片中的1024变为64
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
# 定义损失函数
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in data_loader:
imgs, targets = data
output = tudui(imgs)
# 计算损失函数
result_loss = loss(output, targets)
print(result_loss)
11.3----------------反向传播:backward( )
反向传播:计算每个节点的梯度参数,以选择合适的优化器,对参数进行优化
# 定义损失函数
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in data_loader:
imgs, targets = data
output = tudui(imgs)
# 计算损失函数
result_loss = loss(output, targets)
print(result_loss)
# 进行反向传播,计算每个节点的梯度参数,以选择合适的优化器,对参数进行优化
result_loss.backward()
十二.优化器
优化器就是对神经网络中每个结点的梯度参数进行优化,for就是一轮,多轮需要嵌套循环
#构建一个优化器-------此处为随机梯度下降
optim = torch.optim.SGD(tudui.parameters(), lr=0.01) # 传入的参数为结点的参数, 学习速率
for epoch in range(20):
running_loss = 0.0
for data in data_loader:
imgs, targets = data
outputs = tudui(imgs)
# 计算损失函数
result_loss = loss(outputs, targets)
# 将优化器中结点的梯度参数清零
optim.zero_grad()
# 进行反向传播,计算每个节点的梯度参数,以选择合适的优化器,对参数进行优化
result_loss.backward()
#优化器运行
optim.step()
#计算每轮损失值的大小
running_loss = running_loss + result_loss
print(running_loss)
十三.网络模型的相关设置
13.1 现有网络模型的使用与修改
代码示例
import torch
import torchvision
from torch import nn
# 加载神经网络模型
vgg166_false = torchvision.models.vgg16(pretrained=False) # 是否已训练过,选择为否
vgg166_true = torchvision.models.vgg16(pretrained=True) # 已训练过
# 加载CIFAR10中的训练数据集
train_data = torchvision.datasets.CIFAR10("./DataSet", train=True, transform=torchvision.transforms.ToTensor(), download=True)
# 在神经网络中添加一个层---线性层
# 此为一个sequential的名称 名称 线性层设置
vgg166_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg166_true)
# 修改原先的神经网络中的层---线性层
vgg166_false.classifier[6] = nn.Linear(4096, 10)
print(vgg166_false)
将新添加的线性层放入到classifier中(即sequential中)
13.2 网络模型的保存与读取(加载)
通常使用方式2来进行保存和加载------------------不保存网络模型结构,只保存数据(字典形式)
import torch
import torchvision
# 加载一个网络模型
vgg16 = torchvision.models.vgg16()
# 保存方式1-------优点:不仅保存网络模型的结构,还保存网络模型的参数
torch.save(vgg16, "vgg16_method1.pth") # 参数:网络模型, 文件名
# 保存方式2---------官方推荐,只保存模型的数据(字典形式)
torch.save(vgg16.state_dict(), "vgg16_method2.pth")
----------------------------------------------------------------------------------
import torch
import torchvision
# 方式2------加载数据模型(字典形式)
vgg16 = torchvision.models.vgg16() # 字典形式的保存需要先引用网络模型的结构
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
------------------------如果是在本地目录下已存在的---------------
# --------------------在有自己的神经网络模型的前提下,进行加载--------------
# 需要先引入自己的网络模型,从头文件中引入
model = Tudui()
model.load_state_dict(torch.load("tudui_0.pth", map_location=torch.device('cuda')))
十四.完整的模型训练套路
14.1 完整的模型训练代码示例
项目分为------模型model、数据集进行训练train
tuidui.train( )-------------开始模型训练
tudui.eval( )---------------开始模型测试
import torch
import torchvision
#---------引入所搭建的神经网络------
from p27_model import * # *表示所有的东西
# 准备训练数据集
from torch.utils.data import DataLoader
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=True)
# 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)
# ---------------------数据集都准备完毕,需要搭建的神经网络--------------------
# 1.创建网络模型
tudui = Tudui()
# 2.损失函数
loss_fn = nn.CrossEntropyLoss() # 交叉损失函数
# 3.优化器
learning_rate = 1e-2 # 1 x(10)^(-2) = 1/100 = 0.01
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)
# 4.设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 进行多轮训练--------------------------
for i in range(epoch):
print("------------第{}轮训练开始-------------".format(i+1))
#训练步骤开始
tudui.train()
for data in train_dataloader:
imgs, targets = data
outputs = tudui(imgs)
#计算损失值
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad() # 将每个结点的梯度参数调为0
loss.backward() # 反向传播
optimizer.step() # 优化器调优
total_train_step = total_train_step+1 # 记录训练的次数
print("训练次数: {}, Loss:{}".format(total_train_step, loss.item()))
14.2 利用tensoerboard来呈现模型训练的过程
import torch
import torchvision
#---------引入所搭建的神经网络------
from torch.utils.tensorboard import SummaryWriter
from p27_model import * # *表示所有的东西
# 准备训练数据集
from torch.utils.data import DataLoader
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=True)
# 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)
# ---------------------数据集都准备完毕,需要搭建的神经网络--------------------
# 1.创建网络模型
tudui = Tudui()
# 2.损失函数
loss_fn = nn.CrossEntropyLoss() # 交叉损失函数
# 3.优化器
learning_rate = 1e-2 # 1 x(10)^(-2) = 1/100 = 0.01
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)
# 4.设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加tensorboard进行训练过程的展示
writer = SummaryWriter("logs_train")
# ---------------------进行多轮训练--------------------------
for i in range(epoch):
print("------------第{}轮训练开始-------------".format(i+1))
#--------------------------------训练步骤开始-------------------------------------
tudi.train()
for data in train_dataloader:
imgs, targets = data
outputs = tudui(imgs)
#计算损失值
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad() # 将每个结点的梯度参数调为0
loss.backward() # 反向传播
optimizer.step() # 优化器调优
total_train_step = total_train_step+1 # 记录训练的次数
if total_train_step % 100 == 0: # 当训练次数为100的整数倍时
print("训练次数: {}, Loss:{}".format(total_train_step, loss.item()))
# 记录训练的数据,标量的形式
writer.add_scalar("train_loss", loss.item(), total_train_step)
# --------------------------测试步骤开始--------------------
tudui.eval()
total_test_loss = 0
with torch.no_grad(): # 在进行测试时,不需要梯度参数
for data in test_dataloader:
imgs, targets = data
outputs = tudui(imgs)
loss = loss_fn(outputs, targets)
total_test_loss = total_test_loss + loss .item()
print("整体测试集上的Loss:{}".format(total_test_loss))
# 记录每轮整体测试集的损失值,标量的形式展示
writer.add_scalar("test_loss", total_test_loss, total_test_step)
total_test_step = total_test_step + 1
# 保存每轮的网络模型,其数据用字典来保存
torch.save(tudui, "tudui_{}.pth".format(i))
writer.close()
14.3 计算模型的正确率-----利用argmax( )
其中argmax(1) 参数为1或者0,1为横向,0为纵向
# 测试步骤开始
total_test_loss = 0
total_accuracy = 0 # 定义总体正确率
with torch.no_grad(): # 在进行测试时,不需要梯度参数
for data in test_dataloader:
imgs, targets = data
outputs = tudui(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
十五. 整体流程
总结模型训练的整体流程:准备数据、加载数据、准备模型、设置损失函数、设置优化器、开始训练、最后验证(测试)、结果聚合展示
十六. 利用GPU来训练网络模型
16.1 GPU运行的第一种形式
需要修改原本代码的三个地方:网络模型、数据、损失函数;分别加.cuda( )
修改以上三处的正确形式:
if torch.cuda.is_available():
tudui = tudui.cuda( )
import torch
import torchvision
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Linear, Flatten
from torch.utils.tensorboard import SummaryWriter
#---------引入所搭建的神经网络------
# from p27_model import * # *表示所有的东西
# 准备训练数据集
from torch.utils.data import DataLoader
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=True)
# 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)
# ---------------------数据集都准备完毕,需要搭建的神经网络--------------------
# 1.创建网络模型
class Tudui(nn.Module):
def __init__(self):
super(Tudui, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2), # 此处的padding(增加图片周围格子数)是通过公式计算得来的
MaxPool2d(2), # 池化核的大小为2
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(), # 一个平铺操作
Linear(1024, 64), # 线性层,一个图片中的1024变为64
Linear(64, 10)
)
# 前向传播, 输入后变换为输出
def forward(self, x):
x = self.model1(x)
return x
tudui = Tudui()
if torch.cuda.is_available():
tudui = tudui.cuda()
# 2.损失函数
loss_fn = nn.CrossEntropyLoss() # 交叉损失函数
if torch.cuda.is_available():
loss_fn = loss_fn.cuda()
# 3.优化器
learning_rate = 1e-2 # 1 x(10)^(-2) = 1/100 = 0.01
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)
# 4.设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练的轮数
epoch = 10
# 添加tensorboard进行训练过程的展示
writer = SummaryWriter("logs_train")
# ---------------------进行多轮训练--------------------------
for i in range(epoch):
print("------------第{}轮训练开始-------------".format(i+1))
#--------------------------------训练步骤开始-------------------------------------
tudui.train()
for data in train_dataloader:
imgs, targets = data
if torch.cuda.is_available():
imgs = imgs.cuda()
targets = targets.cuda()
outputs = tudui(imgs)
#计算损失值
loss = loss_fn(outputs, targets)
# 优化器优化模型
optimizer.zero_grad() # 将每个结点的梯度参数调为0
loss.backward() # 反向传播
optimizer.step() # 优化器调优
total_train_step = total_train_step+1 # 记录训练的次数
if total_train_step % 100 == 0: # 当训练次数为100的整数倍时
print("训练次数: {}, Loss:{}".format(total_train_step, loss.item()))
# 记录训练的数据,标量的形式
writer.add_scalar("train_loss", loss.item(), total_train_step)
# ---------------------------------测试步骤开始---------------------------------
tudui.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 = tudui(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
# 保存每轮的网络模型,其数据用字典来保存
torch.save(tudui.state_dict(), "tudui_{}.pth".format(i))
print("模型已保存")
writer.close()
16.2 GPU运行的第二种方式----常用
# 在最开始进行定义,如果有gpu则直接gpu,否则cpu
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
# 在gpu下运行
tudui = tudui.to(device)
十七. 模型测试(demo)套路
利用已经训练好的模型,然后给它提供输入的道具结果;真实应用场景下
image = image.convert('RGB')------加上这一步后,可以适应png,jpg各种格式的图片
from PIL import Image
from p27_model import *
import torch
import torchvision
from torch import nn
image_path = "./imgs/airplane.png"
# 通过Image打开图片对象
image = Image.open(image_path)
# 为了适应各种图片格式
image = image.convert('RGB')
print(image)
# Compose是组合变换
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)),
torchvision.transforms.ToTensor()])
# 将原始图片进行变换
image = transform(image)
# 加载网络模型-第二种形式
model = Tudui()
model.load_state_dict(torch.load("tudui_0.pth", map_location=torch.device('cuda')))
print(model)
# 需要进行变化,因为在模型中所需要的是四个参数
image = torch.reshape(image, (1, 3, 32, 32))
# 开启测试必写代码
model.eval()
with torch.no_grad():
output = model(image)
print(output)
# 将预测结果变的更加可读
print(output.argmax(1))