10.常见的Transforms(一)
我们以图像举例子,不同的图片之间数据分布差异是很大的,有些图片的像素值普遍偏大,而有些图片的像素值偏小。③编写代码,使用Python自带的图片打开方式,然后运行UsefulTransforms,控制台可以看到该图片是PIL格式,大小是889x500,接下来介绍Transforms。使用归一化的目的是将输入数据进行标准化,使输入的数据具有相似的分布。所以在将不同的图片送给神经网络进行推理之前,我们也
常见的Transforms(一)
常见的Transforms想要更好地使用它,也就是使用好它的各个类(Compose、ToTensor、ToPILImage等),我们需要关注以下三个点
- 输入
- 输出
- 作用

图片有不同的格式,打开方式也不同,需要去关注不同的方法让你输入什么类型,输出什么类型
| 图片格式 | 打开方式 |
|---|---|
| PIL | Image.open() ——Python自带的图片打开方式 |
| tensor | ToTensor() |
| narrays | cv.imread() ——Opencv |
案例
①在pycharm项目里面新建一个文件夹image,网上随便找张图片放进该文件夹

②新建一个名为UsefulTransforms的python文件

③编写代码,使用Python自带的图片打开方式,然后运行UsefulTransforms,控制台可以看到该图片是PIL格式,大小是889x500,接下来介绍Transforms
from PIL import Image
img = Image.open("image/pytorch.png")
print(img) # 可以看到类型是PIL


1.Compose 的使用
Compose类就是把不同的 transforms 结合在一起,后面接一个数组,里面是不同的transforms
Example:图片首先要经过中心裁剪,再转换成Tensor数据类型
>>> transforms.Compose([
>>> transforms.CenterCrop(10),
>>> transforms.PILToTensor(),
>>> transforms.ConvertImageDtype(torch.float),
>>> ])

可以看到Compose类里有很多函数,例如初始化__init__, call ,主要说明一下__call__ 的使用

在项目里面新建一个文件夹Test,再创建一个名为CallTest的python文件
class Person:
def __call__(self, name): # 下划线__表示为内置函数
print("__call__" + "Hello " + name)
def hello(self, name): #再自己定义一个函数用来和__call__对比
print("hello" + name)
person = Person() #创建一个person对象,下面用两种方式调用
person("zhangsan") #调用内置函数,如果类定义了内置函数,只需要用对象和需要的属性就可以调用
person.hello("lisi") #调用hello

输出结果如下:

按 Ctrl+p,会提示需要什么参数

2.ToTensor 的使用
ToTensor可以把 PIL Image 或 numpy.ndarray 类型转换为 tensor 类型(转换的原因是因为TensorBoard 必须是 tensor 的数据类型)(运行前要先把之前的logs进行删除)
from PIL import Image
from torch.utils.tensorboard import SummaryWriter
from torchvision import transforms
writer = SummaryWriter("logs")
img = Image.open("images/pytorch.png")
print(img) # 可以看到类型是PIL
# ToTensor的使用
trans_totensor = transforms.ToTensor() # 将类型转换为tensor
img_tensor = trans_totensor(img) # img变为tensor类型后,就可以放入TensorBoard当中
writer.add_image("ToTensor", img_tensor)
writer.close()

运行后,在 Terminal 里输入:
tensorboard --logdir=logs


进入网址后可以看到图片

3.ToPILImage 的使用
与ToTensor的作用相反,ToPILImage 可以把 tensor 数据类型或 ndarray 类型转换成 PIL Image
imagePIL = ToPILImage()(img_tensor)#把tensor数据类型转换回PIL Image
print(imagePIL)
print(img_tensor)

运行后可以看到图片在tensor 数据类型和 PIL Image类型之间成功转换了

