课程学习链接:https://www.bilibili.com/video/BV1hE411t7RN?p=12&vd_source=7ceb7ef632bd249b5aacf41c00b5ea12

数据集的构建-Dataset

可以自定义一个数据集对象,必须继承Dataset类!!需要重写__getitem__函数和__len__函数

自定义的数据集类:

from torch.utils.data import Dataset
from PIL import Image
import os

class Mydata(Dataset):
    def __init__(self, root_dir, label_dir):  
        self.root_dir = root_dir
# self.root_dir = "dataset/train"
        self.label_dir = label_dir
# self.label_dir = "ants"
        self.img_list = os.listdir(os.path.join(root_dir, label_dir))
		
'''
os.path.join(root_dir, label_dir) = "dataset/train/ants" 为蚂蚁图片的相对路径

os.listdir()函数返回路径下的文件或文件夹列表
[918932.jpg,7894398,jpg,...,fadio.jpg]
'''

    def __getitem__(self, idx):
        img_name = self.img_list[idx]
        img_path = os.path.join(self.root_dir, self.label_dir, img_name)
        img = Image.open(img_path)
        label = self.label_dir
        return img, label
        
	def __len__(self):
        return len(self.img_path)

通过__init()函数中的文件名列表,可以在__getitem()方法中通过index获取图片

__getitem__函数的作用:在类实例化后,可以通过索引调用getitem函数

ants_dataset = Mydata("dataset/train", "ants")
img , label = ants_dataset[0]

数据加载器-Dataloader

dataloader用于将构建的数据集中的数据分批次的送入模型中。DataLoader类返回一个迭代器实例,可以通过迭代的方式获取实例中的数据标签

参数如下:

  • dataset:指定数据集
  • batch_size:指定一次将数据集中的几条样本送入神经网络
  • shuffle:指定每一次epoch中是否先打乱,再以一个batch大小取数据
  • num_work:用于多进程运行
  • drop_last:指定最后剩下的不足batch_size数量的样本是否舍弃

代码如下:

import torchvision
from torch.utils.data import DataLoader

#用于获取torchvison中自带的数据集
test_data = torchvision.datasets.CIFAR10("./dataset", train=False, transform=torchvision.transforms.ToTensor())

test_loader = DataLoader(dataset=test_data, batch_size=4, shuffle=True, num_workers=0, drop_last=False)

#迭代的获取数据,data是一个二维列表,第0维代表数据,第一维代表标签
for data in test_loader:
    print(data)
    imgs, targets = data
    print(imgs.shape)
    print(targets)

dataset与dataloader

1.dataloader必须以dataset类为输入
2.sampler只负责输出数据集位置索引列表(可以是所有样本,也可以是一个batch的样本),而collate_fn可以输出real_batch(real_batch即为模型真正的输入),collate_fn有一个默认参数就是一个batch的数据,它通过sampler产出的index list去dataset中取得的(使用getitem方法)。而且collate_fn函数还得实现batch数据的重新组织(从batch->real_batch),例如通过默认参数的到的batch是这样的:[数据1,标签],[数据2,标签]…,要把它变为[数据1,数据2…] [标签,标签2…]

神经网络的基本骨架-nn.module

可以自定义一个模型类,必须继承Model类。在__init__()函数中,需要初始化父类(Model),同时,在定义forward()函数用于前向传播。

一般forward()输出预测值,传入loss_object对象

演示代码如下:

from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear


