最近在知乎看到有人转载了这里的内容,提醒一下,欢迎转载,但是请注明出处,谢谢。

1. nn.Module.cuda() 和 Tensor.cuda() 的作用效果差异

无论是对于模型还是数据,cuda()函数都能实现从CPU到GPU的内存迁移,但是他们的作用效果有所不同。

对于nn.Module:

model = model.cuda()
model.cuda() 

上面两句能够达到一样的效果,即对model自身进行的内存迁移。

对于Tensor:

和nn.Module不同,调用tensor.cuda()只是返回这个tensor对象在GPU内存上的拷贝,而不会对自身进行改变。因此必须对tensor进行重新赋值,即tensor=tensor.cuda().

例子:

model = create_a_model()
tensor = torch.zeros([2,3,10,10])
model.cuda()
tensor.cuda()
model(tensor)    # 会报错
tensor = tensor.cuda()
model(tensor)    # 正常运行

2. PyTorch 0.4 计算累积损失的不同

以广泛使用的模式total_loss += loss.data[0]为例。Python0.4.0之前,loss是一个封装了(1,)张量的Variable,但Python0.4.0的loss现在是一个零维的标量。对标量进行索引是没有意义的(似乎会报 invalid index to scalar variable 的错误)。使用loss.item()可以从标量中获取Python数字。所以改为:

total_loss += loss.item()

如果在累加损失时未将其转换为Python数字,则可能出现程序内存使用量增加的情况。这是因为上面表达式的右侧原本是一个Python浮点数,而它现在是一个零维张量。因此,总损失累加了张量和它们的梯度历史,这可能会产生很大的autograd 图,耗费内存和计算资源。

3. PyTorch 0.4 编写不限制设备的代码

# torch.device object used throughout this script
device = torch.device("cuda" if use_cuda else "cpu")
model = MyRNN().to(device)# train
total_loss= 0
for input, target in train_loader:input, target = input.to(device), target.to(device)hidden = input.new_zeros(*h_shape)       # has the same device & dtype as `input`...                                                               # get loss and optimizetotal_loss += loss.item()# test
with torch.no_grad():                                    # operations inside don't track historyfor input, targetin test_loader:...

4. torch.Tensor.detach()的使用

detach()的官方说明如下:

Returns a new Tensor, detached from the current graph.The result will never require gradient.

假设有模型A和模型B,我们需要将A的输出作为B的输入,但训练时我们只训练模型B. 那么可以这样做:

input_B = output_A.detach()

它可以使两个计算图的梯度传递断开,从而实现我们所需的功能。

5. ERROR: Unexpected bus error encountered in worker. This might be caused by insufficient shared memory (shm)

出现这个错误的情况是,在服务器上的docker中运行训练代码时,batch size设置得过大,shared memory不够(因为docker限制了shm).解决方法是,将Dataloader的num_workers设置为0.

6. pytorch中loss函数的参数设置

以CrossEntropyLoss为例:

CrossEntropyLoss(self, weight=None, size_average=None, ignore_index=-100, reduce=None, reduction='elementwise_mean')
  • reduce = False,那么 size_average 参数失效,直接返回向量形式的 loss,即batch中每个元素对应的loss.
  • reduce = True,那么 loss 返回的是标量:
    • 如果 size_average = True,返回 loss.mean().
    • 如果 size_average = False,返回 loss.sum().
  • weight : 输入一个1D的权值向量,为各个类别的loss加权,如下公式所示:
  • ignore_index : 选择要忽视的目标值,使其对输入梯度不作贡献。如果 size_average = True,那么只计算不被忽视的目标的loss的均值。
  • reduction : 可选的参数有:‘none’ | ‘elementwise_mean’ | ‘sum’, 正如参数的字面意思,不解释。

7. pytorch的可重复性问题

参考这篇博文: PyTorch的可重复性问题 (如何使实验结果可复现)_hyk_1996的博客-CSDN博客

8. 多GPU的处理机制

使用多GPU时,应该记住pytorch的处理逻辑是:

1.在各个GPU上初始化模型。

2.前向传播时,把batch分配到各个GPU上进行计算。

3.得到的输出在主GPU上进行汇总,计算loss并反向传播,更新主GPU上的权值。

4.把主GPU上的模型复制到其它GPU上。

9. num_batches_tracked参数

今天读取模型参数时出现了错误

KeyError: 'unexpected key "module.bn1.num_batches_tracked" in state_dict'

经过研究发现,在pytorch 0.4.1及后面的版本里,BatchNorm层新增了num_batches_tracked参数,用来统计训练时的forward过的batch数目,源码如下(pytorch0.4.1):

    if self.training and self.track_running_stats:self.num_batches_tracked += 1if self.momentum is None:  # use cumulative moving averageexponential_average_factor = 1.0 / self.num_batches_tracked.item()else:  # use exponential moving averageexponential_average_factor = self.momentum

