小土堆pytorch深度学习记录

一.基本配置

1.基本配置

  1. Anaconda配置
  2. pytorch导入
  3. jupyter中导入pytorch

2.帮助学习函数

dir():打开

help():说明书

每写一个点,则利用了他的下属方法

二.Pytorch数据加载

DataSet       Dataloader

1.DataSet

针对大量数据进行数据提取并编号,提供一种方式去获取数据及其label

2.DataLoader

对数据进行的打包压缩,如01234四个,为网络提供不同的数据形式

3.DataSet使用方法

蚂蚁蜜蜂数据集下载:https://download.pytorch.org/tutorial/hymenoptera_data.zip

1.获取所有图片列表,listdir

2.获取图片路径,将蜜蜂和蚂蚁分开,以便于获取

import os
root_dir="dataset/train"
lable_dir="ants"
path=os.path.join(root_dir,lable_dir) #对路径进行拼接

3.完整代码read_data.py

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

class MyData(Dataset):


    def __init__(self,root_dir,label_dir):   #初始化 提供全局变量  类似java的构造构造函数 这里调用了python.Dataset
        self.root_dir=root_dir        #指定全局变量
        self.label_dir=label_dir
        self.path=os.path.join(self.root_dir,self.label_dir)    #拼接路径地址,获取图片路径地址
        self.ima_path=os.listdir(self.path)


    def __getitem__(self, idx):#获取其中的每一个图片
        img_name=self.ima_path[idx]    #self.获取全局的     idx索引 根据索引获得某个图片的名称
        img_item_path=os.path.join(self.root_dir,self.label_dir,img_name)   #获取idx对应图片的整条路径
        img=Image.open(img_item_path)   #图片读取
        label=self.label_dir    #获取标签  如:蚂蚁
        return img,label

    def __len__(self):
        return len(self.ima_path)


root_dir="dataset/train"
ants_label_dir="ants"
ants_dataset=MyData(root_dir,ants_label_dir)   #蚂蚁实例创建

bees_label_dir="bees"
bees_dataset=MyData(root_dir,bees_label_dir)   #蜜蜂实例创建

# img,label= ants_dataset[1]    #获取蚂蚁图片
# img.show()            #展示
#
# img1,label1=bees_dataset[0]
# img1.show()

train_dataset=ants_dataset + bees_dataset  #数据集合并  可以利用到数据集数量不足的时候,人工添加数据集(伪造数据集)


print(len(train_dataset),len(bees_dataset),len(ants_dataset))

img2,label2=train_dataset[3]

print(label2)

3.将图片标签写入txt文件(针对一些标签比较复杂的情况,利用txt文件去保存)

rename_data.pyt

# 这段代码的作用是将指定目录下的所有以".jpg"结尾的图片文件的标签写入同名的".txt"文件中。假设有一个名叫"antsimage"的目录,里面存放了一些以"ants"开头的蚂蚁图片,我们需要将其标签写入同名的".txt"文件中,以便后续使用。
# 代码核心部分使用了Python的os模块来定位文件位置和创建文件,主要分为以下步骤:
#
# 定义根目录rootdir、目标目录targetdir和标签label。在该段代码中,rootdir指的是存放所有图片的目录;targetdir指的是存放待处理图片的目录名称,本例中为"ants_image";而label则是标签,这里为"ants"。
# 获取目标文件夹下所有图片文件的名称,并去掉文件扩展名".jpg",只保留文件名。
# 遍历所有文件,使用with open()语句创建同名".txt"文件,并向其中写入标签label。
# 循环结束后,所有的图片的标签都写入了同名".txt"文件中,存放在指定的目录out_dir下。
#
# 总之,这段代码的作用是将一些图片的标签写入同名文件中,方便后续使用。
import os

root_dir = 'dataset/train'
target_dir = 'ants'
img_path = os.listdir(os.path.join(root_dir, target_dir))
label = target_dir.split('_')[0]
out_dir = 'ants_label'
for i in img_path:
    file_name = i.split('.jpg')[0]
    with open(os.path.join(root_dir, out_dir,"{}.txt".format(file_name)),'w') as f:
        f.write(label)

三.Tensorboard的使用

  • 可以看到loss如何变动,可以看出什么时间应该用什么样的模型。
  • 可以看到在某一步输入是什么,输出是什么

1.环境搭建与入门

    def add_scalar(
        self,
        tag,
        scalar_value,  #纵坐标
        global_step=None,  #横坐标
        walltime=None,
        new_style=False,
        double_precision=False,
    ):

1.导入tensorboard库 设定超时时间  避免下载失败

pip install --default-timeout=100 tensorboard

2.设置y=x 或y=2x展示

from torch.utils.tensorboard import SummaryWriter
#将时间文件存储到Logs文件下
writer=SummaryWriter("logs")

# writer.add_image() #添加image

for i in range(100):
    writer.add_scalar("y=2x",2*i,i)  #添加数

writer.close()

3.执行完2后生成了log文件在terminal终端执行命令打开log文件

(pytorch) D:\workSoftware\python\TensorBoard>tensorboard --logdir=logs

这里的logdir=事件文件夹名字

当众多人使用一个6006端口时候,防止冲突,可以指定端口

D:\workSoftware\python\TensorBoard>tensorboard --logdir=logs --port=6007

 4.点击生成的链接即可产生图像

2.具体数据集加案例

1.标准的可以传入的数据类型应该为上述中的一种

2.常用的方法PIL读取的图片类型为

此类型不满足要求

3.这里选择用numpy型,用opencv读取

4.也可以使用numpy.array(),对pil图片进行转换

5.具体代码

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

#将时间文件存储到Logs文件下
writer=SummaryWriter("logs")

image_path="data/train/bees/16838648_415acd9e3f.jpg"
img_PIL=Image.open(image_path)
img_array=np.array(img_PIL)    #转换图片格式
print(type(img_array))
print(img_array.shape)  #3通道在最后一位,

writer.add_image("test",img_array,2,dataformats='HWC') #添加image

# for i in range(100):
#     writer.add_scalar("y=2x",2*i,i)  #添加数

writer.close()

此处add_image中传入的2就代表步数,可以设置1或者2,1为蚂蚁,2为蜜蜂】

