PyTorch入门
PyTorch入门
前言:
会用到的工具包pytorch(导入方式为import torch
,import torchvision
)、numpy、matplotlib.pyplot,os,PIL
参考资料:《深度学习之pytorch实战计算机视觉》
一、Pytorch的tensor类型
正如numpy的nadrry与pandas的dataframe一样,pytorch也有自己的类型叫做tensor,我们认识一样tensor类型如何转化
torch.FloatTensor():
- 这个与
np.array()
类似,当你在括号中输入一个列表他就能帮你转化成浮点型的Tensor类型
- 这个与
torch.IntTensor():
- 在括号中输入一个列表,使得他将这个列表转化成一个整形的Tensor类型
二、pytorch的生成tensor数组
这个也跟numpy中的np.random
类似,下面来演示几个常用的
torch.rand()
- 在括号中输入维度,无需元组括起来,就可以随机生成0-1之间的指定维度的随机浮点数tensor数组
torch.randn()
- 在括号中输入维度,无需元组括起来,就可以随机生成均值为的指定维度的随机浮点数tensor数组
torch.range()
- 在指定的范围内生成等差数列,第一个参数,起始点,第二个参数,终点,第三个参数步长
torch.zeros()
- 类似于np.zeros(),在输入维度后,无需元组括起来,就会生成每个元素的值都为0的指定维度的tensor数组
三、pytorch的运算
加减乘除,数乘,点乘等方法
- 加法:
torch.add()
,参数可输入两个tensor,也可输入一个tensor一个常量 - 绝对值:
torch.abs()
- 裁剪:
torch.clamp()
三个参数:第一个数据集,第二个下界,第三个上界 - 除法:
torch.div()
参数可输入两个tensor,也可输入一个tensor一个常量 - 点乘:
torch.mul()
两个tensor,对应位置相乘,一个常量乘tensor每一个元素的位置 - 求幂运算:
torch.pow()
可两个tensor,也可一个tensor一个常量 - 阵乘法:
torch.mm()
注意维度 - 矩阵乘法(矩阵和向量):
torch.mv()
注意维度
四、pytorch.autofrad()中的Variable对象
Variable(数据集,requires_grad = False)
requires_grad
:为False时,自动梯度计算的过程中不会保留梯度值,Ture时则会保留梯度值- 获取Variable对象a的值:
a.data
,当对象只有一个数据时使用a.item()
- 查看其梯度:
a.grad.data
- 将梯度重置:
a.grad.data.zero_()
五、pytorch自定义模型
需要引入torch.nn.Module
类来完成
- 首先定义一个类,让他继承
torch.nn.Module
这个类 - 假设我们的这个类叫做Model(
class Model(torch.nn.Moduele):
) - 然后我们定义它的初始化方法__init__:用
super
函数来引入父类的初始化方法。(super(Model,self).__init__()
) - 然后用
self.名称 = torch.nn.Sequential(模型内容)
来定义模型 torch.nn.Sequential
表示的是一个容器,比如卷积中的卷积层,池化层,激活层都可以放置在里面,我们还可以设置另一个新的torch.nn.Sequential
来存放全连接层- 在这个容器中我们可以存放很多模型
torch.nn.Linear()
:线性激活,接收参数有三个:输入的特征数,输出的特征数,是否使用偏置(b)torch.nn.ReLU()
:ReLU激活函数torch.nn.Conv2d()
:卷积层:接收参数第一第二分别是输入的通道数,输出的通道数,kernel_size:卷积核(过滤器)大小,stride:步长,padding:填充值torch.nn.MaxPool2d()
:最大池化层,kernel_size:池化窗口大小,stride:步长,padding:填充值torch.nn.Dropout()
:随机失活,p每个节点随机丢失的概率,在卷积神经网络中一般用在全连接层的部分中torch.nn.RNN()
:input_size:输入数据特征数,hidden_size:隐藏层的输出特征数,num_layers:循环层对叠数,默认1,bias:是否使用偏置默认True,batch_first:布尔值,False(序列长度,批次数量,输入或输出特征) True:(批次数量,序列长度,输入或输出特征)torch.nn.Upsample(scale_factor=2,mode="nearest")
- 重采样,用于解压池化层的压缩,
- scale_factor:解压的倍数
- mode:默认nearest(最邻近法),还有linear(线性插值法),bilinear(双线性插值法),trilinear(三线性插值法)
model.parameters()
获得模型中的各个参数
如果想要吧模型放入GPU里面计算,在定义好model后加个.cuda()
,再对Variable对象后面加个.cuda()
六、pytorch损失函数定义(lost function)
torch.nn.MSELoss()
:均方误差函数计算损失值,prew_y,ytorch.nn.L1Loss()
:平均绝对误差torch.nn.CrossEntropyLoss()
:交叉熵- 关于小批量计算损失值的说明:
- 记住最后输出的损失值,应该是使用:$ loss = \frac {每个批量的损失值之和 * 每个批量的样本数}{总样本数}$
七、pytorch.optim参数自动优化
主要类型有:SGD,AdaGrad,RMSProp,Adam
使用流程:
- 在开始训练时,定义优化算法(Adam自动调整learning_rate,但是可以设定lr,其他优化方法也可以),将需要优化的参数作为
# 定义优化参数方法
optimzer = torch.optim.Adam(model.parameter())
# 定义损失函数方法
loss_f = torch.nn.CrossEntropyLoss()
# 在更新参数前使用,将梯度清零
optimzer.zero_grad()
# 计算损失值
loss = loss_f(prev_y,y)
# 计算梯度
loss.backward()
# 更新参数
optimizer.step()
八、 torchvision中的datasets和trainsforms
torchvision是专门用来解决CV(Computer Vision)问题的一个工具包
一般我们使用
from torchvision import trainsforms,datasets
来导入
- transforms用于对导入的数据集进行转化
- 常用方法:
trainsforms.Compose()
转化容器,参数是用列表括起来的转化方式transforms.Resize()
:按照我们的需求对图片进行缩放,一般输入一个(h,w)的参数,h高度,w宽度transforms.Scale()
:和Resize一样transforms.CenterCrop()
:以图片中心为原点按照输入参数的进行裁剪,输入元组宽高transforms.RandomCrop()
:对图片,按照输入参数的尺寸进行随机裁剪transforms.RandomVerticalFlip()
,对载入图片按照随机概率进行垂直翻转,输入的参数随机概率,默认值为0.5- (常用)
transforms.ToTensor()
,对载入的图片数据进行类型转换,将之前的构造PIL图片转换成Tensor数据类型 - (常用)
ransforms.Normalize(mean=[0.5],std=[0.5])
,对数据进行标准化,参数可以修改 transforms.ToPILImage()
用于将tensor变量的数据转化成PIL图片
- 一般使用
transform = transforms.Compose([转化内容])
来定义转化方式 - 获取框架自带的数据集:
data_train = datasets.数据名(root="目录",trannsform=转化方式,train=True(是否为训练集),download=True(从网上下载))
data_test = datasets.数据名(root="目录",transform=转化方式,train=Flase)
九、pytorch装载数据集(data_train为例)
需要的工具:torch.utils.data.DataLoader()
参数: datasets是数据集,batch_size是批量的大小,shuffle是是否进行随机打乱
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)
- 由于我们用plt输出的时候要求图像的维度是(样本数,高度,宽度,通道),但是我们的tensor中是(样本数,通道,高度,宽度)
- 所以我们要使用
img = img.numpy().transpose(1,2,0)
来实现转换plt输出格式,对用GPU训练后的数据,需要在numpy前面加上.cpu() - 然后就可以
plt.imshow(img)
了,如果没有出现图片就加一个plt.show()
-
用于训练、预测
- 首先要了解
enumerate()
函数,他用于返回可迭代对象中的索引和数据,第一个参数输入可迭代对象,第二个参数输入索引起始位置 - 使用for循环:
for batch,data in enumerate(dataloader,1):
遍历这个可迭代对象 - 我们的data由数据集合标签集组成,我们分别用X,y存放
X,y=data
- 将X和y转化成Variable对象,看情况是否加.cuda
- 进行预测:
y_pred = model(X)
- 预测结束后他不会直接告诉我们标签,而是是某个标签的可能性
- 我们要使用
_,pred = torch.max(y_pred.data,1)
来提取- 这个方法可以找到我们指定维度的最大值,然后返回他的值和索引,由于他的索引就是他的标签,因此我们只取索引。
- 他有两个参数,第一个是预测后的数据(input),第二个是指定的维度(dim)
- 首先要了解
十、 模型导入与修改
在计算机视觉领域中,要训练一个好的模型是很耗费时间和精力的,于是我们产生了迁移学习,在别人训练过的模型基础上我们进行再训练,从而使得这个模型倾向于解决我们的问题。
要引用别人的模型,我们需要使用到torchvision中的models
- 引入别人模型
model = models.vgg16(pretrained=True)
- pretrained = True,引入别人已经训练好的参数,需要下载
- 我们要使用别人的模型,但是最后我们输出的特征一般和别人的模型不同,于是我们就要对其进行一定的修改
- 在引入模型之后我们要对未修改的部分进行冻结,使得在训练的过程中只更新我们修改部分的参数而不修改原有的参数
for parma in model.parameters():
parme.requires_grad = False
- 然后修改他们输出的那部分,我们可以用
print(model)
查看他们输出部分的模型叫什么名字 - 使用
model.名字 = torch.nn.Sequential()
进行修改 - 如果我们使用的是卷积模型,就是对全连接层进行修改
model.fc = torch.nn.Sequential(
修改内容(其他的可以不改变,但是在最后输出的一句Linear中我们需要把输出维度改成我们希望的)
)
- 由于其他部分不需要训练参数,但是修改部分需要,于是我们定义optimizer来实现训练修改部分的参数
optimizer = torch.optim.Adam(model.fc.parameters())
十一、OS文件操作
需要的python包os
os.path.dirname()
用于返回目录的目录名os.path.exists()
用于测试输入参数指定的文件是否存在os.path.isdir()
用于测试输入参数是否是目录名os.path.isfile()
用于测试输入参数是否为一个文件os.path.samefile()
用于测试两个输入的路径参数是否指向同一个文件os.path.split()
用于对输入参数中的目录名进行分割,返回一个元组,元组由目录名和文件名组成os.path.join()
将输入参数中的两个名字拼接成一个完整的文件路径
十二、从外部导入数据
分为两种,提取单个数据和提取数据集,需要PIL中的Image
-
提取单个数据:
- 定义转换方式transform
- 导入图片
img = Image.open("路径")
- 对图片进行转换
img =tranform(img)
- 因为我们的图片可能不只一张,于是我们需要提高他的维度
img = img.unsqueeze(0)
在0维度前增加一个维度,0的数值可以修改- 这样提取一张的步骤就完成了
-
提取数据集
- 定义数据集路径(到数据集所在文件夹即可,这里的文件夹中还有子文件夹,子文件夹中的子文件夹分别表示他们的标签)
- 定义转化方式transform,以字典的形式
- 然后无脑执行以下操作(在我的文件夹中包含train和valid的两个子文件夹,这两个子文件夹中还有两个不同的标签的文件夹)
# 转换类型
data_transform = {x:transforms.Compose([transforms.Resize([224,224]),transforms.ToTensor(),transforms.Normalize(mean=[0.5],std=[0.5])]) for x in ["train","valid"]}
# 打开文件并转换
image_datasets = {x:datasets.ImageFolder(root = os.path.join(data_dir,x),transform=data_transform[x]) for x in ["train","valid"]}
# 装载数据
dataloader = {x:torch.utils.data.DataLoader(dataset = image_datasets[x],batch_size=16,shuffle=True) for x in ["train","valid"]}
模型保存与引入
保存整个模型:torch.save(model,Path)
保存模型参数:torch.save(net.state_dict(),Path)
加载整个模型:model = torch.load(Path)
加载参数:model = model.load_state_dict(torch.load(Path))