小土堆P15dataloader笔记

目录

P6继承Dataset,读取自己创建的数据集

p7tensorboard的使用

图片从pil转换为numpy型

img_arrry = np.array(img)

 p10transforms的使用

p12,13 常见的transforms

p14 torchvision中数据集的使用

p15dataloader的使用

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

 p17卷积操作

p18卷积层 

p19神经网络-最大池化层的使用

 p20非线性激活

p21神经网络-----线性层及其它层介绍 

 p22搭建小实战和Sequential的使用

 p23损失函数与反向传播

p24优化器

p25pytorch给我们提供的网络模型

p26网络模型的保存与读取

p27、28、29完整的模型训练套路

 p30利用GPU训练

p32完整的模型验证套路


(113条消息) PyTorch深度学习快速入门教程【小土堆】 学习笔记_阿尼亚要好好读书呀的博客-CSDN博客


 P1pytorch的环境安装和配置

1、下载anaconda(包含大量的package)

在代码中,如果一个函数作为工具,一个package就是一个工具包

要记住anaconda的安装路径 

如果在看到括号左边的(base)那就是安装成功。

2、深度学习离不开显卡,pytorch和tensorflow仅支持英伟达的显卡。

有没有显卡对学习pytorch并没有影响,显卡主要起到训练加速的作用。

显卡的配置涉及:驱动+CUDA Toolkit(后者可以跟随pytorch一键安装)

在任务管理器看到显卡型号,说明驱动正确安装

 3、管理环境

一个package相当于一个工具包,把环境理解为一个房子。里面本身拥有一个base房子,新建一个名为111的房子,里面有不同版本的pytorch.

1、新建虚拟环境 conda create -n env_name python=3.8(有哪些环境:conda env list)

2、conda activate env_name

3、安装pytorch(推荐1.1以上,有tensorboard)

测试有没有安装成功


 P2python编辑器的选择和安装

pycharm、jupyter

jupyter默认安装在base中,在pytorch中安装jupyter

1、进入pytorch环境中,在pytorch中安装一个包 conda install nb_conda

2、输入jupyter notebook

3、

4、运行代码块是 shift+回车


p4 python中的两大法宝函数

 

dir():打开,看见有什么东西

help():像说明书

 

帮助文档

1、

2、


P5 pycharm和jupyter的对比

 jupyter notebook

python、python控制台、和jupyter notebook区别


P6继承Dataset,读取自己创建的数据集

 在pytorch中如何加载数据

读取数据涉及到的类:Dataset、Dataloader

Dataset:获取其中的数据、并编号

                提供一种方式去获取数据及其label

Dataloader:对数据进行打包

                        为后面的网络提供不同的数据形式

实操:识别蚂蚁和蜜蜂

 获取所有图片的索引

self.img_path = os.listdir(self.path)  # 先获得那个文件夹的地址,然后把这个文件夹下的所有内容变成一个列表,这个列表有对应的索引号

os.path.join(self.root_dir,self.label_dir)   #图片的路径地址  把上面两个地址相加

from torch.utils.data import Dataset
from PIL import Image # 读取图片
import os  #获取所有图片的一个列表

class MyData(Dataset):     #创建一个类 然后去继承Dataset
    def __init__(self,root_dir,label_dir):#初始化  图片地址列表 图片标签
        self.root_dir = root_dir
        self.label_dir = label_dir
        self.path = os.path.join(self.root_dir,self.label_dir)   #图片的路径地址  把上面两个地址相加
        self.img_path = os.listdir(self.path)  # 先获得那个文件夹的地址,然后把这个文件夹下的所有内容变成一个列表,这个列表有对应的索引号

    def __getitem__(self, idx):# 获取对应的每一个图片
        img_name = self.img_path[idx]   #获取对应位置的图片,现在是只知道了图片的名称
        img_item_path = os.path.join(self.root_dir,self.label_dir,img_name)   #每一个图片的位置,图片的相对路径
        img =Image.open(img_item_path)
        label = self.label_dir
        return img, label
    def __len__(self):
        return len(self.img_path)

root_dir = "dataset/train"
ants_label_dir = "ants"
bees_label_dir = "bees"

ants_dataset = MyData(root_dir, ants_label_dir)  # 蚂蚁的实例
bees_dataset = MyData(root_dir, bees_label_dir)  # 蜜蜂的实例

img, label = ants_dataset[1]# __getitem__是构造方法不用调用
img.show()

train_dataset =ants_dataset + bees_dataset  # 蚂蚁数据集和蜜蜂数据集的集合, 数据集的拼接


p8tensorboard的使用

from torch.utils.tensorboard import SummaryWriter # 导入类
按住ctrl,点击想看的类,看他的说明文档
writer = SummaryWriter("logs") # 实例化类, 对应的事件文件保存在logs文件夹
#经常使用的方法有两个
writer.add_image() , writer.add_scalar()#添加标量数据
#最后关闭
writer.close()

writer.add_scalar("名字",scalar_value对应的是y,global_value对应的是x轴)
在终端输入tensorboard --logdir=logs --port=6007
#可以改变端口号避免和别人用一样的端口
from torch.utils.tensorboard import SummaryWriter # 导入类
writer = SummaryWriter("logs") # 实例化类, 对应的事件文件保存在logs文件夹
for i in range(100):
    writer.add_scalar("y=x", i, i)
#最后关闭
writer.close()

from torch.utils.tensorboard import SummaryWriter # 导入类
writer = SummaryWriter("logs") # 实例化类, 对应的事件文件保存在logs文件夹
for i in range(100):
    writer.add_scalar("y=2x", 2i, i)
#最后关闭
writer.close()


 writer.add_image('test',img_arrry,2,dataformats='HWC')

其中img_arrry需要是numpy或者tensor类型,但是用PIL方法读取到的数据是jepg类型。

tensorboard可以在网页可视化图像

# 2是代表第二步

writer.add_image('test',img_arrry,2,dataformats='HWC')

# img_arrry 需要是numpy或者Tensor类型,且形状是chw,否则要转换

图片从pil转换为numpy型

img_arrry = np.array(img)

step从3开始,并且很多图像没显示的,在terminal那里,最后面加一个 --samples_per_plugin=images=1000

from torch.utils.tensorboard import SummaryWriter # 导入类

from PIL import Image

import numpy as np
image_path='dataset/train/bees/29494643_e3410f0d37.jpg'
img = Image.open(image_path) # 获取图片
img_arrry = np.array(img)
print(img_arrry.shape)

writer = SummaryWriter("logs") # 实例化类 保存在logs文件夹
writer.add_image('test',img_arrry,2,dataformats='HWC') # 在项目文件夹中放入图片,可以是自己的也可以是下载数据集
# 用OpenCV获取图片是numpy型

