PyTorch计算机视觉训练中的基础知识点和细节

一般用pytorch进行深度学习的简单流程大概是:
先使用训练数据对搭建好的神经网络模型进行训练并完成参数优化;然后使用优化好的模型对测试数据进行预测,对比预测值和真实值之间的损失值,同时计算出结果预测的准确率。

预备知识

  1. pytorch中图像处理主要用到两个核心库,torch和torchvision
  2. torch.nn中的类是实现网络搭建的核心类
  3. torchvision主要实现数据处理,导入和预览等

对于一般的数据集如MNIST,COCO,ImageNet,CIFCAR等都可以通过torchvision.datasets快速下载

from torchvision import datasets 
data_train  = datasets.MNIST(
  			root='../data/',#指定数据集下载之后存放的路径
  			transfrom = transform,#指定导入数据集时需要对数据进行哪种变换
  			train = True,#指定数据集下载完成之后需要载入哪一部分数据
  			download = True
)

torch.transforms

torch.transforms 中提供了丰富的类对载入数据进行变换,之所以要进行数据变换,是因为不同的网络对于输入图像的大小尺寸,通道数要求不一样
pytorch中的要求的图像数据的格式为
[batch,channels,height,width]
(1)torchvison.transforms.Resize:对于载入的图片数据按我们需求的大小进行缩放。
输入参数:整型数据或者类似于(h,w)的序列,其中h为高度,w为宽度,但是如果使用的是一个整型数据,那么表示缩放的宽度和高度都是这个整型数据值

(2)torchvison.transforms.Scale:用于对载入的图片数据按我们需求的大小进行缩放,用法与Resize类似,但是现在使用Scale会提示你,这个函数已经不推荐使用了,所以一般读取图像数据后,如果要进行图像的缩放,推荐使用Resize,同时,numpy和opencv中也有很多缩放的工具

(3)torchvision.transforms.CenterCrop:用于对载入的图片以图片中心为参考点,按我们需要的大小进行裁剪。
输入参数:同(1)

(4)torchvision.transfroms.RandomCrop:用于对载入的图片按我们需要的大小继续随机裁剪。
输入参数:同(1)

(5)torchvision.transforms.RandomHorizontalFilp:用于对载入的图片按随机概率机芯水平翻转。
输入参数:可以自定义一个概率值,默认是0.5

(6)torchvision.transforms.RandomVerticalFilp:用于对载入的图片按随机概率进行垂直翻转。
输入参数:同(5)

(7)torchvision.transforms.ToTensor:用于对载入的图片数据进行类型转换,将之前构成PIL图片的数据转换成Tensor数据类型的变量,让Pytorch能够对其进行计算和处理

(8)torchvision.transforms.ToPILImage:用于将Tensor变量的数据转换成PIL图片

细节点:

采用opencv或者PIL读取图像数据,有以下需要注意的点:
1.opencv读取图像不管是灰度图还是RGB彩图,都默认读成彩图,因此在特定任务下需要对图像通道进行改变。而且通过cv2加载的图片,默认色道格式为BGR,可通过cv2.cvtColor函数进行转换;通过PIL加载的图片,默认色道格式为RGB,可通过图像的convert方法进行转换。
2.opencv读取图像后,数据类型是
PIL读取图像后数据类型是
3.PIL读取图像(不论是灰度图还彩色图)不显示通道数,而opencv在读取灰度图时不显示通道数,但转换成tensor之后,会显示(而且通常是第一个维度为通道数,之后再进行扩展维度,将batch加入到tensor之中后,便可以送入训练好的模型进行测试)
4.将图像数据加载转换为tensor时(不采用transforms变换时),需要进行transpose,即扩充图像数据维度使其变成pytorch希望的图像数据形式[batch,channels,height,width]
5.读取的图像都可以直接通过torchvision.transfroms这个图像预处理工具进行变换,效率较高,同时这里有个魔鬼细节由上述(7)(8)也可以看出这一点,pytorch比较支持PIL与tensor的转换,transfroms.Compose只接受PIL转换来的图像也就是输入数据类型要是****

from torchvision import transfroms 
#数据变换
normalize = transforms.Normalize(mean=[0.5,0.5,0.5], std=[0.5, 0.5, 0.5])#用于标准化
transfrom = transforms.Compose(
					transfroms.Resize(size=[28,28]),#对图像大小进行缩放
					transfroms.ToTensor(),#转换成tensor
					nomalize#标准化,可自定义,如上所示
					)
#读取图像
#采用PIL
img = Image.open(path)#如需要转换成RGB则.convert('RGB'),如需转换成GRAY,则.convert('L')
img = transform(img)#数据变换
img = img.unsqeeze(0)#升维 ,dim=0之前加一维

#采用opencv
img = cv.imread(path)#读取数据
img = cv.cvtColor(img,cv.COLOR_BGR2GRAY)#彩图换成灰度图
#细节点,opencv读取图像数据后的输出是ndarray数组,需要将其转换成PIL.Image.Image类型
img = Image.fromarray(img)#转换成PIL类型
img = transfrom(img)#数据变换
img = img.unsqeeze(0)

有些步骤熟练了可以直接连着写,看起来就会比较简洁

数据预览和数据装载

数据下载完成之后,还需要对数据进行装载。
我们可以理解为,数据载入是对图片的处理,在完成处理之后,我们需要将这些图片打包好送入模型进行训练,而装载就是打包的过程
数据的装载使用的是torch.utils.data.DataLoader类

