基于pytorch的深度学习使用

文章目录

  • 引言
  • 一、 基础知识
    • 1. 神经网络的基本骨架----nn.Module的使用
      • 1)pytorch中模型的介绍
      • 2)代码实现
    • 2. 卷积操作
      • 1)pytorch中的卷积
      • 2)卷积的理解
      • 3)代码实现
      • 4)利用数据集进行卷积
    • 3. 池化
      • 1)pytorch中的池化
      • 2)代码实现
    • 4.非线性激活
      • 1)pytorch中的非线性激活
      • 2)代码实现
    • 5.线性层
      • 1)pytorch中的线性层
      • 2)代码实现
    • 5. CIFAR10的网络结构
    • 6. 损失函数和反向传播
      • 1)pytorch中的损失函数
      • 2)代码实现
    • 7.优化器
      • 1)pytorch中的优化器
      • 2)代码实现
  • 二、 网络模型
    • 1. 现有网络的修改及使用
      • 1)现有模型
      • 2)在现有网络上添加
      • 3)在现有网络上修改
    • 2. 模型的保存和读取
      • 1)方法一
      • 2)方法二(推荐)
      • 3)文件大小
  • 三、完整的训练模型套路
    • 1. 分类的基础知识
    • 2. 完成的训练步骤
  • 四、利用GPU训练
    • 1. pytorch方法一
    • 2. pytorch方法二
  • 五、完整的模型验证套路
    • 1. 方式一存储,方式一加载
    • 2.方式二存储,方式二加载
  • 结束语

引言

  我们将通过pytorch提供的模型学习深度学习,在此之前,我们需要配置pytorch环境以及jupyter环境(没有搭建的可以看我上一篇文章),我也是初学者,谨以此记录一下学习的笔记,通过接下来的学习,我可能会不断的补充笔记。

一、 基础知识

1. 神经网络的基本骨架----nn.Module的使用

1)pytorch中模型的介绍

  首先,我们要先进入到pytorch的官网,再点击导航栏中Docs下的PyTorch,如下图所示:
基于pytorch的深度学习使用_第1张图片  然后,在右侧的导航栏中,选中我们要用的nn(Neural network)框架,如下图所示:
基于pytorch的深度学习使用_第2张图片

  • containers          骨架
  • Convolution Layers      卷积层
  • Pooling layers         池化层
  • Padding layers        填充层
  • Non-linear Activations(weighted sum, nonlinearity)  非线性激活
  • Non-linear Activations(other)  非线性激活
  • Normalization Layers      正则化层

  我们先进入到containers这里面,会看到有对其里面内容的基本介绍:
基于pytorch的深度学习使用_第3张图片
  我们在选中其中的第一个属性Module,进入到里面,我们可以看到这个的代码与介绍:
基于pytorch的深度学习使用_第4张图片
  这里看代码就需要对继承等编程知识有一定的基础(在此,继承我就不多讲了,默认有一定的编程能力)。在新的类中,我们重写了一些方法,这里是重写了初始化与前向传播的方法。通过前向传播方法,我们可以看到模型的运行流程是输入->卷积(conv1)->非线性(relu)->卷积(conv2)->非线性(relu)->输出。
  前向传播:就是给模型一个输入,通过一个关系表达式或函数表达式的运算,最终得到一个输出。

2)代码实现

  打开pycharm,创建一个工程,创建一个python文件,输入以下代码:

import torch
from torch import nn

class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self,input):
        output = input + 1
        return output
# 创建一个对象
deepMd = DeepMd()
x = torch.tensor(1.0)
output = deepMd(x)
print(output)

  我们可以得到结果tensor(2.),如下图所示:
在这里插入图片描述
  到此,我们框架就有了大概的了解。

2. 卷积操作

1)pytorch中的卷积

  我们还是在nn(Neural network)框架中点击 Convolution Layers跳转到卷积层中的一些信息。
基于pytorch的深度学习使用_第5张图片
  我们主要是用的是nn.Conv2d这个卷积。因此,我们需要借用torch.nn.functional这里面的nn.Conv2d。其实你不必太过于纠结他们两个之间的关系,你只要明白我们是通过 torch.nn.functional来理解torch.nn。
  在调用torch.nn.functional.conv2d()这个方法的时候,我们需要输入一些参数:
基于pytorch的深度学习使用_第6张图片

2)卷积的理解

  在卷积的时候,我们需要一个输入,一个卷积核,才能得到我们的卷积结果,如下图所示:
基于pytorch的深度学习使用_第7张图片
  当我们进行卷积的时候,我们从输入图像的最左上方开始框出一个与卷积核大小相等的区域,将其与卷积核的对应位置相乘,再相加,我们会得到结果的的一个输出。如下图所示,简单的理解就是一个(5X5)的输入,卷积核是(3X3),那么我们的输出就是(3X3)的结果。(这里我们默认卷积步是1,此时你不需要懂结果为什么是(3X3)。你要理解的是每卷积一次,输出结果对应在(3X3)的位置上)。那么我将从输入图像的最左上方开始框出一个(3X3)的区域与卷积核进行对应位置相乘,再相加,最后的计算结果会放在输出(3X3)结果的“a11”位置。
基于pytorch的深度学习使用_第8张图片
基于pytorch的深度学习使用_第9张图片
  接下来,我们理解一下stride这个参数。当我们设置stride为一个整数时(向上面那样),那么我们就是理解成每卷积完一次后,首先要向有走整数个单位后,进行卷积。当我们移动到右边的边缘时(也就是卷积核的右侧与输入图像的右侧重合),我们需要回到这一行的起始位置,另其向下移动整数个单位进行卷积。依次重复,直到卷积核移动到输入图像的右下角,卷积结束。
  上面是最简单的理解,我们也可以参考pytorch官网的参数理解,可以自由设置左移的距离和下移的距离,即(sH,sW)。不管你设置的stride是多少,都要遵循先左移,再下移,以此循环往复。
  再接下来,我们看一下padding的理解,padding的是指可以理解为在我们的输入图像的外面添加多宽的边距,通过下面这张图可以更好地理解padding。
基于pytorch的深度学习使用_第10张图片

3)代码实现

import torch
import torch.nn.functional as F
input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])
kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])
print(input.shape)
print(kernel.shape)
# 结果为:
# torch.Size([5, 5])
# torch.Size([3, 3])
# 根据pytorch的文档,这并不符合conv2d的卷积输入的格式,我们需要进行修改
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)

  通过运行,我们能得到最终的卷积结果,与我们上面理解里面的运算结果是一致的。
基于pytorch的深度学习使用_第11张图片
  你可以修改stride的值,看看与你自己的计算结果是否一致。

下面代码是padding = 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]])
print(input.shape)
print(kernel.shape)
# 结果为:
# torch.Size([5, 5])
# torch.Size([3, 3])
# 根据pytorch的文档,这并不符合输入的格式,我们需要进行修改
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)

output1 = F.conv2d(input, kernel, stride=2)
print(output1)

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

4)利用数据集进行卷积

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

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

# 搭建简单神经网络
class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__init__()
        self.conv1 = Conv2d(in_channels=3, out_channels=6, kernel_size=3, stride=1, padding=0)
    def forward(self, x):
        x = self.conv1(x)
        return x
deepMd = DeepMd()
writer = SummaryWriter("../logs")

step = 0
for data in dataloader:
    imgs, targets = data
    output = deepMd(imgs)
    # print(output.shape)
    # 输入的大小
    print(imgs.shape)
    print(output.shape)
    # torch.Size([64, 3, 32, 32])
    writer.add_images("input", imgs, step)
    # torch.Size([64, 6, 30, 30])

    output = torch.reshape(output, (-1, 3, 30, 30))
    writer.add_images("output", output, step)

    step = step + 1

  运行完此程序后,我们可以通过pycharm打开我们的终端,进入到我们所在的pytorch环境下,输入如下命令,则会给我们一个地址,我们进入到此地址会看到我们的图片。

tensorboard --logsdir=logs

基于pytorch的深度学习使用_第12张图片

3. 池化