#
# for i in range(100):
#     writer.add_scalar("y=2x", 2*i, i) # 在终端输入tensorboard --logdir=logs --port=6007
writer.close()

 p10transforms的使用

对图片进行变换

Transforms.py就像一个工具箱,里面有to_tensor、resize等工具

图片经过工具后输出我们想要的一个图片的结果

为什么想使用tensor: tensor包装了我们反向神经网络所需要的理论基础的一些参数
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

# 读取numpy类型
import cv2
cv_image = cv2.imread("dataset/train/ants/49375974_e28ba6f17e.jpg")
print(type(cv_image)) # <class 'numpy.ndarray'>

write = SummaryWriter("logs")
img = Image.open("dataset/train/ants/49375974_e28ba6f17e.jpg") # python内置的一个打开图片的库
print(img) # 可以看一下图片的类型
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x313 at 0x28BBF148850>

# totensor  transforms该如何被使用
trans_totensor = transforms.ToTensor() # 实例化transform里的totensor
# 因为to_tensor是transforms里的类所以要先实例化
img_tensor = trans_totensor(img) # 把图片转换为tensor类型

write.add_image("ant", img_tensor)# 因为write.add_image里numpy面的图片参数要或tensor类型
# tensor包装了我们反向神经网络所需要的理论基础的一些参数
write.close()

p12,13 常见的transforms

 不同图片类型各自的打开方式:

 transforms.compose把transforms进行组合

from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

# 读取numpy类型
import cv2
cv_image = cv2.imread("dataset/train/ants/49375974_e28ba6f17e.jpg")
print(type(cv_image)) # <class 'numpy.ndarray'>

write = SummaryWriter("logs")
img = Image.open("dataset/train/ants/49375974_e28ba6f17e.jpg") # python内置的一个打开图片的库
print(img) # 可以看一下图片的类型
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=500x313 at 0x28BBF148850>

# totensor的使用 transforms该如何被使用
trans_totensor = transforms.ToTensor() # 实例化transform里的totensor
# 因为to_tensor是transforms里的类所以要先实例化
img_tensor = trans_totensor(img) # 把图片转换为tensor类型
write.add_image("ant", img_tensor)# 因为write.add_image里numpy面的图片参数要或tensor类型
# tensor包装了我们反向神经网络所需要的理论基础的一些参数
write.close()

# normalize 归一化  灰度直方图的时候有用
# output[channel] = (input[channel] - mean[channel]) / std[channel]归一化的公式
print(img_tensor[0][0][0]) # 原始图片的第【0】【0】【0】位置的像素的输出
trans_norm = transforms.Normalize([0.8, 0.8, 0.8], [0.5, 0.5, 0.5])
# 参数是均值和标准差,因为图片有RGB三个通道所以要三个
img_norm = trans_norm(img_tensor)
write.add_image("norm", img_norm, 2)
print(img_norm[0][0][0])# 归一化后图片的第【0】【0】【0】位置的像素的输出


# resize  改变图片尺寸
print(img.size) # 看一下图片原本大小
trans_resize = transforms.Resize((100, 100))  #实例化transform的resize类,改变大小
img_resize = trans_resize(img) # 输入图片 图片需要是pil类型
print(img_resize) # 看一下img resize 输出类型 结果输出还是PIL类型
# 现在想让输出在transboard显示  需要把图片转换为Tensor类型
img_resize = trans_totensor(img_resize) # 把图片转换为tensor类型
write.add_image("resize", img_resize,1)
print(img_resize)
write.close()

# compose  把不同的transforms连接在一起
trans_resize_2 = transforms.Resize(100) # 先实例化 按照边最短的缩放,等比缩放
trans_compose = transforms.Compose([trans_resize_2, trans_totensor])# 相当于一个组合 先变化大小 再变成Tensor类型
trans_resize_2 = trans_compose(img) # 这里也需要是pil类型
write.add_image("resize", trans_resize_2, 2)

# Randomcrop 随机裁剪,如果只给一个值不会像resize等比缩放,只会是一个正方形
trans_crop = transforms.RandomCrop((100, 100))
trans_compose2 = transforms.Compose([trans_crop, trans_totensor])
for i in range(10):
    img_crop = trans_compose2(img)
    write.add_image("randomcrop1", img_crop, i)

总结:
使用类里的方法的话要
关注输入和输出类型
多看官方文档
关注方法需要什么参数
不知道返回值的时候  print();print(type());debug;


p14 torchvision中数据集的使用

 下载了数据集CIFR10

实现了transforms和datasets的联合使用

# transforms和dataset的联合使用
import torchvision
from torch.utils.tensorboard import SummaryWriter


dataset_transform = torchvision.transforms.Compose(
    [
        torchvision.transforms.ToTensor()
    ]
)
# datasets和之前自定义的dataset一样
# 在torchvision里导入CIFAR10数据集
# root 把数据集存放在什么位置, train=True训练数据集,download=True进行一个下载
train_set = torchvision.datasets.CIFAR10(root="./dataset1", train=True, transform=dataset_transform,download=True)
# 测试数据集,download=True
test_set = torchvision.datasets.CIFAR10(root="./dataset1", train=False,transform=dataset_transform, download=True)

# 想看测试集里的第一个数据集
# print(test_set[0]) # 输入有两部分  一部分是图片,一部分是target
# # 可以打一个断点,可以看到train_set里面有的参数
# print(test_set.classes)
# img, target = test_set[0]
# print(img, target)



# print(train_set[0])
# img1, target1 = train_set[0]
# print(img1, target1)
# print(test_set.classes)
# print(test_set.classes[target])
# print(test_set.classes[target1])
# img.show()


# 用tensorboard显示
# 测试集中包含两个数据 一个是图片 一个是类别标签
writer = SummaryWriter("p14")
for i in range(10):
    img, target = test_set[i]
    writer.add_image("test", img, i)
writer.close() # 一定要记得关闭

 如果想自己下载数据集,但是在输出中,没有给出下载路径,可以按住ctrl键点击,查看源码,里面有一个URL,粘贴到迅雷当中下载,之后再把文件拷贝到项目中。


p15dataloader的使用

dataloader相当于一个加载器,把数据加载到神经网络当中
dataset就是告诉我们数据集在什么地方,第一张,第二张数据是什么,这个数据集中共有多少张数据 dataloader batch_size=4每次取牌取四张,shuffle=True是不是打乱,num_workers=0加载数据是采用多进程,还是单进程,drop_last=False最后除不尽是舍去还是不舍 

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 准备的测试数据集,transform中把图片转为Tensor类型
test_data = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(), download=True)
# dataset就是告诉我们数据集在什么地方,第一张,第二张数据是什么,这个数据集中共有多少张数据
# dataloader相当于一个加载器,把数据加载到神经网络当中
# dataloader batch_size=4每次取牌取四张,shuffle=True是不是打乱,num_workers=0加载数据是采用多进程,还是单进程,drop_last=False最后除不尽是舍去还是不舍
test_loader = DataLoader(dataset=test_data, batch_size=4, shuffle=True,num_workers=0, drop_last=False)