要创建新的   就将传入的“test”改为其他的名字

四.Transform

1.基础知识

在Dataset中很常用,通常是对图像进行变换,比如图像要统一到统一的尺寸,或者对图像其中的数据进行类的转化,演示一般是运行完一个方法后展示结果,最简单的就是用Tensorboard

在settings-keymap-Xxxxxx 中可以找xxxxx对应的快捷键

导入模块

from torchvision import transforms

结构

2.基本用法,案例Totensor

1.PIL image转为tensor

from PIL import Image
from torchvision import transforms

#1.tensor数据类型是什么样子?与普通的有什么区别
# 2.transform如何使用
#使用transforms.ToTensor来解决

img_path="data/hymenoptera_data/train/ants/0013035.jpg"
img=Image.open(img_path)

#实例化
tensors_trans=transforms.ToTensor()
#调用ToTensor中的call方法
tensors_img=tensors_trans(img)

print(tensors_img)

执行结果

tensor数据类型里面包装了许多在神经网络基础中所要用到的参数,

神经网络中许多时候都会转会成tensor型,然后进行训练,会用到transform

  • backwards_hooks 根据结果,利用反向传播对前面的参数进行调整。
  • _grad:梯度
  • _grad_fn:梯度的方法

2.numpy.ndarray转为tensor

用OpenCv转化

3.常见的Tranform

理解不同格式下,用什么打开,返回什么

3.1对于实例化的理解(  __call__  )

  • compose:讲不同的transform组合在一起
  • ToTensor     
    from PIL import Image
    from torch.utils.tensorboard import SummaryWriter
    from torchvision import transforms
    
    writer=SummaryWriter("logs")
    img=Image.open("images/课表.jpg")
    print(img)
    
    
    #  1.ToTensor的使用
    
    #java中构造方法可以直接传参
    #在python中要把class先实例化,此时不能传参,必须接受以后,在下一个语句传参
    trans_totensor=transforms.ToTensor() #实例化
    img_tensor=trans_totensor(img)
    writer.add_image("ToTensor",img_tensor)
    writer.close()
    
    

  • add_image
  • ToPILImage:将图片转为PIL类型
  • Normalize:归一化,
  • 作用:1消除奇异值及样本数据中与其他数据相比特别大或者特别小的数据,加快训练速度。2.不同维度之间的特征在数值上量纲可能不一样,归一化让量纲变得差不多,这样帮助梯度下降更快,更容易求解
  • from PIL import Image
    from torch.utils.tensorboard import SummaryWriter
    from torchvision import transforms
    
    writer=SummaryWriter("logs")
    img=Image.open("images/test.jpg")
    print(img)
    
    
    #  1.ToTensor的使用
    
    #java中构造方法可以直接传参
    #在python中要把class先实例化,此时不能传参,必须接受以后,在下一个语句传参
    trans_totensor=transforms.ToTensor() #实例化
    img_tensor=trans_totensor(img)
    writer.add_image("ToTensor",img_tensor)
    
    
    #   2.Normalize 归一化的使用
    print(img_tensor[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)
    
    writer.close()
    
    tensorboard --logdir logs
    

  • Resize:修改图片尺寸,输入PIL格式的图片,缩放。
  • Compose Resize -2 输入单个值
  • transforms.Compose 是 PyTorch 中用于创建图像预处理操作序列的函数。它允许将多个图像变换操作组合成一个序列,以便在对图像进行预处理时一次性应用这些操作。
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms

writer=SummaryWriter("logs")
img=Image.open("images/test.jpg")
print(img)


#  1.ToTensor的使用

#java中构造方法可以直接传参
#在python中要把class先实例化,此时不能传参,必须接受以后,在下一个语句传参
trans_totensor=transforms.ToTensor() #实例化
img_tensor=trans_totensor(img)
writer.add_image("ToTensor",img_tensor)


#   2.Normalize 归一化的使用
#
print(img_tensor[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)

# 3.Resize
print(img.size)
trans_resize=transforms.Resize((512,512))

#img PIL--resize-->img_resize PIL
img_resize=trans_resize(img)
print(img_resize.size)

#img_resize PIL->totensor -> img_resize:tensor
img_resize=trans_totensor(img_resize)
writer.add_image("Resize",img_resize,0)


# 4 Compose  Resize  -2   输入
trans_resize_2=transforms.Resize(512)#将宽和高调整为512
#相当于一个合并的功能,按照写的列表执行流程
trans_compose=transforms.Compose([trans_resize_2,trans_totensor])
img_resize_2=trans_compose(img)
print(img_resize_2.shape)

writer.add_image("Resize",img_resize_2,1)


writer.close()
  • RandomCrop:随机裁剪  给定一个尺寸,随即裁剪为一个正方形。
  • # 5.RandomCrop
    trans_random=transforms.RandomCrop((512,1000))
    trans_compose_2=transforms.Compose([trans_random,trans_totensor])
    for i in range(10):
        img_crop=trans_compose_2(img)
        writer.add_image("RandomCropHW",img_crop,i)
    

4.对函数使用方法的研究

  1. 关注输入和输出类型
  2. 关注方法需要什么参数
  3. 不知道返回值,print  print(type())

5.数据集与tranform结合

之前都是对单张图片的处理,这里开始处理多张图片

1.数据集的获取

torchvision.datasets — PyTorch master documentationicon-default.png?t=N7T8https://pytorch.org/docs/1.0.0/torchvision/datasets.html

  • mnist:手写文字,入门数据集
  • Coco:目标检测,语义分割
  • CIFAR10:物体识别的数据集

可以用迅雷 传入下载链接  或者在download设置为true

2.具体案例

此处用了CIFAR10数据集,用transform+dataset进行处理

import torchvision
from torch.utils.tensorboard import SummaryWriter

dataset_tranform=torchvision.transforms.Compose([
    torchvision.transforms.ToTensor()
])

train_set=torchvision.datasets.CIFAR10(root="./dataset",train=True,transform=dataset_tranform,download=False)
test_set=torchvision.datasets.CIFAR10(root="./dataset",train=False,transform=dataset_tranform,download=False)


writer=SummaryWriter("datafind")
for i in range(10):
    img,target=test_set[i]  #此处的img就是图像 target是clsses的索引 class[target]可以取到图片的类别
    writer.add_image("test_set",img,i)

writer.close()

五.DataLoader

  • dataset只是获得图片的位置,索引对应的是哪个数据。
  • dataloader将数据加载到神经网络,从dataset中取数据

将数据加载到神经网络,每次从dataset中取数据,并规定取数据的方式。

  • dataset:之前学过的自定义的dataset
  • batch_size:一摞牌,每次摸几张
  • shuffle:是否打乱,默认为false一般设置为true(则改变了顺序)
  • num_workers:加载数据是单进程还是多进程,>0的时候在window会出现错误
  • drop_last:每次取三张图,一共100张,剩下的是否舍去,true即为舍去

1.先下载cifar-10数据集

2代码1

import torchvision
from torch.utils.data import DataLoader

#准备的数据集
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)

#测试数据中第一张图片以及target
img,target=test_data[0]
print(img.shape)  #3表示图象是RGB3通道的  32x32尺寸
print(target)    #3表示图像类别是3

for data in test_loader:
    imgs,targets=data
    print(imgs.shape)
    print(targets)

运行结果

输出的结果是batch,通道数,高,宽

tensor中对应的8,5,1,0分别为四张图片对应的索引

3.代码2

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)  #3表示图象是RGB3通道的  32x32尺寸
print(target)    #3表示图像类别是3