大概可以看出,这个参数和训练时的归一化的计算方式有关。

因此,我们可以知道该错误是由于训练和测试所用的pytorch版本(0.4.1版本前后的差异)不一致引起的。具体的解决方案是:如果是模型参数(Orderdict格式,很容易修改)里少了num_batches_tracked变量,就加上去,如果是多了就删掉。偷懒的做法是将load_state_dict的strict参数置为False,如下所示:

load_state_dict(torch.load(weight_path), strict=False)

还看到有人直接修改pytorch 0.4.1的源代码把num_batches_tracked参数删掉的,这就非常不建议了。

10. 训练时损失出现nan的问题

最近在训练模型时出现了损失为nan的情况,发现是个大坑。暂时先记录着。

可能导致梯度出现nan的三个原因:

1.梯度爆炸。也就是说梯度数值超出范围变成nan. 通常可以调小学习率、加BN层或者做梯度裁剪来试试看有没有解决。

2.损失函数或者网络设计。比方说,出现了除0,或者出现一些边界情况导致函数不可导,比方说log(0)、sqrt(0).

3.脏数据。可以事先对输入数据进行判断看看是否存在nan.

补充一下nan数据的判断方法:

注意!像nan或者inf这样的数值不能使用 == 或者 is 来判断!为了安全起见统一使用 math.isnan() 或者 numpy.isnan() 吧。

例如:

import numpy as np# 判断输入数据是否存在nan
if np.any(np.isnan(input.cpu().numpy())):print('Input data has NaN!')# 判断损失是否为nan
if np.isnan(loss.item()):print('Loss value is NaN!')

11. ValueError: Expected more than 1 value per channel when training

当batch里只有一个样本时,再调用batch_norm就会报下面这个错误:

  raise ValueError('Expected more than 1 value per channel when training, got input size {}'.format(size))

没有什么特别好的解决办法,在训练前用 num_of_samples % batch_size 算一下会不会正好剩下一个样本。

可以考虑将`DataLoader`的`drop_last`选项设为True,这样的话,当最后一个batch凑不满时,就会舍弃掉。

12. 优化器的weight_decay项导致的隐蔽bug

我们都知道weight_decay指的是权值衰减,即在原损失的基础上加上一个L2惩罚项,使得模型趋向于选择更小的权重参数,起到正则化的效果。但是我经常会忽略掉这一项的存在,从而引发了意想不到的问题。

这次的坑是这样的,在训练一个ResNet50的时候,网络的高层部分layer4暂时没有用到,因此也并不会有梯度回传,于是我就放心地将ResNet50的所有参数都传递给Optimizer进行更新了,想着layer4应该能保持原来的权重不变才对。但是实际上,尽管layer4没有梯度回传,但是weight_decay的作用仍然存在,它使得layer4权值越来越小,趋向于0。后面需要用到layer4的时候,发现输出异常(接近于0),才注意到这个问题的存在。

虽然这样的情况可能不容易遇到,但是还是要谨慎:暂时不需要更新的权值,一定不要传递给Optimizer,避免不必要的麻烦。

13. 优化TensorDataset的数据加载速度

`TensorDataset`提供了已经完全加载到内存中的矩阵的数据读取接口。在使用`TensorDataset`的时候,如果直接用`DataLoader`,会导致数据加载速度非常缓慢,严重拖慢训练速度,分析和解决方案详见Faster PyTorch TensorDataset | The Standard Book of Spells

(感谢网友sinat_26833407分享)

14. 训练底层视觉模型时出现损失值为nan的一个可能性

严格来说这不属于pytorch的坑,但是先记在这里吧。

在用低光照图像训练时,有时会用到random_crop操作,如果不小心裁切到全黑的子区域的话,就会产生一个所有像素值都相同的没有任何信息量的输入,此时如果网络比较深而且用了Instance Norm的话就很容易导致梯度爆炸数值溢出(因为Instance Norm会一直把输出一直变成0,而卷积层因为具有平移等效性不会打破这种平衡)。

这种导致梯度溢出的奇怪bug还是非常难排查的,最好还是在程序里加一下输入数据的格式和数值范围的检查。如果数据集是提前裁剪好而不是训练时裁剪的话,还得注意图像的像素值经过JPG压缩保存成文件后会改变(本来不是全0的图像保存成jpg后有可能就变成了全0)。

15. autocast()和no_grad()混用导致unexpected behaviour

Pytorch中autocast()和no_grad()混用导致unexpected behaviour - 知乎