# 测试数据中第一张图片及target
# batch_size=4 相当于取test_data[0]、test_data[1]、test_data[2]、test_data[3],
# 对应的img和target分别进行打包,打包成imgs,targets,作为dataloader的一个返回
img, target = test_data[0]
print(img.shape) # 图片大小 3通道 32*32     》》》torch.Size([3, 32, 32])
print(target)   # 返回3   >>>3



writer = SummaryWriter("p15")
step = 0
for data in test_loader:
    imgs, targets = data # 图片是随机抓取的
    # print(imgs.shape)  # 图片大小 >>>torch.Size([4, 3, 32, 32])
    # print(targets)  # >>>tensor([2, 0, 4, 4])
    writer.add_images("testp15", imgs, step)  #writer.add_images 注意这里加s
    step += 1
writer.close()

最后在终端输入:tensorboard --logdir=p15 --port=6007 在tensorboard中显示

dataloader中的imgs是在dataset中随机取得4张图片,targets是对应的四个标签


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

神经网络的工具都在torch.nn里

container是一个骨架,给神经网络定义了一些结构,在结构中添加不同的内容,就可以组成神经网络

骨架的搭建

container中有6个模块

最常用的是module

初始化函数:菜单栏,code,gennerate, override methods(重写这个方法)

下面写一个简单的神经网络

import torch
from torch import nn

# 搭建自己的神经网络,名字叫Tudui
# containers里面是神经网络的骨架
# 定义神经网络的模板
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()  # 这个是必须要的,调用父类的初始化函数
    def forward(self, input): # 前向传播
        output = input + 1
        return output  # 我们这个神经网络很简单 你给他一个输入   输出就是输入+1
# 创建神经网络
tudui = Tudui()  # 相当于拿上面的模板创建出来的网络
x = torch.tensor(1.0)
out = tudui(x)
print(out)

如果想看执行的过程可以打一个断点,进行调试 


 p17卷积操作

torch.nn是对torch.function的一个封装

CLASStorch.nn.Conv2d(in_channelsout_channelskernel_sizestride=1padding=0dilation=1groups=1bias=Truepadding_mode='zeros')

torch.nn.functional.conv2d(inputweightbias=Nonestride=1padding=0dilation=1groups=1)

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]
])

# 因为nn.conv是需要四个参数,改变数据形状
# 卷积的inpute(minibatch,in_channels,高,宽)
input = torch.reshape(input, (1, 1, 5, 5))
# WEIGHT要求,(out_channel,in_channels/groups,高,宽)
kernel = torch.reshape(kernel, (1, 1, 3, 3))

print(input.shape)
print(kernel.shape)

output = F.conv2d(input, kernel, stride=1) # 调用卷积 步长为1,padding默认为0
print(output)

output = F.conv2d(input, kernel, stride=2) # 调用卷积 步长为2
print(output)
output = F.conv2d(input, kernel, stride=1, padding=1) # 调用卷积,padding=1
print(output)

p18卷积层 

nn.Conv1d 1维卷积 

nn.Conv2d 2维卷积

CLASS

torch.nn.Conv2d(in_channelsout_channelskernel_sizestride=1padding=0dilation=1groups=1bias=Truepadding_mode='zeros')

dilation=1空洞卷积,bias=True加一个偏置

如果输入通道是1,输出通道是2,那就是有两个卷积核,这两个卷积核不一定是一样的

 如果输入通道是3,输出通道是4,是用了几个卷积核??

 

比较重要的公式,写论文,或者看别人论文的时候,没有给padding和stride,就要自己计算。

vgg16


p19神经网络-最大池化层的使用

nn.maxpool最大池化层,有时也被称为下采样

nn.maxunpool上采样

最常用torch.nn.MaxPool2d(kernel_sizestride=Nonepadding=0dilation=1return_indices=Falseceil_mode=False)

一般只设置一个kernel_size

stride的默认值和卷积层不一样,它的默认值是kernel_size

dilation:卷积核没有挨在一起,也叫空洞卷积

ceil_mode:floor向下取整,ceiling:向上取整

最大池化操作: kernel_size池化核,取池化核覆盖之下最大的数

ceil允许有出界部分,floor不允许

 池化操作的输入也是需要4维,(batchsize,通道数,高,宽) 

 

 上面的矩阵进行池化操作,最后输出池化后的结果。

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) # 最大池化没有办法对Long类型操作,需要转换一下类型
# 因为nn.conv是需要四个参数,改变数据形状,满足输入要求
input = torch.reshape(input, (-1, 1, 5, 5))

# 神经网络
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        # 最大池化层
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
    def forward(self,input):
       output = self.maxpool1(input)
       return output   # 神经网络就搭建好了

# 创建神经网络
tudui = Tudui()
# 给神经网络一个输入
output = tudui(input)
print(output)

 输出:

池化有什么作用呢:保留输入特征,但降低数据量

 可以输入图片看一下

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

dataset = torchvision.datasets.CIFAR10(root="./dataset1", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=True)
dataloader = DataLoader(dataset=dataset, batch_size=64)


# 神经网络
class Tudui(nn.Module):
    def __init__(self) -> None:
        super().__init__()
        # 最大池化层
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
    def forward(self,input):
       output = self.maxpool1(input)
       return output   # 神经网络就搭建好了

# 创建神经网络
tudui = Tudui()

# 在tensboard显示
writer = SummaryWriter("p19")
# 从dataloader取数据
step = 0
for data in dataloader:
    imgs, target = data
    output = tudui(imgs)
    writer.add_images("input1", imgs, step)
    writer.add_images("output1",output, step)
    step = step + 1
writer.close()

 经过池化操作后,图片会变得有点模糊,神经网络当中训练的数据量就会大大减少,加快训练。

所以一般都会在经过卷积之后,进行池化,然后进行一次线性激活。


 p20非线性激活

 Non-linear Activations

给神经网络引入一些非线性的特质,先看RELU怎么使用的

torch.nn.ReLU(inplace=False)

 inplace参数是否原地操作的意思,是否对原来的变量改变,默认是False

 输入,输出类型:输入是(batch_size,*)

输入一个张量,看进行非线性激活ReLU的结果

import torch
from torch.nn import ReLU
from torch import nn

