Pytorch:主要组成模块 -学习笔记

Pytorch:主要组成模块 -学习笔记,第1张

Pytorch:主要组成模块 -学习笔记 基本配置

1.导入必须的包。

2.超参数的统一设置。

  • batch size

  • 初始学习率(初始)

  • 训练次数(max_epochs)

  • 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")
数据读入

PyTorch数据读入是通过Dataset+Dataloader的方式完成的,Dataset定义好数据的格式和数据变换形式,Dataloader用iterative的方式不断读入批次数据。

用Dataset进行数据读取

继承Dataset 类需要override 以下⽅法:

from torch.utils.data import Dataset
class trainDataset(Dataset):
    def __init__(self):
    #用于向类中传入外部参数,同时定义样本集

    def __getitem__(self,index):
    #用于逐个读取样本集合中的元素,可以进行一定的变换,并将返回训练/验证所需的数据

    def __len__(self):
    #用于返回数据集的样本数
用DataLoader来按批次读入数据
val_loader=torch.utils.data.DataLoader(train_data, batch_size=batch_size, num_workers=4, shuffle=True, drop_last=True)

# batch_size:样本是按“批”读入的,batch_size就是每次读入的样本数
# num_workers:有多少个进程用于读取数据
# shuffle:是否将读入的数据打乱
# drop_last:对于样本最后一部分没有达到批次数的样本,不再参与训练

PyTorch中的DataLoader的读取可以使用next和iter来完成

import matplotlib.pyplot as plt
images, labels = next(iter(val_loader))
print(images.shape)
plt.imshow(images[0].transpose(1,2,0))
plt.show()
模型的构建

PyTorch中神经网络构造一般是基于 Module 类的模型来完成的。Module 类是 nn 模块里提供的一个模型构造类,是所有神经⽹网络模块的基类,我们可以继承它来定义我们想要的模型。

所有的模型都需要继承torch.nn.Module , 需要实现以下⽅法:

class MyModel(torch.nn.Module):
    def __init__(self):
        super(MyModel, self).__init__()
        # 声明带有模型参数的层(神经网络)
    def forward(self,x):
        # 定义模型的前向计算,即如何根据输入x计算返回所需要的模型输出
        return

model = MyModel()

其中forward() ⽅法是前向传播的过程。在实现模型时,我们不需要考虑反向传播。系统将通过⾃动求梯度⽽自动⽣成反向传播所需的 backward 函数

损失函数

PyTorch中一些常用的损失函数(一般通过torch.nn调用),及每个损失函数的功能介绍、数学公式和调用代码。

L1损失函数

功能: 计算输出y和真实标签target之间的差值的绝对值。