PyTorch踩过的坑(长期更新,转载请注明出处)相关推荐

  1. 片上总线Wishbone 学习—— 转载请注明出处:http://blog.csdn.net/ce123

    片上总线Wishbone 学习(零)前言 声明:版权所有,欢迎转载! 转载请注明出处:http://blog.csdn.net/ce123 为了更加升入的理解片上系统,比如S3C2440等,今天开始学 ...

  2. 引用请注明出处和转载请注明出处?我的看法

    很多文章和网站 都有这么一条: 引用请注明出处和转载请注明出处,有的无非多了个什么 保留法律权力 之类的 其实想想看,国外XX 小站 "拿去用了" 怎么办,起诉? BT下载&quo ...

  3. 手写多位数字识别器实现 (转载请注明出处!)

    1.主要功能 ①界面化的输入方式,进行实时数字识别 ②可以识别多位的数字,例如23,234 ③CNN进行数字识别 2.运行环境 Windows10.python3.7+.tensorflow2.x 3 ...

  4. 淘宝网的实习生笔试题以及经历--2011 4 1(转载请注明出处,即原创网址)

      昨天晚上7:00在西北工业大学,参加了淘宝网的实习生笔试(技术类),我应聘的是软件研发类.这一方面的人很多. 愚人节这一天,而且又下起了雨,路上车慢的很,感觉挺不顺利的,心情有点糟.到达笔试现场后 ...

  5. 面试常问的算法题,吐血总结,转载请注明出处,然后不要忘记点赞!

    面试常问的算法题,吐血总结,转载请注明出处,然后不要忘记点赞! 本人是硕士,西北地区一个末流211,投了四十家公司,面试了二十五次左右,公司大概有百度.阿里.腾讯.字节.华为.海康.美团(给我一天打了 ...

  6. pytorch替换numpy中的一些组件 //转载请注明来源

    numpy可以同时处理两种数据:list和numpy.ndarray. 而torch只能处理张量(Tensor)数据. 1.替换 np.asarray() import torch data=[[1, ...

  7. 以下是常用的代码收集,没有任何技术含量,只是填坑的积累。转载请注明出处,谢谢。...

    1. css 2.x 文字换行 /*强制不换行*/ white-space:nowrap; /*自动换行*/ word-wrap: break-word; word-break: normal; /* ...

  8. Vue2速成手册(原创不易,转载请注明出处)

    文章目录 Vue速成手册 0 前言 1 基础篇 1.1 Hello world 1.1.1 小结 1.2 模板语法 1.3 v-bind数据绑定 1.4 v-model双向数据绑定 1.5 el的两种 ...

  9. 查看文件时去除注释说明内容(原创贴-转载请注明出处)

    需求说明:好多软件配置文件中会有许多以#开头的注释说明内容和空行,需求是在查看文件的时候不显示这些内容. 1:过滤掉以#开头的行. 命令格式:cat 文件路径 | grep '^#'举例:cat /u ...

最新文章

  1. 基于对应点的6D姿态识别
  2. 修改zabbix后台登录账号和密码,提升为超级管理员
  3. 有关 AI 人才的 6 个真相
  4. 【struts2】struts2简介
  5. myisam和innodb到底谁更快
  6. 如何收集常见的前端性能信息
  7. SQlite数据库的C编程接口(二) 数据库连接 ——《Using SQlite》读书笔记
  8. 这就是XcodeGhost作者的原话
  9. 计算机网络体系结构(详图)
  10. 黑客防线2012合订本
  11. R查看和更改工作路径的命令
  12. java环境_linu安装jdk
  13. 一位外包女程序员的心酸史和无奈
  14. 有测试智商的软件不,测试智商的软件有哪些
  15. c#——完美实现短信验证
  16. 【油猴脚本 Greasemonkey】GM_xmlhttpRequest内部实现原理
  17. 云计算介绍 tcp/ip协议介绍及配置
  18. 3.3.4.2.2 Decimation-in-Frequency (DIF) Radix-2 FFT
  19. c语言中-1 ind,ind c是什么意思
  20. 简单的数字变化:0-9循环

热门文章

  1. 谷歌工程师薪资有多少 羡慕嫉妒恨
  2. 考研英语二-阅读解题技巧:
  3. 局域网内QQ代理设置
  4. Creo 二次开发-自动标注球标
  5. Java系列技术之Hibernate5操作数据库-钟洪发-专题视频课程
  6. 借助这个宝藏神器,我成为全栈了
  7. 通过小狼毫/rime输入法在飞书中输入Tex/Latex公式的效果-2
  8. 2022DASCTF X SU 三月春季挑战赛 checkin 各种脚本学习分析
  9. ASM(五) 利用TreeApi 解析生成及转换Class
  10. 数字经济专家高泽龙谈“金融元宇宙”与“元宇宙金融”