input = torch.tensor([[1, -0.5],
                     [-1, 3]])
input = torch.reshape(input, (-1,1,2,2))
print(input.shape)

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui,self).__init__()
        self.relu1 = ReLU()
    def forward(self,input):
        output = self.relu1(input)
        return output

# 创建网络
tudui = Tudui()
output = tudui(input)
print(input)
print(output)

 

 用图片展示sigmoid激活函数

import torch
from torch.nn import ReLU, Sigmoid
from torch import nn
from torch.utils.data import DataLoader
import torchvision
from torch.utils.tensorboard import SummaryWriter

# 导入数据集
dataset = torchvision.datasets.CIFAR10(root="./dataset1", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=True)
dataloader = DataLoader(dataset=dataset, batch_size=64)

# 搭建网络
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui,self).__init__()
        self.relu1 = ReLU()
        self.sigmod1 = Sigmoid()
    def forward(self,input):
        output = self.sigmod1(input)
        return output

# 创建网络
tudui = Tudui()

# 在tensboard显示
writer = SummaryWriter("p20")
step = 0
for data in dataloader:
    imgs, target = data
    output = tudui(imgs)
    writer.add_images("input", imgs, step)
    writer.add_images("output",output, step)
    step = step + 1
writer.close()

step从3开始,并且很多图像没显示的,在terminal那里,最后面加一个

 --samples_per_plugin=images=1000

即 tensorboard --logdir=p20 --samples_per_plugin=images=1000


p21神经网络-----线性层及其它层介绍 

 

 normalization layers(归一化)的作用:加快神经网络的训练速度

 transformer layers

linear layers

dropout layers:防止过拟合,比较简单可以拿来练手,看有没有看懂官方文档

embedding layers:自然语言处理用到的,

distance function:计算误差

重点说一下线性层:

import torch
import torchvision
from torch import nn
from torch.nn import Linear
from torch.utils.data import DataLoader

dataset = torchvision.datasets.CIFAR10(root="./dataset1", train=False,
                                         transform=torchvision.transforms.ToTensor(),
                                         download=True)
dataloader = DataLoader(dataset=dataset, batch_size=64,drop_last=True)

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.liner1 = Linear(196608,10)# 输入feature, 输出feature
    def forward(self, input):
        output = self.liner1(input)
        return output

# 搭建网络
tudui = Tudui()

for data in dataloader:
    imgs, target = data
    print(imgs.shape) #torch.Size([64, 3, 32, 32]) 64张3通道32*32的图片
    # output =torch.reshape(imgs,(1,1,1,-1)) # 把图片展平了

    output = torch.flatten(imgs) # 展平变成一行 torch.Size([196608])
    print(output.shape)# torch.Size([1, 1, 1, 196608])
    output = tudui(output)
    print(output.shape) #torch.Size([1, 1, 1, 10])  #之前产生了报错 把dataloader里的drop_last=True

 p22搭建小实战和Sequential的使用

container中的Sequential还没讲

结合CIFAR10来讲解Sequential

 第一层卷积,输入是3*32*32,输出是32*32*32,从3通道变成了32通道

  • 卷积核也是3通道的,对应计算之后加权结果是1通道,也就是32个卷积核产生32通道;
  • 输出通道数等于卷积核个数,与输入通道数无关
  • 经过卷积图片的大小没变,还是32*32,可以通过公式计算参数值

没有用Sequential

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