class Tutui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.model = Sequrntial(
        	Conv2d(3, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 64, 5, padding=2,
        	MaxPool2d(2),
        	Flatten(),
        	Linear(1024, 64),
        	Linear(64, 10)
        )

    def forward(self, input):
        output = self.model(input)
        return output

#实例化土推模型
tutui = Tutui()

#把input传入神经网络,自动调用forward方法
#输入input还未定义
output = tutui(input)
print(output)

损失函数、反向传播、优化器

损失函数

很简单,直接实例化一个损失函数类,如L1Loss,输入预测值和标签,计算损失 l o s s loss loss

代码如下:

import torch
from torch.nn import L1Loss

predictive_value = torch.tensor([1, 2, 3], dtype=torch.float32)
label = torch.tensor([1, 2, 5], dtype=torch.float32)

predictive_value = torch.reshape(predictive_value, (1, 1, 1, 3))
label = torch.reshape(label, (1, 1, 1, 3))

loss_object = L1Loss()
loss_value = loss_object(predictive_value, label)
print(loss_value)

反向传播

根据得到的loss_value,调用backward方法。注意!调用backward方法的是不是创建的loss_object实例,而是得到的loss_value对象。

from torch.utils.data import Downloader
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear


class Tutui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.model = Sequrntial(
        	Conv2d(3, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 64, 5, padding=2,
        	MaxPool2d(2),
        	Flatten(),
        	Linear(1024, 64),
        	Linear(64, 10)
        )
    def forward(self, input):
        output = self.model(input)
        return output


dataset = torchvison.datasets.CIFAR10("./data", train=False, transform=torvison.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset, batch_size=1)

#交叉熵损失对象
loss_object = nn.CrossEntropyLoss()
#神经网络对象
tutui = Tutui()

for data in downloader:
	imgs, targets = data
	output = tutui(imgs)
	#计算loss值
	loss_value = loss_object(output, targets)
	#反向传播!!!!!!
	loss_value.backward()

优化器

优化器利用损失反向传播反向优化模型的权重矩阵(参数)。注意!一定记得每条样本反向传播前,执行梯度清零操作optimizer.zero_grad()

参数优化基本步骤:

  1. 计算loss
  2. 梯度清零
  3. 反向传播——根据loss计算网络参数的梯度
  4. 优化!——根据计算的梯度对网络参数进行更新

一些参数:

  • 第一个参数:设置神经网络中优化的参数,可以只优化部分层,也可以全部神经网络
  • 学习率:即步长(梯度下架算法中每次走多远),一般设置 l r = 0.01 lr=0.01 lr=0.01

代码如下:

import torch
from torch.utils.data import Downloader
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear


class Tutui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        self.model = Sequrntial(
        	Conv2d(3, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 32, 5, padding=2,
        	MaxPool2d(2),
        	Conv2d(32, 64, 5, padding=2,
        	MaxPool2d(2),
        	Flatten(),
        	Linear(1024, 64),
        	Linear(64, 10)
        )
    def forward(self, input):
        output = self.model(input)
        return output


dataset = torchvison.datasets.CIFAR10("./data", train=False, transform=torvison.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset, batch_size=1)

#交叉熵损失对象
loss_object = nn.CrossEntropyLoss()
#神经网络对象
tutui = Tutui()
#优化器对象!!!!!!!!
optim = torch.optim.SGD(tudui.parameter(), lr=0.01)

for epoch in range(20):
	sum_loss = 0.0
	for data in downloader:
		imgs, targets = data
		output = tutui(imgs)
		#计算loss值
		loss_value = loss_object(output, targets)
		#梯度清零!!!!!!!!!!
		optim.zero_grad()
		#反向传播
		loss_value.backward()
		#优化!!!!!!!
		optim.step()
		sum_loss = sum_loss + loss_value
	print(sum_loss)

模型的保存和加载

模型保存

  • 保存方式1:既可以保存网络模型的结构,还可以保存模型的参数
import torch
import torchvison

#直接下载torchvison自带的模型,存入vgg16中
vgg16_model = torchvison.models.vgg16(pretrained=Flase)

#第一个参数是待保存的模型,第二个参数是保存路径
torch.save(vgg16_model, "vgg16_metod1.pth")
  • 保存方式2:不保存网络模型的结构,只保存模型的参数(官方推荐)

state_dic()方法:将模型vgg16的状态(参数)保存成字典形式

import torch
import torchvison

#直接下载torchvison自带的模型,存入vgg16中
vgg16_model = torchvison.models.vgg16(pretrained=Flase)

#第一个参数是待保存的模型的状态,第二个参数是保存路径
torch.save(vgg16.state_dict(), "vgg16_metod2.pth")

模型加载

  • 对应保存方式1的模型读取
    如果加载的模型时自定义的,在加载模型前,需要定义好模型的结构,或是把包含模型结构的模块import进来

      from model_save import *
    

exmaple:

import torch

#参数是保存模型的路径
model = torch.load("./vgg16_method1.pth")
print(model)
  • 对应保存方式2的模型读取
    step1:新建网络模型
    step2:加载字典
import torch
import torchvison

#新建模型
model = torchvison.model.vgg16(pretrained=False)
#加载模型状态字典
model.load_state_dict(torch.load("./vgg16_method2.pth"))
print(model)

数据可视化-Tensorboard

tensorboard主要功能:

  • 数据可视化
  • 模型网络架构可视化
  • 跟踪模型指标,如损失、准确性等

启动Tensorboard

  1. 本地启动,在终端(Termianl)输入并运行

    tensorboard --logdir=<directory_name>

Tensorboard代码

from torch.utils.tensorboard import SummaryWriter
import numpy as np
from PIL import Image

#writer为tensorboard对象,logs指定tensorboard生成文件的存放目录
writer = SummaryWriter("logs")

# 图片获取和数据转换
img_PIL = Image.open("dataset/train/bees/16838648_415acd9e3f.jpg")
img_array = np.array(img_PIL)

writer.add_image("test", img_array, 2, dataformats="HWC")
# y=2x
for i in range(100):
    writer.add_scalar("y=2x", 2*i, i)

#关闭tensorboard对象
writer.close()

更多推荐