torch.nn.L1Loss(size_average=None, reduce=None, reduction='mean')`
​
# ‘reduction’参数决定了计算模式。一共有三种模式:
# none:逐个元素计算。
# sum:所有元素求和,返回标量。
# mean:加权平均,返回标量。 
# 如果选择‘none’,那么返回的结果是和输入元素相同尺寸的。默认计算方式是求平均。

计算公式

实现代码

loss = nn.L1Loss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()
print('L1损失函数的计算结果为',output)
L1损失函数的计算结果为 tensor(1.5729, grad_fn=)
MSE损失函数

功能:计算输出y和真实标签target之差的平方。

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

计算公式:

实现代码:

loss = nn.MSELoss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()
print('MSE损失函数的计算结果为',output)
MSE损失函数的计算结果为 tensor(1.6968, grad_fn=)
平滑L1 (Smooth L1)损失函数

功能: L1的平滑输出,其功能是减轻离群点带来的影响

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

计算公式:

代码实现:

loss = nn.SmoothL1Loss()
input = torch.randn(3, 5, requires_grad=True)
target = torch.randn(3, 5)
output = loss(input, target)
output.backward()
print('SmoothL1Loss损失函数的计算结果为',output)
SmoothL1Loss损失函数的计算结果为 tensor(0.7808, grad_fn=)
目标泊松分布的负对数似然损失 功能: 泊松分布的负对数似然损失函数
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 的情况。

数学公式:

  • 当参数log_input=True:

  • 当参数log_input=False:

loss = nn.PoissonNLLLoss()
log_input = torch.randn(5, 2, requires_grad=True)
target = torch.randn(5, 2)
output = loss(log_input, target)
output.backward()
​print('PoissonNLLLoss损失函数的计算结果为',output)
PoissonNLLLoss损失函数的计算结果为 tensor(0.7358, grad_fn=)
KL散度

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

torch.nn.KLDivLoss(size_average=None, reduce=None, reduction='mean', log_target=False)

# reduction:计算模式,可为 none/sum/mean/batchmean。

# none:逐个元素计算。
​
# sum:所有元素求和,返回标量。
​
# mean:加权平均,返回标量。
​
# batchmean:batchsize 维度求平均值。

计算公式:

inputs = torch.tensor([[0.5, 0.3, 0.2], [0.2, 0.3, 0.5]]) target = torch.tensor([[0.9, 0.05, 0.05], [0.1, 0.7, 0.2]], dtype=torch.float) loss = nn.KLDivLoss() output = loss(inputs,target)​
print('PoissonNLLLoss损失函数的计算结果为',output)
PoissonNLLLoss损失函数的计算结果为 tensor(-0.3335)
MarginRankingLoss

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

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

# margin:边界值,x{1}与x{2}之间的差异值。

# reduction:计算模式,可为 none/sum/mean。

计算公式:

 

loss = nn.MarginRankingLoss() 
input1 = torch.randn(3, requires_grad=True) 
input2 = torch.randn(3, requires_grad=True) 
target = torch.randn(3).sign() 
output = loss(input1, input2, target) output.backward()​

print('MarginRankingLoss损失函数的计算结果为',output)
MarginRankingLoss损失函数的计算结果为 tensor(0.7740, grad_fn=)
多标签边界损失函数

功能: 对于多标签分类问题计算损失函数。

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

# reduction:计算模式,可为 none/sum/mean。

计算公式:

loss = nn.MultiLabelMarginLoss() 
x = torch.FloatTensor([[0.9, 0.2, 0.4, 0.8]]) 
# for target y, only consider labels 3 and 0, not after label -1 
y = torch.LongTensor([[3, 0, -1, 1]]) # 真实的分类是,第3类和第0类 
output = loss(x, y)​
print('MarginRankingLoss损失函数的计算结果为',output)
MarginRankingLoss损失函数的计算结果为 tensor(0.4500)
二分类损失函数
torch.nn.SoftMarginLoss(size_average=None, reduce=None, reduction='mean')torch.nn.(size_average=None, reduce=None, reduction='mean')

功能: 二分类的 logistic 损失。

计算公式:


inputs = torch.tensor([[0.3, 0.7], [0.5, 0.5]])  # 两个样本,两个神经元
target = torch.tensor([[-1, 1], [1, -1]], dtype=torch.float) 
 # 该 loss 为逐个神经元计算,需要为每个神经元单独设置标签
​
loss_f = nn.SoftMarginLoss()
output = loss_f(inputs, target)
​
print('SoftMarginLoss损失函数的计算结果为',output)
SoftMarginLoss损失函数的计算结果为 tensor(0.6764)
优化器

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,下面我们先来看下所有优化器的基类Optimizer。定义如下:

class Optimizer(object):
    def __init__(self, params, defaults):        
        self.defaults = defaults
        self.state = defaultdict(dict)
        self.param_groups = []

# `defaults`:存储的是优化器的超参数
{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}

# `state`:参数的缓存

# `param_groups`:管理的参数组,是一个list,其中每个元素是一个字典,顺序是params,lr,momentum,dampening,weight_decay,nesterov,

Optimizer还有以下的方法

zero_grad()清空所管理参数的梯度,Pytorch的特性是张量的梯度不自动清零,因此每次反向传播后都需要清空梯度。step()执行一步梯度更新,参数更新add_param_group()添加参数组load_state_dict()加载状态参数字典,可以用来进行模型的断点续训练,继续上次的参数进行训练state_dict()获取优化器当前状态信息字典

注意:

  1. 每个优化器都是一个类,我们一定要进行实例化才能使用,比如下方实现:

    class Net(nn.Moddule):
        ···
    net = Net()
    optim = torch.optim.SGD(net.parameters(),lr=lr)
    optim.step()
  2. optimizer在一个神经网络的epoch中需要实现下面两个步骤:

    1. 梯度置零

    2. 梯度更新

optimizer = torch.optim.SGD(net.parameters(), lr=1e-5)
for epoch in range(EPOCH):
	...
	optimizer.zero_grad()  #梯度置零
	loss = ...             #计算loss
	loss.backward()        #BP反向传播
	optimizer.step()       #梯度更新
训练和评估

完成了上述设定后就可以加载数据开始训练模型了。首先应该设置模型的状态:如果是训练状态,那么模型的参数应该支持反向传播的修改;如果是验证/测试状态,则不应该修改模型参数。在PyTorch中,模型的状态设置非常简便,如下的两个 *** 作二选一即可:

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

我们前面在DataLoader构建完成后介绍了如何从中读取数据,在训练过程中使用类似的 *** 作即可,区别在于此时要用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

一个完整的训练过程如下所示:

def train(epoch):
    model.train()
    train_loss = 0
    for data, label in train_loader:
        data, label = data.cuda(), label.cuda()
        optimizer.zero_grad()
        output = model(data)
        loss = criterion(label, output)
        loss.backward()
        optimizer.step()
        train_loss += loss.item()*data.size(0)
    train_loss = train_loss/len(train_loader.dataset)
    print('Epoch: {} tTraining Loss: {:.6f}'.format(epoch, train_loss))
​

对应的,一个完整的验证过程如下所示:

def val(epoch):       
    model.eval()
    val_loss = 0
    with torch.no_grad():
        for data, label in val_loader:
            data, label = data.cuda(), label.cuda()
            output = model(data)
            preds = torch.argmax(output, 1)
            loss = criterion(output, label)
            val_loss += loss.item()*data.size(0)
            running_accu += torch.sum(preds == label.data)
    val_loss = val_loss/len(val_loader.dataset)
    print('Epoch: {} tTraining Loss: {:.6f}'.format(epoch, val_loss))

 

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/3972797.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-10-21
下一篇 2022-10-21

发表评论

登录后才能评论

评论列表(0条)

保存