pytorch | loss不收敛或者训练中梯度grad为None的问题

这篇具有很好参考价值的文章主要介绍了pytorch | loss不收敛或者训练中梯度grad为None的问题。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

0. 个人觉得有用的参考

  1. 原因定位:
    • https://blog.csdn.net/weixin_44231148/article/details/107240840
    • Pytorch中自定义网络参数,存在梯度但不进行更新 - 漱石的文章 - 知乎
    • https://zhuanlan.zhihu.com/p/92729376
      https://zhuanlan.zhihu.com/p/508458545
  2. 介绍hooks:
    • https://zhuanlan.zhihu.com/p/553627695
    • https://medium.com/analytics-vidhya/pytorch-hooks-5909c7636fb
  3. [强推] 介绍autograd机制,有很多demo,对理解hooks以及autograd非常有帮助:
    • PyTorch 源码解读之 torch.autograd:梯度计算详解 - OpenMMLab的文章 - 知乎
      https://zhuanlan.zhihu.com/p/321449610

其他的想到再补

1. 笔者的一些经验

  1. 笔者血泪史中最重要的一点:网络输出到求loss之间的操作,尽可能简洁
    • 如果NN的输出直接和label可以进行对比,那是最好的情况,比如输出是猫还是狗这种tag
    • 如果不能直接进行对比,则应该尽可能简洁,同时注意以下问题:

1. 1 尽可能注意

  • 避免原地操作:原地操作无法溯源,backward的时候找不到之前的值了
    • 能用torch.squeeze(x),不用x.squeeze_()
    • 能用loss = loss + loss_2,不用loss += loss_2,另外,后者的写法pytorch也会报错
  • 使用pytorch内置的函数或者内置的操作
    • 如果是四则运算可以用+ - * /等无所谓,但是如果是其他操作,pytorch的函数一定比自己写的要好(能用torch的轮子不要自己造),比如logsumexp这种函数,之前还都要自己写,但是现在pytorch也已经帮你写好勒~
  • 尽可能的向量化执行操作。

2. 常用工具

  • 列举一些用过的debug工具,主要用于定位weight不更新,loss不收敛,以及grad为None
  • 工具有好有坏。

2.1 利用hooks输出grad

  1. 众所周知pytorch不保存中间梯度值,所以如果想知道grad到底传没传过去,建议使用pytorch提供的hooks机制

    • hooks机制可能不是很好理解,可以参考上面我给出的一些对autograd和hooks进行介绍的链接。
    • 总之,我的理解是,
      • hooks可以加在pytorch计算图中任何一个地方,开销不大,方便debug,可以获取计算图中任何一个地方的grad或者weight值,尤其是计算图中间节点的grad
      • hook 函数是一个自己定义的函数,只是对函数的input有一些要求,具体要求取决于用的是什么hook
  2. 笔者常用的一套是基于register_hook

grads = {}

def save_grad(name):
	# 返回hook函数 
    def hook(grad):
    # 简单粗暴的直接输出,存到grads中也可以
        # grads[name] = grad
        print(f"name={name}, grad={grad}")
    return hook

def loss_fn(output, target):	

	#### 先对output作一些操作,然后再求mse
	output1 = f_1(output)
	#### 有时候需要检查这个操作会不会影响梯度
	output1.register_hook(save_grad('output1'))
	
	output2 = f_2(output1)
	loss = mse(output2 , target)
	return loss 
for batch_id, data in enumerate(train_loader): 
#.......省略细节,只展示主干

	output = mlp(input_data)
	
	loss = loss_fn(output, target)
	
    optimizer.zero_grad()
    # Only a backward hook is possible for Tensors.
    # 只有执行完backward()之后才会注册hooks
    loss.backward() 
    optimizer.step()

  1. 另一套常用的方法是下面的,基于register_forward_hookregister_full_backward_hook
# hook functions have to take these 3 input
def hook_forward_fn(module, input, output):
    print("It's forward: ")
    print(f"module: {module}")
    print(f"input: {input}")
    print(f"output: {output}")
    print("="*20)

def hook_backward_fn(module, grad_input, grad_output):
    print("It's backward: ")
    print(f"module: {module}")
    print(f"grad_input: {grad_input}")
    print(f"grad_output: {grad_output}")
    print("="*20)