writer=SummaryWriter("dataloader")
step=0
for data in test_loader:
    imgs,targets=data
    # print(imgs.shape)
    # print(targets)
    writer.add_images("test_data_drop_last",imgs,step)
    step=step+1

writer.close()

六.基本骨架 nn.module

1.基本内容

  • Containers:骨架(容器),定义了神经网络的结构,添加内容就可以组成神经网络
  • Convolution Layers:卷积层
  • model继承nn.Module

案例

2.搭建自己的网络-代码

import torch
from torch import nn


class extend(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

    def forward(self,input):
        output=input+1
        return output

model=extend()
x=torch.tensor(1.0)
output=model(x)
print(output)

3.pytorch类,方法基础知识:

在PyTorch中,模型的forward方法定义了数据在模型中正向传播(forward propagation)的过程。这个方法接收一个输入张量,并返回一个输出张量(或者是一组输出张量,具体取决于模型的结构)。

一般来说,PyTorch中模型的forward方法的典型写法如下:

import torch
import torch.nn as nn

class MyModel(nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        # 在这里定义模型的各个层

    def forward(self, input):
        # 在这里定义正向传播过程
        output = ...
        return output
  1. 类定义 (MyModel):

    • MyModel类继承自nn.Module,这是PyTorch中定义神经网络模型的基类。
  2. 初始化方法 (__init__):

    • __init__方法中,通常会定义模型的各个层(例如卷积层、池化层、全连接层等)和其他需要的组件。这些层的初始化应该在__init__方法中完成。
  3. forward方法 (forward):

    • forward方法定义了数据在模型中如何进行正向传播。
    • 它接收一个input参数,这是输入到模型的张量。
    • 在方法中,input经过一系列的层和激活函数处理,最终得到一个输出张量output
    • output的形状通常取决于模型的设计,比如如果是分类模型,则可能是(batch_size, num_classes)的形状,每个元素代表每个类的预测概率或得分。
  4. 返回值:

    • forward方法的返回值通常是一个张量或一组张量,代表了模型对输入的处理结果。

根据模型的具体结构,forward方法会有不同的实现。例如,如果模型由多个层组成,forward方法会将输入张量依次传递给这些层,并通过激活函数产生最终的输出。

下面是一个简单的示例,展示了如何定义一个简单的全连接神经网络模型,并实现它的forward方法:

import torch
import torch.nn as nn

class SimpleModel(nn.Module):
    def __init__(self):
        super(SimpleModel, self).__init__()
        self.fc1 = nn.Linear(784, 256)  # 输入大小为784,输出大小为256
        self.fc2 = nn.Linear(256, 10)   # 输入大小为256,输出大小为10(10个类别)

    def forward(self, x):
        # x的形状为(batch_size, 784)
        x = torch.relu(self.fc1(x))  # 第一层全连接层,使用ReLU激活函数
        x = self.fc2(x)              # 第二层全连接层,没有激活函数,输出即为预测值
        return x

 在这个例子中:

  • __init__方法中定义了两个全连接层。
  • forward方法中,输入x经过第一层全连接层后,使用ReLU激活函数,然后经过第二层全连接层得到输出。

通过这种方式,模型的forward方法可以根据实际情况灵活地定义,以适应各种深度学习任务的需求。

七.神经结构的使用

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]])
#由于conv2d的输入参数需要是四维的,所以用reshape。将原来的二维张量变成四维张变量,增加了批次维度和通道维度
input=torch.reshape(input,(1,1,5,5))
kernel=torch.reshape(kernel,(1,1,3,3))
print(input.shape)
print(kernel.shape)

output=F.conv2d(input,kernel,stride=1)
print(output)

输出结果

八.卷积层

1.概念

参数说明如下:

  • in_channels:输入张量的通道数目,也就是输入数据的深度。如果输入数据是 RGB 彩色图片,则输入通道数为 3,如果是灰度图像,则输入通道数为 1。
  • out_channels:输出张量的通道数目,也就是卷积核(滤波器)的数量。每个卷积核可以提取一种特征。多个卷积核可以提取不同的特征,从而得到更丰富的特征表示。
  • kernel_size:卷积核的大小。可以是一个整数,表示正方形卷积核的边长;也可以是一个元组 (h, w),表示卷积核的高度和宽度。
  • stride:卷积核的步长。可以是一个整数,表示在水平和垂直方向上的相邻卷积窗口之间的距离;也可以是一个元组 (h, w),表示在水平和垂直方向上的步长。
  • padding:填充值的大小。可以是一个整数,表示在输入张量周围添加多少行和列的填充值;也可以是一个元组 (h, w),表示在水平和垂直方向上的填充数量。
  • dilation:卷积核的扩张率。可以是一个整数,表示卷积核中间的空洞大小;也可以是一个元组 (h, w),表示在水平和垂直方向上的空洞大小。
  • groups:输入张量和输出张量之间的连接方式。默认值为 1,表示传统的卷积操作。当 groups=in_channels 时,输入张量中的每个通道都会分别与卷积核中的通道进行卷积操作,并将结果合并。当 groups=out_channels 时,输出张量中的每个通道都由不同的输入通道进行卷积操作,并将结果合并。
  • bias:是否使用偏置项。默认值为 True,表示使用偏置项;如果设为 False,则不使用偏置项。
  • padding_mode:填充方式。可以是 'zeros' 或 'circular'

