发布于 

pytorch-learning

两大法宝函数

  • dir():打开、看见
  • help():说明书

    如何加载数据

  • Dataset
  • Dataloader
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    from torch.utils.data import Dataset  
    from PIL import Image # 操作图片
    import os # 操作系统

    class MyData(Dataset):

    def __init__(self, root_dir, label_dir):
    self.root_dir = root_dir
    self.label_dir = label_dir
    self.path = os.path.join(root_dir, label_dir)
    self.img_path = os.listdir(self.path)

    def __getitem__(self, idx): # 内置函数
    img_name = self.img_path[idx]
    img_item_path = os.path.join(self.root_dir, self.label_dir, img_name)
    img = Image.open(img_item_path)
    label = self.label_dir
    return img, label

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


    root_dir = "dataset/train"
    ants_label_dir = "ants_image"
    ants_dataset = MyData(root_dir, ants_label_dir)

    TensorBoard

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    from torch.utils.tensorboard import SummaryWriter  
    import numpy as np
    from PIL import Image

    writer = SummaryWriter("logs")
    image_path = "dataset/train/ants_image/0013035.jpg"
    img_PIL = Image.open(image_path)
    img_array = np.array(img_PIL)

    print(img_array.shape)

    writer.add_image("test", img_array, 1, dataformats="HWC")
    # writer.add_scalar()

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

    writer.close()

    Transforms结构及用法

    transforms.py 工具箱
  • totensor
  • resize
    通过 transforms.ToTensor去看两个问题
  1. transforms该如何使用(python)
  2. 为什么我们需要Tensor数据类型
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    from torch.utils.tensorboard import SummaryWriter  
    from torchvision import transforms
    from PIL import Image

    img_path = "dataset/train/ants_image/0013035.jpg"
    img = Image.open(img_path)
    writer = SummaryWriter("logs")

    tensor_trans = transforms.ToTensor() # 创建工具
    tensor_img = tensor_trans(img) # 使用工具

    writer.add_image("Tensor_img", tensor_img)

    writer.close()

    常见的Transforms

  • 输入 PIL Image.open()
  • 输出 tensor ToTensor()
  • 作用 narays cv.imread()
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    from PIL import Image  
    from torchvision import transforms
    from torch.utils.tensorboard import SummaryWriter

    writer = SummaryWriter("logs")
    img = Image.open("dataset/train/ants_image/0013035.jpg")

    #ToTensor
    trans_tensor = transforms.ToTensor()
    img_tensor = trans_tensor(img)

    writer.add_image("ToTensor", img_tensor)

    # Normalize
    print(img_tensor[0][0][0])
    trans_norm = transforms.Normalize([1, 3, 5], [1, 1, 1])
    img_norm = trans_norm(img_tensor)
    print(img_norm[0][0][0])
    writer.add_image("Normalize", img_norm, 1)

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

    # Compose
    trans_compose = transforms.Compose([trans_resize, trans_tensor])
    img_compose = trans_compose(img)
    writer.add_image("compose", img_compose, 1)

    # RandomCrop
    trans_random = transforms.RandomCrop((500, 1000))
    trans_compose_2 = transforms.Compose([trans_random, trans_tensor])
    for i in range(10):
    img_crop = trans_compose_2(img)
    writer.add_image("RandomCrop", img_crop, i)

    writer.close()

    工具食用方法

    关注输入输出,官方文档

    torchvision中的数据集使用

    在PyTorch中,train=True表示使用CIFAR-10数据集的训练集,而train=False表示使用测试集。在训练模型时,我们使用训练集来训练模型,然后使用测试集来评估模型的性能。因此,我们需要将数据集分成训练集和测试集.
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    import torchvision  
    from PIL import Image
    from torch.utils.tensorboard import SummaryWriter

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

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

    print(test_set.classes)

    # img, target = test_set[0]
    # print(img)
    # print(target)
    # print(test_set.classes[target])
    # img.show()
    # print(test_set[0])
    write = SummaryWriter("p10")
    for i in range(10):
    img, target = test_set[i]
    write.add_image("test_set", img, i)

    write.close()

    DataLoader

  • dataset:要从中加载数据的数据集。
  • batch_size:每个批次中的样本数。
  • shuffle:是否对数据进行洗牌。
  • num_workers:用于数据加载的子进程数。
  • drop_last:如果数据集大小不能被批次大小整除,则是否删除最后一个不完整的批次

    神经网络的基本骨架

    nn.Module是PyTorch中所有神经网络模块的基类。它包含层和一个方法forward(input),该方法返回输出。它是一种方便的封装参数的方法,具有将它们移动到GPU、导出、加载等的帮助程序。您的模型也应该继承这个类。模块也可以包含其他模块,允许将它们嵌套在树形结构中。您可以将子模块分配为常规属性。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import torch  
    from torch import nn


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

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


    tudui = Tudui()
    x = torch.tensor(1.0)
    output = tudui(x)
    print(output)

    卷积操作

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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]])

    input = torch.reshape(input, (1, 1, 5, 5)) # 增加batchsize和channel
    kernel = torch.reshape(kernel, (1, 1, 3, 3))

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

    output = F.conv2d(input, kernel, stride=1)
    output2 = F.conv2d(input, kernel, stride=2)
    output3 = F.conv2d(input, kernel, stride=1, padding=1)

    print(output)
    print(output2)
    print(output3)
    torch.nn.Conv2d是一个类,它可以创建一个二维卷积层,而torch.nn.functional.conv2d是一个函数,它可以对一个输入图像进行二维卷积操作。

