PyTorch主要模块

一,深度学习任务流程

PyTorch的强大使得深度学习任务像搭积木一样。

机器学习流程:一般分为这几个步骤:数据加载—数据预处理—划分数据集—选择模型—定义损失函数,优化器,超参数—验证评估

ML与DL的不同
1,数据:由于DL所需数据量大,所以需要按批(batch)读取;
2,模型:DL的网络层数较深,且有特定功能的网络层,就跟盖房子一样,需要逐层搭建,或预定义模块再组装;
3,加速:DL由于数据大,模型深,所以需要加速,需要
GPU
并行运算等。

深度学习流程:流程类似于ML,按批读入数据—模型构建—放入GPU中训练—损失函数反向传播—优化器—训练/验证—调整评估

二,基本流程

1,基本配置

导包:涉及表格的可能用pandas,图片可能用到cv2,可视化可能用matplotlib,seaborn等。但是以下包基本是深度学习项目必须的;

import os
import numpy as np
import torch
import torch.nn as nn
from torch.utils.data import Dataset, DataLoader #数据加
import torch.optim as optimizer #优化器

超参数设置:超参数统一设置,方便后续调试修改:

  1. batch size=16 # 批次大小
  2. lr = 1e-4 # 初始学习率
  3. epochs = 100 # 训练次数

GPU配置:常见有两种方式

# 方案一:使用os.environ,这种情况如果使用GPU不需要设置,0表示显卡0,1表示显卡1.用几块写几块。
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'

# 方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可,model.to_device(device)
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")

2,数据读入

PyTorch通过Dataset+DataLoader读取数据。
Dataset定义好数据的格式和数据变换形式,DataLoader用iterative的方式不断读入批次数据
Dataset:有两种数据读取方式:
1,下载并使用Pytorch提供的内置数据集,需要继承PyTorch自身的Dataset类
2,定义自己的Dataset类实现灵活数据读取。同时还要对数据进行必要的变换,比如说将图片统一成一致的大小。需要将图片转化为Tensor类,具体可以看实战部分。
主要包含三个函数:

  • init: 用于向类中传入外部参数,同时定义样本集
  • getitem: 用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据
  • len: 用于返回数据集的样本数

DataLoader:构建好Dataset后,就可以使用DataLoader来按批次读入数据了,实现代码如下:

from torch.utils.data import DataLoader

train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=4, shuffle=True, drop_last=True)
val_loader = torch.utils.data.DataLoader(val_data, batch_size=batch_size, num_workers=4, shuffle=False)
  • batch_size:样本是按“”读入的,batch_size就是每次读入的样本数
  • num_workers:有多少个进程用于读取数据
  • shuffle:是否将读入的数据打乱
  • drop_last:对于样本最后一部分没有达到批次数的样本,使其不再参与训练

3,模型构建

PyTorch中神经网络构造基于** Module 类**的模型来完成的,Module 类是 nn 模块里提供的一个模型构造类,是所有神经⽹络模块的基类。神经网络通过层定义+层顺序的方式进行构建。

不含模型参数的层: MyLayer 类通过继承 Module 类自定义了一个将输入减掉均值后输出的层,并将层的计算定义在了 forward 函数里。这个层里不含模型参数。

import torch
from torch import nn

class MyLayer(nn.Module):
    def __init__(self, **kwargs):
        super(MyLayer, self).__init__(**kwargs)
    def forward(self, x):
        return x - x.mean()  

含模型参数的层:自定义含模型参数的自定义层。其中的模型参数可以通过训练学出。Parameter 类其实是 Tensor 的子类,如果一 个 Tensor 是 Parameter ,那么它会⾃动被添加到模型的参数列表里。

class MyListDense(nn.Module):
    def __init__(self):
        super(MyListDense, self).__init__()
        self.params = nn.ParameterList([nn.Parameter(torch.randn(4, 4)) for i in range(3)])
        self.params.append(nn.Parameter(torch.randn(4, 1)))

    def forward(self, x):
        for i in range(len(self.params)):
            x = torch.mm(x, self.params[i])
        return x
net = MyListDense()
print(net)

关键参数解释

  • torch.Tensor - 一个多维数组,支持诸如backward()等的自动求导操作,同时也保存了张量的梯度
  • nn.Module - 神经网络模块。是一种方便封装参数的方式,具有将参数移动到GPU、导出、加载等功能。
  • nn.Parameter - 张量的一种,当它作为一个属性分配给一个Module时,它会被自动注册为一个参数。
  • autograd.Function - 实现了自动求导前向和反向传播的定义,每个Tensor至少创建一个Function节点,该节点连接到创建Tensor的函数并对其历史进行编码。

4,模型初始化

一个好的权重值,会使模型收敛速度提高,使模型准确率更精确。使用torch.nn.init。
torch.nn.init使用:根据实际模型来使用torch.nn.init进行初始化,通常使用isinstance来进行判断模块属于什么类型。

import torch
import torch.nn as nn

conv = nn.Conv2d(1,3,3)
linear = nn.Linear(10,1)

isinstance(conv,nn.Conv2d)
isinstance(linear,nn.Conv2d)

对于不同的类型层,我们就可以设置不同的权值初始化的方法。

# 查看随机初始化的conv参数
conv.weight.data
# 查看linear的参数
linear.weight.data

# 对conv进行kaiming初始化
torch.nn.init.kaiming_normal_(conv.weight.data)
conv.weight.data
# 对linear进行常数初始化
torch.nn.init.constant_(linear.weight.data,0.3)
linear.weight.data

