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
26from 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
18from 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去看两个问题
- transforms该如何使用(python)
- 为什么我们需要Tensor数据类型
1
2
3
4
5
6
7
8
9
10
11
12
13
14from 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
39from 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
25import 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
17import 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)卷积操作
torch.nn.Conv2d是一个类,它可以创建一个二维卷积层,而torch.nn.functional.conv2d是一个函数,它可以对一个输入图像进行二维卷积操作。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
27import 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)
你的代码中有三个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 | import torch |
代码中有两个部分,一个是数据集和数据加载器的定义,另一个是自定义卷积层类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
34import 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 | import torch |
神经网络-线性层及其他层介绍
线性层是一种神经网络中的基本模块,它使用一个权重矩阵对输入特征进行线性变换,得到输出特征。线性层的输入和输出都是二维张量,形状为[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
36import 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
40import 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 提供了两种保存和读取网络模型的方式:
- 第一种是保存整个网络模型,包括模型结构和参数。这种方式可以直接使用 torch.save(model, ‘model.pth’) 和 model = torch.load(‘model.pth’) 函数来实现。1
- 第二种是只保存网络参数,也就是状态字典(state_dict)。这种方式可以使用 torch.save(model.state_dict(), ‘model_params.pth’) 和 model.load_state_dict(torch.load(‘model_params.pth’)) 函数来实现。21
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 | import torch |
利用GPU训练
1. 找到
- 网络模型
- 数据(输入输出)
- 损失函数
.cuda()
2. .to(device)
device = torch.device("cpu")
Torch.device("cuda")
完整的模型验证套路(测试, demo)
利用已经训练好的模型,然后给它提供输入
1 | import torch |