这些参数可以根据具体的任务和网络结构进行调整。例如,可以通过设置 in_channelsout_channels 来控制网络的深度和宽度,通过调整 kernel_sizestride 来控制卷积核的大小和步长,通过设置 padding 来控制填充方式,等等。

2.代码 

import torch
from torch import nn


class extend(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

    def forward(self,input):
        output=input+1
        return output

model=extend()
x=torch.tensor(1.0)
output=model(x)
print(output)

卷积代码

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=False)

dataloader = DataLoader(dataset, batch_size=64)


class Convolu(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = Conv2d(3, 6, 3, 1, 0)

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


convolu = Convolu()
print(convolu)

writer = SummaryWriter("./logs")
step = 0
for data in dataloader:
    imgs, targets = data
    output = convolu(imgs)
    # torch.Size([64, 3, 32, 32])
    writer.add_images("inputconvolu", imgs, step)
    # torch.Size([64, 6, 30, 30])

    # -1表示自动计算维度大小第一个维度会根据 output 张量的总元素数量和其他维度的大小自动计算出来,以保证总元素数量不变,
    output=torch.reshape(output, (-1, 3, 30, 30))
    writer.add_images("outputconvolu", output, step)
    step = step + 1

九.池化层

1.概念

参数

  • kernel_size:池化窗口的大小。这是一个整数或元组,指定池化窗口的高度和宽度。例如,kernel_size=2表示池化窗口的高度和宽度都为2,而kernel_size=(2, 3)表示高度为2,宽度为3。

  • stride:池化窗口的步幅。这也是一个整数或元组,指定池化窗口沿着输入张量的高度和宽度的移动步幅。默认值为kernel_size,这意味着池化窗口不重叠。

  • padding:填充的大小。如果设置为非零值,则在输入的每一边都填充相应数量的零值。填充可确保输出特征图的大小与输入特征图相同,或者与所期望的大小相匹配。默认值为0。

  • dilation:膨胀系数。这是一个整数或元组,指定池化窗口中每个元素之间的间隔。默认值为1,表示池化窗口中的元素之间没有间隔。

  • return_indices:是否返回最大值的索引。如果设置为True,则返回池化过程中每个最大值的索引位置,这在某些情况下可能很有用,默认为False。

  • ceil_mode:是否采用“向上取整”模式。如果设置为True,则使用“向上取整”来计算输出特征图的大小。默认为False。下图为案例

  • count_include_pad:是否包括填充值在内。如果设置为True,则在池化过程中,填充值将被视为有效值。默认为True

一般只设置kenrnal_size,上图所示例子为最大池化

2.代码一   5x5图像

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]])
input=torch.reshape(input,(-1,1,5,5))
print(input.shape)

class Maxpool(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.maxpool1=MaxPool2d(3,ceil_mode=True)#对于cell_mode的解释在参数解释位置

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

maxpool=Maxpool()
output=maxpool(input)
print(output)

输出结果

3.代码二:  CIFAR10数据集

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=False,transform=torchvision.transforms.ToTensor())

dataloader=DataLoader(dataset,batch_size=64)

