Geeks_Z の Blog Geeks_Z の Blog
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)

Geeks_Z

AI小学生
首页
  • 学习笔记

    • 《HTML》
    • 《CSS》
    • 《JavaWeb》
    • 《Vue》
  • 后端文章

    • Linux
    • Maven
    • 汇编语言
    • 软件工程
    • 计算机网络概述
    • Conda
    • Pip
    • Shell
    • SSH
    • Mac快捷键
    • Zotero
  • 学习笔记

    • 《数据结构与算法》
    • 《算法设计与分析》
    • 《Spring》
    • 《SpringMVC》
    • 《SpringBoot》
    • 《SpringCloud》
    • 《Nginx》
  • 深度学习文章
  • 学习笔记

    • 《PyTorch》
    • 《ReinforementLearning》
    • 《MetaLearning》
  • 学习笔记

    • 《高等数学》
    • 《线性代数》
    • 《概率论与数理统计》
  • 增量学习
  • 哈希学习
GitHub (opens new window)
  • Python

  • MLTutorials

  • 卷积神经网络

  • 循环神经网络

  • Transformer

  • VisionTransformer

  • 扩散模型

  • 计算机视觉

  • PTM

  • MoE

  • LoRAMoE

  • LongTailed

  • 多模态

  • 知识蒸馏

  • PEFT

  • 对比学习

  • 小样本学习

  • 迁移学习

  • 零样本学习

  • 集成学习

  • Mamba

  • PyTorch

    • PyTorch概述

    • Tensors

    • 数据处理

    • 模型

    • 训练

      • 基本配置
      • 损失函数
      • 优化器
        • 优化器
        • Optimizer
          • Optimizer 属性
          • Optimizer 方法
          • zero_grad()
          • 使用示例
          • step()
          • 使用示例
          • addparamgroup()
          • 使用示例
        • torch.optim
          • torch.optim.lr_scheduler
        • 实例
      • PyTorch计算图
    • 并行计算

    • 可视化

    • 实战

    • timm

    • Pytorch Lightning

    • 数据增强

    • 面经与bug解决

    • 常用代码片段

    • Reference
  • CL

  • CIL

  • 小样本类增量学习FSCIL

  • UCIL

  • 多模态增量学习MMCL

  • LTCIL

  • DIL

  • 论文阅读与写作

  • 分布外检测

  • GPU

  • 深度学习调参指南

  • AINotes
  • PyTorch
  • 训练
Geeks_Z
2023-01-26
目录

优化器

优化器

PyTorch 中的优化器是用于管理并更新模型中可学习参数的值,使得模型输出更加接近真实标签。

Optimizer

Optimizer是优化器的基类

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

Optimizer 属性

  • defaults:存储的是优化器的超参数,例子如下:
{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}
1
  • state:参数的缓存,例子如下:
defaultdict(<class 'dict'>, {tensor([[ 0.3864, -0.0131],
        [-0.1911, -0.4511]], requires_grad=True): {'momentum_buffer': tensor([[0.0052, 0.0052],
        [0.0052, 0.0052]])}})
1
2
3
  • param_groups:管理的参数组,是一个 list,其中每个元素是一个字典,顺序是 params,lr,momentum,dampening,weight_decay,nesterov,例子如下:
[{'params': [tensor([[-0.1022, -1.6890],[-1.5116, -1.7846]], requires_grad=True)], 'lr': 1, 'momentum': 0, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}]
1

Optimizer 方法

  • zero_grad():清空所管理参数的梯度。由于 PyTorch 的特性是张量的梯度不自动清零,因此每次反向传播之后都需要清空梯度。代码如下:
  • step():执行一步梯度更新
  • add_param_group():添加参数组,主要代码如下:
  • state_dict():获取优化器当前状态信息字典
  • load_state_dict():加载状态信息字典,包括 state 、momentum_buffer 和 param_groups。主要用于模型的断点续训练。我们可以在每隔 50 个 epoch 就保存模型的 state_dict 到硬盘,在意外终止训练时,可以继续加载上次保存的状态,继续训练。