1)pytorch中的池化

  我们还是在nn(Neural network)框架中点击 Padding Layers跳转到池化层中的一些信息。
基于pytorch的深度学习使用_第13张图片
  我们主要是用的是nn.MaxPool2d这个池化。在调用torch.nn.MaxPool2d()这个方法的时候,我们需要输入一些参数:
基于pytorch的深度学习使用_第14张图片

2)代码实现

普通实现:

import torch
from torch import nn
from torch.nn import MaxPool2d

input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]], dtype=torch.float32)
input = torch.reshape(input, (-1, 1, 5, 5))
print(input)

class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__init__()
        # ceil_mode = True表示边缘取最大值
        # ceil_mode = False表示边缘取值使舍去,不取
        # self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)

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

deepMd = DeepMd()
output = deepMd(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("../data", train=False, download=True, transform=torchvision.transforms.ToTensor())

dataloader = DataLoader(dataset, batch_size=64)


class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__init__()
        # ceil_mode = True表示边缘取最大值
        # ceil_mode = False表示边缘取值使舍去,不取
        # self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)
        self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=False)

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


deepMd = DeepMd()

writer = SummaryWriter("../logs_maxpool")
step = 0

for data in dataloader:
    imgs, targets = data
    print(imgs.shape)
    writer.add_images("input", imgs, step)
    output = deepMd(imgs)
    writer.add_images("output", output, step)
    step = step + 1

writer.close()

  运行完此程序后,我们还是通过pycharm打开我们的终端,进入到我们所在的pytorch环境下,输入如下命令,则会给我们一个地址,我们进入到此地址会看到我们的图片。

tensorboard --logsdir=logs_maxpool

4.非线性激活

1)pytorch中的非线性激活

  我们还是在nn(Neural network)框架中点击Non-linear Activations (weighted sum, nonlinearity)跳转到非线性激活中的一些信息。
基于pytorch的深度学习使用_第15张图片

2)代码实现

普通实现:
  我们选用ReLU进行代码实验。

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

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


class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        # inplace=False表示对原来的位置不改变
        self.relu1 = ReLU()

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


deepMd = DeepMd()
output = deepMd(input)
print(output)

利用数据集实现:
  由于ReLU对图像的处理不是很明显,因此我们选用Sigmoid激活函数。

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

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


class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        # inplace=False表示对原来的位置不改变
        self.relu1 = ReLU()
        self.sigmoid1 = Sigmoid()

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


deepMd = DeepMd()
writer = SummaryWriter("../logs_relu")
step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, global_step=step)
    output = deepMd(imgs)
    writer.add_images("output", output, global_step=step)
    step = step + 1

writer.close()

  运行完此程序后,我们还是通过pycharm打开我们的终端,进入到我们所在的pytorch环境下,输入如下命令,则会给我们一个地址,我们进入到此地址会看到我们的图片。

tensorboard --logsdir=logs_relu

5.线性层

1)pytorch中的线性层

  我们还是在nn(Neural network)框架中点击Linear Layers跳转到线性层中的一些信息。
基于pytorch的深度学习使用_第16张图片
  线性层要做的事情其实如下图所示,将一个(5X5)的输入变成一个(1X25),再变成(1X3)。
基于pytorch的深度学习使用_第17张图片

2)代码实现

利用数据集实现:

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

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


class DeepMd(nn.Module):

    def __init__(self):
        super().__init__()
        self.linear1 = Linear(196608, 10)

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


deepMd = DeepMd()

for data in dataloader:
    imgs, targets = data
    print(imgs.shape)  # torch.Size([64, 3, 32, 32])
    # 这一行output = torch.reshape(imgs, (1, 1, 1, -1)) 生成torch.Size([1, 1, 1, 196608])的结果,
    # 其作用个下面这一行的作用是一样的
    output = torch.flatten(imgs)  # torch.Size([196608])
    print(output.shape)
    output = deepMd(output)
    print(output.shape)  # torch.Size([1, 1, 1, 10])

5. CIFAR10的网络结构

  这是一个简单的CIFAR10的网络结构,我们需要通过代码搭建这么一个结构。
