浅学 Pytorch

(一)Dataset

Dataset 是一个抽象类,用于表示数据集。它封装了数据的加载和预处理逻辑,使得数据的读取和处理更加灵活和易于管理。在PyTorch中,torch.utils.data.Dataset 是一个基类,用户可以继承并实现自己的数据集。

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

class CustomDataset(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 __len__(self):
        return len(self.img_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


root_dir = 's-data/train'
ants_label_dir = 'ants_img'
bees_label_dir = 'bees_img'
ants_dataset = CustomDataset(root_dir, ants_label_dir)
bees_dataset = CustomDataset(root_dir, bees_label_dir)

img, label = bees_dataset[0]
img.show()

(二)TensorBoard

TensorBoard 是一个强大的可视化工具,它主要用于可视化和分析神经网络的训练过程,包括损失和准确率的变化、模型结构、图像数据、激活值等。

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

writer = SummaryWriter('logs')
img_path = 's-data/train/bees_img/16838648_415acd9e3f.jpg'
img_PIL = Image.open(img_path)
img_array = np.array(img_PIL)
# global_step 表示写入的步数(类似索引)
writer.add_image('test', img_array, 2, dataformats='HWC')

for i in range(100):
    writer.add_scalar('y=2x', 3 * i, i)

writer.close()

运行:

tensorboard --logdir=logs  --port=6007

(三)常见的 Transforms

1. ToTensor

它将形状为 (H, W, C) 且像素值在 [0, 255] 范围的 PIL 图像或 NumPy 数组转换为形状为 (C, H, W) 且像素值在 [0.0, 1.0] 范围的PyTorch张量。

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

writer = SummaryWriter('logs')
img = Image.open('data/train/bees/17209602_fe5a5a746f.jpg')

trans_totensor = transforms.ToTensor()
img_tensor = trans_totensor(img)
writer.add_image('ToTensor', img_tensor)

writer.close()

在这里插入图片描述

2. Normalize

标准化的目的是使数据的各个特征具有相似的尺度,从而提高模型的训练效率和稳定性。用于标准化张量图像(tensor image)的每个通道。该变换接受两个参数:均值(mean)和标准差(std),并使用以下公式进行标准化:
output[channel] = (input[channel] - mean[channel]) / std[channel]

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

writer = SummaryWriter('logs')
img = Image.open('data/train/bees/17209602_fe5a5a746f.jpg')

trans_norm = transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
img_norm = trans_norm(img_tensor)
writer.add_image('Normalize', img_norm, 1)

writer.close()

在这里插入图片描述

3. Resize

用于将输入的PIL图像调整到模型所需的固定尺寸。
接受目标尺寸作为参数,可以是一个整数或一个二元元组:

  • 二元元组:如果提供一个二元元组,例如 (height, width),Resize 将图像调整为指定的高度和宽度。
  • 整数:如果提供一个整数,Resize 将保持图像的长宽比不变,并将图像的较短边调整为该整数长度,较长边则根据原始比例自动调整。
from PIL import Image
from torchvision import transforms
from torch.utils.tensorboard import SummaryWriter

writer = SummaryWriter('logs')
img = Image.open('data/train/bees/17209602_fe5a5a746f.jpg')

trans_resize = transforms.Resize((300, 300))
trans_resize2 = transforms.Resize(500)
img_resize = trans_resize(img)
img_resize2 = trans_resize2(img)
writer.add_image('Resize', trans_totensor(img_resize), 1)
writer.add_image('Resize', trans_totensor(img_resize2), 2)

writer.close()

4. RandomCrop、CenterCrop

RandomCrop 可以从输入图像中随机裁剪出一个指定大小的区域。
CenterCrop 可以 从图像中心裁剪出指定大小的区域。

trans_random = transforms.RandomCrop(200)
img_random = trans_random(img)
writer.add_image('RandomCrop', trans_totensor(img_random), 1)

trans_center = transforms.CenterCrop(200)
img_center = trans_center(img)
writer.add_image('CenterCrop', trans_totensor(img_center), 1)

5. ToPILImage

用于将 tensor 张量或 NumPy 数组转换为 PIL 图像。

trans_pil = transforms.ToPILImage()
img_pil = trans_pil(img_tensor)
print(type(img_pil))  # <class 'PIL.Image.Image'>

6. Compose

它将一系列图像变换按顺序应用于输入图像,形成一个统一的变换流水线。

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

writer = SummaryWriter('logs')
img = Image.open('data/train/bees/17209602_fe5a5a746f.jpg')

transform = transforms.Compose([
    transforms.Resize((300, 300)),
    transforms.CenterCrop(200), 
    transforms.ToTensor(),
    transforms.Normalize([0.5, 0.5, 0.5], [0.5, 0.5, 0.5])
])
img_compose = transform(img)
writer.add_image('Compose', img_compose, 2)

writer.close()

7. ColorJitter

随机更改图像的亮度、对比度、饱和度和色调。

trans_color = transforms.ColorJitter(brightness=1, contrast=1, saturation=1, hue=0.5)
img_color = trans_color(img)
writer.add_image('ColorJitter', trans_totensor(img_color), 1)

8. Grayscale

将图像转换为灰度。默认是1

trans_gray = transforms.Grayscale(3)
img_gray = trans_gray(img)
writer.add_image('Grayscale', trans_totensor(img_gray), 1)

(四)DataLoader

用于加载和批量处理数据集。它提供了常见的数据操作功能,如批量加载、数据洗牌、并行数据加载等,从而简化了数据预处理和模型训练流程。
dataloader = DataLoader(dataset, batch_size=64, shuffle=True, num_workers=4)

  • batch_size:每个批次的数据量大小。比如batch_size=64 表示每次从数据集中取 64 个样本。
  • shuffle:在每个 epoch 结束后,是否对数据进行洗牌。shuffle=True 可以打乱数据的顺序,有助于提高模型的泛化能力。
  • num_workers:用于数据加载的子进程数。比如 num_workers=4 表示使用 4 个子进程加载数据。增加 num_workers 数量可以加速数据加载过程,尤其是在数据预处理复杂或数据集较大时。
  • drop_last:如果数据集大小不能被批量大小整除,drop_last=True 则会丢弃最后一个不完整的批次。
import torchvision
from torch.utils.data import DataLoader
from torch.utils.tensorboard import SummaryWriter

test_data = torchvision.datasets.CIFAR10(root='./CIFA10', train=False, download=True,
                                         transform=torchvision.transforms.ToTensor())

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

writer = SummaryWriter('CIFA-logs')

step = 0
for data in test_loader:
    imgs, targets = data
    writer.add_images('testdata_loader', imgs, step)
    step = step + 1

writer.close()

在这里插入图片描述

(五)神经网络

1. 基本骨架 — nn.Module的使用

在 PyTorch 中,nn.Module 是构建神经网络的基础类。所有的神经网络模块都应继承自 nn.Module,并实现 forward 方法。在该类中,定义了网络的层以及前向传播的方式。

  • 继承 nn.Module:定义一个类来表示你的神经网络,并使它继承 nn.Module。
  • 定义网络层:在 __init__ 方法中定义网络的各个层,并使用 nn.Module 的子模块(如 nn.Linear,nn.Conv2d 等)。
  • 实现前向传播:在 forward 方法中定义输入数据如何通过网络层计算输出。这是网络前向传播的逻辑。
import torch
from torch import nn


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

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


x = torch.tensor(1.0)
model = Module()
output = model(x)
print(output)  # tensor(2.)

2. 卷积操作 — nn.functional.conv

torch.nn.functional.conv 是 PyTorch 中用于直接调用卷积操作的函数。它有多个变体,如 conv1d、conv2d、conv3d,分别对应一维、二维和三维卷积。与 nn.Conv2d 等模块化接口不同,nn.functional.conv 需要手动指定所有的参数,包括权重和偏置,因此更灵活,但也需要更多手动管理。

  • input:输入张量,形状为(minibatch, in_channels, iH, iW),其中minibatch是批量大小,in_channels是输入通道数,iHiW是输入的高度和宽度。
  • weight:卷积核的权重张量,形状为(out_channels, in_channels/groups, kH, kW),其中out_channels是输出通道数,in_channels/groups是每组的输入通道数,kHkW是卷积核的高度和宽度。
  • bias:偏置项,形状为(out_channels)
  • stride:卷积操作的步幅,默认值为1。可以是一个整数或一个元组(sH, sW)
  • padding:输入的填充大小,默认值为0。可以是一个整数或一个元组(padH, padW),用于控制输出的空间维度。
  • dilation:卷积核元素之间的间距,默认值为1。可以是一个整数或一个元组(dH, dW)
  • groups:控制输入和输出的连接方式,默认值为1。groups=1表示标准卷积,groups=in_channels表示深度卷积,每个输入通道有一个单独的滤波器。

`在这里插入图片描述

import torch
import torch.nn.functional as F

# 输入 5x5 图像
input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]])

# 卷积核
kernel = torch.tensor([[1, 2, 1],
                       [0, 1, 0],
                       [2, 1, 0]])

# input – input tensor of shape(batch_size, in_channels, 𝑖𝐻, 𝑖𝑊)
# 转成四维张量
input = torch.reshape(input, (1, 1, 5, 5))
kernel = torch.reshape(kernel, (1, 1, 3, 3))

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

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

在这里插入图片描述

3. 卷积层 — nn.Conv2d

在 PyTorch 中,卷积层可以通过 torch.nn.Conv 模块实现。根据不同的卷积类型,PyTorch 提供了多个类,包括 nn.Conv1d、nn.Conv2d 和nn.Conv3d,分别用于一维、二维和三维卷积操作。最常用的是 nn.Conv2d,用于处理二维图像数据。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

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

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

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

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


cnn = CNN()

writer = tensorboard.SummaryWriter('CIFA-logs')
step = 0
for data in dataloader:
    imgs, targets = data
    output = cnn(imgs)
    writer.add_images('input', imgs, step)
    writer.add_images('output', output, step)
    step += 1
    
writer.close()

在这里插入图片描述

4. 池化层 — 最大池化 nn.MaxPool2d 的使用

nn.MaxPool2d 是 PyTorch 中的一个池化层,用于在卷积神经网络(CNN)中执行二维的最大池化操作。最大池化的目的是通过取局部窗口的最大值来减小特征图的尺寸,从而减少计算量、参数数量和过拟合的风险,同时保留重要的特征信息。

  • kernel_size:窗口的大小,可以是单个整数(表示高度和宽度相同)或元组(分别指定高度和宽度)。
  • stride:步幅,指定窗口移动的步长。可以是单个整数或元组。默认情况下等于 kernel_size。
  • padding:填充,指定在输入张量的边缘填充的大小。默认值为 0。
  • dilaton:控制窗口中元素的间距。默认值为 1。
  • ceil_mode:为 True 时数据不够就取,为 False 数据不够就丢弃。

在这里插入图片描述

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, 5, 5))

class MaxPool(nn.Module):
    def __init__(self):
        super(MaxPool, self).__init__()
        self.maxpool1 = MaxPool2d(3, ceil_mode=True)
        self.maxpool2 = MaxPool2d(3, ceil_mode=False)

    def forward(self, x):
        output1 = self.maxpool1(x)
        output2 = self.maxpool2(x)
        return output1, output2


model = MaxPool()
output1, output2 = model(input)
print(output1)
print(output2)

在这里插入图片描述

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

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

class MaxPool(nn.Module):
    def __init__(self):
        super(MaxPool, self).__init__()
        self.maxpool = MaxPool2d(3, ceil_mode=True)

    def forward(self, x):
        output = self.maxpool(x)
        return output


model = MaxPool()
writer = tensorboard.SummaryWriter('CIFA-logs')
step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images('input', imgs, step)
    output = model(imgs)
    writer.add_images('maxpool_output', output, step)
    step += 1

writer.close()

在这里插入图片描述

5. 非线性激活函数

用于在神经网络中引入非线性特性。它们的作用是在输入数据经过线性变换后,施加一个非线性的映射,从而使得神经网络能够学习到复杂的模式和特征。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

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

input = torch.tensor([[1, -0.5],
                      [-1, 3]])

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

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.relu = ReLU()
        self.sigmoid = Sigmoid()

    def forward(self, x):
        output1 = self.relu(x)
        output2 = self.sigmoid(x)
        return output1, output2


model = Model()
output1, output2 = model(input)
print(output1)
print(output2)

writer = tensorboard.SummaryWriter('CIFA-logs')
step = 0
for data in dataloader:
    imgs, targets = data
    writer.add_images('非线性-input', imgs, step)
    ouput1 = model(imgs)[0]
    writer.add_images('relu', ouput1, step)
    output2 = model(imgs)[1]
    writer.add_images('sigmoid', output2, step)
    step += 1

writer.close()

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6. 线性层 — nn.linear

nn.Linear 是 PyTorch 中用于实现线性变换的层,通常用于全连接神经网络(也称为前馈神经网络)的隐藏层和输出层。它执行的操作是对输入数据进行线性变换,即输入向量乘以权重矩阵并加上偏置项。

import torch
from torch import nn
from torch.nn import Linear

class LinearLayer(nn.Module):
    def __init__(self):
        super(LinearLayer, self).__init__()
        self.linear = Linear(4, 3, bias=True)
        # 随机初始化
        print('weights:', self.linear.weight)
        print('Bias:', self.linear.bias)

    def forward(self, x):
        return self.linear(x)


model = LinearLayer()
input = torch.tensor([[1.0, 2.0, 3.0, 4.0]])
output = model(input)
print(output)

在这里插入图片描述

7. 搭建小实战和Sequential的使用

在这里插入图片描述

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


class CIFAR(nn.Module):
    def __init__(self):
        super(CIFAR, self).__init__()
        # self.conv1 = Conv2d(3, 32, 5, padding=2)
        # self.maxpool1 = MaxPool2d(2)
        # self.conv2 = Conv2d(32, 32, 5, padding=2)
        # self.maxpool2 = MaxPool2d(2)
        # self.conv3 = Conv2d(32, 64, 5, padding=2)
        # self.maxpool3 = MaxPool2d(2)
        # # 它的作用是将多维的输入数据展平成一维。通常在卷积神经网络(CNN)中使用,用于将卷积层或池化层的输出转换为全连接层的输入格式。
        # self.flatten = Flatten()
        # # 全连接层
        # self.linear1 = Linear(64 * 4 * 4, 64)
        # self.linear2 = Linear(64, 10)
        # 第二种写法:
        self.model = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64 * 4 * 4, 64),
            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)
        x = self.model(x)
        return x


cifar = CIFAR()
print(cifar)

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

writer = tensorboard.SummaryWriter("CIFA-logs")
writer.add_graph(cifar, input)
writer.close()

在这里插入图片描述

在这里插入图片描述

8. 损失函数与反向传播

损失函数是一个函数,用于衡量模型的预测输出与实际目标之间的差距。它的值越小,表示模型的预测越接近真实值。损失函数的选择取决于具体的任务类型,如回归、分类等。

L1Loss(也称为 绝对值损失 或 平均绝对误差,MAE):它用于测量预测值和真实值之间的差异,通过计算预测值与真实值之差的绝对值来量化这种差异。
在这里插入图片描述
MSELoss(Mean Squared Error Loss,均方误差损失):特别是在回归任务中。它通过计算预测值和真实值之间差异的平方来量化预测误差,并取所有样本误差的平均值。
在这里插入图片描述
CrossEntropyLoss(交叉熵损失): 是深度学习中常用于分类任务的一种损失函数。它结合了 softmax 激活函数和负对数似然损失,用于衡量模型的预测概率分布与真实标签分布之间的差异。
在这里插入图片描述

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

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

# L1Loss
loss_fn1 = L1Loss()  # 默认是mean,求均值损失
res1 = loss_fn1(inputs, targets)
print(res1)  # tensor(0.6667)

loss_fn2 = L1Loss(reduction='sum')
res2 = loss_fn2(inputs, targets)
print(res2)  # tensor(2.)

# MSELoss
loss_fn3 = MSELoss()
res3 = loss_fn3(inputs, targets)
print(res3)  # tensor(1.3333)

loss_fn4 = MSELoss(reduction='sum')
res4 = loss_fn4(inputs, targets)
print(res4)  # tensor(4.)

# CrossEntropyLoss
loss_fn5 = CrossEntropyLoss()
# 未经过 softmax 的原始分数(logits)
# CrossEntropyLoss 自动将 y_pred 经过 softmax 后计算负对数似然损失,因此不需要手动应用 softmax 函数
y_pred = torch.tensor([[2.0, 1.0, 0.1]])
y_true = torch.tensor([0])
res5 = loss_fn5(y_pred, y_true)
print(res5)  # tensor(0.4170)

反向传播(Backpropagation)是神经网络训练过程中用于计算和更新模型参数的算法。它基于梯度下降的思想,通过计算损失函数关于模型参数的梯度来更新参数,使损失函数的值最小化。
在这里插入图片描述

(六)优化器

torch.optim 是 PyTorch 中用于实现各种优化算法的模块。优化器的作用是更新模型参数,以最小化损失函数。它们基于梯度下降法,但每种优化器有不同的更新策略。

1. SGD (随机梯度下降)

基本的优化算法,逐步更新参数。支持动量项来加速收敛。

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

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

class CIFAR(nn.Module):
    def __init__(self):
        super(CIFAR, self).__init__()
        self.model = Sequential(
            Conv2d(3, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 32, 5, padding=2),
            MaxPool2d(2),
            Conv2d(32, 64, 5, padding=2),
            MaxPool2d(2),
            Flatten(),
            Linear(64 * 4 * 4, 64),
            Linear(64, 10)
        )

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


loss = CrossEntropyLoss()
cifar = CIFAR()
optimizer = torch.optim.SGD(cifar.parameters(), lr=0.001)
for epoch in range(20):
    running_loss = 0
    for data in dataloader:
        imgs, targets = data
        outputs = cifar(imgs)
        res = loss(outputs, targets)
        optimizer.zero_grad()
        res.backward()
        optimizer.step()
        running_loss += res

    print(running_loss)

在这里插入图片描述

(七)现有网络模型的使用及修改

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

vgg16_false = vgg16(weights=None)
vgg16_true = vgg16(weights=VGG16_Weights.DEFAULT)


train_data = torchvision.datasets.CIFAR10('CIFA10', train=True, download=True,
                                          transform=torchvision.transforms.ToTensor())

# 添加一个线性层
vgg16_true.classifier.add_module('7', nn.Linear(1000, 10))
print(vgg16_true)
# 修改一个线性层
vgg16_true.classifier[6] = nn.Linear(4096, 10)
print(vgg16_true)

(八)模型的保存与读取

1. 保存整个模型

import torch
import torchvision

vgg16 = torchvision.models.vgg16(weights=torchvision.models.VGG16_Weights.DEFAULT)
# 保存方式1(保存模型结构 + 参数)
torch.save(vgg16, 'vgg16.pth')
import torch

model = torch.load('vgg16.pth')
print(model)

2. 保存模型的参数(推荐)

import torch
import torch.nn as nn

class Model(nn.Module):
    def __init__(self):
        super(Model, self).__init__()
        self.fc = nn.Linear(10, 1)

    def forward(self, x):
        return self.fc(x)


model = Model()
torch.save(model.state_dict(), 'myModel_path')  # 假设保存的是已经训练好的参数

model = Model()  # 重新实例化(参数是随机初始化的)
model.load_state_dict(torch.load('myModel_path'))  # 将训练好的参数加载进来
print(model)

(九)完整的模型训练套路

model:

import torch
from torch import nn

class CIFAR_Net(nn.Module):
    def __init__(self):
        super(CIFAR_Net, self).__init__()
        self.model = nn.Sequential(
            nn.Conv2d(3, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 32, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32, 64, 5, padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(64 * 4 * 4, 64),
            nn.Linear(64, 10)
        )

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


if __name__ == '__main__':
    cifar = CIFAR_Net()
    input = torch.ones((64, 3, 32, 32))
    output = cifar(input)
    print(output.shape)
import torch
import torchvision
from torch.nn import CrossEntropyLoss
from torch.utils import tensorboard
from torch.utils.data import DataLoader
from model import *

# 准备数据集
train_data = torchvision.datasets.CIFAR10('CIFA10', train=True, download=True,
                                          transform=torchvision.transforms.ToTensor())

test_data = torchvision.datasets.CIFAR10('CIFA10', train=False, download=True,
                                         transform=torchvision.transforms.ToTensor())

# 数据集大小
train_data_size = len(train_data)
test_data_size = len(test_data)
print(f"train_data_size: {train_data_size}, test_data_size: {test_data_size}")

# 加载数据集
train_dataloader = DataLoader(train_data, batch_size=64)
test_loader = DataLoader(test_data, batch_size=64)

# 创建网络模型
cifar = CIFAR_Net()

# 损失函数
loss_fn = CrossEntropyLoss()

# 优化器
learning_rate = 0.01  # 也可以写成 1e-2 = 1 * 10的-2次方
optimizer = torch.optim.SGD(cifar.parameters(), lr=learning_rate)

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

writer = tensorboard.SummaryWriter('CIFA-logs')

for i in range(epoch):
    print(f'第{i + 1}轮训练开始')
    # 训练步骤开始
    cifar.train()
    total_train_loss = 0
    for data in train_dataloader:
        imgs, targets = data
        outputs = cifar(imgs)
        loss = loss_fn(outputs, targets)
        total_train_loss += loss.item()
        # 反向传播
        optimizer.zero_grad()
        loss.backward()
        # 更新权重
        optimizer.step()
        # 记录训练的次数
        total_train_step += 1
        if total_train_step % 100 == 0:
            print(f'第{total_train_step}步训练,loss为{loss.item()}')
            # 添加到tensorboard
            writer.add_scalar('train_loss', loss.item(), total_train_step)
    print(f'第{i + 1}轮训练结束,loss为{total_train_loss}')

    # 测试步骤开始
    cifar.eval()
    total_test_loss = 0
    total_accuracy = 0
    # 上下文管理器,用于在不需要计算梯度的情况下运行PyTorch张量。
    with torch.no_grad():
        for data in test_loader:
            imgs, targets = data
            outputs = cifar(imgs)
            loss = loss_fn(outputs, targets)
            total_test_loss += loss.item()
            accuracy = (outputs.argmax(1) == targets).sum()
            total_accuracy += accuracy.item()
            # 记录测试的次数
            total_test_step += 1
            if total_test_step % 100 == 0:
                print(f'第{total_test_step}步测试,loss为{loss.item()}')
                # 添加到tensorboard
                writer.add_scalar('test_loss', loss.item(), total_test_step)
        print(f'第{i + 1}轮测试结束,loss为{total_test_loss}')
    print(f'第{i + 1}轮测试结束,accuracy为{total_accuracy / test_data_size}')
    writer.add_scalar('test_accuracy', total_accuracy / test_data_size, i + 1)

    torch.save(cifar, f'cifar_{i + 1}.pth')

writer.close()

在这里插入图片描述

(十)利用GPU训练

1. 第一种方法

在下方三处加入 cuda()

  • 网络模型
  • 数据(输入、标注)
  • 损失函数

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

2. 第二种方法

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(十一)完整的模型验证套路

import torch
import torchvision
from PIL import Image

img_path = 'imgs/cat5.png'
image = Image.open(img_path)

transform = torchvision.transforms.Compose([
    torchvision.transforms.Resize((32, 32)),
    torchvision.transforms.ToTensor()
])
image = transform(image)

model = torch.load('cifar_30.pth', weights_only=False, map_location=torch.device('cpu'))

image = torch.reshape(image, (1, 3, 32, 32))
model.eval()
with torch.no_grad():
    output = model(image)

idx = output.argmax(dim=1)
classes = ('airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
print(classes[idx])
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

FG.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值