class Maxpool(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.maxpool1=MaxPool2d(3,ceil_mode=False)

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

maxpool=Maxpool()
step=0
writer=SummaryWriter("./logs19_maxpool")
for data in dataloader:
    imgs,targets=data
    writer.add_images("maxpooinput",imgs,step)
    output=maxpool(imgs)
    writer.add_images("maxpooloutput",output,step)
    step=step+1

writer.close()


输出:池化后图片模糊,类似马赛克,减少了数据量,但保持了特征,加快处理速度

4.总结

卷积的作用是提取特征,池化的作用是降低特征的数据量

十.非线性激活

ReLU

Sigmoid

ReLU中输入参数inplace=true或者false的  区别

true直接将输入变为0,False会进行原地替换 input不变,设置Output为0

sigmoid代码

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

dataset = torchvision.datasets.CIFAR10("./dataset", train=False, download=False,
                                       transform=torchvision.transforms.ToTensor())

dataloader = DataLoader(dataset, batch_size=64)


class Maxpool(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.sigmoid1 = Sigmoid()

    def forward(self, input):
        output = self.sigmoid1(input)  # 因为replace默认是false 必须用output
        return output


sigmoid = Maxpool()
writer = SummaryWriter("./log20unline")

step = 0

for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, global_step=step)
    output = sigmoid(imgs)
    writer.add_images("output", output, step)
    step = step + 1
#

writer.close()

运行结果

十一.线性层及其他层

1.其他层

1.正则化层

nn.BatchNorm2d

归一化,它对输入进行归一化处理,有助于加速训练并提高模型的泛化能力。具体来说,BatchNorm2d对每个输入通道在mini-batch的维度上进行归一化,即对每个通道在每个mini-batch的数据上进行均值和方差的归一化。

100对应为通道数

2.Recurrent layers(递归层)

  1. 循环神经网络(RNN):RNN是一种最简单的递归层,它通过在每个时间步骤将当前输入和前一个时间步骤的隐藏状态进行组合来计算输出。但是,标准RNN存在梯度消失或梯度爆炸的问题,因此在实践中常常使用LSTM或GRU替代。

  2. 长短期记忆网络(LSTM):LSTM是一种带有门控机制的递归层,它能够更好地捕捉序列中的长期依赖关系。LSTM通过门控单元来控制信息的流动,包括输入门、遗忘门和输出门,从而有效地处理梯度消失和梯度爆炸问题。

  3. 门控循环单元(GRU):GRU是LSTM的一种变体,它合并了输入门和遗忘门,从而减少了参数数量并简化了网络结构。尽管它相对于LSTM具有更少的参数,但在某些情况下也能取得很好的性能。

在PyTorch中,这些递归层都可以通过torch.nn模块中的相应类来实现,例如torch.nn.RNNtorch.nn.LSTMtorch.nn.GRU。这些类提供了灵活的接口,可以根据需要配置各种参数,如输入维度、隐藏状态维度、层数等。

3.Transformer Layers

 4.Dropout Layers层

5.Sparse Layers

2.线性层Linear Layers


 

代码1

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

dataset=torchvision.datasets.CIFAR10("dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                     download=False)

dataloader=DataLoader(dataset,batch_size=64,drop_last=True)

class Line(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.linear1=Linear(196608,10)

    def forward(self,input):
        output=self.linear1(input)
        return output
line=Line()

for data in dataloader:
    imgs,targets=data
    print(imgs.shape)
    output=torch.reshape(imgs,(1,1,1,-1))  #高置为1,变成一行
    print(output.shape)
    output=line(output)
    print(output.shape)

这里先处理数据为1,1,1,196608,变为一行,再进行线性层处理。

报错的情况,在dataload添加此参数,因为最后图片的不足64张

drop_last=True

 这里引出了flatten函数,变为一行。

可以替代reshape对于维度中各数的的处理

代码2

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

dataset=torchvision.datasets.CIFAR10("dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                     download=False)

dataloader=DataLoader(dataset,batch_size=64,drop_last=True)

class Line(nn.Module):

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self.linear1=Linear(196608,10)

    def forward(self,input):
        output=self.linear1(input)
        return output
line=Line()

for data in dataloader:
    imgs,targets=data
    print(imgs.shape)
    output=torch.flatten(imgs)
    print(output.shape)
    output=line(output)
    print(output.shape)

输出

与之前的输出产生对比 

3.可研究类别

分类,语义分割,目标检测,实例分割,人体关键点检测,视频分类

 十二.实战与sequential

本次在搭建网络的过程中,展示sequential的好处

代码1

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


class sequantial(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.conv1=Conv2d(3,32,5,padding=2)
        self.maxpoo1=MaxPool2d(2)
        self.conv2=Conv2d(32,32,5,padding=2)
        self.maxpoo2=MaxPool2d(2)
        #如果前后尺寸不变,padding=(卷积核大小-1)/2
        self.conv3=Conv2d(32,64,5,padding=2)
        self.maxpoo3=MaxPool2d(2)
        self.flatten=Flatten()
        self.linear1=Linear(64*4*4,64)
        self.linear2=Linear(64,10)

    def forward(self,x):
        x=self.conv1(x)
        x=self.maxpoo1(x)
        x=self.conv2(x)
        x=self.maxpoo2(x)
        x=self.conv3(x)
        x=self.maxpoo3(x)
        x=self.flatten(x)
        x=self.linear1(x)
        x=self.linear2(x)
        return x
sq=sequantial()
print(sq)

input=torch.ones(64,3,32,32)
output=sq(input)
print(output.shape)

结果

代码2  应用sequential

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


class sequen(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            # 如果前后尺寸不变,padding=(卷积核,大小-1)/2
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64 * 4 * 4, 64),
            Linear(64, 10)
        )

    def forward(self, x):
        x=self.model1(x)
        return x
sq = sequen()
print(sq)
input=torch.ones(64, 3, 32, 32)
output = sq(input)
print(output.shape)

结果

 代码3  可视化 

在2后面添加这段即可


writer=SummaryWriter("./los22sequl")
writer.add_graph(sq,input)
writer.close()

十二.反向传播和损失函数

1.L1loss  function

代码

import torch
from torch.nn import L1Loss

inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5])

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)

2.MSELOSS

差的平方和/平均数

3.交叉熵CrossEntropyLoss

这里以识别狗为案例,代入公式的时候xclass为预测的狗的概率,值越大能使得损失函数越小,后面为log【e的(0.1+0.2+0.3)】,值越小,损失函数越小,效果越好。

nn.CrossEntropyLoss() 的输入通常是模型的输出和对应的真实标签。

具体来说,它接受两个参数:

  1. 模型的输出(input): 这是一个张量,表示模型的预测结果。通常是未经过 softmax 函数的原始预测值。形状通常是 (batch_size, num_classes),其中 batch_size 是批量大小,num_classes 是类别的数量。形状为 (N, C),其中 N 是批量大小,C 是类别的数量。input 应该是未经过 softmax 函数的原始预测值。
  2. 真实标签(target): 这也是一个张量,包含了真实的类别标签。通常是一维张量,形状是 (batch_size,),其中每个元素是一个类别的索引,对应着模型预测的类别。

nn.CrossEntropyLoss() 内部会自动将模型的输出转换为概率分布,并计算交叉熵损失。这个损失函数是用来衡量模型预测与真实标签之间的差异,用于训练模型参数,使模型能够更好地预测样本的类别。

代码一  简单应用交叉熵

import torch
from torch import nn
from torch.nn import L1Loss, MSELoss

inputs=torch.tensor([1,2,3],dtype=torch.float32)
targets=torch.tensor([1,2,5])

inputs=torch.reshape(inputs,(1,1,1,3))
targets=torch.reshape(targets,(1,1,1,3))

loss=L1Loss(reduction="sum")
result=loss(inputs,targets)

lose_mse=MSELoss()
result_mse=lose_mse(inputs,targets)

print(result)
print(result_mse)

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)

输出

代码二  CIFAR10应用

import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
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=1)


class sequen(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            # 如果前后尺寸不变,padding=(卷积核,大小-1)/2
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64 * 4 * 4, 64),
            Linear(64, 10)
        )

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

sq=sequen()
loss=nn.CrossEntropyLoss()

for data in dataloader:
    imgs,targets=data
    outputs=sq(imgs)

    result_loss=loss(outputs,targets)
    print(result_loss)

将卷积模型输出input和目标类别target传入损失函数,得到了神经网络输出和真实输出的误差,也就是损失值。

3.反向传播及梯度下降