4.Normalize(归一化) 的使用
Normalize作用
在深度学习中,推理或训练之前对图像进行预处理,特别是归一化,是一种非常常见的操作。使用归一化的目的是将输入数据进行标准化,使输入的数据具有相似的分布。
我们以图像举例子,不同的图片之间数据分布差异是很大的,有些图片的像素值普遍偏大,而有些图片的像素值偏小。数据分布的不同,会导致神经网络在训练或者推理时出现较大的偏差,有时会导致训练收敛困难,推理误差较大。
所以在将不同的图片送给神经网络进行推理之前,我们也需要对不同的图片中数据分布进行归一化,以纠正不同图片样本之间的数据偏差,从而使得模型更好地完成推理。
T.Normalize(mean, std)

输入(channel,height,width)形式的tensor,并输入每个channel对应的均值和标准差作为参数,函数会利用这两个参数分别将每层标准化(使数据均值为0,方差为1)后输出。即计算公式:

Normalize所需参数
- mean:(list)长度与输入的通道数相同,代表每个通道上所有数值的平均值。
- std:(list)长度与输入的通道数相同,代表每个通道上所有数值的标准差。
将每个通道的均值和标准差作为参数输入,即可使每个通道标准化,即均值为0,方差为1
为何有时参数是固定的0.5?
有时我们会设置传入的mean和std为固定值0.5,是因为把0.5代入带入上面的公式可以得到
output= 2*input -1
如果我们的input 图片像素值为[0,1]范围内,那么经过归一化之后结果即可在[-1 , 1]之间
即将两个参数都设置为0.5并与transforms.ToTensor()一起使用可以使将数据强制缩放到[-1,1]区间上。(标准化只能保证大部分数据在0附近——3σ原则)
这个用法实际上并不是这个函数的本意,只是借用了(x-mean)/std这个公式。
首先,ToTensor可以将图像的值从[0,255]通过out = in/255缩放到[0,1],之后再通过区间化公式:

该式可以使X缩放到范围[a,b]
将[0,1]缩放到[-1,1]:将a=-1,b=1带入上式即可得到x_new = (x-0.5)/0.5,即mean和std都设置为0.5
归一化步骤
- 创建PIL型图片
- 使用ToTensor转换为tensor型对象
- 使用transforms.Normalize(means, std )实例化Normalize对象norm_tool中
- 把tensor图像传入norm_tool中进行归一化处理
- 使用tensorboard可视化图像
代码
#Normalize的使用
print(img_tensor[0][0][0]) # 第0层第0行第0列
trans_norm = transforms.Normalize([0.5,0.5,0.5],[0.5,0.5,0.5]) # mean,std,因为图片是RGB三信道,故传入三个数
img_norm = trans_norm(img_tensor) # 参数输入的类型要是tensor
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm)#添加转化后的照片

运行后可以看到,第一行是没有归一化的数据,下面一行是经过归一化的结果:

output= 2*input -1
0.655=2*0.8275-1
打开tensorboard 网页,结果如下,可以看到经过归一化后的图片产生了明显的变化。

加入step值:
为了让归一化结果更加明显,我们再创建2个step,并且依次修改不同的mean和std,查看对应结果
第一步
#Normalize的使用
print(img_tensor[0][0][0]) # 第0层第0行第0列
trans_norm = transforms.Normalize([4,6,7],[3,2,6]) # mean,std,因为图片是RGB三信道,故传入三个数
img_norm = trans_norm(img_tensor) # 输入的类型要是tensor
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm,1)#第一步

运行结果:

第二步
#Normalize的使用,,需要输入均值mean和标准差std
print(img_tensor[0][0][0]) # 第0层第0行第0列
trans_norm = transforms.Normalize([6,3,2],[9,3,5]) # mean,std,因为图片是RGB三信道,故传入三个数
img_norm = trans_norm(img_tensor) # 参数输入的类型要是tensor
print(img_norm[0][0][0])
writer.add_image("Normalize",img_norm,2)#第二步

运行结果:

对比step 0到step 2,可以看到每一个step的图片都是不一样的。
更多推荐


所有评论(0)