基于pytorch的深度学习使用_第18张图片
  其中,我们需要通过pytorch官网中卷积所提供的的公式,计算出stride和padding的数目。其中,dilation默认为1。
基于pytorch的深度学习使用_第19张图片
这是我们按照前面所说的方式一步步写的模型,并没有用到Sequential。

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


class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        self.conv1 = Conv2d(3, 32, 5, stride=1, padding=2)
        self.maxPool1 = MaxPool2d(2)
        self.conv2 = Conv2d(32, 32, 5, stride=1, padding=2)
        self.maxPool2 = MaxPool2d(2)
        self.conv3 = Conv2d(32, 64, 5, stride=1, padding=2)
        self.maxPool3 = MaxPool2d(2)
        self.flatten = Flatten()
        self.linear1 = Linear(1024, 64)
        self.linear2 = Linear(64, 10)
        
    def forward(self, x):
        x = self.conv1(x)
        x = self.maxPool1(x)
        x = self.conv2(x)
        x = self.maxPool2(x)
        x = self.conv3(x)
        x = self.maxPool3(x)
        x = self.flatten(x)
        x = self.linear1(x)
        x = self.linear2(x)
        return x


deepMd = DeepMd()
print(deepMd)

# 检查网络正确性
input = torch.ones(64, 3, 32, 32)
output = deepMd(input)
print(output.shape)

当我们使用Sequential的时候,会发现简化了很多。

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

class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, stride=1, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

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


deepMd = DeepMd()
print(deepMd)

# 检查网络正确性
input = torch.ones((64, 3, 32, 32))
output = deepMd(input)
print(output.shape)

6. 损失函数和反向传播

1)pytorch中的损失函数

  我们还是在nn(Neural network)框架中点击Loss Functions跳转到损失函数中的一些信息。
基于pytorch的深度学习使用_第20张图片
  损失函数的作用有两个,一个就是计算实际输出和目标之间的差距,另一个是为我们更新输出提供一定的依据(反向传播),这个依据就是梯度

2)代码实现

这是几个不同的损失函数计算结果的代码。

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

# dtype=torch.float32表示浮点数
inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)

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

loss = L1Loss(reduction='sum')
result = loss(inputs, targets)
loss_mse = MSELoss()
result_mse = loss_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)

这里我们通过搭建损失函数网络。

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("../data", train=False, transform=torchvision.transforms.ToTensor(), download=True)
dataloader = DataLoader(dataset, batch_size=1)


class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, stride=1, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

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


loss = nn.CrossEntropyLoss()
deepMd = DeepMd()
for data in dataloader:
    imgs, targets = data
    outputs = deepMd(imgs)
    result_loss = loss(outputs, targets)
    # result_loss.backward()

  其实,上面代码就是一个有自己搭建的网络以及自己设定的损失函数,最后一行代码是经过损失函数后要再进行反向传播,我们可以通过断点调试的方法,可以看到当我们没有反向传播的时候,梯度grad是没有的,一旦我们经过反向传播,我们会获得梯度的一些值。如下图所示:
查找路径是自己的网络deepMd–>module1–>Protected Attributes–>_modules–>‘0’–>weight–>grad

没有经过反向传播的grad
基于pytorch的深度学习使用_第21张图片

经过反向传播后的grad
基于pytorch的深度学习使用_第22张图片

7.优化器

1)pytorch中的优化器

  我们的优化器是在torch.optim当中。
基于pytorch的深度学习使用_第23张图片

2)代码实现

import torch.optim
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("../data", train=False, transform=torchvision.transforms.ToTensor(),
                                       download=True)
dataloader = DataLoader(dataset, batch_size=1)