# Set the hooks
mlp.conv1.register_forward_hook(hook_forward_fn)
mlp.conv1.register_full_backward_hook(hook_backward_fn)

  1. 上面两种hooks的区别是:
    • register_hook用于对某个tensor进行加钩子,比如我写的loss函数(没继承module
    • hook_forward_fnhook_backward_fn用于对继承了module的class/对象进行加钩子,比如上面的mlp这个网络

2.2 其他方法输出grad [不建议]

  1. 利用比如retain_graph或者什么方式,也可以保留中间节点的grad值,但是不建议使用,因为内存开销大,偶尔debug下还可以

2.3 tensorboard输出weight值

  1. 利用tensorboard输出weight值可以清楚的看到有没有更新,或者权重更新的方向是不是自己满意的方向
  2. 下图就是一个随着epoch的增加不更新的weight
    pytorch | loss不收敛或者训练中梯度grad为None的问题
  3. 假设你已经掌握了一点点tensorboard的使用方法,下面是我常用的一个demo:
def plot_alpha(writer,mlp,epoch,tag_str):
    """
    plot weight of 'alpha' in tensorboard
    Args:
        writer:  tensorboard writer
        mlp:     the NN model
        epoch:   epoch
        tag_str: the name of the plot window
    """
    for name, param in mlp.named_parameters():
        # 简单写法:想画什么就大概记录下这一层的名字‘block_alpha’,想画权重就是‘weight’,偏移就是'bias'
        if 'block_alpha' in name and 'weight' in name:
            writer.add_histogram(tag=name + tag_str, values=param.data.clone().cpu().numpy(), global_step=epoch)


for batch_id, data in enumerate(train_loader): 
#.......省略细节,只展示主干

	output = mlp(input_data)
	
	loss = loss_fn(output, target)
	
    optimizer.zero_grad()
    loss.backward()
    optimizer.step()
	# plot
    if epoch%3==0:	# 每3个epoch, 画一次weight
        # Record the weight
    	plot_alpha(writer,mlp,epoch,opt.tag_str)
    	
  1. 其他方法:使用注册hooks的方式进行,hook_forward_fnhook_backward_fn上面展示过了

2.4 [不好用] torch.autograd.gradcheck

  1. 代码大概:
from torch.autograd.gradcheck import gradcheck
# grad check
input_test = torch.randn((2,3,300), requires_grad=True,device=device)
test_ans = gradcheck(mlp.to(device), input_test, eps=1e-3)  #, eps=1e-6, atol=1e-4
print("Are the gradients correct: ", test_ans)

  1. 不好用的点在于精度问题,复杂网络或者复杂的loss函数,经常由于精度问题导致无法通过gradcheck
    • 有时候把精度eps设的大一点还可以通过这个梯度检查,但是还有什么意义呢。。

2.5 [不是很好用但也还行]网上的梯度流可视化demo

  1. 来自:https://github.com/t-vi/pytorch-tvmisc/blob/master/visualize/bad_grad_viz.ipynb
  2. 最后可以可视化输出,有问题的节点会被标红

2.6 torch.autograd.detect_anomaly()

  1. 之前用过,但是加上这个后速度非常慢,所以后来也没用过了,想起来再补

欢迎交流:)文章来源地址https://www.toymoban.com/news/detail-475156.html

