如何调试单个cpp_PyTorch Internals 1:源代码调试方法

最近由于疫情的原因宅在家里,刚好有时间看看PyTorch的内部实现。计划这将是一个系列的文章,用来对阅读过程进行记录。这是这个系列的第一篇文章,将介绍如何对PyTorch的源代码进行调试。

相比于TensorFlow,PyTorch的前端python接口设计更加简洁合理,非常适合研究人员快速对新的idea进行实验,同时最近的几个版本也在不断改进其c++后端,使其也能将研究人员训练好的模型部署到实际的工业环境中。一般在做实验时,使用python前端提供的接口就可以完成绝大部分的需求,但是如果能够对PyTorch内部的实现有个大概的认识则可以更好的帮助我们了解库的使用。

一般在阅读大型工程的源代码时,可以通过在关键代码处打断点的方式帮助我们更好的理解代码内部函数间的调用从而理解框架的整体结构。

PyTorch的代码由python前端和c++计算后端构成,对于python部分的代码的调试比较简单,直接使用pdb即可实现。而c++部分代码的调试则相对比较麻烦,需要在c++端捕获python端的运行状态。本文采用了gdb的方式实现c++部分代码的调试。为此,首先需要通过从源码编译的方式安装PyTorch。源码编译安装可以参考官方提供的教程https://github.com/pytorch/pytorch#from-source和https://github.com/pytorch/pytorch/blob/master/CONTRIBUTING.md,本文采用的是Ubuntu18.04系统,PyTorch源代码的版本为1.3.0。具体的步骤如下:

1. 新建一个纯净的conda环境

2. 安装必要的库

conda install numpy ninja pyyaml mkl mkl-include setuptools cmake cffi typing 

3. 下载源代码

git clone --recursive https://github.com/pytorch/pytorch 
cd pytorch 
# if you are updating an existing checkout 
git submodule sync 
git submodule update --init --recursive 

4. 在PyTorch代码根目录下进行编译

export CMAKE_PREFIX_PATH=${CONDA_PREFIX:-"$(dirname $(which conda))/../"} 
DEBUG=1 USE_DISTRIBUTED=0 USE_MKLDNN=0 USE_CUDA=0 BUILD_TEST=0 USE_FBGEMM=0 USE_NNPACK=0 USE_QNNPACK=0 python setup.py develop 

正常情况下应该在半个小时左右就可以完成编译,如果编译过程中出现错误有可能是你的电脑内存不够,可以考虑通过挂载swap的方式增大虚拟内存。

按照debug模式完成编译后,便可以通过加断点的方式进行调试。调试的思路如下:首先运行python代码,获取当前进程的id号,然后采用gdb对该进程进行捕获,进一步使用gdb在c++层面对代码进行调试。

本文将采用vscode进行调试的工作,我们首先用vscode打开源代码的根目录,然后点击左侧的debug按钮,首次打开时会让我们设置launch.json文件对gdb调试的相关参数进行设置。其中"program"指向我们使用的python文件的路径。

ca67cec0d9ce49fa4940ff1f9c9a1ca5.png

完成设置后,我们便可以正式开始对PyTorch代码进行调试了。

为了方便讲解,本文将以以下的卷积代码为例:

import torch 
inp = torch.rand(1,3,224,224) 
m=torch.nn.Conv2d(3,64,3) 
out=m(inp) 

首先在vscode中启动上述代码,并在进行具体的卷积计算的代码`out=m(inp)`处打上断点,使程序暂时停在这个地方。

de5ccfd11876ba07844401f45168fead.png

然后用vscode中在debug模式下运行pytorch代码,在启动gdb的时候会要求我们输入需要捕获的进程的id,我们也可以直接输入运行的python程序的文件名,vscode会自动帮我们补充对应的进程的id。

1f55ef836d137b5c659acf756102adf8.png

点击确认后系统可能会要求获取root权限,输入y即可。

58514a85459b10b50d0932c9556d4ccd.png

由于上述的python代码在执行过程中最先调用的c++代码为`static PyObject * THPVariable_conv2d(PyObject* self_, PyObject* args, PyObject* kwargs)`,因此可以在该函数处加上断点,当断点成功加载后,可以看到加的断点已经变红,表示断点已成功被绑定到当前的代码中,同时出现了类似下图的log信息。

b129b6278c1f607ab97640957969fb43.png

此时我们便可以继续执行上述的python代码,点击运行后c++侧的代码便会停在对应的断点处。也就是说,PyTorch的执行已经从python层面进入了c++层面,利用gdb我们便可以继续深入调试并理解PyTorch的代码了。

7b076a0d6a0b92c9b1b10636e7da94ee.png

关于conv2d函数在c++层面的具体实现,我们将在下一篇文章中进行介绍,欢迎关注。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值