概述
前言
这篇笔记继续学习pytorch
的数据预处理方式transforms
,前三篇笔记学习了transforms
的使用流程,和各种方法实现。这篇笔记包括两个要点,第一是在已经选好transform
方法transform1,transform2,transform3...
,并且都设置好参数数的前提下,如何在每次迭代的时候选择不同组的transform
方法或者使用不同的调用顺序,第二是如何自定义transform
方法 ,虽然pytorch提供了很多transform方法,但有时可能也需要自己定义。本笔记提供了在图片上添加椒盐和高斯噪声 的数据增强方法。本笔记的知识框架主要来源于深度之眼,并依此作了内容的丰富拓展,拓展内容主要源自对torch文档的翻译理解,所用数据来源于网络。
数据预处理方法具体实现见:
深度之眼Pytorch打卡(九):Pytorch数据预处理——预处理过程与数据标准化(transforms过程、Normalize原理、常用数据集均值标准差与数据集均值标准差计算)
深度之眼Pytorch打卡(十):Pytorch数据预处理——数据统一与数据增强(上)
深度之眼Pytorch打卡(十一):Pytorch数据预处理——数据增强(下)
几篇数据增强笔记所涉代码及数据见:Poetair/Pytorch-Learning/transforms
transform选择
- transforms.RandomChoice()
torchvision.transforms.RandomChoice(transforms)
transforms
是一个由若干预处理方法组成的列表transforms=[transform1,transform2,transform3,.....]
,该方法就是随机从该列表中随机取一个方法来执行。
transforms.RandomChoice(
[transforms.RandomGrayscale(1), transforms.ColorJitter(hue=0.5), transforms.RandomRotation(60, resample=2)]),
transforms.ToTensor(),
- transforms.RandomApply()
torchvision.transforms.RandomApply(transforms, p=0.5)
依概率p
执行transforms
,并且执行时按照顺序执行其中每一个预处理方法。transforms
是由若干预处理方法组成的list
或者是tuple
。
transforms.RandomApply([transforms.Pad(50, fill=(100, 130, 110)), transforms.RandomAffine(degrees=0, shear=40), transforms.RandomVerticalFlip(1)], 0.5),
transforms.ToTensor(),
- transforms.RandomOrder()
torchvision.transforms.RandomOrder(transforms)
按照随机的顺序执行transforms
中每一个预处理方法,transforms
是由若干预处理方法组成的list
。
transforms.RandomOrder([transforms.Pad(100, fill=(100, 130, 110)), transforms.CenterCrop(200)]),
transforms.ToTensor(),
transform方法自定义
观察Pytorch
提供的transform
方法,我们会发现,每一个transform
方法都有一个默认输入和一个默认输出,输入往往是PIL Image
,输出往往也是PIL Image
,当然有特例,比如随机擦除(输入是TenSor),ToTensor
(输出是归一化张量)和Normalize
(输入是张量)等。
以Resize
为例,从以下源码中可以看出transform
方法的基本代码结构。__init__
中定义一些该类必要的其他参数,如概率p
,标准差std
,均值mean
等。__call__()
中实现数据预处理方法,默认输入便是在这里使用的。大多数的transform
方法的具体实现,都是直接调用的torch
的Function
里的函数,如这里的F.resize()
。而在我们自定义预处理方法时,需要在这里自己写。
class Resize(object):
def __init__(self, size, interpolation=Image.BILINEAR):
assert isinstance(size, int) or (isinstance(size, Iterable) and len(size) == 2)
self.size = size
self.interpolation = interpolation
def __call__(self, img): # __call___,让类实例变成一个可以被调用的对象,像函数
return F.resize(img, self.size, self.interpolation)
- 添加椒盐噪声
椒盐噪声是脉冲噪声的特例,指灰度值很低或者灰度值很高的随机点噪声,在图像上就表现为很暗的点(椒)和很亮的点(盐)随机分布。用添加过椒盐噪声的数据集训练出来的模型,对被椒盐噪声污染的测试图像应该会更鲁棒。椒盐噪声的添加,根据想要的噪声密度density
,在图像内随机的像素位置,对像素点赋值为0或255
,彩色图赋(255,255,255)或者(0,0,0)
。
噪声添加的基本实现,额外参数只有density
,其需要在__init__
定义,而__call__
中则添加,向图片中随机撒椒盐的程序。
撒椒、盐的密度(等于椒、盐出现的概率值):d = density/2.0
。
信号密度(等于原图像像素出现的概率值):d = 1-density
。
有了各种信号出现的概率,现在就需要根据概率值,随机的在图像上去选择点。用Numpy
中的random.choice()
函数产生掩膜mask
来实现。
random.choice()
numpy.random.choice(a, size=None, replace=True, p=None)
a: 整型数值或者一维数组。为数字时,表示生成的mask
中的值,是从np.arange(a)
中根据概率p
随机采样得到的。为一数组时,则表示生成的mask
中的值,是随机选择数组中a
中的一个值,选择概率由p
中对应位置的概率值决定。
size: 生成mask
的大小或输出数组大小,为整型(一维)或者元组(多维)。
replace: 为True
时,输出数组中的元素可以重复,反之不可重复。
p: a
中对应元素的概率,若没有给出,默认它们等概率。
import numpy as np
mask = np.random.choice(99, 100, replace=False)
print(mask)
ValueError: Cannot take a larger sample than population when 'replace=False'
,replace=False
时,a
取值范围应该比size
大。
在添加椒盐噪声的应用中,共有三类点,只需要在mask
中用三个值便可以区分,三个值的概率分别就是椒、盐和原像素出现的概率。类似如下代码:
mask = np.random.choice((0, 1, 2), size=(224, 224, 1), p=[0.1, 0.1, 0.8])
my_transforms.py
import numpy as np
from PIL import Image
class AddSaltPepperNoise(object):
def __init__(self, density=0):
self.density = density
def __call__(self, img):
img = np.array(img) # 图片转numpy
h, w, c = img.shape
Nd = self.density
Sd = 1 - Nd
mask = np.random.choice((0, 1, 2), size=(h, w, 1), p=[Nd/2.0, Nd/2.0, Sd]) # 生成一个通道的mask
mask = np.repeat(mask, c, axis=2) # 在通道的维度复制,生成彩色的mask
img[mask == 0] = 0 # 椒
img[mask == 1] = 255 # 盐
img= Image.fromarray(img.astype('uint8')).convert('RGB') # numpy转图片
return img
调用:
my_transforms.AddSaltPepperNoise(0.2),
transforms.ToTensor(),
结果:
- 添加高斯噪声
高斯噪声,即分布服从正态分布的噪声,是一种非常常见的噪声,其叠加在图像的每一个点上。主要参数有方差、均值和幅值。用numpy.random.normal
函数来产生服从高斯分布的噪声。
random.normal()
numpy.random.normal(loc=0.0, scale=1.0, size=None)
loc: 均值。浮点值或者数组
scale:标准差。浮点值或者数组。
size: 输出尺寸。整型值或者元组。
N = amplitude*numpy.random.normal(loc=mean, scale=variance, size=(224, 224, 1))
my_transforms.py
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 = Image.fromarray(img.astype('uint8')).convert('RGB')
return img
主函数使用:
my_transforms.AddGaussianNoise(mean=0, variance=1, amplitude=20),
transforms.ToTensor(),
结果:
参考
https://pytorch.org/docs/stable/torchvision/transforms.html#torchvision-transforms
https://blog.csdn.net/u012936765/article/details/53200918
https://docs.scipy.org/doc/numpy-1.14.0/reference/generated/numpy.random.normal.html
https://docs.scipy.org/doc/numpy-1.15.0/reference/generated/numpy.random.choice.html#numpy.random.choice
最后
以上就是漂亮小松鼠为你收集整理的深度之眼Pytorch打卡(十二):Pytorch数据预处理——选择与自定义transforms(通过向图片上添加椒盐噪声、高斯噪声增来强数据的数据增强方法)的全部内容,希望文章能够帮你解决深度之眼Pytorch打卡(十二):Pytorch数据预处理——选择与自定义transforms(通过向图片上添加椒盐噪声、高斯噪声增来强数据的数据增强方法)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复