PyTorch 编写代码遇到的问题及解决方案

PyTorch编写代码遇到的问题

错误提示:no module named xxx

xxx为自定义文件夹的名字

因为搜索不到,所以将当前路径加入到包的搜索目录

解决方法:

import sys
sys.path.append('..') #将上层目录加入到搜索路径中
sys.path.append('/home/xxx') # 绝对路径
import os
sys.path.append(os.getcwd()) #  #将当前工作路径加入到搜索路径中

还可以在当前终端的命令行设置

export PYTHONPATH=$PYTHONPATH:./

错误提示:AttributeError: ‘NoneType' object has no attribute ‘shape' height, width, channel = img.shape

在Linux系统下img.shape报错AttributeError: ‘NoneType' object has no attribute ‘shape'

img=cv2.imread(),读取一张图片时,img.shape是包含三个量的元组,分别是:

img.shape[0]:图像的高度

img.shape[1]:图像的宽度

img.shape[2]:图像的通道数

解决方法:读的文件出错 或者查看文件路径是否正确

错误提示 :TypeError: slice indices must be integers or None or have an index method

cropped_im = img[ny1 : ny2, nx1 : nx2, :]

解决方法:需要将ny1 : ny2, nx1 : nx2转换成int类型

错误提示 :Input type (torch.cuda.DoubleTensor) and weight type (torch.cuda.FloatTensor) should be the same

以下三小段分别是Data type CPU tensor GPU tensor

32-bit floating point torch.FloatTensor torch.cuda.FloatTensor

64-bit floating point torch.DoubleTensor torch.cuda.DoubleTensor

出错在类型转换

np.float更改为np.float32

import torchvision.transforms as transforms
import numpy as np
transform = transforms.ToTensor()
def convert_image_to_tensor(image):
    """convert an image to pytorch tensor
        image: numpy array , h * w * c
        image_tensor: pytorch.FloatTensor, c * h * w
        """
    image = image.astype(np.float32)
    return transform(image)

错误提示:RuntimeError: zero-dimensional tensor (at position 0) cannot be concatenated

版本问题 旧式写法

import torch
x = torch.tensor(0.1)
y = torch.tensor(0.2)
z = torch.cat((x, y))

改成新式写法

x = torch.tensor([0.1])
y = torch.tensor([0.2])
z = torch.cat((x, y))
print(z)

结果

tensor([0.1000, 0.2000])

错误提示:TypeError: ‘float' object is not subscriptable

多了下标 a = x.tolist()[0]

去除下标 a = x.tolist()

错误提示:argument ‘input' (position 1) must be Tensor, not list

需要将list转换成tensor

假设a是list

torch.tensor(a)

GPU模型和CPU模型之间的转换

假设原来保存的是GPU模型,要转换为CPU模型

torch.save(model, os.path.join( "./complete.pth"))
cpu_model = torch.load("./complete.pth", map_location=lambda storage, loc: storage)
dummy_input = torch.randn(1, 3, 224, 224)

假设原来保存的是CPU模型,要转换为GPU模型

device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
torch.save(model, os.path.join( "./complete.pth"))
gpu_model = torch.load("./complete.pth", map_location=lambda storage, loc: storage.cuda)
dummy_input = torch.randn(1, 3, 224, 224)
dummy_input = dummy_input.to(device)

错误提示 RuntimeError: Subtraction, the - operator, with a bool tensor is not supported. If you are trying to invert a mask, use the ~ or logical_not() operator instead.

原代码

# Store only unsuppressed boxes for this class
image_boxes.append(class_decoded_locs[1 - suppress])
image_labels.append(torch.LongTensor((1 - suppress).sum().item() * [c]).to(device))
image_scores.append(class_scores[1 - suppress])

更改为

image_boxes.append(class_decoded_locs[~suppress])
image_labels.append(torch.LongTensor((~ suppress).sum().item() * [c]).to(device))
image_scores.append(class_scores[~suppress])

错误提示 RuntimeError: Expected object of scalar type Byte but got scalar type Bool for argument #2 ‘other' in call to _th_max

原代码

suppress = torch.zeros((n_above_min_score), dtype=torch.uint8).to(device) 

更改为

suppress = torch.zeros((n_above_min_score), dtype=torch.bool).to(device)  

UserWarning: volatile was removed and now has no effect. Use with torch.no_grad(): instead.

#之前旧版本
...
x = Variable(torch.randn(1), volatile=True)
return x

#新版
with torch.no_grad():
    ...
    x = torch.randn(1)
return x

错误提示

RuntimeError: Attempting to deserialize object on CUDA device 1 but torch.cuda.device_count() is 1. Please use torch.load with map_location to map your storages to an existing device.

或者是 RuntimeError: expected device cuda:0 but got device cuda:1

错误原因之一

使用了CUDA 1显卡训练保存的模型文件,使用CUDA 0验证

代码中写了

