【PyTorch基础教程9】优化器和训练过程

简介: (2)optimizer在一个神经网络的epoch中需要实现下面两个步骤:梯度置零,梯度更新

学习总结

(1)每个优化器都是一个类,一定要进行实例化才能使用,比如:

class Net(nn.Moddule):
    ···
net = Net()
optim = torch.optim.SGD(net.parameters(), lr=lr)
optim.step()

(2)optimizer在一个神经网络的epoch中需要实现下面两个步骤:

梯度置零,梯度更新。

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

一、优化器

深度学习的目标是通过不断改变网络参数,使得参数能够对输入做各种非线性变换拟合输出,本质上就是一个函数去寻找最优解,只不过这个最优解是一个矩阵,而如何快速求得这个最优解是深度学习研究的一个重点——以经典的resnet-50为例,它大约有2000万个系数需要进行计算,那么我们如何计算出来这么多的系数,有以下两种方法:


(1)第一种是最直接的暴力穷举一遍参数,这种方法的实施可能性基本为0,堪比愚公移山plus的难度。

(2)为了使求解参数过程更加快,人们提出了第二种办法,即就是是BP+优化器逼近求解。


因此,优化器就是根据网络反向传播的梯度信息来更新网络的参数,以起到降低loss函数计算值,使得模型输出更加接近真实标签。


二、Pytorch的优化器

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 = []

ptimizer有三个属性:

  • defaults:存储的是优化器的超参数,例子如下:
{'lr': 0.1, 'momentum': 0.9, 'dampening': 0, 'weight_decay': 0, 'nesterov': False}
  • 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]])}})
  • 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}]

Optimizer还有以下的方法:

  • zero_grad():清空所管理参数的梯度,Pytorch的特性是张量的梯度不自动清零,因此每次反向传播后都需要清空梯度。
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
  • step():执行一步梯度更新,参数更新
def step(self, closure): 
    raise NotImplementedError
  • add_param_group():添加参数组
def add_param_group(self, param_group):
    assert isinstance(param_group, dict), "param group must be a dict"
# 检查类型是否为tensor
    params = param_group['params']
    if isinstance(params, torch.Tensor):
        param_group['params'] = [params]
    elif isinstance(params, set):
        raise TypeError('optimizer parameters need to be organized in ordered collections, but '
                        'the ordering of tensors in sets will change between runs. Please use a list instead.')
    else:
        param_group['params'] = list(params)
    for param in param_group['params']:
        if not isinstance(param, torch.Tensor):
            raise TypeError("optimizer can only optimize Tensors, "
                            "but one of the params is " + torch.typename(param))
        if not param.is_leaf:
            raise ValueError("can't optimize a non-leaf Tensor")
    for name, default in self.defaults.items():
        if default is required and name not in param_group:
            raise ValueError("parameter group didn't specify a value of required optimization parameter " +
                             name)
        else:
            param_group.setdefault(name, default)
    params = param_group['params']
    if len(params) != len(set(params)):
        warnings.warn("optimizer contains a parameter group with duplicate parameters; "
                      "in future, this will cause an error; "
                      "see github.com/pytorch/pytorch/issues/40967 for more information", stacklevel=3)
# 上面好像都在进行一些类的检测,报Warning和Error
    param_set = set()
    for group in self.param_groups:
        param_set.update(set(group['params']))
    if not param_set.isdisjoint(set(param_group['params'])):
        raise ValueError("some parameters appear in more than one parameter group")
# 添加参数
    self.param_groups.append(param_group)
  • load_state_dict() :加载状态参数字典,可以用来进行模型的断点续训练,继续上次的参数进行训练