class DeepMd(nn.Module):
    def __init__(self):
        super().__init__()
        self.module1 = Sequential(
            Conv2d(3, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, stride=1, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, stride=1, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(1024, 64),
            Linear(64, 10)
        )

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


# 损失函数
loss = nn.CrossEntropyLoss()
deepMd = DeepMd()
# 优化器
optim = torch.optim.SGD(deepMd.parameters(), lr=0.01)
for epoc in range(20):
    running_loss = 0.0
    # 这是对这个网络进行一层的学习
    for data in dataloader:
        imgs, targets = data
        outputs = deepMd(imgs)
        result_loss = loss(outputs, targets)
        # 将梯度清零
        optim.zero_grad()
        # 反向传播
        result_loss.backward()
        # 对参数调优
        optim.step()
        running_loss = running_loss + result_loss
    print(running_loss)

这段代码其实就算一个相对完整的代码,有前向传播,后向传播,参数优化等。

二、 网络模型

1. 现有网络的修改及使用

1)现有模型

  我们通过模型vgg16进行修改。

import torchvision.datasets

vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)

  我们可以看到输出:
基于pytorch的深度学习使用_第24张图片基于pytorch的深度学习使用_第25张图片

2)在现有网络上添加

  最后,经过线性层的输出是1000个分类,如果我们想要对其进行修改,让其最后的输出是10。(我们此处是对vgg_true进行的修改。)

from torch import nn
import torchvision.datasets

vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)

# 因为vgg16的输出是1000,我们需要添加一个线性层使其输出为10
# add_linear是我们添加的名字,nn.Linear是我们添加的线性层
vgg16_true.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)

基于pytorch的深度学习使用_第26张图片基于pytorch的深度学习使用_第27张图片

  这里可以看出,我们添加的线性层是在整个vgg16里面添加的,如果我们想要添加到Sequential里面的话,需要进行如下操作:

from torch import nn
import torchvision.datasets

vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)

# 因为vgg16的输出是1000,我们需要添加一个线性层使其输出为10
# add_linear是我们添加的名字,nn.Linear是我们添加的线性层
vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)

基于pytorch的深度学习使用_第28张图片基于pytorch的深度学习使用_第29张图片

3)在现有网络上修改

import torchvision.datasets

vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_false)

基于pytorch的深度学习使用_第30张图片基于pytorch的深度学习使用_第31张图片
  我们想要将其classifier中的第六层的out_features修改成10,则代码如下:

from torch import nn
import torchvision.datasets

vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_false)

# 要注意这个classifier[?]里面的数要与模型中的数对应
vgg16_false.classifier[6] = nn.Linear(4096, 10)
print(vgg16_false)

基于pytorch的深度学习使用_第32张图片基于pytorch的深度学习使用_第33张图片

2. 模型的保存和读取

1)方法一

保存

  这种方式不仅将模型保存下来,还将模型参数进行了保存。

import torch
import torchvision

# pretrained=False表示我们没有对模型进行训练,而是使用了他原来训练的一些参数
vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式1
# 这种方式不仅将模型保存下来,还将模型参数进行了保存
torch.save(vgg16, "vgg16_method1.pth")

基于pytorch的深度学习使用_第34张图片
加载

import torch
import torchvision.models

# 用保存的方式一的形式加载模型
model = torch.load("vgg16_method1.pth")
print(model)

2)方法二(推荐)

保存

  这种方式保存的不再是模型的结构,而是模型的参数。

import torch
import torchvision

# pretrained=False表示我们没有对模型进行训练,而是使用了他原来训练的一些参数
vgg16 = torchvision.models.vgg16(pretrained=False)

# 保存方式2(官方推荐)
# 这种方式保存的不再是模型的结构,而是模型的参数
# state_dict()是将其保存成一个字典的python形式
torch.save(vgg16.state_dict(), "vgg16_method2.pth")

基于pytorch的深度学习使用_第35张图片
加载

import torch
import torchvision.models

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

  你会发现打印出的是一个字典形式。

恢复
  当我们在这种情况下存储的是字典的形式,我们要恢复成网络模型,需要以下操作:

import torch
import torchvision.models

# model存储的是字典形式,需要load_state_dict加载字典形式的数据
model = torch.load("vgg16_method2.pth")
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(model)

print(vgg16)

3)文件大小

  我们打开该目录下的终端命令窗口,输入ls或者dir都可以(如果输入后不成功,多敲几下回车,再输入命令试试,我也不知道什么原因),查看所有问价的大小:

ls

基于pytorch的深度学习使用_第36张图片
  我们可以看到第二种方法的存储方式比第一种的小,此处表现得不是很明显,当我们模型特别的大时,这能帮助我们节省存储空间。