device = torch.device(“cuda” if torch.cuda.is_available() else “cpu”)

可以在命令行设置让哪些GPU可见

export CUDA_VISIBLE_DEVICES=1 #GPU编号
export CUDA_VISIBLE_DEVICES=0,1,2,3#4张显卡可见

也可以在代码里改成

checkpoint = torch.load(checkpoint,map_location=‘cuda:0')

错误提示

raise ConnectionError(e, request=request)
requests.exceptions.ConnectionError: HTTPConnectionPool(host='localhost', port=8097): Max retries exceeded with url: /update (Caused by NewConnectionError('<urllib3.connection.HTTPConnection object at 0x7f3111915e80>: Failed to establish a new connection: [Errno 111] Connection refused',))
Exception in user code:

解决方案

因为没有启动visdom可视化程序,所有报错

在终端执行命令 visdom之后就能看到如下信息

Checking for scripts.
It's Alive!
INFO:root:Application Started
You can navigate to http://localhost:8097

nn.Module.cuda() 和 Tensor.cuda()

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

Model:

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

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

Tensor:

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

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

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

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

自适应 CPU 和 GPU设备的 trick

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = Model().to(device)

total_loss = 0
for input, target in train_loader:
 input, target = input.to(device), target.to(device)
 ...
 total_loss = total_loss + loss.item()

with torch.no_grad():
 for input, target in test_loader:
 ...

torch.Tensor.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

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

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', 正如参数的字面意思。

多GPU的处理机制

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

在各个GPU上初始化模型。

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

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

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

训练时损失出现nan的问题

训练模型时出现损失为 nan 的情况

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

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

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

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

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

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

import numpy as np
if np.any(np.isnan(input.cpu().numpy())):
 print("Input data has NaN!")
if(np.isnan(loss.item())):
 print("Loss value is NaN!")

pytorch 内存泄漏

torch.as_tensor(data, dtype=None,device=None)->Tensor : 为data生成tensor。

如果data已经是tensor,且dtype和device与参数相同,则生成的tensor会和data共享内存。如果data是ndarray,且dtype对应,devices为cpu,则同样共享内存。其他情况则不共享内存。

import torch
import numpy
a = numpy.array([1, 2, 3])
t = torch.as_tensor(a)

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 浅谈Pytorch中autograd的若干(踩坑)总结

    关于Variable和Tensor 旧版本的Pytorch中,Variable是对Tensor的一个封装:在Pytorch大于v0.4的版本后,Varible和Tensor合并了,意味着Tensor可以像旧版本的Variable那样运行,当然新版本中Variable封装仍旧可以用,但是对Varieble操作返回的将是一个Tensor. import torch as t from torch.autograd import Variable a = t.ones(3,requires_grad=

  • 解决Pytorch中的神坑:关于model.eval的问题

    有时候使用Pytorch训练完模型,在测试数据上面得到的结果令人大跌眼镜. 这个时候需要检查一下定义的Model类中有没有 BN 或 Dropout 层,如果有任何一个存在 那么在测试之前需要加入一行代码: #model是实例化的模型对象 model = model.eval() 表示将模型转变为evaluation(测试)模式,这样就可以排除BN和Dropout对测试的干扰. 因为BN和Dropout在训练和测试时是不同的: 对于BN,训练时通常采用mini-batch,所以每一批中的mean

  • pytorch掉坑记录:model.eval的作用说明

    训练完train_datasets之后,model要来测试样本了.在model(test_datasets)之前,需要加上model.eval(). 否则的话,有输入数据,即使不训练,它也会改变权值. 这是model中含有batch normalization层所带来的的性质. 在做one classification的时候,训练集和测试集的样本分布是不一样的,尤其需要注意这一点. 补充知识:pytorch测试的时候为何要加上model.eval() Do need to use model.e

  • 解决Numpy与Pytorch彼此转换时的坑

    前言 ​   最近使用 Numpy包与Pytorch写神经网络时,经常需要两者彼此转换,故用此笔记记录码代码时踩(菜)过的坑,网上有人说: Pytorch 又被称为 GPU 版的 Numpy,二者的许多功能都有良好的一一对应. ​但在使用时还是得多多注意,一个不留神就陷入到了 一根烟一杯酒,一个Bug找一宿 的地步. 1.1.numpy --> torch ​   使用 torch.from_numpy() 转换,需要注意,两者共享内存.例子如下: import torch import num

  • PyTorch 编写代码遇到的问题及解决方案

    PyTorch编写代码遇到的问题 错误提示:no module named xxx xxx为自定义文件夹的名字 因为搜索不到,所以将当前路径加入到包的搜索目录 解决方法: import sys sys.path.append('..') #将上层目录加入到搜索路径中 sys.path.append('/home/xxx') # 绝对路径 import os sys.path.append(os.getcwd()) # #将当前工作路径加入到搜索路径中 还可以在当前终端的命令行设置 export

  • Android计算器编写代码

    其实这个安卓计算机,所有的后台思想与<C#计算器编写代码>是一模一样的.Win窗体程序移植到安卓,从C#到Java其实很简单的,因为两者的基本语法都很相像,唯一的难点是安卓的xml布局部分,不像C#窗体能够直接拖.  还是如下图一个能够完成基本四则运算的计算器: 先在res\values\strings.xml设置按钮相应的字体,以免布局文件警告满天飞: <?xml version="1.0" encoding="utf-8"?> <r

  • C#拼图游戏编写代码(2)

    前言:在C#拼图游戏编写代码程序设计 之 C#实现<拼图游戏>(上),上传了各模块代码,而在本文中将详细剖析原理,使读者更容易理解并学习,程序有诸多问题,欢迎指出,共同学习成长! 正文: 拼图是一个非常经典的游戏,基本每个人都知道他的玩法,他的开始,运行,结束.那么,当我们想要做拼图的时候如何入手呢?答案是:从现实出发,去描述需求(尽量描述为文档),当我们拥有了全面的需求,就能够提供可靠的策略,从而在代码中实现,最终成为作品! (一)需求: (这个需求书写较为潦草,为广大小白定制,按照最最最普

  • keras topN显示,自编写代码案例

    对于使用已经训练好的模型,比如VGG,RESNET等,keras都自带了一个keras.applications.imagenet_utils.decode_predictions的方法,有很多限制: def decode_predictions(preds, top=5): """Decodes the prediction of an ImageNet model. # Arguments preds: Numpy tensor encoding a batch of p

  • 关于vue-cli3打包代码后白屏的解决方案

    前言 : 最近使用了vue-cli3.0 开发了一个移动网页端项目,准备打包发布了.按照以往的流程 npm run build 问题来了 打开 dist index.html 文件发现白屏.打开调试后 发现文件引用路径不对 根据以往的经验 根目录下新建 vue.config.js 配置 publicPath module.exports = { ... runtimeCompiler: true, publicPath: './' ... } 满心欢喜的打开,结果还是白屏.打开调试发现文件路径是

  • Pytorch深度学习gather一些使用问题解决方案

    目录 问题场景描述 问题的思考 gather的说明 问题的解决 问题场景描述 我在复现Faster-RCNN模型的过程中遇到这样一个问题: 有一个张量,它的形状是 (128, 21, 4) roi_loc.shape = (128, 21, 4) 与之对应的还有一个label数据 gt_label.shape = (128) 我现在的需求是将label当作第一个张量在dim=1上的索引,将其中的数据拿出来. 具体来说就是,现在有128个样本数据,每个样本中有21个长度为4的向量.label也是1

  • pytorch显存一直变大的解决方案

    在代码中添加以下两行可以解决: torch.backends.cudnn.enabled = True torch.backends.cudnn.benchmark = True 补充:pytorch训练过程显存一直增加的问题 之前遇到了爆显存的问题,卡了很久,试了很多方法,总算解决了. 总结下自己试过的几种方法: **1. 使用torch.cuda.empty_cache() 在每一个训练epoch后都添加这一行代码,可以让训练从较低显存的地方开始,但并不适用爆显存的问题,随着epoch的增加

  • Pytorch测试神经网络时出现 RuntimeError:的解决方案

    Pytorch测试神经网络时出现"RuntimeError: Error(s) in loading state_dict for Net" 解决方法: load_state_dict(torch.load('net.pth') 在前,增加 model = nn.DataParallel(model) 就可以了. 比如 net = NET() net.cuda() net = nn.DataParallel(net) net.load_state_dict(torch.load('ne

  • C#计算器编写代码

    利用C#编写一个计算器.如下图,能够完成基本的四则运算. 当然这个程序甚至还不上Windows附件那个自带的多功能计算器.  不过这个程序的逻辑还是非常值得思考的,首先你要考虑好用户按+ - * / =等运算符号.数字键之后计算器的状态记录问题.  然后要防止多次按某一个键的问题.比如小数点.就不应该让用户在输入一个数的时候键入两次.  最后,还要弄两个数组,一个存放用户在输入的数字,另一个存放用户输入的符号.  制作过程如下,  1.布局如下,同时可以参考<简单实现C#窗体程序判断是否闰年 >

  • Android入门计算器编写代码

    这个简易计算器是我按照一本android开发入门书学的,书上的第一个例子就是计算器的编写.计算器的编写主要涉及到按键的布局和按键输入要点. 一个总的Lnearlayout的布局下orientation设置为vertical垂直分布,然后此布局下再设置1给我Edittext的一个文本框4个Lnearlayout子布局(第4个布局里可以嵌套另外3个Lnearlayout的布局来实现按钮排版)这4个子布局在你的界面上肯定是垂直分布的,因为你的总布局设置vertical.第一个子布局放置4个Button

随机推荐