本文最后更新于:1 年前
[[#1.python|1.python]]
[[#1.数据加载|1.数据加载]]
[[#1.数据加载#1.1DataSet|1.1DataSet]]
[[#2.TensorBoard|2.TensorBoard]]
[[#2.TensorBoard#2.1 绘图|2.1 绘图]]
[[#2.TensorBoard#2.2 添加图片|2.2 添加图片]]
[[#3.Transforms|3.Transforms]]
[[#3.Transforms#3.1 ToTensor|3.1 ToTensor]]
[[#3.Transforms#3.2 Compose|3.2 Compose]]
心得体会
1. python
Python 类中的双下划线 (double underscore)开头的方法通常被称为”魔法方法” (magic methods)。这些方法可以实现一些特殊的功能或对类进行修改。以下是一些常见的双下划线方法及其作用:
init (): 构造函数, 用于初始化类的实例。
str (): 当使用 print 输出对象时, 打印该方法的返回值。
repr (): 返回对象的机器可读字符串表示形式。
del (): 析构函数, 删除对象时被调用。
call (): 允许将对象视为函数调用。
getitem (): 通过索引访问元素的方法, 使得对象可以像列表那样进行切片。
len (): 返回对象长度的方法, 使得对象可以对 len () 函数生效。
eq (): 判断两个对象是否相等的方法, 使得对象可以使用 == 进行比较。
lt (): 小于比较的方法, 可以使用 < 进行比较。
add (): 实现对象的加法运算。
iter (): 实现迭代器接口, 使得对象可以被用于 for 循环。
metaclass : 元类, 用于创建类对象。
所以双下划线方法主要是实现一些内置的功能或魔法方法, 让 Python 类拥有一些特殊的行为。我们自己编写类时, 如果需要实现某些特殊功能, 可以通过编写双下划线方法来实现。
正文
1. 数据加载 1.1 DataSet
继承 DataSet 类并重写__getitem__和 len 方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import torchfrom PIL import Imagefrom torch.utils.data import Datasetimport osclass 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 __getitem__ (self, index ): img_name = self.img_path[index] img_item_path = os.path.join(self.path,img_name) img = Image.open (img_item_path) label = self.label_dir return img,label def __len__ (self ): return len (self.img_path)
1 2 3 4 5 root_dir = 'dataset/train' ants_label_dir = 'ants_image' bees_label_dir = 'bees_image' ants_dataset = CustomDataset(root_dir,ants_label_dir) bees_dataset = CustomDataset(root_dir,bees_label_dir)
小数据集可以通过➕叠加为大数据集
1 2 3 4 5 6 7 img,label = ants_dataset[1 ] img.show() img,label = bees_dataset[0 ] img.show() train_dataset = ants_dataset+bees_dataset img,label = train_dataset[124 ] img.show()
加载或下载数据集
1 2 3 4 5 6 7 8 9 10 11 import torchvision dataset_trans = torchvision.transforms.Compose([ torchvision.transforms.ToTensor() ]) train_set = torchvision.datasets.CIFAR10(root="./data/datasets/CIFAR" , train=True , transform=dataset_trans, download=False ) test_set = torchvision.datasets.CIFAR10(root="./data/datasets/CIFAR" , train=False , transform=dataset_trans, download=False ) writer = SummaryWriter("logs" )for i in range (10 ): img_tensor, target = test_set[i] writer.add_image("test_set" , img_tensor, i) writer.close()
1.2 DataLoder
加载数据集将多个数据 Tensor 和和标签分别打包成一个大的整体 batch
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 import torchvisionfrom torch.utils.data import DataLoaderfrom torch.utils.tensorboard import SummaryWriter train_set = torchvision.datasets.CIFAR10(root="./data/datasets/CIFAR" ,train=True ,transform=torchvision.transforms.ToTensor(),download=False ) test_set = torchvision.datasets.CIFAR10(root="./data/datasets/CIFAR" ,train=False ,transform=torchvision.transforms.ToTensor(),download=False ) test_loder = DataLoader(dataset=test_set,batch_size=64 ,shuffle=True ,num_workers=0 ,drop_last=False ) writer = SummaryWriter("logs" )for epoch in range (2 ): step = 0 for data in test_loder: imgs,targets = data writer.add_image("epoch_{}" .format (epoch), imgs, step, dataformats='NCHW' ) step+=1 writer.close()
[!NOTE] Tip
shuttle = true
,则每轮打包成 batch 的数据顺序不同,提高训练效果
writer.add_image("epoch_{}".format(epoch), imgs, step, dataformats='NCHW')
需要指定图片数据类型 dataformats
2. TensorBoard
TensorBoard 是一个用于可视化和监控机器学习模型训练过程的工具。它可以帮助您跟踪实验指标(如损失和准确率)、呈现模型计算图以及将嵌入向量投影到较低维度的空间等[1]。以下是使用 TensorBoard 的一般步骤:
安装 TensorBoard:您可以使用 pip 安装 TensorBoard,例如 pip install tensorboard
。
导入 TensorBoard:在 Python 代码中,导入 TensorBoard 库,例如 import tensorflow as tf
。
在代码中添加 TensorBoard 回调:在您的机器学习模型训练代码中,添加 TensorBoard 回调函数。这将允许 TensorBoard 在训练过程中记录指定的指标和数据。
启动 TensorBoard 服务器:在终端中,使用命令 tensorboard --logdir=<log_directory>
启动 TensorBoard 服务器。其中,<log_directory>
是您保存 TensorBoard 日志文件的目录。
在浏览器中查看 TensorBoard:在浏览器中输入 http://localhost:6006
,您将能够查看 TensorBoard 的可视化界面。
在 TensorBoard 界面中,您可以查看训练过程中的损失曲线、准确率曲线等指标图表。您还可以查看模型计算图、嵌入向量的投影等[1]。
2.1 绘图 1 2 3 4 5 from torch.utils.tensorboard import SummaryWriter writer = SummaryWriter("logs" )for i in range (100 ): writer.add_scalar("y=x" ,i,i) writer.close()
2.2 添加图片 1 2 3 4 5 6 7 8 9 from torch.utils.tensorboard import SummaryWriterimport numpy as npfrom PIL import Image writer = SummaryWriter("logs" ) img_path = "dataset/train/ants_image/1030023514_aad5c608f9.jpg" img_pil = Image.open (img_path) img_array = np.array(img_pil) writer.add_image("ant_test" ,img_array,2 ,dataformats='HWC' ) writer.close()
3.1 ToTensor
通过 transforms. ToTensor 去看两个问题
transforms 该如何使用 (python)?
为什么我们需要 Tensor 数据类型?
1 2 3 4 5 6 7 8 9 10 11 12 from torchvision import transformsfrom PIL import Imageimport cv2 img_path = "./dataset/train/ants_image/0013035.jpg" img_PIL=Image.open (img_path) img_cv = cv2.imread(img_path) transform_tensor = transforms.ToTensor() img_tensor = transform_tensor(img_cv)print (img_tensor.shape) writer = SummaryWriter("logs" ) writer.add_image("tensor_image" ,img_tensor) writer.close()
[!NOTE] Tips
cv 2 的 imread 读取的图片类型为 ndarray
PIL 的 Image. open 读取的图片类型为 JpegImageFile
3.2 Compose
Compose 类是将多种 transforms 操作叠加在一起, 初始化 compose 类后, 执行__call__方法循环执行组合操作
1 2 3 4 5 6 transform_compose = transforms.Compose([transforms.CenterCrop(10 ),transforms.ToTensor(),transforms.ConvertImageDtype(torch.float ),]) img_compose = transform_compose(img_PIL)print (type (img_compose)) writer = SummaryWriter("logs" ) writer.add_image("compose_tensor_image" ,img_compose) writer.close()
3.3 Normalize
对图像进行正则化, 传参包括各通道均值和标准差
1 2 3 4 trans_normalize = transforms.Normalize([0.5 , 0.5 , 0.5 ],[0.5 , 0.5 , 0.5 ]) img_norm = trans_normalize(img_tensor)print (img_norm[0 ][0 ][0 ]) writer.add_image("Normalize" ,img_norm)
3.4 Resize
改变 PILImage 图像尺寸
1 2 3 4 5 6 7 8 9 from torchvision import transforms trans_resize= transforms.Resize(256 ) trans_resize= transforms.Resize(size=(256 , 256 ), interpolation=Image.BICUBIC) trans_resize= transforms.Resize(max_size=256 , ratio=2 ) img_resize = trans_resize(img_tensor)print (img_resize.shape)
3.5 RandomCrop
随机裁剪图像, 指定裁剪后的图像大小进行随机裁剪, 支持输入格式为 PILImage 和 Tensor
1 2 3 4 trans_randomcrop = transforms.RandomCrop(512 ) img_randomcrop = trans_randomcrop(img_tensor)print (img_randomcrop.shape) writer.add_image("randomcrop" ,img_randomcrop)
神经网络基本骨架 4.1 nn_module
module 是是所有网络模块的基类 ,必须继承该类并重写部分方法,构造方法、前向传播等
1 2 3 4 5 6 7 8 9 10 11 12 import torch from torch import nn class Simple_Nn (nn.Module): def __init__ (self, *args, **kwargs ) -> None : super ().__init__(*args, **kwargs) def forward (self, input ): output = input + 1 return output simple_nn = Simple_Nn() input = torch.tensor(1.0 ) output = simple_nn(input ) print (output)
4.2 nn.Conv2d(卷积)
卷积层的使用,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 27 28 29 30 31 32 33 34 35 36 37 38 39 import torch import torchvision from torch import nn from torch.nn import Conv2d, MaxPool2d, ReLU from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter test_sets = torchvision.datasets.CIFAR10("./data/datasets/CIFAR" , train=False , transform=torchvision.transforms.ToTensor(), download=True ) dataloader = DataLoader(test_sets, batch_size=64 , shuffle=True ) class My_Cnn (nn.Module): def __init__ (self, ): super (My_Cnn, self).__init__() self.conv1 = Conv2d(in_channels=3 , out_channels=6 , kernel_size=3 , stride=1 , padding=0 ) def forward (self, x ): map1 = self.conv1(x) output = self.nonlinear1(map1) return output mycnn = My_Cnn() print (mycnn) step = 0 writer = SummaryWriter("logs" ) for data in dataloader: imgs, targets = data output = mycnn(imgs) output = torch.reshape(output, [-1 , 3 , 30 , 30 ]) print ("Batch:" + str (step), imgs.shape) print ("Batch:" + str (step), output.shape) writer.add_image("input_img" , imgs, step, dataformats="NCHW" ) writer.add_image("output_img" , output, step, dataformats="NCHW" ) step += 1
Tensorboard结果:
4.3 nn.MaxPool2d(最大池化)
最大池化保持特征图通道数不变的前提下,大小减少约一半左右,起到减小网络参数,提取关键特征,加快收敛速度(本身不具备特征提取作用)。
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.nn import MaxPool2d from torch import nn from torch.utils.data import DataLoader from torch.utils.tensorboard import SummaryWriter test_sets = torchvision.datasets.CIFAR10("./data/datasets/CIFAR" , train=False , transform=torchvision.transforms.ToTensor(), download=True ) dataloader = DataLoader(test_sets, batch_size=64 , shuffle=True ) class NiuMa (nn.Module): def __init__ (self ): super (NiuMa, self).__init__() self.maxpool = MaxPool2d(3 , ceil_mode=True ) def forward (self, input ): return self.maxpool(input ) writer = SummaryWriter("logs" ) niuma = NiuMa() step = 0 for data in dataloader: imgs, targets = data output = niuma(imgs) writer.add_image("input_maxpool" , imgs, step, dataformats="NCHW" ) writer.add_image("output_maxpool" , output, step, dataformats="NCHW" ) print ("batch:" + str (step), imgs.shape, output.shape) step += 1 writer.close()
Tensorboard结果: 输入图像 最大池化输出图像
4.4 非线性激活
非线性激活对输入进行非线性处理,从而拟合出需要的模型,非线性越多拟合效果越好,但容易过拟合,ReLU激活函数
是最常用的非线性激活函数。
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 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/datasets/CIFAR" , train=False , transform=torchvision.transforms.ToTensor(), download=True ) dataloader = DataLoader(dataset, batch_size=64 , shuffle=True ) class NiuMa (nn.Module): def __init__ (self ): super (NiuMa, self).__init__() self.relu = ReLU() self.sigmoid = Sigmoid() def forward (self, input ): return self.sigmoid(input ) writer = SummaryWriter("logs" ) niuma = NiuMa() step = 0 for data in dataloader: imgs, targets = data output = niuma(imgs) writer.add_image("output_sigmoid" , output, global_step=step, dataformats="NCHW" ) step += 1 writer.close()
TensorBoard结果:
Sigmoid非线性激活
4.5 线性层
线性层一般为网络最后的全连接层,分类问题则经过softmax得到各个类别的概率。
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 import torch import torchvision.datasets from torch import nn from torch.nn import Linear from torch.utils.data import DataLoader dataset = torchvision.datasets.CIFAR10("./data/datasets/CIFAR" , train=False , transform=torchvision.transforms.ToTensor(), download=True ) dataloader = DataLoader(dataset, batch_size=64 , shuffle=True , drop_last=True ) class NiuMa (nn.Module): def __init__ (self ): super (NiuMa, self).__init__() self.linear = Linear(196608 , 10 ) def forward (self, input ): return self.linear(input ) niuma = NiuMa() for data in dataloader: imgs, targets = data imgs = torch.flatten(imgs) print (imgs.shape) output = niuma(imgs) print (output.shape, output)
常用函数手册 ![[pytorch常用函数手册.pdf]]
参考文献 PyTorch快速入门(小土堆)