三、完整的训练模型套路

1. 分类的基础知识

  在讲完整的训练模型之前,我们先要了解一下针对分类的最后处理。
基于pytorch的深度学习使用_第37张图片
  我们以上面这个图片为基础,我们在每次测试的时候,经过训练后的模型得到的outputs输出都要取得分类的结果,将其与我们的目标结果进行比较,得到正确的个数。例如:上图有两个图片,经过训练模型后,我们达到输出的概率。第一张图片的结果是[0.1, 0.2],即这个模型认为他是第一类的概率是0.1,第二类的概率是0.2,所以第二类的概率相对而言比较大,因此,我们就可以认为这张图片是第二类,那么我们怎么得到他是第二类呢?,这时候我们就需要经过argmax()函数后会得到最大概率的下标,也就是得到结果1。同理,第二张图片的结果也是1。
  接下来,我们需要将这个预测的结果与实际的目标结果进行比较,是否正确。例如图中,我们目标结果是第一张图片分类是0,第二张图片分类是1,也就是[0, 1]。但是预测的是[1, 1],所以经过preds == inputs target 这个判断后,会返回[False, True]。在经过sum()函数后,会统计正确的个数。

import torch
outputs = torch.tensor([[0.1, 0.2],
                       [0.3, 0.4]])
print(outputs.argmax(1))
preds = outputs.argmax(1)
targets = torch.tensor([0, 1])
print((preds == targets).sum())

2. 完成的训练步骤

  我们完整的训练模型时,需要有非常好的规范,因此,我们需要建立两个文件,一个是 model.py 文件用来存储网络模型,另一个是 train.py 文件用来做一些其他的设置。我们要保证将这两个python文件放在同一个根目录下。
model.py

import torch
from torch import nn


# 搭建神经网络
class DeepMd(nn.Module):
    def __init__(self):
        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(1024, 64),
            nn.Linear(64, 10)
        )

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


# 测试我们的网络模型
if __name__ == '__main__':
    deepMd = DeepMd()
    input = torch.ones((64, 3, 32, 32))
    output = deepMd(input)
    print(output.shape)

train.py

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

from model import *


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

# length 长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))

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

# 创建网络模型
deepMd = DeepMd()

# 损失函数
loss_fn = nn.CrossEntropyLoss()

# 优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(deepMd.parameters(), lr=learning_rate)

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

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