def load_state_dict(self, state_dict):
    r"""Loads the optimizer state.
    Arguments:
        state_dict (dict): optimizer state. Should be an object returned
            from a call to :meth:`state_dict`.
    """
    # deepcopy, to be consistent with module API
    state_dict = deepcopy(state_dict)
    # Validate the state_dict
    groups = self.param_groups
    saved_groups = state_dict['param_groups']
    if len(groups) != len(saved_groups):
        raise ValueError("loaded state dict has a different number of "
                         "parameter groups")
    param_lens = (len(g['params']) for g in groups)
    saved_lens = (len(g['params']) for g in saved_groups)
    if any(p_len != s_len for p_len, s_len in zip(param_lens, saved_lens)):
        raise ValueError("loaded state dict contains a parameter group "
                         "that doesn't match the size of optimizer's group")
    # Update the state
    id_map = {old_id: p for old_id, p in
              zip(chain.from_iterable((g['params'] for g in saved_groups)),
                  chain.from_iterable((g['params'] for g in groups)))}
    def cast(param, value):
        r"""Make a deep copy of value, casting all tensors to device of param."""
      .....
    # Copy state assigned to params (and cast tensors to appropriate types).
    # State that is not assigned to params is copied as is (needed for
    # backward compatibility).
    state = defaultdict(dict)
    for k, v in state_dict['state'].items():
        if k in id_map:
            param = id_map[k]
            state[param] = cast(param, v)
        else:
            state[k] = v
    # Update parameter groups, setting their 'params' value
    def update_group(group, new_group):
       ...
    param_groups = [
        update_group(g, ng) for g, ng in zip(groups, saved_groups)]
    self.__setstate__({'state': state, 'param_groups': param_groups})
  • state_dict():获取优化器当前状态信息字典
def state_dict(self):
    r"""Returns the state of the optimizer as a :class:`dict`.
    It contains two entries:
    * state - a dict holding current optimization state. Its content
        differs between optimizer classes.
    * param_groups - a dict containing all parameter groups
    """
    # Save order indices instead of Tensors
    param_mappings = {}
    start_index = 0
    def pack_group(group):
    ......
    param_groups = [pack_group(g) for g in self.param_groups]
    # Remap state to use order indices as keys
    packed_state = {(param_mappings[id(k)] if isinstance(k, torch.Tensor) else k): v
                    for k, v in self.state.items()}
    return {
        'state': packed_state,
        'param_groups': param_groups,
    }

四、实验

五、训练与评估

完成了上述设定后就可以加载数据开始训练模型了。之前在DataLoader构建完成后介绍了如何从中读取数据,在训练过程中使用类似的操作即可,区别在于此时要用for循环读取DataLoader中的全部数据

训练过程:

# -*- coding: utf-8 -*-
"""
Created on Sun Oct 17 12:04:24 2021
@author: 86493
"""
# 训练状态,模型参数应该支持反向传播的修改
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()
    # 后续还可以计算模型准确率等指标  

完整的:

def train(epoch):
    model.train()
    train_loss = 0
    for data, label in train_loader:
        # 将数据放到GPU上用于后续计算
        data, label = data.cuda(), label.cuda()
        # 开始用当前批次数据训练时先清零优化器的梯度
        optimizer.zero_grad()
        # 将data送入模型中训练
        output = model(data)
        # 计算损失函数
        loss = criterion(label, output)
        # 将loss反向传播回网络
        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))

验证/测试的流程基本与训练过程一致,不同点在于:

  • 需要预先设置torch.no_grad,以及将model调至eval模式
  • 不需要将优化器的梯度置零
  • 不需要将loss反向回传到网络
  • 不需要更新optimizer

