Task02:pytorch基础模块
机器学习一般流程
基本配置
导入必要的数据处理包,常见的有如下几种
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
对于深度学习任务,一般有几个超参数可以统一设置,主要有
- batch size
- 初始学习率
- 训练次数
- GPU配置
参数可统一设置为
batch_size = 16
lr = 1e-4
max_epochs = 100
GPU设置有两种常见方式,
# 方案一:使用os.environ,这种情况如果使用GPU不需要设置
os.environ['CUDA_VISIBLE_DEVICES'] = '0,1'
# 方案二:使用“device”,后续对要使用GPU的变量用.to(device)即可
device = torch.device("cuda:1" if torch.cuda.is_available() else "cpu")
数据读入
主要指通过Dataset和Dataloader方式读入数据
- Dataset:定义数据格式、数据变换形式
- Dataloader:以iterative方式读入数据
Dataset类主要包括三个函数 __init__
:向类中传入外部参数,同时定义样本集__getitem__
:逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据__len__
:返回样本集的样本数
Dataloader类主要属性- batch_size:样本按“批”读入,指每次读入的样本数
- num_workers:用于读取数据的进程数
- shuffle:是否将样本数据打乱
- drop_last:抛弃最后一部分未达到批次数的样本
模型构建
构造神经网络
pytorch中神经网络构造基于Module类模型进行。Module 类是 nn 模块里提供的一个模型构造类,是所有神经⽹网络模块的基类。
这里主要是通过一个简单实例,认识pytorch中的神经网络模型,多层感知机,创建模型参数,前向计算任务。
神经网络中的常见层
- 不含模型参数的层
- 含模型参数的层
- 二维卷积层
将输入和卷积核做互相关运算,加上一个标量偏差得到输出。模型参数包括卷积核和标量偏差,训练模型时,通常对卷积核随机初始化,迭代运算卷积核和偏差。
卷积窗口形状为 p × q p \times q p×q,卷积核的高和宽分别为 p p p和 q q q。
填充:在输入的高和宽的两侧填充元素(通常为0)
卷积核的高和宽不同时,通过设置相应的不同填充数使输入和输出具有相同的高和宽。
二维互相关运算中,卷积窗口从输入数组的最左上方开始,按从左往右、从上往下 的顺序,依次在输⼊数组上滑动。我们将每次滑动的行数和列数称为步幅(stride)。
步幅:在输出的高和宽的两侧减少元素 - 池化层
每次对输入数据一个固定形状窗口(池化窗口)中的元素计算输出。
直接计算池化窗口内元素的最大值或者均值,对应运算分别称为最大池化或者平均池化。
在二维最⼤池化中,池化窗⼝口从输⼊数组的最左上⽅方开始,按从左往右、从上往下的顺序,依次在输⼊数组上滑动。当池化窗口滑动到某⼀位置时,窗口中的输入子数组的最大值即输出数组中相应位置的元素。
torch.nn
包用来构建神经网,只支持小批量样本输入,不支持单个样本输入,而nn
包则依赖于autogrand
来定义模型并对进行求导。
模型示例
一个神经网络的典型训练过程包括:
- 定义包含一些可学习参数(或者叫权重)的神经网络
- 输入数据集进行迭代
- 通过网络处理输入数据
- 计算 loss (输出和正确答案的距离)
- 将梯度反向传播给网络的参数
- 使用规则更新网络的权重
LeNet
一些模块
torch.tensor
:一个多维数组,支持诸如backward()等的自动求导操作,同时也保存了张量的梯度nn.module
:神经网络模块。是一种方便封装参数的方式,具有将参数移动到GPU、导出、加载等功能nn.parameter
:张量的一种,当它作为一个属性分配给一个Module时,它会被自动注册为一个参数auto.function
:实现了自动求导前向和反向传播的定义,每个Tensor至少创建一个Function节点,该节点连接到创建Tensor的函数并对其历史进行编码
AlexNet
损失函数
模型的负反馈
二分类交叉熵损失函数
torch.nn.BCELoss(weight=None, size_average=None, reduce=None, reduction='mean')
#功能:计算二分类任务时的交叉熵(Cross Entropy)函数。在二分类中,label是{0,1}。对于进入交叉熵函数的input为概率分布的形式。一般来说,input为sigmoid激活层的输出,或者softmax的输出
#主要参数: weight:每个类别的loss设置权值
#size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。
#reduce:数据类型为bool,为True时,loss的返回是标量
计算公式(形式有误)
KaTeX parse error: Expected '}', got '\right' at position 180: … } \end{array} \̲r̲i̲g̲h̲t̲.
交叉熵损失函数
torch.nn.CrossEntropyLoss(weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='mean')
#功能:计算交叉熵函数
#主要参数: weight:每个类别的loss设置权值。
#size_average:数据为bool,为True时,返回的loss为平均值;为False时,返回的各样本的loss之和。
#ignore_index:忽略某个类的损失函数。
#reduce:数据类型为bool,为True时,loss的返回是标量
计 算 公 式 如 下 : loss ( x , class ) = − log ( exp ( x [ class ] ) ∑ j exp ( x [ j ] ) ) = − x [ class ] + log ( ∑ j exp ( x [ j ] ) ) 计算公式如下: \operatorname{loss}(x, \text { class })=-\log \left(\frac{\exp (x[\text { class }])}{\sum_{j} \exp (x[j])}\right)=-x[\text { class }]+\log \left(\sum_{j} \exp (x[j])\right) 计算公式如下:loss(x, class )=−log(∑jexp(x[j])exp(x[ class ]))=−x[ class ]+log(j∑exp(x[j]))
损失函数
torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')
#功能: 计算输出y和真实标签target之间的差值的绝对值
#reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。 mean:加权平均,返回标量。 如果选择none,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均
L n = ( ∣ x n − y n ∣ g ) L_{n} =( | x_{n}-y_{n}|g) Ln=(∣xn−yn∣g)
MSE损失函数
torch.nn.MSELoss(size_average=None, reduce=None, reduction='mean')
#功能:计算输出y和真实标签target之差的平方
#reduction参数决定了计算模式。有三种计算模式可选:none:逐个元素计算。 sum:所有元素求和,返回标量。默认计算方式是求平均
l n = ( x n − y n ) 2 l_{n}=\left(x_{n}-y_{n}\right)^{2} ln=(xn−yn)2
平滑L1 (Smooth L1)损失函数
目标泊松分布的负对数似然损失
KL散度
MarginRankingLoss
多标签边界损失函数
二分类损失函数
多分类的折页损失
三元组损失
HingEmbeddingLoss
余弦相似度
CTC损失函数
pytorch优化器
优化器
通过不断改变网络参数,使得参数能够对输入做各种非线性变换拟合输出,进而寻找最优解。
方法:
- 暴力求解
- BP+优化器逼近求解
就是根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值,使得模型输出更加接近真实标签
pytorch优化器
库torch.optim
提供的优化器有
- torch.optim.ASGD
- torch.optim.Adadelta
- torch.optim.Adagrad
- torch.optim.Adam
- torch.optim.AdamW
- torch.optim.Adamax
- torch.optim.LBFGS
- torch.optim.RMSprop
- torch.optim.Rprop
- torch.optim.SGD
- torch.optim.SparseAdam
优化器继承于基类optimizer
class Optimizer(object):
def __init__(self, params, defaults):
self.defaults = defaults
self.state = defaultdict(dict)
self.param_groups = []
属性
-
defaults:存储的是优化器的超参数
-
state:参数的缓存
-
param_groups:管理的参数组
方法 -
zero_grad():清空所管理参数的梯度
-
step():执行一步梯度更新,参数更新
-
add_param_group():添加参数组
-
load_state_dict() :加载状态参数字典,可以用来进行模型的断点续训练,继续上次的参数进行训练
-
state_dict():获取优化器当前状态信息字典
训练与评估
设置模型的状态
- 训练状态:模型参数应该支持反向传播的修改
- 验证/测试状态:不应该修改模型参数
model.train() # 训练状态
model.eval() # 验证/测试状态
#for循环读取DataLoader中的全部数据
for data, label in train_loader:
#将数据放到GPU上用于后续计算,以.cuda()为例
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
可视化
必要时对必要信息进行可视化处理