for i in range(epoch):
    print("--------第{} 轮训练开始---------".format(i + 1))

    # 训练步骤开始
    deepMd.train()  # 可有可没有
    for data in train_dataloader:
        imgs, targets = data
        outputs = deepMd(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step = total_train_step + 1
        # .item()是将tensor数据类型变成一个真实的数字
        if total_train_step % 100 == 0:
            print("训练次数:{},loss:{}".format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    deepMd.eval()  # 可有可没有
    total_test_loss = 0
    total_accuracy = 0
    # 让模型的梯度消除
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            outputs = deepMd(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            # 当我们进行分类问题的时候,我们就需要下面这一行代码,如果是目标检测或者自然语言处理的时候,就暂时不需要。
            # argmax(1)指的是横向对比大小,返回最大值的下标
            # argmax(0)指的是纵向对比大小,返回最大值的下标
            # == 值的是输出概率结果与目标的结果是否一致,是返回True,否则返回False
            # sum()是用来计算统计True的个数
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print("整体测试集上的Loss:{}".format(total_test_loss))
    print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step = total_test_step + 1

    torch.save(deepMd, "deepMd_{}.pth".format(i + 1))
    # torch.save(deepMd.state_dict(), "deepMd_{}.pth".format(i+1))
    print("模型已保存")

writer.close()

  这段代码可能会运行出错,查看一下是不是存储模型的时候报的错,如果是,那么就换一种存储方式。(我第一遍运行的时候没有问题,但是第三四次运行时就报“attribute lookup DeepMd on _main _failed”错误)

四、利用GPU训练

1. pytorch方法一

  当我们使用GPU进行训练和测试的时候,我们需要在原来的代码上对网络模型、数据(输入、标注)以及损失函数进行修改,判断他们是否有GPU。

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
# from model import *


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

# length 长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))

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


# 创建网络模型
class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__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(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x
deepMd = DeepMd()
if torch.cuda.is_available():
    deepMd = deepMd.cuda()

# 损失函数
loss_fn = nn.CrossEntropyLoss()
if torch.cuda.is_available():
    loss_fn = loss_fn.cuda()

# 优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(deepMd.parameters(), lr=learning_rate)

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

# 添加tensorboard
writer = SummaryWriter("../logs_train")
start_time = time.time()
for i in range(epoch):
    print("--------第{} 轮训练开始---------".format(i + 1))

    # 训练步骤开始
    deepMd.train()  # 可有可没有
    for data in train_dataloader:
        imgs, targets = data
        if torch.cuda.is_available():
            imgs = imgs.cuda()
            targets = targets.cuda()
        outputs = deepMd(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step = total_train_step + 1
        # .item()是将tensor数据类型变成一个真实的数字
        if total_train_step % 100 == 0:
            end_time = time.time()
            print(end_time - start_time)
            print("训练次数:{},loss:{}".format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    deepMd.eval()  # 可有可没有
    total_test_loss = 0
    total_accuracy = 0
    # 让模型的梯度消除
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            if torch.cuda.is_available():
            	imgs = imgs.cuda()
                targets = targets.cuda()
            outputs = deepMd(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            # 当我们进行分类问题的时候,我们就需要下面这一行代码,如果是目标检测或者自然语言处理的时候,就暂时不需要。
            # argmax(1)指的是横向对比大小,返回最大值的下标
            # argmax(0)指的是纵向对比大小,返回最大值的下标
            # == 值的是输出概率结果与目标的结果是否一致,是返回True,否则返回False
            # sum()是用来计算统计True的个数
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print("整体测试集上的Loss:{}".format(total_test_loss))
    print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step = total_test_step + 1

    # torch.save(DeepMd(), "deepMd_{}.pth".format(i+1))
    torch.save(deepMd.state_dict(), "deepMd_{}.pth".format(i+1))
    print("模型已保存")

writer.close()

  如果你电脑上没有GPU,你可以访问谷歌的Google Colab,它给你提供的GPU进行试验,一周大概可以免费试用30个小时。

2. pytorch方法二

  pytorch还给我们提供了第二种方法来利用GPU训练,主要就是通过“.to(device)”这个函数对网络模型、数据(输入,标注)以及损失函数进行修改。

import torch
import torchvision
from torch import nn
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter
import time
# from model import *

# 定义一个设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

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

# length 长度
train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度为:{}".format(train_data_size))
print("测试数据集的长度为:{}".format(test_data_size))

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


# 创建网络模型
class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__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(1024, 64),
            nn.Linear(64, 10)
        )

    def forward(self, x):
        x = self.model(x)
        return x
deepMd = DeepMd()
deepMd = deepMd.to(device)

# 损失函数
loss_fn = nn.CrossEntropyLoss()
loss_fn = loss_fn.to(device)

# 优化器
learning_rate = 0.01
optimizer = torch.optim.SGD(deepMd.parameters(), lr=learning_rate)

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

# 添加tensorboard
writer = SummaryWriter("../logs_train")
start_time = time.time()
for i in range(epoch):
    print("--------第{} 轮训练开始---------".format(i + 1))

    # 训练步骤开始
    deepMd.train()  # 可有可没有
    for data in train_dataloader:
        imgs, targets = data
        imgs = imgs.to(device)
        targets = targets.to(device)
        outputs = deepMd(imgs)
        loss = loss_fn(outputs, targets)

        # 优化器优化模型
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()

        total_train_step = total_train_step + 1
        # .item()是将tensor数据类型变成一个真实的数字
        if total_train_step % 100 == 0:
            end_time = time.time()
            print(end_time - start_time)
            print("训练次数:{},loss:{}".format(total_train_step, loss.item()))
            writer.add_scalar("train_loss", loss.item(), total_train_step)

    # 测试步骤开始
    deepMd.eval()  # 可有可没有
    total_test_loss = 0
    total_accuracy = 0
    # 让模型的梯度消除
    with torch.no_grad():
        for data in test_dataloader:
            imgs, targets = data
            imgs = imgs.to(device)
            targets = targets.to(device)
            outputs = deepMd(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss = total_test_loss + loss.item()
            # 当我们进行分类问题的时候,我们就需要下面这一行代码,如果是目标检测或者自然语言处理的时候,就暂时不需要。
            # argmax(1)指的是横向对比大小,返回最大值的下标
            # argmax(0)指的是纵向对比大小,返回最大值的下标
            # == 值的是输出概率结果与目标的结果是否一致,是返回True,否则返回False
            # sum()是用来计算统计True的个数
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy = total_accuracy + accuracy
    print("整体测试集上的Loss:{}".format(total_test_loss))
    print("整体测试集上的正确率:{}".format(total_accuracy/test_data_size))
    writer.add_scalar("test_loss", total_test_loss, total_test_step)
    writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
    total_test_step = total_test_step + 1

    # torch.save(DeepMd(), "deepMd_{}.pth".format(i+1))
    torch.save(deepMd.state_dict(), "deepMd_{}.pth".format(i+1))
    print("模型已保存")

writer.close()

五、完整的模型验证套路

  前面我们讲个两种存储模型的方式,那么我们就会有两种加载的方式。我们采用一狗的照片进行测试。

1. 方式一存储,方式一加载

  不知道什么原因,我在计算机中运行存储方式一的代码总是报错(前面成功过一两次),因此我在Google Colab中运行。

import torch
import torchvision
from PIL import Image
from torch import nn


image_path = "../imgs/dog.png"
image = Image.open(image_path)
print(image)
image = image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)), torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape)


# 搭建神经网络
class DeepMd(nn.Module):
    def __init__(self):
        super(DeepMd, self).__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(1024, 64),
            nn.Linear(64, 10)
        )

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


# 第一种加载方式
deepMd = DeepMd()
model = torch.load("deepMd_9.pth")
print(model)
image = torch.reshape(image, (1, 3, 32, 32))
model.eval()
with torch.no_grad():
    output = model(image)
print(output)

print(output.argmax(1))

  原来的分类:
基于pytorch的深度学习使用_第38张图片
  运行的最终结果可以得到:
在这里插入图片描述
  运行的结果是第5类,所以对应的分类是dog,这个结果是正确的。

2.方式二存储,方式二加载

import torch
import torchvision
from PIL import Image
from torch import nn

image_path = "../imgs/dog.png"
image = Image.open(image_path)
print(image)
image = image.convert('RGB')
transform = torchvision.transforms.Compose([torchvision.transforms.Resize((32, 32)), torchvision.transforms.ToTensor()])
image = transform(image)
print(image.shape)

# 搭建神经网络
class DeepMd(nn.Module):
    def __init__(self):
        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(1024, 64),
            nn.Linear(64, 10)
        )

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

# 如果在GPU训练的模型,想在CPU上测试,那么需要加入下面一行代码
# model = torch.load("deepMd_10.pth", map_location=torch.device('cpu'))
model = torch.load("deepMd_10.pth")
deepMd = DeepMd()
deepMd.load_state_dict(model)
print(model)
image = torch.reshape(image, (1, 3, 32, 32))
print(image.shape)
deepMd.eval()
with torch.no_grad():
    output = deepMd(image)
print(output)

print(output.argmax(1))

  原来的分类:
基于pytorch的深度学习使用_第39张图片
  运行的最终结果可以得到:
在这里插入图片描述
  运行的结果是第5类,所以对应的分类是dog,这个结果是正确的,与第一种方式对应了。

  如果你的结果验证的不对,可能与你训练的次数和学习速率有关,你可以更改这两个参数从新训练,再用训练的模型验证你的结果是否正确。

结束语

  以上我是结合着视频学习的,如果你有时间,你可以结合PyTorch深度学习的快速入门视频一起学习。

你可能感兴趣的:(深度学习,pytorch,python)