设为首页 | 加入收藏

欢迎访问幸运彩票app下载ios-幸运彩票app3132-幸运彩票app手机下载

活动预告 >> 幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息

机器之心发布

作者:zasdfgbnm

本文介绍一个用于 PyTorch 代码的实用东西 TorchSnooper。作者是TorchSnooper的作者,也是PyTorch开发者之一

GitHub 项目地址: https://github.com/zasdfgbnm/TorchSnooper


咱们或许遇到这姿态的困扰:比方说运转自己编写的 PyTorch 代码的时分,PyTorch 提示你说数据类型不匹配,需求一个 double 的 tensor 可是你给的却是 float;再或许便是需求一个 CUDA tensor, 你给的却是个 CPU tensor。比方下面这种:


RuntimeError: Expected object of scalar type Double but got scalar type Float


这种问题调试起来很费事,因为你不知道从哪里开端出问题的。比方你或许在代码的第三行用 torch.zeros 新建了一个 CPU tensor, 然后这个 tensor 进行了若干运算,满是在 CPU 上进行的,一向没有报错,直到第十行需求跟你作为输入传进来的 CUDA tensor 进行运算的时分,才报错。要调试这种过错,有时分就不得不一行行地手写 print 句子,十分费事。


再或许,你或许脑子里幻想着将一个 tensor 进行什么姿态的操作,就会得到什么姿态的成果,可是 PyTorch 半途报错说 tensor 的形状不匹配,或许压根没报错可是终究出来的形状不是咱们想要的。这个时分,咱们往往也不知道是什么当地开端跟咱们「预期的发作违背的」。咱们有时分也得需求刺进一大堆 print 句子才干找到原因。


TorchSnooper 便是一个规划了用来处理这个问题的东西。TorchSnooper 的装置十分简略,只需求履行规范的 Python 包装置指令就好:


pip install torchsnooper


装置完了今后,只需求用 @torchsnooper.snoop() 装修一下要调试的函数,这个函数在履行的时分,就会主动 print 出来每一行的履行成果的 tensor 的形状、数据类型、设备、是否需求梯度的信息。


装置完了今后,下面就用两个比如来阐明一下怎样运用。


比如1


比方说咱们写了一个十分简略的函数山药豆:


def myfunc(mask, x):
    y = torch.zeros(6)
    y.masked_scatter_(mask, x)
    return y


咱们是这姿态运用这个函数的:


mask = torch.tensor([010110], device='cuda')
source = torch.tensor([1.02.03.0], device='cuda')
y = myfunc(mask, source)


上面的代码看起来好像没啥问题,可是实际上跑起来,却报错了:


RuntimeError: Expected object of backend CPU but got backend CUDA for argument #2 'mask'


问题在哪里呢?让咱们 snoop 一下!用 @torchsnooper.snoop() 装修一下 myfunc 函数:


import torch
import torchsnooper

@torchsnooper.snoop()
def myfunc(mask, x):
    y = torch.zeros(6)
    y.masked_scatter_(mask, x)
    return y

mask = torch.tensor([010110], device='cuda')
source = torch.tensor([1.02.03.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)


结合咱们的过错,咱们首要去看输出的每个变量的设备,找找最早从哪个变量开端是在 CPU 上的。咱们注意到这一行:


New var:....... y = tensor<(6,), float32, cpu>


这一行直接告知咱们,咱们创立了一个新变量 y, 并把一个 CPU tensor 赋值给了这个变量。这一行对应代码中的 y = torch.zeros(6)。所以咱们意识到,在运用 torch.zeros 的时分,假如不人为指定设备的话,默许创立的 tensor 是在 CPU 上的。咱们把这一行改成 y = torch.zeros(6, device='cuda'),这一行的问题就修正了。


这一行的问题尽管修正了,咱们的问题并没有处理完好,再跑修改正的代码仍是报错,可是这个时分过错变成了:


RuntimeError: Expected object of scalar type Byte but got scalar type Long for argument #2 'mask'


好吧,这次过错出在了数据类型上。这次过错报告比较有提示性,咱们大约能知道是咱们的 mask 的数据类型错了。再看一遍 TorchSnooper 的输出,咱们注意到:


Starting var:.. mask = tensor<(6,), int64, cuda:0>


公然,咱们的 mask 的类型是 int64, 而不该该是应有的 uint8。咱们把 mask 的界说修改好:


mask = torch.tensor([010110], device='cuda', dtype=torch.uint8)


然后就能够运转了。


比如 2


这次咱们要构建一个简略的线性模型:


model = torch.nn.Linear(21)


咱们想要拟合一个平面 y = x1 + 2 * x2 + 3,所以咱们创立了这样一个数据集:


x = torch.tensor([[0.00.0], [0.01.0], [1.00.0], [1.01.0]])
y = torch.tensor([3.05.04.06.0])


咱们运用最一般的 SGD 优化器来进行优化,完好的代码如下:


import torch

model = torch.nn.Linear(21)

x = torch.tensor([[0.00.0], [0.01.0], [1.00.0], [1.01.0]])
y = torch.tensor([3.05.04.06.0])

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)
for _ in range(10):
    optimizer.zero_grad()
    pred = model(x)
    squared_diff = (y - pred) ** 2
    loss = squared_diff.mean()
    print(loss.item())
    loss.backward()
    optimizer.step()