class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=32, kernel_size=5,padding=2)
        # 输出还是32*32,没有改变尺寸,肯定有padding,根据卷积公式计算padding
        self.maxpool1 = MaxPool2d(kernel_size=2)
        self.conv2 = Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2)
        self.maxpool2 = MaxPool2d(kernel_size=2)
        self.conv3 = Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2)
        self.maxpool3 = MaxPool2d(kernel_size=2)
        self.flatten = Flatten()# 展平
        self.liner1 = Linear(in_features=1024,out_features=64)
        # 最后生成10个类别所以out_features=10
        self.liner2 = Linear(in_features=64, out_features=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.liner1(x)
        x = self.liner2(x)
        return x
tudui = Tudui()

print(tudui)
# Tudui(
#   (conv1): Conv2d(3, 5, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#   (maxpool1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#   (conv2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#   (maxpool2): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#   (conv3): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#   (maxpool3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#   (flatten): Flatten(start_dim=1, end_dim=-1)
#   (liner1): Linear(in_features=1024, out_features=64, bias=True)
#   (liner2): Linear(in_features=64, out_features=10, bias=True)
# )

# 测试网络对不对
input = torch.ones((64, 3, 32, 32))
output = tudui(input)
print(output.shape)  # torch.Size([64, 10])一张图片第10 但是有64张图片

 使用Sequential,测试网络对不对,除了print,也可以在tensorboard中显示

import torch
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.tensorboard import SummaryWriter


class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model1 = Sequential(
            Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            # 输出还是32*32,没有改变尺寸,肯定有padding,根据卷积公式计算padding
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Flatten(), # 展平
            Linear(in_features=1024, out_features=64),
            # 最后生成10个类别所以out_features=10
            Linear(in_features=64, out_features=10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x

tudui = Tudui()

print(tudui)
# Tudui(
#   (model1): Sequential(
#     (0): Conv2d(3, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#     (1): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#     (2): Conv2d(32, 32, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#     (3): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#     (4): Conv2d(32, 64, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2))
#     (5): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
#     (6): Flatten(start_dim=1, end_dim=-1)
#     (7): Linear(in_features=1024, out_features=64, bias=True)
#     (8): Linear(in_features=64, out_features=10, bias=True)
#   )
# )

# 测试网络对不对
input = torch.ones((64, 3, 32, 32))
output = tudui(input)
print(output.shape)# torch.Size([64, 10])一张图片第10 但是有64张图片
# 除了print,也可以在tensorboard中显示
writer = SummaryWriter("p22")
writer.add_graph(tudui,input)
writer.close()

 


 p23损失函数与反向传播

 loss funcion

  1. 计算实际输出和目标之间的差距
  2. 为我们更新输出提供一定的依据(反向传播)
  3. 注意输入和输出的类型
import torch
from torch.nn import L1Loss
from torch import nn

input = torch.tensor([1, 2, 3], dtype=float)
target = torch.tensor([1, 2, 5], dtype=float)
# 因为想要的输入是由batch_size (1batch_size,1channel,1*3)
input = torch.reshape(input, (1, 1, 1, 3))
target = torch.reshape(target,(1, 1, 1, 3))

# L1损失函数  一定要关注输入的大小
loss = L1Loss()
result = loss(input, target)
print(result)

# mse损失函数,平方差
loss_mse = nn.MSELoss()
result_mse = loss_mse(input, target)
print(result_mse)

# 交叉熵CrossEntropyLoss适用于分类
x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
# 前面要求输入是(N,C)c是有多少类的意思
x = torch.reshape(x, (1, 3))# 1batch_size,有3类
loss_cross = nn.CrossEntropyLoss()
result = loss_cross(x, y)
print(result)

 在网络中用损失函数

result_loss.backward()计算反向传播,知道每个结点的梯度
import torch
import torchvision
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
from torch.utils.data import DataLoader

# 导入数据集
dataset = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset=dataset, batch_size=4)

# 新建的神经网络
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model1 = Sequential(
            Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            # 输出还是32*32,没有改变尺寸,肯定有padding,根据卷积公式计算padding
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Flatten(), # 展平
            Linear(in_features=1024, out_features=64),
            # 最后生成10个类别所以out_features=10
            Linear(in_features=64, out_features=10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x
loss = nn.CrossEntropyLoss()
tudui = Tudui()
for data in dataloader:
    imgs, targets = data # 图片是随机抓取的
    outputs = tudui(imgs) # 通过神经网络得到的一个输出
    # # 我们看一下outputs和targets长什么样子,看选择什么样的损失函数
    # print(outputs)
    # print(targets)
    result_loss = loss(outputs,targets)
    result_loss.backward() # 反向传播,计算梯度
    print("ok")

 


p24优化器

 在设置优化器的时候基本上就是设置一个模型参数和一个学习率。

一开始使用大的学习率,后面使用小的学习率学习

result_loss.backward()计算反向传播,知道每个结点的梯度

有了这个梯度我们就可以使用优化器,调整参数

在官方文档找优化器

 有很多不同的优化器

优化器就是:

  1. 先定义一个优化器,optim = torch.optim.SGD(tudui.parameters(), lr=0.01)
  2. 然后把每个参数的梯度都清零,optim.zero_grad()
  3. 调用损失函数的backward(反向传播)求出每个节点的梯度result_loss.backward()
  4. 最后调用optim.step()对每个参数进行调优,optim.step()

 loss和优化器进行关联

  • 你对optim进行step操作时,step就会把它自身反向传播后的结果得用进去
  • loss函数在其中只是起到了一个提供梯度的作用,而这个梯度就藏在optim中

先复制上一节有损失函数的代码,再加上优化器

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

# 导入数据集
dataset = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset=dataset, batch_size=1)

# 新建的神经网络
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model1 = Sequential(
            Conv2d(in_channels=3, out_channels=32, kernel_size=5, padding=2),
            # 输出还是32*32,没有改变尺寸,肯定有padding,根据卷积公式计算padding
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=32, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Conv2d(in_channels=32, out_channels=64, kernel_size=5, padding=2),
            MaxPool2d(kernel_size=2),
            Flatten(), # 展平
            Linear(in_features=1024, out_features=64),
            # 最后生成10个类别所以out_features=10
            Linear(in_features=64, out_features=10)
        )

    def forward(self, x):
        x = self.model1(x)
        return x
# 损失函数
loss = nn.CrossEntropyLoss()
tudui = Tudui()
# 设置优化器,用随机梯度下降
# torch.optim.SGD(params, lr=<required parameter>, momentum=0, dampening=0, weight_decay=0, nesterov=False)
optim = torch.optim.SGD(tudui.parameters(), lr=0.01)
for epoch in range(20):
    running_loss = 0.0
    # 这个循环只是对这个循环的一轮学习
    for data in dataloader:
        imgs, targets = data # 图片是随机抓取的
        outputs = tudui(imgs) # 通过神经网络得到的一个输出
        result_loss = loss(outputs, targets) # 得到输出和真实数据的一个差距
        optim.zero_grad()# 把参数的梯度设置为0
        result_loss.backward() # 反向传播,计算梯度 得到了每个可以调节参数的梯度
        optim.step()# 对每个参数进行调优
        # print(result_loss) # 每一个结点上的loss值
        running_loss = running_loss + result_loss# 每一轮总体误差的总和
    print(running_loss)

p25pytorch给我们提供的网络模型

这些模型该如何使用和修改,

本节介绍了torchvision中 的模型

 

本节讲解分类模型VGG16

torchvision.models.vgg16(pretrained: bool = Falseprogress: bool = True**kwargs) → torchvision.models.vgg.VGG

Parameters:
  • pretrained (bool) – If True, returns a model pre-trained on ImageNet
  • True说明这个数据集已经在模型中训练好了
  • progress (bool) – If True, displays a progress bar of the download to stderr
  • True显示下载进度条 ,False不显示

pretrained= True,说明已经在训练集上把参数训练好了


 导入ImageNet数据集,提示报错这个数据集不公开,需要自己手动下载,放到根目录中。

数据集太大,up没有进行展示

split="train"是要训练还是验证

# 一个点是当前路径,split="train" 是要训练集还是测试集
train_data = torchvision.datasets.ImageNet(root="./dataImgNet",split="train", download=True,
                                           transform=torchvision.transforms.ToTensor())

imagenet是1000个类别,如何把用这个1000个类别的模型用到10分类上


如何使用vgg16这种可以分1000中类别的网络分类CIFAR10这种10类别的

  • 方法1:向其中加入一个线性层把1000输出为10类别
vgg16_true.add_module('add_linear',nn.Linear(1000,10))

  • 方法2:改变现有模型的线性层使其输出10类别
vgg16_false.classifier[6] = nn.Linear(4096,10)


 全部代码

import torchvision
from torch import nn

# # 一个点是当前路径,split="train" 是要训练集还是测试集
# train_data = torchvision.datasets.ImageNet(root="./dataImgNet",split="train", download=True,
#                                            transform=torchvision.transforms.ToTensor())

# pretrained=False只是加载网络模型,只是把代码加载了,其中的参数不用下载
vgg16_false = torchvision.models.vgg16(pretrained=False,progress=True)
# pretrained=True,需要下载卷积层对应的参数是多少,池化层对应的参数,这些参数就是刚刚说的在ImageNet数据集中训练好的
vgg16_true = torchvision.models.vgg16(pretrained=True,progress=True)
# print(vgg16_true)  # 可以分1000种类别

# 把数据分成了10类,之前的vgg16是把数据分成了1000个类别,那我们如何应用这个模型
train_data = torchvision.datasets.CIFAR10(root="./dataset1", train=True, transform=torchvision.transforms.ToTensor(),
                                          download=True)
print("-----------------------------------------------------------")
# 改动现有的网络结构
# 方法1:加一层
vgg16_true.add_module('add_linear',nn.Linear(1000,10))
# 输出添加后的网络
print(vgg16_true)
print("-----------------------------------------------------------")

# 如果想在这里加(classifier): Sequential(
#     (0): Linear(in_features=25088, out_features=4096, bias=True)
#     (1): ReLU(inplace=True)
#     (2): Dropout(p=0.5, inplace=False)
#     (3): Linear(in_features=4096, out_features=4096, bias=True)
#     (4): ReLU(inplace=True)
#     (5): Dropout(p=0.5, inplace=False)
#     (6): Linear(in_features=4096, out_features=1000, bias=True)
#   )
vgg16_true.classifier.add_module('add_linear',nn.Linear(1000,10))
# 输出添加后的网络
print(vgg16_true)

print("-----------------------------------------------------------")
# 方法2 修改模型参数,改成输入是4096,输出是10个特征
vgg16_false.classifier[6] = nn.Linear(4096,10)
print(vgg16_false)

p26网络模型的保存与读取

后面的讲解内容: 

  • 模型的保存,加载
  • 完整的模型训练套路-GPU训练
  • 完整的模型验证套路(测试、demo)套路,利用训练好的模型,然后给它提供输入

 两种方式保存和加载模型

 方式1,保存模型

先定义了一个模型,然后保存

# 保存方式1,不仅保存了网络模型的结构,也保存了网络模型中的一些参数

vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式1,不仅保存了网络模型的结构,也保存了网络模型中的一些参数
torch.save(vgg16, "vgg16_method1.pth")

 方式1,对应加载模型

# 方式1 --》保存方式1,加载模型
model = torch.load("vgg16_method1.pth")# 指定路径
print(model)

方式2,保存模型,官方推荐的保存方式

不保存模型结构只保存模型参数

vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式2,不保存模型的结构,只保存了模型的参数
# 参数保存成字典的形式
# 官方推荐的保存方式
torch.save(vgg16.state_dict(),"vgg16_method2.pth")
# 把vgg16保存成字典的形式

 方式2,对应的加载模型

# 方式2
model = torch.load("vgg16_method2.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)

 如果要用方式1的话,要让程序能够访问到模型定义的方式

可以在加载模型的.py文件中加上

from p26_moldel_save import *   # 把所有的都导入过来

 方式1的陷阱

在一个.py文件中,先定义一个神经网络

# 陷阱
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui,self).__init__()
        self.conv1 = nn.Conv2d(3, 64,kernel_size=3)
    def forward(self,x):
        x = self.conv1(x)
        return x
tudui = Tudui()
torch.save(tudui,"tudui_method1.pth")

 陷阱,在另一个.py文件中加载出问题

# 陷阱,会出问题
model =torch.load('tudui_method1.pth')
print(model)

解决办法:需要把Tudui这个类放到这里来,但是不需要创建对象tudui = Tudui()

# 需要把Tudui这个类放到这里来,但是不需要创建对象tudui = Tudui()
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui,self).__init__()
        self.conv1 = nn.Conv2d(3, 64,kernel_size=3)
    def forward(self,x):
        x = self.conv1(x)
        return x
model =torch.load('tudui_method1.pth')
print(model)
# Tudui(
#   (conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1))
# )

实际项目中的解决办法在加载模型的.py文件中  加上from p26_moldel_save import *# 把所有的都导入过来

# 也不算一个陷阱,真正写项目当中,不会把模型复制来复制去,会定义在一个单独的文件夹
from p26_moldel_save import *# 把所有的都导入过来
model =torch.load('tudui_method1.pth')
print(model)

p27、28、29完整的模型训练套路

训练

1.准备数据集,并知道数据集的长度:

2.利用dataloader加载数据集

3.搭建神经网络

验证模型输入时  64个batchsize,3通道,图片大小是32*32

4.在训练文件夹引入model.py文件夹,创建网络模型

model.py和train.py在一个文件夹下

5.定义损失函数和优化器

 6.设置训练网络的参数

7.训练


验证:如何知道训练一轮之后,模型的效果

在每轮验证之后,测试

不进行调优,只测试

改进测试输出:


在tensorboard显示

分类问题中的正确率


 tudui.train()# 对特定层有作用dropout   训练开始时

tudui.eval()# 对特定层有作用dropout等  测试开始时


总结完整过程:

准备数据集

准备dataloader

创建网络模型、损失函数、优化器

设置一些训练当中的参数

设置训练的轮数epoch

tudui.train()# 对特定层有作用dropout让网络进入训练状态

# 没有梯度,这里是用在测试数据集中的。
with torch.no_grad():

以CIFAR10作为本节课的例子,完成对这个数据集的分类问题

model.py一定要和你的主文件在同一个文件夹下

 模型单独在一个.py文件中

# 搭建神经网络
import torch
from torch import nn

class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
            nn.MaxPool2d(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(64 * 4 * 4, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x

# to test if the neural network is right  主方法
# 在这里测试这个网络的正确性
if __name__ == '__main__':
    tudui = Tudui() #创造一个网络模型
    # 验证模型的准确性
    # 给定一个确定的尺寸,看输出的尺寸是不是我们想要的
    input = torch.ones((64, 3, 32, 32)) # 64个batch_size,3个通道,32*32的
    output = tudui(input)
    # 输出torch.Size([64, 10]) 说明有64行 10列,64说明有64张图片   10列每一列是是那个种类的概率
    print(output.shape)

 其他代码

1. 一般会把loss写成loss.item(),加上loss.item()转换为一个真实的数,不带tensor()

# 计算正确率,1是指横向比较

2.outputs.argmax(1)横向最大,argmax可以求出横向的最大值所在位置

accuracy = (outputs.argmax(1) == targets).sum()  # 括号里输出的值会是 ture false,然后false相当于0,ture相当于1,求和


完整代码

import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

# 把模型中所有东西都引入过来
# 引入网络
from model import *

# 准备数据集
# 训练数据集
train_data = torchvision.datasets.CIFAR10(root="./dataset1", train=True, transform=torchvision.transforms.ToTensor(),
                                          download=True)
# 测试数据集
test_data = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(),
                                         download=True)

# length 训练数据集有多少张   新知识点   如何获得数据集的长度
train_data_size = len(train_data)
test_data_size = len(test_data)

# if train_data_size=10,训练数据集的长度为:10
print(f"训练数据集的长度为:{train_data_size}") # 这个写法是常用的字符串格式化
print("测试数据集的长度为:{}".format(test_data_size))
# load dataset with DataLoder
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 把模型剪切到了model中

# 创建网络模型
tudui = Tudui()

# 创建损失函数,也放在nn包里,分类问题可以用交叉熵
loss_fn = nn.CrossEntropyLoss()

# 定义优化器
# 学习速率
# learning_rate = 0.01
# 1e-2 = 1 x (10)^(-2) = 1/100 = 0.01
learning_rate = 1e-2
# 随机梯度下降优化器,参数是 对哪一个部分进行优化,网络模型.parameters  学习速率
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)


# 接下来开始训练网络

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练轮数,循环10轮
epoch = 10

# 添加tensorboard
writer = SummaryWriter("logs_train")


# i从0一直到9  训练10轮
for i in range(epoch):
    print("------第{} 轮开始------".format(i + 1))
    # 训练网络模型开始
    # 从训练数据中取数据
    # 训练步骤开始
    tudui.train()# 对特定层有作用dropout
    for data in train_dataloader:
        imgs, targets = data
        outputs = tudui(imgs) # 把训练数据放到网络当中
        # 输出和真实目标的误差是多少
        # 参数是预测的输出的真实的目标放进去
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        # 优化 梯度清零,为了上次的梯度不会影响这次的优化
        optimizer.zero_grad()
        # 调用损失函数的反向传播,得到每个参数结点的梯度
        loss.backward()
        # 对参数进行优化
        optimizer.step()  # 到此就是对参数进行了一次优化,也就是做了一次训练

        # 训练次数加1,
        # loss.item()   如果a= torch.tensor(5) ptint(a) 得到tensor(5)
        #print(a.item()) 得到 5
        total_train_step = total_train_step + 1
        # 一般会把loss写成loss.item(),,加上loss.item()转换为一个真实的数,不带tensor()
        #print(f"训练次数是:{total_train_step}时, 损失值是:{loss}")
        # 不想全部输出 没次100的倍数输出
        if total_train_step % 100 == 0:
            print(f"训练次数是:{total_train_step}时, 损失值是:{loss.item()}")
            writer.add_scalar("train_loss", loss.item(), total_train_step)


    # 怎么知道有没有达到训练的需求
    # 测试不用对模型进行调优了  就是对现有模型的测试
    # 测试步骤开始
    tudui.eval()# 对特定层有作用dropout等
    total_test_loss = 0 # 求整个测试集上的loss
    total_accuracy = 0 # 整体正确率
    # 没有梯度
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            outputs = tudui(imgs)
            loss = loss_fn(outputs, targets)
            # 相求整个测试集上的loss
            total_test_loss = total_test_loss + loss.item()

            # 计算正确率,1是指横向比较
            accuracy = (outputs.argmax(1) == targets).sum()  # 括号里输出的值会是 ture false,然后false相当于0,ture相当于1,求和
            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, "tudui_{}.pth".format(i))
    print("模型已保存")


writer.close()


 p30利用GPU训练

2种方式使用gpu

第一种使用GPU的方式

1.找到网络模型tudui数据(输入、标注)imgs,tragets损失函数loss_fun,再调用.cuda()进行返回就可以。优化器和数据集(train_dataset)是没有cuda的

tudui = tudui.cuda()
loss_fn = loss_fn.cuda()
imgs = imgs.cuda()
targets = targets.cuda()

是否有cuda

用来计时

import time
start_time = time.time()
end_time = time.time()

print("时间", end_time-start_time)


 自己电脑没gup的可以去colab(需要梯子)、kaggle、阿里云天池  极光

google.colab 新建笔记本

kaggle跑项目

文件》修改》笔记本设置

完整代码

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time  #用来计时
# 准备数据集
# 训练数据集
train_data = torchvision.datasets.CIFAR10(root="./dataset1", train=True, transform=torchvision.transforms.ToTensor(),
                                          download=True)
# 测试数据集
test_data = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(),
                                         download=True)