给每一个需要调优的参数,如卷积核的参数,grad(梯度),当采用反向传播时候,每一个需要更新的参数都有一个对应的梯度,当优化的时候,利用梯度,对其中的参数进行优化,最终达到损失函数减小的作用。(梯度下降法)

实例理解

Debug

在定义的模型名字-->mode1-->保护属性-->modules-->weight-->grad

grad刚开始为none,在经过backwards(反向传播)之后,算出了梯度的参数,然后优化器,就可以实现梯度的下降。

4.对于梯度和损失函数的理解

梯度和损失函数是深度学习中两个关键概念,它们之间有着密切的关系,但又各自有着不同的含义和作用。

  1. 梯度

    • 梯度是一个向量,表示函数在某一点的变化率或者斜率。在深度学习中,通常指的是损失函数关于模型参数的梯度,即损失函数对模型参数的偏导数。
    • 梯度告诉我们在当前参数值处,沿着哪个方向可以使损失函数增加或减小最快。通过梯度下降法,我们可以根据梯度的信息来更新模型参数,使得损失函数逐渐降低,从而找到最优的模型参数。
  2. 损失函数

    • 损失函数是用来衡量模型预测值与真实值之间的差异程度的函数。它是深度学习模型优化的目标函数,我们希望通过最小化损失函数来使得模型的预测尽可能接近真实值。
    • 损失函数的选择取决于具体的任务和模型类型,常见的损失函数包括均方误差(Mean Squared Error,MSE)、交叉熵损失函数(Cross-Entropy Loss)、对比损失函数(Contrastive Loss)等。

关系和区别

  • 关系:梯度是损失函数关于模型参数的偏导数,它反映了损失函数在当前模型参数下的变化率。在训练过程中,我们通过计算损失函数关于模型参数的梯度,来指导模型参数的更新,以最小化损失函数。
  • 区别:梯度是一个向量,是对损失函数的变化率进行描述;而损失函数是一个标量,用来衡量模型预测值与真实值之间的差异。梯度是指导模型参数更新的依据,而损失函数是我们要最小化的目标。

总的来说,梯度和损失函数是深度学习中优化过程的核心概念,梯度指导着模型参数的更新方向,而损失函数则是我们要优化的目标。通过不断地计算损失函数关于模型参数的梯度,并根据梯度信息来更新模型参数,我们可以逐步优化模型,使其在训练数据上的预测效果不断提升。

十三.优化器

优化器都在这个位置(optimizer)

  • optimizer.step() 方法是 PyTorch 中用于执行优化器步骤的重要方法之一,它会根据优化器的设置和计算得到的梯度来更新模型参数,从而最小化损失函数。
  • "lr:通常是深度学习中优化器(optimizer)的一个参数,代表学习率(learning rate)。学习率是控制模型参数更新步长的一个重要超参数,它决定了在每次迭代中模型参数沿着梯度方向更新的幅度。学习率太大可能导致模型无法收敛,学习率太小则可能导致训练速度过慢。

核心代码

 
optim=torch.optim.SGD(sq.parameters(),lr=0.01)#学习率太大 不稳定 太小 学习速度慢
                                              # 开始用大的,后面用小的
optim.zero_grad()
result_loss.backward()
optim.step()

torch.optim.SGD():随机梯度下降法

完整代码

import torch
import torchvision.datasets
from torch import nn
from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
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=1)


class sequen(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()

        self.model1 = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            # 如果前后尺寸不变,padding=(卷积核,大小-1)/2
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64 * 4 * 4, 64),
            Linear(64, 10)
        )

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

sq=sequen()
loss=nn.CrossEntropyLoss()
optim=torch.optim.SGD(sq.parameters(),lr=0.01)#学习率太大 不稳定 太小 学习速度慢
                                              # 开始用大的,后面用小的
for epoch in range(20):
    runing_loss=0.0
    for data in dataloader:
        imgs, targets = data
        outputs = sq(imgs)
        result_loss = loss(outputs, targets)
        optim.zero_grad()
        result_loss.backward()
        optim.step()
        runing_loss=runing_loss+result_loss
    print(runing_loss)

通常在训练神经网络时,我们会在每个训练迭代(或每个批次)计算损失,并将其累积到一个运行损失中,以便跟踪训练过程中损失的变化情况。

  • runing_loss: 这是一个变量,用于存储累积的运行损失。
  • result_loss: 这是当前迭代(或批次)计算得到的损失值。
  • runing_loss + result_loss: 表示将当前计算得到的损失值加到累积的运行损失中,以更新它。

运行结果

十四.现有网络模型的使用和修改(Vgg16)

1.思路

最开始准备用ImageNet数据集,由于数据集100g,占用内存太大,所以直接去看vgg16的参数的pretrained参数在True和False的区别

  1. torchvision.models.vgg16(pretrained=False):

    • 这会创建一个 VGG-16 模型的实例,但不会加载预训练的权重。
    • 模型的权重会随机初始化,即所有的卷积核和全连接层的参数都将以随机的方式初始化。
    • 这个模型通常用于需要从头开始训练的任务,或者需要对模型进行自定义修改的情况下。
  2. torchvision.models.vgg16(pretrained=True):

    • 这会创建一个 VGG-16 模型的实例,并加载在 ImageNet 数据集上预训练的权重。
    • 预训练的权重可以帮助提高模型的性能和收敛速度,尤其是在图像分类等任务上。
    • 加载预训练的权重后,模型的参数将被初始化为在大规模图像分类任务上学到的特征表示。这意味着模型已经学会了提取一般的图像特征,可以直接在其他数据集上进行微调或特征提取等任务,而无需从头开始训练整个模型。
train_data=torchvision.datasets.ImageNet("./data_image_net",split='train',download=True,
                                          transform=torchvision.transforms.ToTensor())

2.实例一:查看vgg的true和false的区别

true会下载,记载已经预训练过的模型的权重。

import torchvision

# train_data=torchvision.datasets.ImageNet("./data_image_net",split='train',download=True,
#                                           transform=torchvision.transforms.ToTensor())

vgg16_false=torchvision.models.vgg16(pretrained=False)
vgg16_false=torchvision.models.vgg16(pretrained=True)#True的时候会进行下载