zero_grad()

在 PyTorch 中,zero_grad()函数用于将模型中所有参数的梯度重置为零。这是因为在神经网络训练过程中,每次进行反向传播(backpropagation)时,梯度是累积计算的,而不是被替换。因此,在处理每个批次(batch)的数据之前,我们需要调用zero_grad()来确保梯度的正确计算。

def zero_grad(self, set_to_none: bool = False):
    for group in self.param_groups:
        for p in group['params']:
            if p.grad is not None:  #梯度不为空
                if set_to_none:
                    p.grad = None
                else:
                    if p.grad.grad_fn is not None:
                        p.grad.detach_()
                    else:
                        p.grad.requires_grad_(False)
                    p.grad.zero_()# 梯度设置为0
1
2
3
4
5
6
7
8
9
10
11
12

zero_grad()函数有两种常见的使用方式:model.zero_grad()和optimizer.zero_grad()。这两种方式在功能上是等效的,它们都会将模型中所有参数的梯度设置为零。当使用optimizer = optim.Optimizer(model.parameters())时,这两种方式可以互换使用,其中Optimizer可以是 SGD、Adam 等优化器。

使用示例

import torch
import torch.optim as optim

# 定义模型和优化器
model = ...  # 这里应该是你的模型定义
optimizer = optim.SGD(model.parameters(), lr=0.01)  # 使用SGD优化器,学习率为0.01

# 训练循环
for inputs, targets in dataloader:
    # 前向传播
    outputs = model(inputs)
    # 计算损失
    loss = criterion(outputs, targets)
    # 梯度清零
    optimizer.zero_grad()  # 或者使用 model.zero_grad()
    # 反向传播
    loss.backward()
    # 更新参数
    optimizer.step()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

在上面的示例中,我们首先定义了一个模型和一个优化器。然后,在训练循环中,我们首先对模型进行前向传播以计算输出,接着计算损失,然后调用optimizer.zero_grad()来清零梯度,进行反向传播以计算梯度,最后使用优化器更新模型的参数。

step()

step()方法执行以下操作:

  1. 梯度获取:在调用step()之前,通常已经通过loss.backward()计算了损失函数关于模型参数的梯度。这些梯度存储在模型参数的.grad属性中。

  2. 参数更新:step()方法会根据优化器(如 SGD、Adam 等)中定义的更新规则,以及当前的学习率和其他超参数,来更新模型的参数。对于每个参数,它会使用相应的梯度信息来调整参数值,以便在下一次迭代中更好地拟合训练数据。

  3. 内部状态更新:一些优化器(如 Adam)还维护了参数的内部状态,如一阶矩估计和二阶矩估计。在调用step()时,这些内部状态也会根据当前的梯度和参数进行更新。

需要注意的是,在每次调用step()之前,通常需要先调用optimizer.zero_grad()来清除之前累积的梯度。这是因为 PyTorch 中的梯度是累积的,如果不进行清零操作,新的梯度将会与之前的梯度相加,导致错误的更新。

此外,step()方法通常与训练循环中的批次(batch)处理配合使用。在每个批次处理完成后,都会调用step()来更新模型参数,以便在下一个批次中继续优化。

张量 weight 的形状为2×2,并设置梯度为 1,把 weight 传进优化器,学习率设置为 1,执行optimizer.step()更新梯度,也就是所有的张量都减去 1。

使用示例

weight = torch.randn((2, 2), requires_grad=True)
weight.grad = torch.ones((2, 2))

optimizer = optim.SGD([weight], lr=1)
print("weight before step:{}".format(weight.data))
optimizer.step()
print("weight after step:{}".format(weight.data))
1
2
3
4
5
6
7

输出为:

weight before step:tensor([[0.6614, 0.2669],
        [0.0617, 0.6213]])
weight after step:tensor([[-0.3386, -0.7331],
        [-0.9383, -0.3787]])
1
2
3
4

add_param_group()

在 PyTorch 的torch.optim.Optimizer类中,add_param_group()方法用于向优化器中添加一个参数组。这允许你为模型的不同部分设置不同的学习率或其他优化参数。这在训练复杂的神经网络时非常有用,特别是当你希望某些层的学习率高于其他层时。

