作者 | hyk_1996

来源 | CSDN博客

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 optimize
    total_loss += loss.item()

# test
with torch.no_grad():                                    # operations inside don't track history
    for 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的可重复性问题
参考这篇博文:
https://blog.csdn.net/hyk_1996/article/details/84307108
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 += 1
        if self.momentum is None:  # use cumulative moving average
            exponential_average_factor = 1.0 / self.num_batches_tracked.item()
        else:  # use exponential moving average
            exponential_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 算一下会不会正好剩下一个样本。
12. 优化器的weight_decay项导致的隐蔽bug
我们都知道weight_decay指的是权值衰减,即在原损失的基础上加上一个L2惩罚项,使得模型趋向于选择更小的权重参数,起到正则化的效果。但是我经常会忽略掉这一项的存在,从而引发了意想不到的问题。
这次的坑是这样的,在训练一个ResNet50的时候,网络的高层部分layer4暂时没有用到,因此也并不会有梯度回传,于是我就放心地将ResNet50的所有参数都传递给Optimizer进行更新了,想着layer4应该能保持原来的权重不变才对。但是实际上,尽管layer4没有梯度回传,但是weight_decay的作用仍然存在,它使得layer4权值越来越小,趋向于0。后面需要用到layer4的时候,发现输出异常(接近于0),才注意到这个问题的存在。
虽然这样的情况可能不容易遇到,但是还是要谨慎:暂时不需要更新的权值,一定不要传递给Optimizer,避免不必要的麻烦。
扫码查看原文
▼▼▼

(*本文为 AI科技大本营转载文章,转载联系原作者

精彩推荐

2019 中国大数据技术大会(BDTC)再度来袭!豪华主席阵容及百位技术专家齐聚,15 场精选专题技术和行业论坛,超强干货+技术剖析+行业实践立体解读,深入解析热门技术在行业中的实践落地。6.6 折票限时特惠(立减1400元),学生票仅 599 元!

推荐阅读

PyTorch踩过的12坑 | CSDN博文精选相关推荐

  1. 谈谈我在PyTorch踩过的12坑

    点击上方"码农突围",马上关注 这里是码农充电第一站,回复"666",获取一份专属大礼包 真爱,请设置"星标"或点个"在看&quo ...

  2. PyTorch实现L2和L1正则化的方法 | CSDN博文精选

    作者 | pan_jinquan 来源 | CSDN博文精选 目录 1.torch.optim优化器实现L2正则化 2.如何判断正则化作用了模型? 2.1未加入正则化loss和Accuracy 2.1 ...

  3. 云原生开发环境初探 | CSDN 博文精选

    作者 | 倚天码农 责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 此前,我们分享了云原生的引申含义(https://blog.csdn.net/weixin_38748858/arti ...

  4. 一文读懂GoogLeNet神经网络 | CSDN博文精选

    作者 | .NY&XX 来源 | CSDN博客 本文介绍的是著名的网络结构GoogLeNet,目的是试图领会其中结构设计思想. GoogLeNet特点 优化网络质量的生物学原理 GoogLeN ...

  5. 数学建模三剑客MSN | CSDN博文精选

    作者 |  天元浪子 来源 | CSDN博文精选 (*点击阅读原文,查看作者更多精彩文章) 1.前言 2.三剑客之Numpy 2.1 数组对象 2.1.1 数据类型 2.1.2 创建数组 2.1.3 ...

  6. gensim词向量Word2Vec安装及《庆余年》中文短文本相似度计算 | CSDN博文精选

    作者 | Eastmount 来源 | CSDN博文精选 (*点击阅读原文,查看作者更多精彩文章) 本篇文章将分享gensim词向量Word2Vec安装.基础用法,并实现<庆余年>中文短文 ...

  7. 干货:NIST评测(SRE19)获胜团队声纹识别技术分析 | CSDN博文精选

    作者 | xjdier 来源 | CSDN博文精选 (*点击阅读原文,查看作者更多精彩文章) 近日,NIST说话人识别技术评测 (Speaker Recognition Evaluation,SRE) ...

  8. 利用MTCNN和FaceNet实现人脸检测和人脸识别 | CSDN博文精选

    作者 | pan_jinquan 来源 | CSDN博文精选 (*点击阅读原文,查看作者更多文章) 人脸检测和人脸识别技术算是目前人工智能方面应用最成熟的技术了.本博客将利用MTCNN和FaceNet ...

  9. 使用自己的数据集训练MobileNet、ResNet实现图像分类(TensorFlow)| CSDN博文精选

    作者 | pan_jinquan 来源 | CSDN博文精选 之前写了一篇博客<使用自己的数据集训练GoogLenet InceptionNet V1 V2 V3模型(TensorFlow)&g ...

最新文章

  1. ADAS辅助驾驶_自动驾驶_技术点列表
  2. 【BZOJ-1127】KUP 悬线法 + 贪心
  3. Python正则表达式用法总结
  4. 2010年04月 小记(MVC2validation, svn)
  5. CSDN下载频道于2014年7月17日改版,23日-24日系统维护
  6. 目前人工智能技术,主要有应用于哪些领域?
  7. Pipeline快速入门
  8. w3c标准语言,W3C标准 - W3C中国
  9. 深度学习基础知识整理
  10. python 爱心文字墙_博客园墙裂推荐!从未见过如些清新脱俗的完整Python+requests接口自动化测试框架搭建文章!...
  11. python如何创建一个文件夹_利用Python怎么创建一个文件夹
  12. weiphp短信接口教程
  13. nginx uwsgi django部署
  14. docker容器 如何精简镜像减小体积
  15. 智慧工地-未来工地新形态
  16. 利用xls下载链接下载资源
  17. 爆料:955不加班公司名单(2023最新版)
  18. 支付宝蚂蚁庄园线下支付链接,支付宝蚂蚁庄园线下支付地址
  19. 十二生肖在英文中的寓意
  20. HighCharts中柏拉图上显示数值

热门文章

  1. ASP.net(C#)批量上传图片(完整版)
  2. 大有可为的“正则表达式”(二)
  3. Luna的大学读书史(1,Intro)
  4. 视频工具ffmpeg
  5. HDU 2561 第二小整数
  6. Alpha冲刺(9/10)
  7. 关于 MongoDB 与 SQL Server 通过本身自带工具实现数据快速迁移 及 注意事项 的探究...
  8. 转载:HBuilder常用快捷键
  9. zookeeper入门系列 : 分布式事务
  10. 01--安装Activiti流程设计器eclipse插件