你的代码中有三个conv2d的调用,它们的区别是:

  • output = F.conv2d(input, kernel, stride=1):这个调用没有使用padding参数,所以输出的形状是(1, 1, 3, 3)。
  • output2 = F.conv2d(input, kernel, stride=2):这个调用使用了stride参数为2,所以输出的形状是(1, 1, 2, 2)。
  • output3 = F.conv2d(input, kernel, stride=1, padding=1):这个调用使用了padding参数为1,所以输出的形状是(1, 1, 5, 5)。

神经网络-卷积层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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("data", train=False, transform=torchvision.transforms.ToTensor(), download=True)

dataloader = DataLoader(dataset, 64, shuffle=True)


class Tudui(nn.Module):
def __init__(self):
super(Tudui, 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


tudui = Tudui()

writer = SummaryWriter("p11")

step = 0
for data in dataloader:
imgs, targets = data
output = tudui(imgs)
writer.add_images("input", imgs, step)

output = torch.reshape(output, (-1, 3, 30, 30))

writer.add_images("output", output, step)

step += 1

代码中有两个部分,一个是数据集和数据加载器的定义,另一个是自定义卷积层类Tudui的定义和使用。

  • 数据集和数据加载器的定义:这里你使用了torchvision.datasets.CIFAR10来下载并加载CIFAR10数据集,它包含了60000张32x32的彩色图像,分为10个类别。你使用了torchvision.transforms.ToTensor()来把图像转换为张量,并且只加载了测试集。你使用了torch.utils.data.DataLoader来创建一个数据加载器,它可以按照批次大小为64,随机打乱顺序地提供数据。
  • 自定义卷积层类Tudui的定义和使用:这里你继承了torch.nn.Module类来创建一个自定义卷积层类Tudui。在__init__方法中,你使用了torch.nn.Conv2d来创建一个二维卷积层,它可以把输入通道数为3的图像转换为输出通道数为6的特征图,使用了3x3的卷积核,步长为1,没有填充。在forward方法中,你把输入x通过self.conv1进行卷积操作,并返回结果。然后你创建了一个Tudui的实例tudui,并用它对dataloader中的每一批图像进行处理。你使用了torch.utils.tensorboard.SummaryWriter来创建一个写入器writer,并用它把输入图像和输出特征图写入到TensorBoard中。

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

    最大池化(Max Pooling)是一种常用的池化操作,它可以减少特征图的大小,降低计算量和内存消耗,同时保留最重要的特征。
  • kernel_size:滤波器的大小,也就是每次取最大值的窗口大小。可以是一个整数,表示窗口是正方形的,也可以是一个元组,表示窗口是矩形的。
  • stride:滤波器的步长,也就是每次移动的距离。默认值是kernel_size,表示没有重叠。可以是一个整数,表示水平和垂直方向上都相同,也可以是一个元组,表示水平和垂直方向上不同。
  • padding:在输入特征图两边添加的填充值。默认值是0,表示不添加填充。可以是一个整数,表示两边都相同,也可以是一个元组,表示两边不同。填充值为负无穷大(-inf),表示被忽略。
  • dilation:滤波器中元素之间的间隔。默认值是1,表示没有间隔。可以是一个整数,表示水平和垂直方向上都相同,也可以是一个元组,表示水平和垂直方向上不同。
  • return_indices:是否返回最大值对应的索引。默认值是False,表示不返回。如果为True,则返回一个与输出形状相同的张量(tensor),包含每个最大值在输入特征图中的位置(行列号)。这个参数在后续使用torch.nn.MaxUnpool2d进行反池化时有用。
  • ceil_mode:是否使用向上取整而不是向下取整来计算输出形状。默认值是False,表示使用向下取整。如果为True,则使用向上取整。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    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 Tudui(nn.Module):
    def __init__(self):
    super(Tudui, self).__init__()
    self.maxpool1 = MaxPool2d(kernel_size=3, ceil_mode=True)

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


    tudui = Tudui()
    writer = SummaryWriter("logs_maxpool")

    step = 0
    for data in dataloader:
    imgs, targets = data
    writer.add_images("input", imgs, step)
    output = tudui(imgs)
    writer.add_images("output", output, step )

    step = step + 1

    writer.close()

    神经网络-非线性激活

    非线性激活函数是指在神经网络的神经元上运行的函数,负责将神经元的输入映射到输出端。非线性激活函数对于神经网络去学习、理解非常复杂和非线性的函数来说具有十分重要的作用。它们将非线性特性引入到网络中。

如果我们的神经网络只使用线性激活函数,则无论多深的网络最终输出也不过是所以输入的简单线性组合,这并不具有拟合任意函数的能力,因此我们需要引入非线性激活函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import torch  
from torch import nn
from torch.nn import ReLU

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

class TuDui(nn.Module):
def __init__(self):
super(TuDui, self).__init__()
self.relu1 = ReLU()

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

tudui = TuDui()
output = tudui(input)
print(output)

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

线性层是一种神经网络中的基本模块,它使用一个权重矩阵对输入特征进行线性变换,得到输出特征。线性层的输入和输出都是二维张量,形状为[batch_size, size]。线性层可以用于实现全连接层,即每个输入神经元与每个输出神经元都有连接。

线性层的参数有:

  • in_features:输入特征的数量,即输入张量的列数
  • out_features:输出特征的数量,即输出张量的列数
  • bias:是否添加偏置项,默认为True

    Sequential的使用

    它有三个卷积层,三个最大池化层,两个全连接层和一个Flatten层。它的输入是一个64x3x32x32的张量,输出是一个64x10的张量。你还使用了SummaryWriter来可视化你的模型结构。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    import torch  
    from torch import nn
    from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential
    from torch.utils.tensorboard import SummaryWriter


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

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

    return x


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

    writer = SummaryWriter("logs_seq")
    writer.add_graph(tudui, input)
    writer.close()

    损失函数与反向传播

    神经网络的损失函数是用来衡量网络输出与期望输出之间的差异,反向传播是一种算法,用来计算损失函数对网络参数的梯度,并根据梯度更新参数,使损失函数达到最小
    神经网络的梯度是一个重要的概念,它指示了在函数的某一点,沿着哪个方向函数值上升最快,以及上升的速度有多快
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    import torch  
    import torchvision
    from torch import nn
    from torch.nn import Conv2d, MaxPool2d, Flatten, Linear, Sequential, CrossEntropyLoss
    from torch.utils.data import DataLoader
    from torch.utils.tensorboard import SummaryWriter

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

    class TuDui(nn.Module):
    def __init__(self):
    super(TuDui, self).__init__()
    self.model1 = 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(1024, 64),
    Linear(64, 10)
    )

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

    return x


    tudui = TuDui()
    loss = CrossEntropyLoss()

    for data in dataloader:
    imgs, targets = data
    outputs = tudui(imgs)
    result_loss = loss(outputs, targets)
    print(result_loss)
    result_loss.backward()

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

    如果你想使用预训练模型,你可以参考 Pytorch 的官方文档或者 Pytorch Hub,那里有很多现成的模型和示例代码。