初始化函数封装:将各种初始化方法定义为一个initialize_weights()的函数并在模型初始后进行使用。如下代码遍历当前模型的每一层,然后判断各层属于什么类型,然后根据不同类型层,设定不同的权值初始化方法。

def initialize_weights(self):
	for m in self.modules():
		# 判断是否属于Conv2d
		if isinstance(m, nn.Conv2d):
			torch.nn.init.xavier_normal_(m.weight.data)
			# 判断是否有偏置
			if m.bias is not None:
				torch.nn.init.constant_(m.bias.data,0.3)
		elif isinstance(m, nn.Linear):
			torch.nn.init.normal_(m.weight.data, 0.1)
			if m.bias is not None:
				torch.nn.init.zeros_(m.bias.data)
		elif isinstance(m, nn.BatchNorm2d):
			m.weight.data.fill_(1) 		 
			m.bias.data.zeros_()	

5,损失函数

二分类交叉熵损失函数:计算二分类任务时的交叉熵(Cross Entropy)函数。在二分类中,label是{0,1}。对于进入交叉熵函数的input为概率分布的形式。一般来说,input为sigmoid激活层的输出,或者softmax的输出。

torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
# weight:每个类别的loss设置权值
# size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和
# reduce:数据类型为bool,为True时,loss的返回是标量。

交叉熵损失函数:交叉熵函数

torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
ignore_index:忽略某个类的损失函数

L1损失函数:计算输出y和真实标签target之间的差值的绝对值。

torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
# reduction有三种计算模式可选
# none:逐个元素计算。sum:所有元素求和,返回标量。mean:加权平均,返回标量。默认求平均

MSE损失函数:计算输出y和真实标签target之差的平方。

torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
# reduction参数与L1一样

平滑L1 (Smooth L1)损失函数: L1的平滑输出,其功能是减轻离群点带来的影响

torch.nn.SmoothL1Loss(size_average=None, reduce=None, reduction='mean', beta=1.0)

目标泊松分布的负对数似然损失: 泊松分布的负对数似然损失函数

torch.nn.PoissonNLLLoss(log_input=True, full=False, size_average=None, eps=1e-08, reduce=None, reduction='mean')
# log_input:输入是否为对数形式,决定计算公式
# full:计算所有 loss,默认为 False
# eps:修正项,避免 input 为 0 时,log(input) 为 nan 的情况

KL散度:计算KL散度,也就是计算相对熵。用于连续分布的距离度量,并且对离散采用的连续输出空间分布进行回归通常很有用。

torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False)
# reduction:计算模式,可为 none/sum/mean/batchmean

MarginRankingLoss:计算两个向量之间的相似度,用于排序任务。该方法用于计算两组数据之间的差异。

torch.nn.MarginRankingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

多标签边界损失函数: 对于多标签分类问题计算损失函数

torch.nn.MultiLabelMarginLoss(size_average=None, reduce=None, reduction='mean')

二分类损失函数:计算二分类的 logistic 损失

torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')torch.nn.(size_average=None, reduce=None, reduction='mean')

多分类的折页损失:计算多分类的折页损失

torch.nn.MultiMarginLoss(p=1, margin=1.0, weight=None, size_average=None, reduce=None, reduction='mean')

三元组损失: 计算三元组损失

torch.nn.TripletMarginLoss(margin=1.0, p=2.0, eps=1e-06, swap=False, size_average=None, reduce=None, reduction='mean')

HingEmbeddingLoss:对输出的embedding结果做Hing损失计算

torch.nn.HingeEmbeddingLoss(margin=1.0, size_average=None, reduce=None, reduction='mean')

余弦相似度:对两个向量做余弦相似度

torch.nn.CosineEmbeddingLoss(margin=0.0, size_average=None, reduce=None, reduction='mean')

CTC损失函数:用于解决时序类数据的分类

torch.nn.CTCLoss(blank=0, reduction='mean', zero_infinity=False)

注:具体公式及理解后续赘述。

6,训练与评估

训练:训练状态,那么模型的参数应该支持反向传播的修改

model.train()   # 训练状态

评估:验证/测试状态,则不应该修改模型参数

model.eval()   # 验证/测试状态

训练流程

# 用for循环读取DataLoader中的全部数据
for data, label in train_loader:

# 将数据放到GPU上用于后续计算
data, label = data.cuda(), label.cuda()

# 用当前批次数据做训练时,应当先将优化器的梯度置零
optimizer.zero_grad()

# 将data送入模型中训练
output = model(data)

# 预先定义的criterion计算损失函数
loss = criterion(output, label)

# 将loss反向传播回网络:
loss.backward()

# 使用优化器更新模型参数:
optimizer.step()

评估流程:验证/测试的流程基本与训练过程一致,不同点在于:

  • 需要预先设置torch.no_grad,以及将model调至eval模式
  • 不需要将优化器的梯度置零
  • 不需要将loss反向回传到网络
  • 不需要更新optimizer

7,可视化

一般为了便于观察,通常会使用可视化的方式,将结果更直观的展现出来。比如分类的ROC曲线,以及训练验证过程中的损失函数曲线等。
:关于可视化,后续会专门出一节。

三,PyTorch基础实战

基础实战——Fashion-mnist时装分类

文章链接:基础实战——Fashion-mnist时装分类。

你可能感兴趣的:(pytorch深度学习,pytorch,深度学习,人工智能)