一、损失函数和反向传播
(1)、概念
损失函数(Loss Function)是机器学习和深度学习中都非常核心的概念。它用于量化模型的预测结果与实际结果之间的差异,作为训练过程中优化算法的目标。简单来说,损失函数衡量的是模型的预测错误程度。
反向传播(Backpropagation,缩写为BP)是“误差反向传播”的简称,是一种与最优化方法(如梯度下降法)结合使用的,用来训练人工神经网络的常见方法。 该方法对网络中所有权重计算损失函数的梯度。 这个梯度会反馈给最优化方法,用来更新权值以最小化损失函数。、
(2)、示例
L1Loss和MSELoss
代码
import torch
from torch.nn import L1Loss
inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)
inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))
loss = L1Loss()
loss_mse = MSELoss()
result1 = loss(inputs, targets)
result2 = loss_mse(inputs, targets)
print(result1)
print(result2)
CrossEntropyLoss交叉熵
Pytorch中CrossEntropyLoss()函数的主要是将softmax-log-NLLLoss合并到一块得到的结果。
1、Softmax后的数值都在0~1之间,所以ln之后值域是负无穷到0。
2、然后将Softmax之后的结果取log,将乘法改成加法减少计算量,同时保障函数的单调性 。
3、NLLLoss的结果就是把上面的输出与Label对应的那个值拿出来(下面例子中就是:将log_output\logsoftmax_output中与y_target对应的值拿出来),去掉负号,再求均值。
公式如下:
示例
import torch
from torch.nn import L1Loss, MSELoss, CrossEntropyLoss
inputs = torch.tensor([1, 2, 3], dtype=torch.float32)
targets = torch.tensor([1, 2, 5], dtype=torch.float32)
inputs = torch.reshape(inputs, (1, 1, 1, 3))
targets = torch.reshape(targets, (1, 1, 1, 3))
loss = L1Loss()
loss_mse = MSELoss()
result1 = loss(inputs, targets)
result2 = loss_mse(inputs, targets)
#print(result1)
#print(result2)
x = torch.tensor([0.1, 0.2, 0.3])
y = torch.tensor([1])
x = torch.reshape(x, (1, 3))
loss_cross = CrossEntropyLoss()
result_cross = loss_cross(x, y)
print(result_cross)
反向传播
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
class TEST(nn.Module):
def __init__(self):
super(TEST, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
test1 = TEST()
for data in dataloader:
imgs, targets = data
outputs = test1(imgs)
result_loss = loss(outputs, targets)
result_loss.backward()
print("ok")
通过使用backward()函数使其进行反向传播,计算出每个节点的参数的梯度,可以通过梯度选择合适的优化器,对参数进行优化,对loss达到降低的目的
二、优化器
(1)、概念
优化器(optimizer)在深度学习中扮演着至关重要的角色,它们用于调整模型参数以最小化训练过程中定义的损失函数。PyTorch中的torch.optim模块提供了各种优化算法的实现,使得用户可以轻松地在训练过程中选择合适的优化器来优化模型。
这个模块包含了许多不同的优化器类,其中最常见的是随机梯度下降(SGD)、Adam、Adagrad等。每个优化器都有自己的超参数(如学习率、动量等),可以根据具体任务的需求进行调整。
parameters()函数是nn.Module类中的一个方法,用于返回模型中所有需要学习的参数。这些参数通常是神经网络中的权重和偏置。
当你调用模型的parameters()方法时,它会返回一个包含所有参数的迭代器,你可以通过遍历这个迭代器来访问每个参数。通常,你可以将这些参数传递给优化器,以便在训练过程中更新它们。
优化器中的参数可以根据具体的优化算法和任务需求而定。以下是一些常见的优化器参数及其含义:
-
lr(learning rate): 学习率,控制每次参数更新的步长。较大的学习率可能导致参数更新过大,难以收敛;而较小的学习率可能导致收敛速度过慢。通常需要进行调试以找到合适的学习率。
-
momentum: 动量,用于加速SGD在相关方向上的更新,并减少摆动。它是一个在0到1之间的值,0表示没有动量,1表示完全使用动量。动量的作用类似于物理学中的惯性,有助于克服局部极小值。
-
weight_decay: 权重衰减(L2正则化),用于防止模型过拟合。它通过对模型参数的更新进行惩罚,使得参数的幅度较小,有助于提高模型的泛化能力。
-
betas: Adam优化器中的参数,用于计算一阶矩和二阶矩的指数衰减率。通常为一个包含两个值的元组,分别表示一阶矩和二阶矩的衰减率。
-
eps: Adam优化器中的参数,用于数值稳定性。防止分母为零的情况发生。
-
amsgrad: Adam优化器中的参数,用于指定是否使用AMSGrad算法。当设为True时,AMSGrad算法会保证更新后的学习率不会比之前的学习率更小。
-
alpha: RMSprop优化器中的参数,用于计算移动平均的系数。
-
centered: RMSprop优化器中的参数,用于指定是否计算中心化的二阶矩。
-
momentum_decay: LARS(Layer-wise Adaptive Rate Scaling)优化器中的参数,用于衰减动量。有助于防止模型训练时的震荡和过拟合。
-
trust_coef: LAMB(Layer-wise Adaptive Moments based optimizer for Batch training)优化器中的参数,用于计算自适应学习率的信任系数。
(2)、示例
import torch
import torchvision.datasets
from torch import nn
from torch.nn import Sequential, Conv2d, MaxPool2d, Flatten, Linear
from torch.utils.data import DataLoader
dataset = torchvision.datasets.CIFAR10("data", train=False, transform=torchvision.transforms.ToTensor(),
download=True)
dataloader = DataLoader(dataset, batch_size=1)
class TEST(nn.Module):
def __init__(self):
super(TEST, self).__init__()
self.model1 = Sequential(
Conv2d(3, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 32, 5, padding=2),
MaxPool2d(2),
Conv2d(32, 64, 5, padding=2),
MaxPool2d(2),
Flatten(),
Linear(1024, 64),
Linear(64, 10)
)
def forward(self, x):
x = self.model1(x)
return x
loss = nn.CrossEntropyLoss()
test1 = TEST()
optim = torch.optim.SGD(test1.parameters(), lr=0.01)
for epoch in range(20): #epoch表示一轮训练
for data in dataloader:
imgs, targets = data
outputs = test1(imgs)
result_loss = loss(outputs, targets)
optim.zero_grad() #将每个节点对应的梯度清零
result_loss.backward() #使用反向传播,求出每个节点的梯度
optim.step() #根据之前计算的梯度来更新模型参数
running_loss = running_loss + result_loss # 每一轮误差的总和
print(running_loss)
从结果可以看出优化器对模型参数进行优化,每轮误差减小
三、现有网络模型的使用及修改
以VGG16为例
import torchvision
# train_data = torchvision.datasets.ImageNet("data_image_net", split='train', download=True,
# transform=torchvision.transforms.ToTensor())
# 以上模型无法直接使用
vgg16_false = torchvision.models.vgg16(pretrained=False)
vgg16_true = torchvision.models.vgg16(pretrained=True)
print(vgg16_true)
对VGG16进行修改
vgg16_true.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)
vgg16_true.classifier.add_module('add_linear', nn.Linear(1000, 10))
print(vgg16_true)
修改没有使用预训练权重的VGG16模型的全连接层
vgg16_false.classifier[6] = nn.Linear(4096, 10)
print(vgg16_false)
四、网络模型的保存和读取
两种保存方式
import torch
import torchvision
vgg16 = torchvision.models.vgg16(pretrained=False)
# 保存方式1,模型结构+模型参数
torch.save(vgg16, "vgg16_method1.pth")
#保存方式2,模型参数(推荐)
torch.save(vgg16.state_dict(), "vgg16_method2.pth") # 保存网络模型中的参数
两种读取方式 (与保存方式一一对应)
import torch
import torchvision
# 方式1->保存方式1,加载模型
model = torch.load("vgg16_method1.pth")
print(model)
# 方式2->加载模型
vgg16 = torchvision.models.vgg16(pretrained=False)
vgg16.load_state_dict(torch.load("vgg16_method2.pth"))
# model = torch.load("vgg16_method2.pth")
print(vgg16)
陷阱
class Trap(nn.Module):
def __init__(self):
super(Trap, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
x = self.conv1(x)
return x
trap = Trap()
torch.save(trap, "trap_method1.pth")
class Trap(nn.Module):
def __init__(self):
super(Trap, self).__init__()
self.conv1 = nn.Conv2d(3, 64, kernel_size=3)
def forward(self, x):
x = self.conv1(x)
return x
model = torch.load('trap_method1.pth')
print(model)
陷阱在读取时,需要再定义类,也可以使用form...import...