add_param_group()方法接受一个字典作为参数,该字典描述了参数组的配置。下面是一些常见的键及其说明:

  • params (iterable): 一个可迭代的参数列表或字典,指定了需要优化的参数。通常,你可以直接传入model.parameters()来获取模型的所有参数,或者通过某些条件筛选特定的参数。
  • weight_decay (float, optional): 权重衰减系数,用于正则化。它通过将权重乘以一个小于 1 的因子来实现,通常设置为类似 0.001 的值。如果未指定,则默认为优化器级别的weight_decay。
  • lr (float, optional): 学习率。它控制参数更新的步长。如果未指定,则默认为优化器级别的学习率。
  • momentum (float, optional): 动量系数,仅对使用动量的优化器(如 SGD)有效。它用于加速 SGD 在相关方向上前进,并抑制震荡。如果未指定,则默认为优化器级别的动量。
  • dampening (float, optional): 阻尼系数,用于调节动量的影响,防止动量过大导致的不稳定。如果未指定,则默认为优化器级别的阻尼。
  • nesterov (bool, optional): 是否使用 Nesterov 动量。当设置为True时,使用 Nesterov 加速梯度(NAG)算法,它是对标准动量方法的一种改进。如果未指定,则默认为优化器级别的 Nesterov 设置。

使用示例

import torch
import torch.optim as optim

# 假设我们有一个简单的模型
model = torch.nn.Sequential(
    torch.nn.Linear(10, 20),
    torch.nn.ReLU(),
    torch.nn.Linear(20, 1)
)

# 创建优化器,并添加默认的参数组
optimizer = optim.SGD(model.parameters(), lr=0.01)

# 为模型的第一层设置不同的学习率
param_group = {'params': model[0].parameters(), 'lr': 0.02}
optimizer.add_param_group(param_group)

# 现在,模型的第一层将使用0.02的学习率,而其余层将使用默认的0.01学习率
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

torch.optim

PyTorch 提供了一个优化器的库torch.optim:

  • torch.optim.SGD
  • torch.optim.ASGD
  • torch.optim.Adadelta
  • torch.optim.Adagrad
  • torch.optim.Adam
  • torch.optim.AdamW
  • torch.optim.Adamax
  • torch.optim.RAdam
  • torch.optim.NAdam
  • torch.optim.SparseAdam
  • torch.optim.LBFGS
  • torch.optim.RMSprop
  • torch.optim.Rprop

torch.optim.lr_scheduler

torch.optim.lr_scheduler 是 PyTorch 中用于调整学习率(learning rate)的模块。在训练神经网络时,学习率是一个非常重要的超参数,它决定了模型参数在每次更新时的步长大小。学习率调度器(scheduler)可以根据训练过程中的某些指标(如验证损失或训练轮次)动态地调整学习率,以优化训练过程。学习率调度应该在优化器更新后应用。