如果你想自定义模型,你需要继承 torch.nn.Module 类,并实现 init 和 forward 方法。init 方法用于定义模型的层和参数,forward 方法用于定义模型的前向传播逻辑。12

无论是使用预训练模型还是自定义模型,你都需要保存和加载模型的状态字典(state_dict),这是一个包含了每个网络层和其对应参数张量的 Python 字典。34

你可以使用 torch.save 和 torch.load 函数来保存和加载状态字典。34

如果你想在不同的设备上保存和加载模型(比如 CPU 和 GPU),你需要注意指定正确的设备信息。

【学习笔记】【Pytorch】十四、现有网络模型的使用及修改_pytorch 修改网络结构_Mr庞.的博客-CSDN博客

网络模型的保存与读取

网络模型的保存与读取是一个常见的需求,它可以帮助我们在不同的设备或场景下使用已经训练好的模型。

不同的深度学习框架有不同的方法来保存和读取网络模型,这里我以 Pytorch 为例,给你简单介绍一下。

Pytorch 提供了两种保存和读取网络模型的方式:

Pytorch 官方推荐使用第二种方式,因为它更灵活和通用,而且占用的空间更小。2

无论哪种方式,你都需要注意在不同设备上保存和加载模型时指定正确的设备信息(比如 CPU 或 GPU)。21