data_loader_train = torch.utils.data.DataLoader(
				dataset=data_train,#指定载入的数据集名称
				batch_size = 64,#设置每个包中的图片数据个数
				shuffle = True)#表示装载过程中会将数据随机打乱顺序并进行打包
数据预览
images , labels = next(iter(data_loader_train))
img = torchvision.utils.make_grid(images)

‘’’
iter,next获取一个批次的图片数据和其对应的图片标签
torchvision.utils中的make_gird类方法将一个批次的图片构造成网格模式。
需要输入的参数是一个批次的装载数据,每个批次的装载数据都是4维的,分别是batch_size,channel,height,weight ,对应一个批次中的数据个数,每张图片的色彩通道,每张图片的高度和宽度。
经过torch.utils.make_grid之后,图片维度变成了(channel,height,weight),这个批次的图片全部被整合到一起,所以在这个维度中对应的值也和以前不一样了,但是色彩通道数保持不变

若要用matplotlib将数据显示成正常图片格式,则使用的数据首先必须是数组,其次这个数组的维度必须是(height,weight,channel),即色彩通道数在最后面。所以还需要通过numpy和transpose完成原始数据类型的转换和数据维度的交换

如果是读取灰度图,即通道数为1的图像,那么在用matplotlib显示图像时,需要将cmap赋值为’gray’,不然显示出来的图像色彩会有偏差

plt.imshow(img,cmap='gray')
plt.show()

模型搭建

搭建模型是使用torch.nn中的类来完成的,例如:
卷积层使用torch.nn.Conv2d类方法搭建
激活层使用torch.nn.ReLU类方法搭建
池化层使用torch.nn.MaxPool2d类方法搭建
全连接层使用torch.nn.Linear类方法搭建
其他自定义的结构,都可以通过组合卷积池化等自定义

同时常用的方法,还可以在nn.functional中找到
部分的具体方法解释如下(均在torch.nn中):

(1)卷积层

常见的如下:

Conv2d:
主要的输入参数:输入通道数,输出通道数,卷积核大小,卷积核移动步长和Padding的值。
其中输入通道数和输出通道数是整型,分别用于确定输入数据的层数和输出数据的层数。
卷积核大小的数据类型是整型,用于确定卷积核的大小
卷积核移动步长的数据类型是整型,用于确定卷积核每次滑动的步长
Paddingde的数据类型是整型,值为0表示不进行边界像素的填充,值大于0表示增加数字所对应边界像素层数

(2)激活层

ReLU:
既可以直接从nn模块调用ReLU,也可以从nn.functional中调用relu,这两个在构建模型激活层的作用是一样的。
Sigmoid:
与ReLU一样,可以nn.Sigmoid也可以nn.functional.sigmoid

(3)池化层

常用的有MaxPool2d和
MaxPool2d:用于实现CNN中的最大池化层
主要输入参数:池化窗口大小,池化窗口移动步长和Paddingde值

(4)全连接层

Linear::对传入的数据应用线性变换:
y = x A T + b y = xA^T + b y=xAT+b也就是实现全连接的目的
主要输入参数:输入大小,输出大小,偏差默认为True,表示需要学习偏差

(5)Dropout

用于防止CNN在训练过程中发生过拟合,其工作原理简单来说就是在模型训练过程中,以一定的随机概率将CNN的部分参数归零,以达到减少相邻两层神经连接的目的
输入参数:概率值,默认为0.5

model搭建

eg:

import torch.nn as nn
from torch.nn.functional as F
#LeNet5最初是用于解决手写数字集MNIST的10分类任务,输入是1×32×32的灰度图像
class LeNet5(nn.Module):
	def __init__(self):
		super(LeNet5,self).__init__()
		self.conv1 = nn.Conv2d(1,6,5)#output 6*28*28
		self.pool1 = nn.MaxPool2d(2,2)#output 6*14*14
		self.conv2 = nn.Conv2d(6,16,5)#output 16*10*10 
		self.pool2 = nn.MaxPool2d(2,2)#output 16*5*5
		self.fc1 = nn.Linear(120)#output 120
		self.fc2 = nn.Linear(84)#output 84
		self.fc3 = nn.Linear(10)#output 10
	def forward(self,x):
		x = self.conv1(x)
		x = F.relu(x)
		x = self.pool1(x)
		x = self.conv2(x)
		x = F.relu(x)
		x = self.pool2(x)
		x = x.view(16*5*5)
		x = F.relu(self.fc1(x))
		x = F.relu(self.fc2(x))
		x = self.fc3(x)
		return x
	

可以看出上面这种代码风格还是比较详细的,下面试试另一种代码风格,让model变得更加简洁一点

class LeNet5(nn.Module):
	def __init__(self):
		self.conv = nn.Sequential(
		 				nn.Conv2d(),
		 				nn.ReLU(),
		 				nn.MaxPool(),
		 				nn.Conv2d(),
		 				nn.ReLU(),
		 				nn.MaxPool()		
		)
		self.dense = nn.Sequential(
						nn.Linear(),
						nn.ReLU(),
						nn.Linear(),
						nn.ReLU(),
						nn.Linear()
		)
	def forward(self,x):
		x = self.conv(x)
		x = x.view(-1,16*5*5)
		x = self.dense(x)
		return x 

更多详细介绍请参考PyTorch官方文档
PyToch官方文档

你可能感兴趣的:(pytorch,计算机视觉,深度学习)