# length 训练数据集有多少张   新知识点   如何获得数据集的长度
train_data_size = len(train_data)
test_data_size = len(test_data)

# if train_data_size=10,训练数据集的长度为:10
print(f"训练数据集的长度为:{train_data_size}") # 这个写法是常用的字符串格式化
print("测试数据集的长度为:{}".format(test_data_size))
# load dataset with DataLoder
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 把模型剪切到了model中
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
            nn.MaxPool2d(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(64 * 4 * 4, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x

# 创建网络模型
tudui = Tudui()
tudui = tudui.cuda()
# 创建损失函数,也放在nn包里,分类问题可以用交叉熵
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.cuda()
# 定义优化器
# 学习速率
# learning_rate = 0.01
# 1e-2 = 1 x (10)^(-2) = 1/100 = 0.01
learning_rate = 1e-2
# 随机梯度下降优化器,参数是 对哪一个部分进行优化,网络模型.parameters  学习速率
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)


# 接下来开始训练网络

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练轮数,循环10轮
epoch = 10

# 添加tensorboard
writer = SummaryWriter("p30logs_train")

start_time = time.time()
# i从0一直到9  训练10轮
for i in range(epoch):
    print("------第{} 轮开始------".format(i + 1))
    # 训练网络模型开始
    # 从训练数据中取数据
    # 训练步骤开始
    tudui.train()# 对特定层有作用dropout
    for data in train_dataloader:
        imgs, targets = data
        imgs = imgs.cuda()
        targets = targets.cuda()
        outputs = tudui(imgs) # 把训练数据放到网络当中
        # 输出和真实目标的误差是多少
        # 参数是预测的输出的真实的目标放进去
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        # 优化 梯度清零,为了上次的梯度不会影响这次的优化
        optimizer.zero_grad()
        # 调用损失函数的反向传播,得到每个参数结点的梯度
        loss.backward()
        # 对参数进行优化
        optimizer.step()  # 到此就是对参数进行了一次优化,也就是做了一次训练

        # 训练次数加1,
        # loss.item()   如果a= torch.tensor(5) ptint(a) 得到tensor(5)
        #print(a.item()) 得到 5
        total_train_step = total_train_step + 1
        # 一般会把loss写成loss.item(),,加上loss.item()转换为一个真实的数,不带tensor()
        #print(f"训练次数是:{total_train_step}时, 损失值是:{loss}")
        # 不想全部输出 没次100的倍数输出
        if total_train_step % 100 == 0:
            end_time = time.time()
            print("时间", end_time-start_time)
            print(f"训练次数是:{total_train_step}时, 损失值是:{loss.item()}")
            writer.add_scalar("train_loss", loss.item(), total_train_step)


    # 怎么知道有没有达到训练的需求
    # 测试不用对模型进行调优了  就是对现有模型的测试
    # 测试步骤开始
    tudui.eval()# 对特定层有作用dropout等
    total_test_loss = 0 # 求整个测试集上的loss
    total_accuracy = 0 # 整体正确率
    # 没有梯度
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            imgs = imgs.cuda()
            targets = targets.cuda()
            outputs = tudui(imgs)
            loss = loss_fn(outputs, targets)
            # 相求整个测试集上的loss
            total_test_loss = total_test_loss + loss.item()

            # 计算正确率,1是指横向比较
            accuracy = (outputs.argmax(1) == targets).sum()  # 括号里输出的值会是 ture false,然后false相当于0,ture相当于1,求和
            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, "tudui_{}.pth".format(i))
    print("模型已保存")


