3.损失函数,反向传播,优化器


前言

最近学会了如何使用pytorch搭建模型和训练模型,在查找官网资料和博客中也遇到了一些坑,因此写一下关于损失函数等相关问题的研究

一、损失函数

损失函数是算法中比较重要的一部分,通常看论文比较关注的几个点就是网络模型、损失函数、创新点。常用损失函数的有

  • 平均绝对误差L1Loss
  • 均方误差MSFLoss
  • 交叉熵损失CROSSENTROPYLOSS

1.L1Loss,MSELoss

该损失函数常用与回归问题
在这里插入图片描述
根据官方文档知道,他是结果与目标值进行相减后取绝对值。
注:input与target必须得有相同的维度

input = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)

input = torch.reshape(input, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))

loss = nn.L1Loss(reduction='mean')
#绝对值误差。'none':分别相减 'sum':相减后求和  'mean':对求和的结果再进行取平均值
result = loss(input, targets)
print(result)
--tensor(0.6667)

mse损失是用来比较两个样本相似度的一个程度,mse值越小则模型的性能越好。下述数据均方误差结果:((1-1)2+(2-2)2+(3-5)2)/3

lose_mse = nn.MSELoss()
#平方差误差
result = lose_mse(input,targets)
print(result)
--tensor(1.3333)

2.交叉熵函数

这个在图像分类中使用最多,通常是来处理分类问题。
计算的方法如下:
在这里插入图片描述
比如举如下例子,目标检测的标签是0,loss值为
loss = -0.5 + ln(e0.5+e0.36+e0.23)= 0.9680

input = torch.tensor([0.5,0.36,0.23],dtype=torch.float32)
target = torch.tensor([0])
input = torch.reshape(input,shape=(1,3))
loss = nn.CrossEntropyLoss()
result = loss(input,target)
print(result)
--tensor(0.9680)

注:target的范围是从0开始的,其值不能超过当前分类的范围
在这里插入图片描述

3.DICE损失

常用于分割任务中的损失函数。
Dice系数是一种集合相似度度量函数,通常用于计算两个样本的相似度(值得范围为[0,1]),公式为:

DiceCoefficient= 2 ∣ X ∩ Y ∣ ∣ x ∣ + ∣ Y ∣ \frac{2\left | X\cap Y \right |}{\left | x \right |+\left | Y \right |} x+Y2XY

其中, ∣ X ∩ Y ∣ \left | X\cap Y \right | XY表示集合X和Y的交集, ∣ X ∣ \left | X \right | X ∣ Y ∣ \left | Y \right | Y表示其元素个数,对于分割任务而言, ∣ X ∣ \left | X \right | X ∣ Y ∣ \left | Y \right | Y分别表示分割的Ground True和Predict mask。

由于Dice损失和Dice系数的关系是:DiceLoss = 1 - DiceCoefficient,由此得到Dice Loss的公式为:

DiceLoss= 1 − 2 ∣ X ∩ Y ∣ ∣ x ∣ + ∣ Y ∣ 1- \frac{2\left | X\cap Y \right |}{\left | x \right |+\left | Y \right |} 1x+Y2XY
通常为了防止分母为0,通常会在分子和分母添加一个偏移量

二、反向传播、优化器

在上述损失函数中,我们均能得到当前模型的一个训练情况,通过损失值为下一步模型训练的参数进行梯度下降,找到一个合适的值,这个步骤就是反向传播,在模型训练时会用到。
使用损失函数的backward()方法即可进行反向传播,其次通常要使用优化器来优化模型参数。pytorch官网上给出的优化器一般使用模板如下:

2.1优化器模板

optimizer = optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
#optimizer = optim.Adam([var1, var2], lr=0.0001)
for input, target in dataset:
    optimizer.zero_grad() #将上一步得到的参数梯度清零
    output = model(input)
    loss = loss_fn(output, target)
    loss.backward()
    optimizer.step()

在上述模型中使用的是学习率为0.01。在大多数情况下学习率不是一直不变的,特别是在训练的轮数较大时,学习率需要做出调整,一般采用自适应的学习率方法。pytorch采用的学习率方法和及其运算可以采纳这篇博客:
https://blog.csdn.net/XiaoyYidiaodiao/article/details/124678206
以下采用LambdaLR的方法进行自适应学习率算法。算法模板如下:

2.2自适应学习率模板

learning_rate = 1e-2
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
lambda1 = lambda epoch: (epoch) // 2
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1)
for epoch in range(epochs):
	train_data
	valid_data
	scheduler.step() 

通过对mnist数据集进行训练,学习率保持0.01和自适应学习率最终的loss值有不同,使用自适应学习率,该算法的收敛度更快。

三、对MNIST进行模型训练

import time
from turtle import pd

import torch.optim
import torchvision
from torch import nn, optim
from torchvision import datasets, transforms
from torch.utils.data import DataLoader
import numpy as np
import matplotlib.pyplot as plt

start = time.perf_counter()

train_data = datasets.MNIST(root="./MNIST",
                            train=True,
                            transform=transforms.ToTensor(),
                            download=False)

test_data = datasets.MNIST(root="./MNIST",
                           train=False,
                           transform=transforms.ToTensor(),
                           download=False)

train_loader = DataLoader(dataset=train_data,
                          batch_size=64,
                          shuffle=True)

test_loader = DataLoader(dataset=test_data,
                         batch_size=64,
                         shuffle=True)


class mymodel(nn.Module):
    def __init__(self):
        super(mymodel, self).__init__()
        self.model1 = nn.Sequential(
            nn.Conv2d(in_channels=1, out_channels=32, kernel_size=3),
            nn.MaxPool2d(2),
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3),
            nn.MaxPool2d(2, stride=2),
            nn.Flatten(),
            nn.Linear(in_features=1600, out_features=64),
            nn.ReLU(),
            nn.Linear(in_features=64, out_features=10)
        )

    def forward(self, input):
        return self.model1(input)


model = mymodel()

loss = nn.CrossEntropyLoss()

iterations = 0

learning_rate = 1e-2
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate)
lambda1 = lambda epoch: (epoch) // 2
scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lambda1)

for epoch in range(20):
    running_loss = 0.0
    print(" -----------------the {} number of training epoch --------------".format(epoch))
    model.train()
    for data in train_loader:
        imgs, targets = data
        outputs = model(imgs)
        result_loss = loss(outputs, targets)
        optimizer.zero_grad()
        result_loss.backward()
        optimizer.step()
        running_loss += result_loss

        iterations += 1
        if iterations % 100 == 0:
            print(
                "Epoch: {} | Iteration: {} | lr: {} | loss: {} | np.mean(loss): {} "
                .format(epoch, iterations, optimizer.param_groups[0]['lr'],result_loss.item(),
                        np.mean(result_loss.item())))

    print("第", epoch, "次", running_loss)
    scheduler.step()

    if (epoch + 1) % 20 == 0:
        print("Save state, iter: {} ".format(iterations))
        torch.save(model.state_dict(), "lrmymodel{}.pth".format(epoch))


end = time.perf_counter()
runTime = end - start
print("运行时间:", runTime)

运行结果如图:
在这里插入图片描述
在这里插入图片描述

总结

本文讲解了常见的一些损失函数,对于交叉熵损失函数进行了重点描述,也讲了反向传播和优化器部分,同时采用自适应学习率算法能够加速loss的收敛情况。

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

explorer_a

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值