torchvision中调用各种transform源码分享_高斯_标准化等
2021/9/28 12:40:43
本文主要是介绍torchvision中调用各种transform源码分享_高斯_标准化等,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
提示:麻烦点赞,拒绝白嫖
文章目录
- 前言
- 一、数据增强
- 二、Transform
- 1.基础使用示例
- 2.标准化
- 3.其他Transform
- 总结
前言
torchvision中封装好了多种图片数据增强的操作,调用非常的方便,今天一起来学习以下各个transform的使用方法。
一、数据增强
数据增强是一个很有效地提升模型精度的方法,通过让模型学习一些经过转置,加噪等形式的特征,可以使得模型拥有更好的鲁棒性。
但是需要注意的是,并不是任何时候都适合去无脑的把所有Transform安排上。首先,如果训练集数量非常充足,但特征足够简单,有时候是不需要Transform的。另外,笔者认为应该更加考虑测试集里面的数据集是啥样的,应该通过Transform使得训练集样本向测试集靠拢。
二、Transform
1.基础使用示例
定义一个transform,这里应该和定义的函数放在同级最好。ToTensor方法已经将图片的值从0-255映射到0-1了,所有不要再除以255了。
from torchvision import transforms as transforms loadfold = transforms.Compose([ transforms.ToTensor(), ])
以下写在main函数里面,通过继承dataset类,从文件夹读入图片。loadfold即为上面定义的transform,而Y_train_orig该数据集的标签,root是该数据集的相对路径。注意MyData_loadfold是在util下的一个文件,而util是和main同级的一个文件夹,MyData_loadfold文件在以下也提供了。
from util.myData_loadfold import MyData_loadfold from torch.utils.data import DataLoader train_dataset = MyData_loadfold(transform=loadfold, Y=Y_train_orig, root=imgtrainfold) train_loader = DataLoader(train_dataset, batch_size=1, shuffle=True)
MyData_loadfold.py
import torch from torch.utils.data import DataLoader, Dataset from torchvision import transforms from PIL import Image import os import numpy as np import re class MyData_loadfold(Dataset): # 继承Dataset def __init__(self, transform=None, Y=0, root='', state='Train', k=0): # __init__是初始化该类的一些基础参数 self.transform = transform # 变换 imgs = os.listdir(root) imgs.sort(key=lambda x: int(re.match('(\d+)\.jpg', x).group(1))) self.imgs = [os.path.join(root, i) for i in imgs] self.transforms = transform self.root = root self.state = state self.k = k self.Y = Y self.size = tuple([len(imgs),1]) def __len__(self): return len(self.imgs) def __getitem__(self, index): img_path = self.imgs[index] pil_img = Image.open(img_path) if self.transforms: data = self.transforms(pil_img) else: pil_img = np.asarray(pil_img) data = torch.from_numpy(pil_img) return data, self.Y[index]
2.标准化
除了树模型了,所有数据都需要标准化,标准化效果比归一化效果好一些。虽然toTensor已经将图片的RGB值转换为0-1之间,但是对其进行标准化转为(-1,1)之间效果更好。进行标准化的化首先需要求出样本的均值与方差,对于图片来说,是求其三个通道的均值与方差,imagenet预训练网络已经给了一个均值与方差,但并不符合我们的训练集数据,因此我们需要自己去求训练集的均值与方差,**注意测试集也默认是使用训练集的标准化系数进行标准化的,这是机器学习和深度学习的一个假设前提,测试集符合训练集的分布。**下面是求自己的训练集标准化系数的代码,其中train_loader是上面第一节定义好的。
for i, data in enumerate(train_loader , 1): img, label = data labellist.append(label) imglist.append(img) traindata = torch.cat(imglist, dim=0) stdRGB = [0, 0, 0] avgRGB = [0, 0, 0] for i in range(3): avgRGB[i] = traindata[:, i, :, :].mean() stdRGB[i] = traindata[:, i, :, :].std()
3.其他Transform
这一节就介绍其他transform了,这里只介绍一些常用的。
# 随机放缩裁剪,先进行随机放缩,然后按imgsize*imgsize进行裁剪。 # 每个epoch之间也都是随机裁剪的。 RRC = transforms.Compose([ transforms.RandomResizedCrop(imgsize), transforms.ToTensor(), ]) # 随机裁剪,按imgsize*imgsize进行裁剪。 # 每个epoch之间也都是随机裁剪的。 CC = transforms.Compose([ transforms.CenterCrop(imgsize), transforms.ToTensor(), ]) # 这里是标准化,第一个是Imagenet的参数,第二个是笔者参数,不要自己用 # 去第二节求了再填入。 Normal_transform = transforms.Compose([ # transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),# Imagenet # transforms.Normalize(mean=[0.4772, 0.5595, 0.3851], std=[0.2871, 0.2960, 0.2952]) # all train ]) # 这里是加曝光,这些参数不用太改,反正笔者改了也没啥用 # 但是加了曝光有点用。 CJ_transform = transforms.Compose([ ResizeImage(imgsize), transforms.ColorJitter(brightness=0.5, contrast=0.5, saturation=0.5, hue=0.5), transforms.ToTensor(), ]) # 这里是旋转,角度为30,其他参数可以不看 RR_transform = transforms.Compose([ ResizeImage(imgsize), transforms.RandomRotation(30, resample=False, expand=False, fill=0), transforms.ToTensor(), ]) # 这里是将图片直接左右颠倒的意思,Horizontal,p是概率 RHF_transform = transforms.Compose([ ResizeImage(imgsize), transforms.RandomHorizontalFlip(p=1), transforms.ToTensor(), ]) # 这里是将图片直接上下颠倒的意思,Vertical,p是概率 RVF_transform = transforms.Compose([ ResizeImage(imgsize), # transforms.RandomResizedCrop(imgsize), transforms.RandomVerticalFlip(p=1), transforms.ToTensor(), ]) # 这里是增加高斯噪声,需要一个单独的类,后面提供。 from util import AddGaussianNoise GN_transform = transforms.Compose([ ResizeImage(imgsize), # transforms.RandomResizedCrop(imgsize), AddGaussianNoise.AddGaussianNoise(mean=1, variance=1, amplitude=10), transforms.ToTensor(), ])
AddGaussianNoise.py
import PIL.Image import numpy as np class AddGaussianNoise(object): def __init__(self, mean=0.0, variance=1.0, amplitude=1.0): self.mean = mean self.variance = variance self.amplitude = amplitude def __call__(self, img): img = np.array(img) h, w, c = img.shape N = self.amplitude * np.random.normal(loc=self.mean, scale=self.variance, size=(h, w, 1)) N = np.repeat(N, c, axis=2) img = N + img img[img > 255] = 255 # 避免有值超过255而反转 img = PIL.Image.fromarray(img.astype('uint8')).convert('RGB') return img
总结
笔者和同学参加图片分类的一些比赛,同学认为直接在训练集加transform就行了, 结果精度反而比不加更低。笔者认为更重要的是分析训练集和测试集的图片到底是什么状态。这次比赛实际上测试集大部分图片是正常的,包括训练集也一样大部分都是正常的,也就是没有颠倒,没有噪声等。如果在训练集源样本就直接加transform,会使得模型每个epoch都丢失一部分正常的源样本。因此,笔者通过list等操作实现了累加transform,最终将400张图片的扩充到3600张图片,其中3份源样本,2份随机裁剪,以及曝光,左右颠倒,上下颠倒,旋转30度各一份。这样操作下来一个epoch训练的时间是更慢了,但是收敛也更快了,重要的是这样效果好一点。最后,我想说的是不能一成不变得套用transform,要不断尝试噢。
这篇关于torchvision中调用各种transform源码分享_高斯_标准化等的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-26MATLAB 中 A(7)=[];什么意思?-icode9专业技术文章分享
- 2024-11-26UniApp 中如何实现使用输入法时保持页面列表不动的效果?-icode9专业技术文章分享
- 2024-11-26在 UniApp 中怎么实现输入法弹出时禁止页面向上滚动?-icode9专业技术文章分享
- 2024-11-26WebSocket是什么,怎么使用?-icode9专业技术文章分享
- 2024-11-26页面有多个ref 要动态传入怎么实现?-icode9专业技术文章分享
- 2024-11-26在 UniApp 中实现一个底部输入框的常见方法有哪些?-icode9专业技术文章分享
- 2024-11-26RocketMQ入门指南:搭建与使用全流程详解
- 2024-11-26RocketMQ入门教程:轻松搭建与使用指南
- 2024-11-26手写RocketMQ:从入门到实践的简单教程
- 2024-11-25【机器学习(二)】分类和回归任务-决策树(Decision Tree,DT)算法-Sentosa_DSML社区版