验证的完整过程:

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)) 
相关文章
|
2月前
|
机器学习/深度学习 PyTorch 测试技术
从训练到推理:Intel Extension for PyTorch混合精度优化完整指南
PyTorch作为主流深度学习框架,凭借动态计算图和异构计算支持,广泛应用于视觉与自然语言处理。Intel Extension for PyTorch针对Intel硬件深度优化,尤其在GPU上通过自动混合精度(AMP)提升训练与推理性能。本文以ResNet-50在CIFAR-10上的实验为例,详解如何利用该扩展实现高效深度学习优化。
149 0
|
4月前
|
机器学习/深度学习 PyTorch API
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
本文深入探讨神经网络模型量化技术,重点讲解训练后量化(PTQ)与量化感知训练(QAT)两种主流方法。PTQ通过校准数据集确定量化参数,快速实现模型压缩,但精度损失较大;QAT在训练中引入伪量化操作,使模型适应低精度环境,显著提升量化后性能。文章结合PyTorch实现细节,介绍Eager模式、FX图模式及PyTorch 2导出量化等工具,并分享大语言模型Int4/Int8混合精度实践。最后总结量化最佳策略,包括逐通道量化、混合精度设置及目标硬件适配,助力高效部署深度学习模型。
669 21
PyTorch量化感知训练技术:模型压缩与高精度边缘部署实践
|
10月前
|
存储 物联网 PyTorch
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
**Torchtune**是由PyTorch团队开发的一个专门用于LLM微调的库。它旨在简化LLM的微调流程,提供了一系列高级API和预置的最佳实践
541 59
基于PyTorch的大语言模型微调指南:Torchtune完整教程与代码示例
|
7月前
|
算法 测试技术 Swift
Kimi开源Moonlight-16B-A3B:基于Muon优化器的高效大模型,性能与训练效率双突破!
Kimi开源Moonlight-16B-A3B:基于Muon优化器的高效大模型,性能与训练效率双突破!
192 5
|
9月前
|
机器学习/深度学习 人工智能 PyTorch
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比
本文将系统阐述DPO的工作原理、实现机制,以及其与传统RLHF和SFT方法的本质区别。
622 22
使用PyTorch实现GPT-2直接偏好优化训练:DPO方法改进及其与监督微调的效果对比
|
机器学习/深度学习 并行计算 PyTorch
优化技巧与策略:提高 PyTorch 模型训练效率
【8月更文第29天】在深度学习领域中,PyTorch 是一个非常流行的框架,被广泛应用于各种机器学习任务中。然而,随着模型复杂度的增加以及数据集规模的增长,如何有效地训练这些模型成为了一个重要的问题。本文将介绍一系列优化技巧和策略,帮助提高 PyTorch 模型训练的效率。
941 0
|
10月前
|
并行计算 监控 搜索推荐
使用 PyTorch-BigGraph 构建和部署大规模图嵌入的完整教程
当处理大规模图数据时,复杂性难以避免。PyTorch-BigGraph (PBG) 是一款专为此设计的工具,能够高效处理数十亿节点和边的图数据。PBG通过多GPU或节点无缝扩展,利用高效的分区技术,生成准确的嵌入表示,适用于社交网络、推荐系统和知识图谱等领域。本文详细介绍PBG的设置、训练和优化方法,涵盖环境配置、数据准备、模型训练、性能优化和实际应用案例,帮助读者高效处理大规模图数据。
201 5
|
并行计算 PyTorch 算法框架/工具
基于CUDA12.1+CUDNN8.9+PYTORCH2.3.1,实现自定义数据集训练
文章介绍了如何在CUDA 12.1、CUDNN 8.9和PyTorch 2.3.1环境下实现自定义数据集的训练,包括环境配置、预览结果和核心步骤,以及遇到问题的解决方法和参考链接。
704 4
基于CUDA12.1+CUDNN8.9+PYTORCH2.3.1,实现自定义数据集训练
|
10月前
|
算法 Python
SciPy 教程 之 SciPy 优化器 3
SciPy 的 optimize 模块提供了多种最优化算法,如查找函数最小值或方程的根。通过 `optimize.root` 可以解决非线性方程,而 `minimize` 函数则用于最小化目标函数,支持多种优化方法。例如,使用 BFGS 方法最小化函数 \(x^2 + x + 2\),可得到最小值 1.75 和对应的 x 值 -0.5。
188 1
|
11月前
|
机器学习/深度学习 算法 数据可视化
如果你的PyTorch优化器效果欠佳,试试这4种深度学习中的高级优化技术吧
在深度学习领域,优化器的选择对模型性能至关重要。尽管PyTorch中的标准优化器如SGD、Adam和AdamW被广泛应用,但在某些复杂优化问题中,这些方法未必是最优选择。本文介绍了四种高级优化技术:序列最小二乘规划(SLSQP)、粒子群优化(PSO)、协方差矩阵自适应进化策略(CMA-ES)和模拟退火(SA)。这些方法具备无梯度优化、仅需前向传播及全局优化能力等优点,尤其适合非可微操作和参数数量较少的情况。通过实验对比发现,对于特定问题,非传统优化方法可能比标准梯度下降算法表现更好。文章详细描述了这些优化技术的实现过程及结果分析,并提出了未来的研究方向。
308 1

热门文章

最新文章

推荐镜像

更多