完整的模型训练套路

argmax 是一个数学函数,它用于找到使目标函数取得最大值的输入(或参数)。1

在机器学习中,argmax 常用于找到具有最大预测概率的类别。2

例如,如果有一个分类器可以对一张图片进行四种类别的预测(猫、狗、鸟、鱼),并输出每种类别的概率(0.2、0.3、0.4、0.1),那么 argmax 操作可以返回最大概率对应的类别(鸟)或者索引(2)。

在 Python 中,可以使用 numpy.argmax() 函数来实现 argmax 操作。34

这个函数接受一个数组作为输入,并返回沿着指定轴的最大值的索引。如果没有指定轴,则返回整个数组中的最大值的索引。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
import torch  
import torchvision
from torch.utils.tensorboard import SummaryWriter

from model import Tudui

# 准备数据集
from torch import nn
from torch.utils.data import DataLoader

train_data = torchvision.datasets.CIFAR10("data", train=True, transform=torchvision.transforms.ToTensor(), download=True)
test_data = torchvision.datasets.CIFAR10("data", train=False, transform=torchvision.transforms.ToTensor(), download=True)


# 长度
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)


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

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

# 优化器
learing_rate = 1e-2
ooptimizer = torch.optim.SGD(tudui.parameters(), lr=learing_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))

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

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

total_train_step = total_train_step + 1
if total_train_step % 100 == 0:
print("训练次数:{}, Loss: {}".format(total_train_step, loss.item()))
writer.add_scalar("train_loss", loss.item(), total_train_step)

# 测试步骤开始
tudui.eval()
total_test_loss = 0
total_accuracy = 0
with torch.no_grad():
for data in test_dataloader:
imgs, targets = data
outputs = tudui(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_loss, total_test_step)
writer.add_scalar("test_accuracy", total_accuracy/test_data_size, total_test_step)
total_test_step = total_test_step + 1

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

writer.close()

利用GPU训练

1. 找到
- 网络模型
- 数据(输入输出)
- 损失函数
.cuda()
2. .to(device)
device = torch.device("cpu")
Torch.device("cuda")

完整的模型验证套路(测试, demo)

利用已经训练好的模型,然后给它提供输入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import torch  
import torchvision
from PIL import Image
from torch import nn

# 传入图片处理
img_path = "./imgs/dog.jpg"
img = Image.open(img_path)
img = img.convert("RGB")
transform = torchvision.transforms.Compose([
torchvision.transforms.Resize((32, 32)),
torchvision.transforms.ToTensor()
])
img = transform(img)
img = torch.reshape(img, (1, 3, 32, 32))
img = img.cuda()

# 开始识别
model = torch.load("tudui_0.pth")
model.cuda()
model.eval()
with torch.no_grad():
output = model(img)
print(output.argmax(1))

本站由 @Eureka 使用 Stellar 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。