debug看权重

classifier-->protectes-->modules--->0>weight

为true时,vgg是训练好的

为false时候,就是像我们自己写的卷积层,都是固定的

可以看出vgg16可以做一个1000类别的分类

 3.实例二:对vgg网络层中的内容进行修改

将1000分类变为10分类(对全连接层的修改也叫迁移学习)

方法一:再添加一层全连接层

import torchvision
from torch import nn

# train_data=torchvision.datasets.ImageNet("./data_image_net",split='train',download=True,
#                                           transform=torchvision.transforms.ToTensor())

vgg16_false=torchvision.models.vgg16(pretrained=False)
vgg16_true=torchvision.models.vgg16(pretrained=True)#True的时候会进行下载
print(vgg16_true)

train_data=torchvision.datasets.CIFAR10("./dataset",True,transform=torchvision.transforms.ToTensor(),
                                        download=False)

vgg16_true.classifier.add_module('add_linear',nn.Linear(1000,10))
print(vgg16_true)

结果

方法二:对原有的最后全连接层参数修改

import torchvision
from torch import nn

# train_data=torchvision.datasets.ImageNet("./data_image_net",split='train',download=True,
#                                           transform=torchvision.transforms.ToTensor())

vgg16_false=torchvision.models.vgg16(pretrained=False)
vgg16_true=torchvision.models.vgg16(pretrained=True)#True的时候会进行下载
print(vgg16_true)

vgg16_false.classifier[6]=nn.Linear(4096,10)
print(vgg16_false)

结果:输出由1000变为了10 

 十五.对网络模型的保存和加载

1.保存和读取方式一(模型结构+参数)

保存

import torch
import torchvision

vgg16=torchvision.models.vgg16(pretrained=False)

#保存方式1  模型的结构+参数
torch.save(vgg16,"vgg16_method1.pth")

读取

import torch
import torchvision
from torchvision.models import VGG16_Weights

# 方式一 加载模型
model=torch.load("vgg16_method1.pth")
print(model)

2.保存和读取方式二(将模型参数保存为字典形式)

保存

import torch
import torchvision

vgg16=torchvision.models.vgg16(pretrained=False)
#保存方式二     将vgg模型参数保存成python中的字典形式(官方推荐)

torch.save(vgg16.state_dict(),"vgg16_method2.pth")

读取:字典变为结构类型

import torch
import torchvision
from torchvision.models import VGG16_Weights

#方式二  加载模型
#从字典状态变回结构状态
vgg16=torchvision.models.vgg16(weights=VGG16_Weights)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
print(vgg16)

3.陷阱(在方式一的时候出现)

import torch
import torchvision
from torch import nn


