导言:
“RuntimeError: Expected object of scalar type Double but got scalar type Float”,这样的错误想必无数次在运行时出现,代码调试是一个十分头疼的问题,头疼归头疼,但总要解决。有些错误从提示就能看出在哪有问题,但要解决这个问题,却不一定是在提示的地方改代码。
解决这类问题的最好方法就是在输出完整的过程,查看运行过程中每一行代码中参数的类型,shape等。从而快速、精确定位到需要改的地方。
点个关注,每天更新两篇计算机视觉的文章
torch snooper
Pytorch有一个十分好用的工具–torchsnooper,在可能出现bug的函数前加一个声明,即可在运行过程中输出这个函数每行代码的所有信息。
安装:
pip install torchsnooper
还有另一个同样的工具– snoop。
pip install snoop
示例:
import torch
def myfunc(mask, x):
y = torch.zeros(6)
y.masked_scatter_(mask, x)
return y
mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda')
source = torch.tensor([1.0, 2.0, 3.0], device='cuda')
y = myfunc(mask, source)
复制代码
运行后出现以下问题:
RuntimeError: Expected object of backend CPU but got backend CUDA for argument #2 'mask'
复制代码
解决办法:使用torchsnooper,在代码前加入import torchsnooper 和@torchsnooper.snoop()
import torch
import torchsnooper
@torchsnooper.snoop()
def myfunc(mask, x):
y = torch.zeros(6)
y.masked_scatter_(mask, x)
return y
mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda')
source = torch.tensor([1.0, 2.0, 3.0], device='cuda')
y = myfunc(mask, source)
复制代码
运行将会出现以下内容:
Starting var:.. mask = tensor<(6,), int64, cuda:0>
Starting var:.. x = tensor<(3,), float32, cuda:0>
21:41:42.941668 call 5 def myfunc(mask, x):
21:41:42.941834 line 6 y = torch.zeros(6)
New var:....... y = tensor<(6,), float32, cpu>
21:41:42.943443 line 7 y.masked_scatter_(mask, x)
21:41:42.944404 exception 7 y.masked_scatter_(mask, x)
复制代码
从提示中可以看出Y是一个在CPU上的tensor, 因此可以将y改为
y = torch.zeros(6, device=’cuda’)
再次运行将会出现新的问题:
RuntimeError: Expected object of scalar type Byte but got scalar type Long for argument #2 'mask'
复制代码
scalar的类型应为int,但却用的是long。在上方torchsnooper输出的提示中可以看出mask的类型为int64,从而定位出问题在这里,将其改为uint8就可以了.
mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda', dtype=torch.uint8)
复制代码
snooper
下面介绍另一种方法,本人一直用的是这种。
在可能出现bug的函数前使用声明@snoop,在执行到这个函数时将会显示这个函数的所有信息。
import torch
import torchsnooper
import snoop
torchsnooper.register_snoop()#在文件前面调用这个函数
@snoop #把这个声明放在想要输出的函数前
def myfunc(mask, x):
y = torch.zeros(6)
y.masked_scatter_(mask, x)
return y
mask = torch.tensor([0, 1, 0, 1, 1, 0], device='cuda')
source = torch.tensor([1.0, 2.0, 3.0], device='cuda')
y = myfunc(mask, source)
复制代码
snoop的另一种用法:使用with torchsnooper.snoop()
with torchsnooper.snoop():
for _ in range(100):
optimizer.zero_grad()
pred = model(x)
squared_diff = (y - pred) ** 2
loss = squared_diff.mean()
print(loss.item())
loss.backward()
optimizer.step()
复制代码
输出如下:
New var:....... x = tensor<(4, 2), float32, cpu>
New var:....... y = tensor<(4,), float32, cpu>
New var:....... model = Model( (layer): Linear(in_features=2, out_features=1, bias=True))
New var:....... optimizer = SGD (Parameter Group 0 dampening: 0 lr: 0....omentum: 0 nesterov: False weight_decay: 0)
22:27:01.024233 line 21 for _ in range(100):
New var:....... _ = 0
22:27:01.024439 line 22 optimizer.zero_grad()
22:27:01.024574 line 23 pred = model(x)
New var:....... pred = tensor<(4, 1), float32, cpu, grad>
22:27:01.026442 line 24 squared_diff = (y - pred) ** 2
New var:....... squared_diff = tensor<(4, 4), float32, cpu, grad>
22:27:01.027369 line 25 loss = squared_diff.mean()
New var:....... loss = tensor<(), float32, cpu, grad>
22:27:01.027616 line 26 print(loss.item())
22:27:01.027793 line 27 loss.backward()
22:27:01.050189 line 28 optimizer.step()
复制代码
y的shape为(4,)而pred的shape为(4,1)。从而定位出问题在于pred多了一维,在代码中加一行pred = model(x).squeeze()即可解决问题。
本文来源于公众号 CV技术指南 的技术总结系列。
欢迎关注公众号 CV技术指南 ,专注于计算机视觉的技术总结、最新技术跟踪、经典论文解读。
在公众号中回复关键字 “技术总结” 可获取以下文章的汇总pdf。
其它文章