可是运转的进程咱们发现,loss 降到 1.5 左右就不再降了。这是很不正常的,因为咱们构建的数据都是无差错落在要拟合的平面上的,loss 应该降到 0 才算正常。


乍看上去,不知道问题在哪里。抱着试试看的主意,咱们来 snoop 一会儿。这个比如中,咱们没有自界说函数,可是咱们能够运用 with 句子来激活 TorchSnooper。把练习的那个循环装进 with 句子中去,代码就变成了:


import torch
import torchsnooper

model = torch.nn.Linear(21)

x = torch.tensor([[0.00.0], [0.01.0], [1.00.0], [1.01.0]])
y = torch.tensor([3.05.04.06.0])

optimizer = torch.optim.SGD(model.parameters(), lr=0.1)

with torchsnooper.snoop():
    for _ in range(10):
        optimizer.zero_grad()
        pred = model(x)
        squared_diff = (y - pred) ** 2
        loss 幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息= squared_diff.mean()
        print(loss.item())
        loss.backward()
        optimizer.step()


运转程序,咱们看到了一长串的输出,一点一点阅读,咱们注意到


New var:....... model = Linear(in_features=2, out_features=1, bias=True)
New var:....... x = tensor<(42), float32, cpu>
New var:....... y = tensor<(4,), float32, cpu>
New var:....... optimizer = SGD (Parameter Group 0    dampening: 0    lr: 0....omentum: 0    nesterov: False    weight_decay: 0)
02:38:02.016826 line        12     for _ in range(10):
New var:....... _ = 0
02:38:02.017025 line        13         optimizer.zero_grad()
02:38:02.017156 line        14         pred = model(x)
New var:....... pred = tensor<(41), float32, cpu, grad>
02:38:02.018100 line        15         squared_diff = (y - pred) ** 2
New var:....... squared_diff = tensor<(44), float32, cpu, grad>
02:38:02.018397 line        16         loss = squared_diff.mean()
New var:....... loss = tensor<(), float32, cpu, grad>
02:38:02.018674 line        17         print(loss.item())
02:38:02.018852 line        18         loss.backward()
26.979290008544922
02:38:02.057349 line        19         optimizer.step()


仔细观察这里边各个 tensor 的形状,咱们不难发现,y 的形状是 (4,),而 pred 的形状却是 (4, 1),他们俩相减,因为播送的存在,咱们得到的 squared_diff 的形状就变成了 (4, 4)。


这天然不是咱们想要的成果。这个问题修正起来也很简略,把 pred 的界说改成 pred = model(x).squeeze() 即可。现在再看修改后的代码的 TorchSnooper 的输出:


New var:....... model = Linear(in_features=2, out_features=1, bias=True)
New var:....... x = tensor<(42), float32, cpu>
New var:....... y = tensor<(4,), float32, cpu>
New var:....... optimizer = SGD (Parameter Group 0    dampening: 0    lr: 0....omentum: 0    nesterov: False    weight_decay: 0)
02:46:23.545042 line        12     for _ in range(10):
New var:....... _ = 0
02:46:23.545285 line        13         optimizer.zero_grad()
02:46:23.545421 line        14         pred = model(x).squeeze()
New var:....... pred = tensor<(4,), float32, cpu, grad>
02:46:23.546362 line        15         squared_diff = (y - pred) ** 2
New var:....... squared_diff = tensor<(4,), float32, cpu, grad&g幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息t;
02:46:23.546645 line        16         loss = squared_diff.mean()
New var:....... loss = tensor<(), float32, cpu, grad>
02:46:23.546939 幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息;line        17      幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息   print(loss.item())
02:46:23.幸运彩票app下载ios-PyTorch代码调试利器: 主动print每行代码的Tensor信息547133 line        18         loss.backward()
02:46:23.591090 line        19         optimizer.step()


现在这个成果看起来就正常了。而且通过测验,loss 现在现已能够降到很挨近 0 了。功德圆满。



本文为机器之心发布,转载请联络本大众号取得授权

✄------------------------------------------------

参加机器之心(全职记者 / 实习生):hr@jiqizhixin.com

投稿或寻求报导:content@jiqizhixin.com

广告 & 商务协作:bd@jiqizhixin.com



上一条      下一条
返回顶部