torch.optim.lr_scheduler 提供了多种学习率调度器,每种调度器都有其特定的参数。以下是一些常用调度器的参数说明:

  1. StepLR: 每训练一定数量的轮次(epochs),学习率按指定的因子衰减。

    • optimizer (Optimizer): 优化器。
    • step_size (int): 学习率衰减的周期,即每隔多少个 epochs 衰减一次。
    • gamma (float, optional): 学习率衰减的因子,默认为 0.1。
    • last_epoch (int, optional): 上一个 epoch 的索引,默认为 -1。
  2. ExponentialLR: 学习率按指数衰减。

    • optimizer (Optimizer): 优化器。
    • gamma (float): 衰减因子。
    • last_epoch (int, optional): 上一个 epoch 的索引,默认为 -1。
  3. CosineAnnealingLR: 学习率按余弦退火策略调整。

    • optimizer (Optimizer): 优化器。
    • T_max (int): 余弦退火周期的一半,即一个完整余弦周期包含的 epochs 数量。
    • eta_min (float, optional): 学习率的最小值,默认为 0。
    • last_epoch (int, optional): 上一个 epoch 的索引,默认为 -1。
  4. ReduceLROnPlateau: 当某个指标(如验证损失)停止改进时,减少学习率。

    • optimizer (Optimizer): 优化器。
    • mode (str): 指标改进的模式,可选 'min' 或 'max'。
    • factor (float): 学习率减少的因子。
    • patience (int): 等待多少个 epochs 无改进后才减少学习率。
    • verbose (bool): 是否打印信息,默认为 False。
    • threshold (float): 测量新的最佳值的阈值,仅用于 'min' 模式。
    • threshold_mode (str): 相对或绝对阈值模式。
    • cooldown (int): 学习率减少后的冷却周期,即多少个 epochs 不调整学习率。
    • min_lr (float or list): 学习率的最小值。
    • eps (float): 提高数值稳定性的小值。
  5. CyclicLR: 学习率在给定范围内循环变化。

    • optimizer (Optimizer): 优化器。
    • base_lr (float or list): 初始学习率。
    • max_lr (float or list): 最大学习率。
    • step_size_up (int): 学习率从 base_lr 增加到 max_lr 的周期长度。
    • step_size_down (int): 学习率从 max_lr 减少到 base_lr 的周期长度。
    • mode (str): 循环的模式,可以是 'triangular', 'triangular2' 或 'exp_range'。
    • gamma (float): 用于 'exp_range' 模式的乘数因子。
    • scale_fn (function): 自定义的缩放函数。
    • scale_mode (str): 缩放模式,可以是 'cycle' 或 'iterations'。
    • cycle_momentum (bool): 是否也循环动量。
    • base_momentum (float or list): 动量的初始值。
    • max_momentum (float or list): 动量的最大值。
    • last_epoch (int): 上一个 epoch 的索引。
  6. LambdaLR: 根据一个 lambda 函数来调整学习率。

    • optimizer (Optimizer): 优化器。
    • lr_lambda (function or list): 用于计算学习率的 lambda 函数或函数列表。
    • last_epoch (int): 上一个 epoch 的索引。

这只是 torch.optim.lr_scheduler 中提供的一些常见调度器及其参数。具体的用法和参数可能因不同的调度器而有所差异。

实例

import os
import torch

# 设置权重,服从正态分布  --> 2 x 2
weight = torch.randn((2, 2), requires_grad=True)
# 设置梯度为全1矩阵  --> 2 x 2
weight.grad = torch.ones((2, 2))
# 输出现有的weight和data
print("The data of weight before step:\n{}".format(weight.data))
print("The grad of weight before step:\n{}".format(weight.grad))
# 实例化优化器
optimizer = torch.optim.SGD([weight], lr=0.1, momentum=0.9)
# 进行一步操作
optimizer.step()
# 查看进行一步后的值,梯度
print("The data of weight after step:\n{}".format(weight.data))
print("The grad of weight after step:\n{}".format(weight.grad))
# 权重清零
optimizer.zero_grad()
# 检验权重是否为0
print("The grad of weight after optimizer.zero_grad():\n{}".format(weight.grad))
# 输出参数
print("optimizer.params_group is \n{}".format(optimizer.param_groups))
# 查看参数位置,optimizer和weight的位置一样,我觉得这里可以参考Python是基于值管理
print("weight in optimizer:{}\nweight in weight:{}\n".format(id(optimizer.param_groups[0]['params'][0]), id(weight)))
# 添加参数:weight2
weight2 = torch.randn((3, 3), requires_grad=True)
optimizer.add_param_group({"params": weight2, 'lr': 0.0001, 'nesterov': True})
# 查看现有的参数
print("optimizer.param_groups is\n{}".format(optimizer.param_groups))
# 查看当前状态信息
opt_state_dict = optimizer.state_dict()
print("state_dict before step:\n", opt_state_dict)
# 进行5次step操作
for _ in range(50):
    optimizer.step()