到了这里,关于pytorch | loss不收敛或者训练中梯度grad为None的问题的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【机器学习】验证集loss震荡(loss的其他问题) 训练深度学习模型loss为nan的原因

    训练过程中发现,train loss一直下降,train acc一直上升;但是val loss、val acc却一直震荡。loss一会上一会下,但是总体趋势是向下的。 “loss震荡但验证集准确率总体下降” 如何解决? 测试集准确率这样震荡是正常的吗? - 李峰的回答 - 知乎 很多经验:loss问题汇总(不收敛、

    2024年02月12日
    浏览(34)
  • YOLO系列训练时出现loss出现nan值或者测试时P\R\map全部为0值的解决办法(GTX16xx系列显卡大坑)

    目录 0 前言(用处不大,可以直接看解决办法) 1 产生问题的原因 2 解决办法 YOLO V5 YOLO V7 2 小结 ☆ 这个问题是GTX16xx用户的大坑,基本上每个GTX16xx用户使用YOLO系列算法,都会遇到这些问题。 这个方法 是不彻底的解决办法 ,牺牲了训练的时间来换取问题的解决,经过本人在

    2024年02月02日
    浏览(44)
  • pytorch或者TensorFlow训练得到的模型嵌入到设备当中使用

    导出模型 : 首先,将已训练的模型导出为一个文件,以便在其他设备上加载和使用。导出的方法和步骤可能因PyTorch或TensorFlow的版本和使用情况而有所不同。一般来说,您需要保存模型的权重参数和结构定义,以及任何必要的标识信息(如输入维度、类别标签等)。 将模型加

    2024年02月16日
    浏览(56)
  • optimizer.zero_grad(), loss.backward(), optimizer.step()的理解及使用

    这三个函数的作用是将梯度归零(optimizer.zero_grad()),然后反向传播计算得到每个参数的梯度值(loss.backward()),最后通过梯度下降执行一步参数更新(optimizer.step())。 简单的说就是进来一个batch的数据,先将梯度归零,计算一次梯度,更新一次网络。 另外一种:将 optimi

    2024年02月09日
    浏览(24)
  • loss = nn.CrossEntropyLoss(reduction=‘none‘)

    nn.CrossEntropyLoss() 函数是 PyTorch 中用于计算交叉熵损失的函数。 其中 reduction 参数用于 控制输出损失的形式 。 当 reduction=\\\'none\\\' 时,函数会输出一个形状为 (batch_size, num_classes) 的矩阵,表示 每个样本的每个类别的损失 。 当 reduction=\\\'sum\\\' 时,函数会对 矩阵求和 ,输出一个标量

    2024年02月14日
    浏览(29)
  • 【小笔记】从算法训练现象分析可能的参数设置问题-loss分析篇

    【学而不思则罔,思而不学则殆】 9.30 首先给出一个理想的训练loss收敛图片:loss平滑的下降,并逐渐收敛到0. 平滑说明学习率设置较合适,收敛到0说明模型在参数空间中收敛到一个很理想的区域。 训练现象: 本质原因: 算法收敛到参数空间中某个较高的“平坦区域”,而

    2024年02月07日
    浏览(26)
  • 训练模型时,wandb关闭问题。你以为加了一句 wandb = None 就能关闭了吗?

    最近在训练模型的时候,总是弹出让我登录wandb官网,先暂且不谈使用wandb的好处。 第一次就把wandb注册了,记得好像需要挂VPN才可以访问。 但是后来才发现,每一次进行训练都会出现 wandb: Currently logged in as: liudawei. Use `wandb login --relogin` to force relogin. 这就意味着每次都得登录

    2024年02月02日
    浏览(33)
  • yolo系列算法训练时loss出现nan值,解决办法(GTX16xx系列显卡的问题)

    1.首先 这个问题时由于GTX16xx系列显卡导致的,只要是使用GTX16xx系列显卡跑yolo系列算法的时候基本上都会遇到这个问题,真是搞得我头大,当我第一次遇到这个问题的时候,我只是简单地认为是 学习率过大导致梯度爆炸 ,但是后来我上网查资料才发现问题出现在我的显卡上

    2023年04月26日
    浏览(36)
  • 机器学习笔记之优化算法(十七)梯度下降法在强凸函数的收敛性分析

    上一节介绍并证明了: 梯度下降法 在 强凸函数 上的收敛速度满足 Q mathcal Q Q -线性收敛 。 本节将介绍:在 更强 的条件下:函数 f ( ⋅ ) f(cdot) f ( ⋅ ) 在其定义域内 二阶可微 , 梯度下降法 在 f ( ⋅ ) f(cdot) f ( ⋅ ) 上的收敛速度存在什么样的结论。 关于 梯度下降法 在

    2024年02月12日
    浏览(33)
  • 机器学习笔记值优化算法(十四)梯度下降法在凸函数上的收敛性

    本节将介绍 梯度下降法 在 凸函数 上的收敛性。 收敛速度:次线性收敛 关于 次线性收敛 ,分为两种 判别 类型: R mathcal R R -次线性收敛与 Q mathcal Q Q -次线性收敛。而次线性收敛的 特点 是: 随着迭代次数的增加,相邻迭代步骤产生的目标函数结果 f ( x k ) , f ( x k + 1 ) f

    2024年02月13日
    浏览(31)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包