#陷阱
class Model(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.conv1=nn.Conv2d(3,64,5)

    def forward(self,x):
        x=self.conv1(x)
        return x
model=Model()
torch.save(model,"fu_method1.pth")

在这里自己写了一个模型并保存于fu_method1.pth,但是在调用的时候

import torch
import torchvision
from torch import nn
from torchvision.models import VGG16_Weights


#陷阱1

model=torch.load("fu_method1.pth")
print(model)

直接用这段代码会报错,必须加上自定义的方法

import torch
import torchvision
from torch import nn
from torchvision.models import VGG16_Weights


#陷阱1
class Model(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.conv1=nn.Conv2d(3,64,5)

    def forward(self,x):
        x=self.conv1(x)
        return x
model=torch.load("fu_method1.pth")
print(model)

这样才能运行,这个陷阱在自己写的代码中能看出来,在调用vgg时候没报错

4.陷阱解决

在真实的 项目中,不会把自定义的方法来回复制,会保存在一个文件夹中,使用的时候,利用import直接引入即可

import torch
import torchvision
from torch import nn

from model_save import *


#陷阱1

model=torch.load("fu_method1.pth")
print(model)

 也可以运行

十六.完整的模型训练套路(一)+(二)

1.数据集

以CIFAR10作为数据集 

神经网络单独搭建到model.py

import torch
from torch import nn

# 搭建神经网络
class Fu(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.model=nn.Sequential(
            nn.Conv2d(3,32,5,1,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


if __name__ == '__main__':
    fu=Fu()
    input=torch.ones((64,3,32,32))
    output=fu(input)
    print(output.shape)

输出结果

 结果显示为64行数据,每一行中的10个值对应为图片在这10个类别的概率、

2.概念及训练代码

概念:

1.训练次数和轮数的区别

在机器学习和深度学习中,"训练的次数" 和 "训练的轮数" 都与训练过程中的迭代次数相关,但它们指代的概念略有不同。

  1. 训练的次数(Number of training iterations):通常指的是模型在整个训练数据集上进行参数更新的总次数。每一次迭代可能包括对整个数据集的一次前向传播和反向传播,以便更新模型的参数。因此,"训练的次数" 可能表示模型参数更新的总次数。

  2. 训练的轮数(Number of training epochs):指的是模型循环遍历整个训练数据集的次数。在每一个轮数(epoch)中,模型会将整个训练数据集用于参数更新。因此,"训练的轮数" 表示模型在整个训练数据集上迭代的次数。

简而言之,"训练的次数" 强调的是模型参数更新的总次数,而 "训练的轮数" 强调的是模型遍历整个训练数据集的次数。

在实际应用中,这两个概念经常会相互关联。比如,通常会根据训练数据集的大小和模型的收敛情况来确定训练的轮数和每轮的次数。

2. optimizer.zero_grad()

optimizer.zero_grad() 是在使用 PyTorch 进行深度学习模型训练时常见的一个操作。这个操作的作用是将优化器中所有参数的梯度归零。

在 PyTorch 中,进行反向传播(backpropagation)计算梯度后,这些梯度会累积到每个参数的.grad属性中。在开始下一次反向传播之前,通常需要先调用 optimizer.zero_grad() 来清除之前的梯度,以避免梯度的累积影响到后续的参数更新。

3.nn.CrossEntropyLoss(output, targets)

nn.CrossEntropyLoss(output, targets) 是在 PyTorch 中用于计算多分类任务中损失函数的常见操作。在这里,output 是模型的输出,targets 是真实的标签。

具体而言,nn.CrossEntropyLoss 结合了 nn.LogSoftmaxnn.NLLLoss 两个操作,用来计算多分类问题中的交叉熵损失。在使用时,通常会将模型的原始输出经过 softmax 操作(将输出转换为概率分布),然后再计算交叉熵损失。

4.optimizer.step()

optimizer.step() 是在使用 PyTorch 进行深度学习模型训练时常见的一个操作。这个操作的作用是根据计算得到的梯度来更新模型参数。

在 PyTorch 中,进行完一次反向传播(backpropagation)后,优化器中的参数梯度已经被计算并存储在每个参数的.grad属性中。调用 optimizer.step() 将会根据这些梯度来更新模型的参数,实现参数的优化。

2.代码:

此段代码要结合上面写的model.py使用

import torch.optim
import torchvision.datasets
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=False)
test_data=torchvision.datasets.CIFAR10("./dataset",train=False,transform=torchvision.transforms.ToTensor(),
                                       download=False)

#查看数据集的图片数
train_data_size=len(train_data)
test_data_size=len(test_data)
print("训练数据集的长度为{}".format(train_data_size))  #将{}这个符号替换为format数据中的数  常用方法
print("测试数据集的长度为{}".format(test_data_size))  #将{}这个符号替换为format数据中的数  常用方法

#利用Dataloader来加载数据集
train_dataloader=DataLoader(train_data,64)
test_dataloader=DataLoader(test_data,64)


#创建网络模型
fu=Fu()

#损失函数  分类问题可以用交叉熵
loss_fn=nn.CrossEntropyLoss()

#定义优化器 用optim中的随机梯度下降
#1e-2=1x(10)^-2=1/100=0.01 科学记数法中的 "e" 表示 "乘以 10 的次方"
learning_rate=0.01
optimizer=torch.optim.SGD(fu.parameters(),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))

    #训练步骤开始
    for data in train_dataloader:
        imgs,targets=data
        outputs=fu(imgs)
        loss=loss_fn(outputs,targets)
        #随机梯度下降已经对每张图片的十个得分进行了softmax,loss也会将target转为Onehot形式


        #优化器优化模型
        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))
            writer.add_scalar("train_loss",loss.item(),total_train_step)

    #模型训练完,用测试数据集看模型效果
    #测试步骤开始
    total_test_loss=0
    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets=data
            outputs=fu(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_step, total_test_step)
    total_test_step=total_test_step+1

    torch.save(fu,"fu_{}.pth".format(i))
    print("模型已保存")

writer.close()

3.运行结果

tensorboard可视化

代码运行截图

4.计算正确率

1.argmax方法理解

1.理解

 argmax为0,纵向比大小。按列最大索引输出

argmax为1,横向比大小。按行最大索引输出

2.先比较识别出的类别与目标类别是否相同

 3.根据判断,计算总的正确次数有多少

 2.应用到自己的代码

    #测试步骤开始
    total_test_loss=0
    total_accuracy=0
    with torch.no_grad():
        for data in test_dataloader:
            imgs,targets=data
            outputs=fu(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_step, 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(fu,"fu_{}.pth".format(i))
    print("模型已保存")

writer.close()

十七.完整的模型训练套路(三)

1.理解偏差

许多网络都会进行这两步,这两步并不是必须调用,不是将网络设置为train和eval模式才能进行。

实际上作用是比较小的。

 只对部分模块有作用,如dropout,  BatchNorm

2.回顾

  1. 准备数据集
  2. dataloader加载数据集
  3. 搭建网络模型
  4. 创建网络模型实例
  5. 定义损失函数
  6. 定义优化器
  7. 设置网络训练的参数
  8. 开始训练
  9. 验证模型
  10. 最后保存模型
  11. 可以将训练结果展示

 十八.使用GPU进行训练(一)

1.模型处调用

2.数据处调用

3.损失函数处调用

https://colab.google/免费的服务器

1.新建笔记本

2.使用gpu

阿里云天池 

都可以在没有GPU的情况下

十九.使用GPU进行训练(二)常用方式

1.定义设备

2.在其他位置引用device

模型

损失函数

训练

验证

二十.完整的模型验证套路

1.用模型测试自己的图片

利用已经训练好的模型,给他提供输入,对模型进行测试。类似于前面的测试

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

#上传真实图片到模型
img_path="./imgs/plane.jpg"
image=Image.open(img_path)
print(image)
# image=image.convert('RGB')

#让图片符合模型resize
transform=torchvision.transforms.Compose([torchvision.transforms.Resize((32,32)),
                                          torchvision.transforms.ToTensor()])
image=transform(image)
print(image.shape)
image.cuda()


class Fu(nn.Module):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__()
        self.model=nn.Sequential(
            nn.Conv2d(3,32,5,1,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

#加载模型,可能需要设置用cpue还是gpu 进行映射
model=torch.load('fu_0.pth')
print(model)
model.cuda()
image=image.to('cuda')

#单个图片,网络要输入batchsize
image=torch.reshape(image,(1,3,32,32))

#最好都写,不然有时候影响效果drop
model.eval()
with torch.no_grad():
    output=model(image)

#将概率转化为便于解读的方式
print(output)
print(output.argmax(1))

输出结果

out就是对应各个类别的概率,argmax输出了最大的概率的索引是哪个,这里对应是6,鸟,所以预测错误

2.看结果对应的是哪个类别

在训练集的文件中debug 

3.换图验证

 这里输入一张飞机图片

类别分析正确,对应0-airplane 

二十.学习github上面的开源代码

 1.先搜索Pytorch,选择最多关注的

2.选择一个类别,先读README.md

这里选择了cyclegan

其中包括安装方法,注意事项,数据集下载、模型训练方式,测试方式等。

train.py

 

 运行python文件,将参数传递,以箭头对应形式去传递参数

 

这里required==true ,则需要指定输入。

将代码下载后,可以看哪里有required,有的话,删除后加一个default、​​​​​​​

 比如这里可以这样修改!

至此,土堆深度学习结束,非常感谢土堆老师提供的教学资源,让我们对于深度学习的入门有了一个好的开始。要继续加油,不断完善自己。

  • 10
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值