# 输出现有状态信息
print("state_dict after step:\n", optimizer.state_dict())
# 保存参数信息
torch.save(optimizer.state_dict(),os.path.join(r"D:\pythonProject\Attention_Unet", "optimizer_state_dict.pkl"))
print("----------done-----------")
# 加载参数信息
state_dict = torch.load(r"D:\pythonProject\Attention_Unet\optimizer_state_dict.pkl") # 需要修改为你自己的路径
optimizer.load_state_dict(state_dict)
print("load state_dict successfully\n{}".format(state_dict))
# 输出最后属性信息
print("\n{}".format(optimizer.defaults))
print("\n{}".format(optimizer.state))
print("\n{}".format(optimizer.param_groups))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49

输出结果

# 进行更新前的数据,梯度
The data of weight before step:
tensor([[-0.3077, -0.1808],
        [-0.7462, -1.5556]])
The grad of weight before step:
tensor([[1., 1.],
        [1., 1.]])
# 进行更新后的数据,梯度
The data of weight after step:
tensor([[-0.4077, -0.2808],
        [-0.8462, -1.6556]])
The grad of weight after step:
tensor([[1., 1.],
        [1., 1.]])
# 进行梯度清零的梯度
The grad of weight after optimizer.zero_grad():
tensor([[0., 0.],
        [0., 0.]])
# 输出信息
optimizer.params_group is
[{'params': [tensor([[-0.4077, -0.2808],
        [-0.8462, -1.6556]], requires_grad=True)], 'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}]

# 证明了优化器的和weight的储存是在一个地方,Python基于值管理
weight in optimizer:1841923407424
weight in weight:1841923407424

# 输出参数
optimizer.param_groups is
[{'params': [tensor([[-0.4077, -0.2808],
        [-0.8462, -1.6556]], requires_grad=True)], 'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}, {'params': [tensor([[ 0.4539, -2.1901, -0.6662],
        [ 0.6630, -1.5178, -0.8708],
        [-2.0222,  1.4573,  0.8657]], requires_grad=True)], 'lr': 0.0001, 'nesterov': True, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0}]

# 进行更新前的参数查看,用state_dict
state_dict before step:
 {'state': {0: {'momentum_buffer': tensor([[1., 1.],
        [1., 1.]])}}, 'param_groups': [{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [0]}, {'lr': 0.0001, 'nesterov': True, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'params': [1]}]}
# 进行更新后的参数查看,用state_dict
state_dict after step:
 {'state': {0: {'momentum_buffer': tensor([[0.0052, 0.0052],
        [0.0052, 0.0052]])}}, 'param_groups': [{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [0]}, {'lr': 0.0001, 'nesterov': True, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'params': [1]}]}

# 存储信息完毕
----------done-----------
# 加载参数信息成功
load state_dict successfully
# 加载参数信息
{'state': {0: {'momentum_buffer': tensor([[0.0052, 0.0052],
        [0.0052, 0.0052]])}}, 'param_groups': [{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [0]}, {'lr': 0.0001, 'nesterov': True, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'params': [1]}]}

# defaults的属性输出
{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}

# state属性输出
defaultdict(<class 'dict'>, {tensor([[-1.3031, -1.1761],
        [-1.7415, -2.5510]], requires_grad=True): {'momentum_buffer': tensor([[0.0052, 0.0052],
        [0.0052, 0.0052]])}})

# param_groups属性输出
[{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False, 'params': [tensor([[-1.3031, -1.1761],
        [-1.7415, -2.5510]], requires_grad=True)]}, {'lr': 0.0001, 'nesterov': True, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'params': [tensor([[ 0.4539, -2.1901, -0.6662],
        [ 0.6630, -1.5178, -0.8708],
        [-2.0222,  1.4573,  0.8657]], requires_grad=True)]}]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#PyTorch
上次更新: 2025/06/25, 11:25:50
损失函数
PyTorch计算图

← 损失函数 PyTorch计算图→

最近更新
01
帮助信息查看
06-08
02
常用命令
06-08
03
学习资源
06-07
更多文章>
Theme by Vdoing | Copyright © 2022-2025 Geeks_Z | MIT License
京公网安备 11010802040735号 | 京ICP备2022029989号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式