writer.close()

 


第二种GPU训练的方式 

.to(device)

Device = torch.device("cpu")

torch.device("cuda")

torch.device("cuda:0") 看有几张显卡

# 定义训练的设备
device = torch.device("cuda:0")/device = torch.device("cpu")
tudui = tudui.to(device)
loss_fn = loss_fn.to(device)
imgs = imgs.to(device)
targets = targets.to(device)

 对比第一种使用GPU的方法

tudui = tudui.cuda()

loss_fn = loss_fn.cuda()

imgs = imgs.cuda()

targets = targets.cuda() 

全部代码

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time  #用来计时

# 定义训练的设备
device = torch.device("cuda:0")
print(device)
# 准备数据集
# 训练数据集
train_data = torchvision.datasets.CIFAR10(root="./dataset1", train=True, transform=torchvision.transforms.ToTensor(),
                                          download=True)
# 测试数据集
test_data = torchvision.datasets.CIFAR10(root="./dataset1", train=False, transform=torchvision.transforms.ToTensor(),
                                         download=True)


# length 训练数据集有多少张   新知识点   如何获得数据集的长度
train_data_size = len(train_data)
test_data_size = len(test_data)

# if train_data_size=10,训练数据集的长度为:10
print(f"训练数据集的长度为:{train_data_size}") # 这个写法是常用的字符串格式化
print("测试数据集的长度为:{}".format(test_data_size))
# load dataset with DataLoder
train_dataloader = DataLoader(train_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

# 把模型剪切到了model中
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
            nn.MaxPool2d(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(64 * 4 * 4, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x

# 创建网络模型
tudui = Tudui()
tudui = tudui.to(device)
# 创建损失函数,也放在nn包里,分类问题可以用交叉熵
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)
# 定义优化器
# 学习速率
# learning_rate = 0.01
# 1e-2 = 1 x (10)^(-2) = 1/100 = 0.01
learning_rate = 1e-2
# 随机梯度下降优化器,参数是 对哪一个部分进行优化,网络模型.parameters  学习速率
optimizer = torch.optim.SGD(tudui.parameters(), lr=learning_rate)


# 接下来开始训练网络

# 设置训练网络的一些参数
# 记录训练的次数
total_train_step = 0
# 记录测试的次数
total_test_step = 0
# 训练轮数,循环10轮
epoch = 10

# 添加tensorboard
writer = SummaryWriter("p30logs_train")

start_time = time.time()
# i从0一直到9  训练10轮
for i in range(epoch):
    print("------第{} 轮开始------".format(i + 1))
    # 训练网络模型开始
    # 从训练数据中取数据
    # 训练步骤开始
    tudui.train()# 对特定层有作用dropout
    for data in train_dataloader:
        imgs, targets = data
        imgs = imgs.to(device)
        targets = targets.to(device)
        outputs = tudui(imgs) # 把训练数据放到网络当中
        # 输出和真实目标的误差是多少
        # 参数是预测的输出的真实的目标放进去
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        # 优化 梯度清零,为了上次的梯度不会影响这次的优化
        optimizer.zero_grad()
        # 调用损失函数的反向传播,得到每个参数结点的梯度
        loss.backward()
        # 对参数进行优化
        optimizer.step()  # 到此就是对参数进行了一次优化,也就是做了一次训练

        # 训练次数加1,
        # loss.item()   如果a= torch.tensor(5) ptint(a) 得到tensor(5)
        #print(a.item()) 得到 5
        total_train_step = total_train_step + 1
        # 一般会把loss写成loss.item(),,加上loss.item()转换为一个真实的数,不带tensor()
        #print(f"训练次数是:{total_train_step}时, 损失值是:{loss}")
        # 不想全部输出 没次100的倍数输出
        if total_train_step % 100 == 0:
            end_time = time.time()
            print("时间", end_time-start_time)
            print(f"训练次数是:{total_train_step}时, 损失值是:{loss.item()}")
            writer.add_scalar("train_loss", loss.item(), total_train_step)


    # 怎么知道有没有达到训练的需求
    # 测试不用对模型进行调优了  就是对现有模型的测试
    # 测试步骤开始
    tudui.eval()# 对特定层有作用dropout等
    total_test_loss = 0 # 求整个测试集上的loss
    total_accuracy = 0 # 整体正确率
    # 没有梯度
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs = tudui(imgs)
            loss = loss_fn(outputs, targets)
            # 相求整个测试集上的loss
            total_test_loss = total_test_loss + loss.item()

            # 计算正确率,1是指横向比较
            accuracy = (outputs.argmax(1) == targets).sum()  # 括号里输出的值会是 ture false,然后false相当于0,ture相当于1,求和
            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, "tudui_{}.pth".format(i))
    print("模型已保存")


writer.close()

有的gpu也这么写

device=torch.device("cuda")

device=torch.device("cuda:0")

device=torch.device("cuda" if torch.cuda.is_available() else "cpu")


p32完整的模型验证套路   test

利用已经训练好的模型给他提供输入

想要知道自己的输出

output对应的是哪个类别,可以在test_data处打一个断点,debug一下。

import torch
import torchvision.transforms
from PIL import Image
from torch import nn

# 两个点是上一层级,一个点是这一层级
imge_path = "./imgs/dog.jpg"
img = Image.open(imge_path)  # PIL类型的图片

# 把几个变换联立在一起
# 先改变图片的大小
transform =torchvision.transforms.Compose(
    [torchvision.transforms.Resize((32, 32)),
    torchvision.transforms.ToTensor()]
)  # compose() 里面写多种变形联立的时候,应该加上[]
image = transform(img)
print(image.shape)  #torch.Size([3, 32, 32])


# 拷贝网络模型
class Tudui(nn.Module):
    def __init__(self):
        super(Tudui, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=5, stride=1, padding=2),
            nn.MaxPool2d(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(64 * 4 * 4, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x

# 加载网络模型
model = torch.load("tudui_5.pth")
print(model)
image = torch.reshape(image,(1,3,32,32))
image = image.cuda()
# 模型转化为测试类型
model.eval()
# 可以节约内存 性能
with torch.no_grad():
    output = model(image)
print(output)  #tensor([[-2.5105, -4.0868,  4.6670, -0.0257,  0.2603,  2.8155, -0.0162,  2.4543,
                #-3.6706, -1.8582]], device='cuda:0')
print(output.argmax(1))# 最大的那个数在哪里

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值