pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-在pytorch中使用
参考深度学习框架pytorch:入门和实践一书第六章
以深度学习框架PyTorch一书的学习-第六章-实战指南为前提
在pytorch中Debug
pytorch作为一个动态图框架,与ipdb结合能为调试过程带来便捷
对tensorflow等静态图来说,使用python接口定义计算图,然后使用c++代码执行底层运算,在定义图的时候不进行任何计算,而在计算的时候又无法使用pdb进行调试,因为pdb调试只能挑事python代码,故调试一直是此类静态图框架的一个痛点
与tensorflow不同,pytorch可以在执行计算的同时定义计算图,这些计算定义过程是使用python完成的。虽然底层的计算也是用C/C++完成的但是我们能够查看python定义部分都变量值,这就足够了
下面我们将举例说明:
- 如何在PyTorch中查看神经网络各个层的输出
- 如何在PyTorch中分析各个参数的梯度
- 如何动态修改PyTorch的训练流程
以第六章的猫狗分类为例,里面的train()函数中有一个设置:
# 进入debug模式
if os.path.exists(opt.debug_file):
import ipdb;
ipdb.set_trace()
即如果设置了这个文件,那么就进入了调试模式
即每次迭代训练到这里的时候就会进入debug模式
首先先将训练运行起来:
user@home:/opt/user/dogcat/chapter6$ python main.py train --env=main --train-data-root=./data/train/ --lr=0.005 --batch-size= --model='ResNet34' --max-epoch= --load-model-path=None --debug-file=./tmp/debug
user config:
env main
vis_port
model ResNet34
train_data_root ./data/train/
test_data_root ./data/test1
load_model_path None
batch_size
use_gpu True
num_workers
print_freq
debug_file ./tmp/debug
result_file result.csv
max_epoch
lr 0.005
lr_decay 0.5
weight_decay 0.0
WARNING:root:Setting up a new session...
WARNING:visdom:Without the incoming socket you cannot receive events from the server or register event handlers to your Visdom client.
/home/home/anaconda3/lib/python3./site-packages/torchvision/transforms/transforms.py:: UserWarning: The use of the transforms.RandomSizedCrop transform is deprecated, please use transforms.RandomResizedCrop instead.
"please use transforms.RandomResizedCrop instead.")
然后这个时候在本地路径下创建tmp/debug文件夹:
user@home:/opt/user/dogcat/chapter6/tmp$ mkdir debug
那么就会因为检测到这个文件夹而进入到调试模式:
39it [:, .58it/s]> /opt/user/dogcat/chapter6/main.py()train() ---> for ii,(data,label) in tqdm(enumerate(train_dataloader)): ipdb>
首先就可以使用l 90命令去查看第90行附近的代码,即上下五行的代码:
19it [:, .92it/s]> /opt/user/dogcat/chapter6/main.py()train() ---> for ii,(data,label) in tqdm(enumerate(train_dataloader)): ipdb> l
target = label.to(opt.device) optimizer.zero_grad()
score = model(input)
loss = criterion(score,target)
loss.backward()
optimizer.step() # meters update and visualize
然后使用break 89在89行处设置断点:
ipdb> break
Breakpoint at /opt/user/dogcat/chapter6/main.py:
这个时候打印一下所有参数及其梯度的标准差:
ipdb> model.named_parameters()
<generator object Module.named_parameters at 0x7f18b61431a8>
ipdb> for (name, p) in model.named_parameters(): print(name, p.data.std(), p.grad.data.std())
pre..weight tensor(0.0541, device='cuda:0') tensor(0.0073, device='cuda:0')
pre..weight tensor(0.2988, device='cuda:0') tensor(0.0037, device='cuda:0')
pre..bias tensor(0.0238, device='cuda:0') tensor(0.0042, device='cuda:0')
layer1..left..weight tensor(0.0358, device='cuda:0') tensor(0.0003, device='cuda:0')
layer1..left..weight tensor(0.2853, device='cuda:0') tensor(0.0008, device='cuda:0')
layer1..left..bias tensor(0.0272, device='cuda:0') tensor(0.0005, device='cuda:0')
layer1..left..weight tensor(0.0313, device='cuda:0') tensor(9.1792e-05, device='cuda:0')
layer1..left..weight tensor(0.2931, device='cuda:0') tensor(0.0010, device='cuda:0')
layer1..left..bias tensor(0.0233, device='cuda:0') tensor(0.0005, device='cuda:0')
layer1..right..weight tensor(0.0771, device='cuda:0') tensor(0.0011, device='cuda:0')
layer1..right..weight tensor(0.2923, device='cuda:0') tensor(0.0012, device='cuda:0')
layer1..right..bias tensor(0.0233, device='cuda:0') tensor(0.0005, device='cuda:0')
layer1..left..weight tensor(0.0313, device='cuda:0') tensor(0.0002, device='cuda:0')
layer1..left..weight tensor(0.2865, device='cuda:0') tensor(0.0005, device='cuda:0')
layer1..left..bias tensor(0.0267, device='cuda:0') tensor(0.0003, device='cuda:0')
layer1..left..weight tensor(0.0311, device='cuda:0') tensor(7.7873e-05, device='cuda:0')
layer1..left..weight tensor(0.2890, device='cuda:0') tensor(0.0008, device='cuda:0')
layer1..left..bias tensor(0.0260, device='cuda:0') tensor(0.0002, device='cuda:0')
layer1..left..weight tensor(0.0313, device='cuda:0') tensor(0.0001, device='cuda:0')
layer1..left..weight tensor(0.3063, device='cuda:0') tensor(0.0005, device='cuda:0')
layer1..left..bias tensor(0.0272, device='cuda:0') tensor(0.0002, device='cuda:0')
layer1..left..weight tensor(0.0312, device='cuda:0') tensor(6.5418e-05, device='cuda:0')
layer1..left..weight tensor(0.2905, device='cuda:0') tensor(0.0006, device='cuda:0')
layer1..left..bias tensor(0.0249, device='cuda:0') tensor(0.0001, device='cuda:0')
layer2..left..weight tensor(0.0313, device='cuda:0') tensor(0.0001, device='cuda:0')
layer2..left..weight tensor(0.2959, device='cuda:0') tensor(0.0001, device='cuda:0')
layer2..left..bias tensor(0.0254, device='cuda:0') tensor(0.0001, device='cuda:0')
layer2..left..weight tensor(0.0289, device='cuda:0') tensor(1.8391e-05, device='cuda:0')
layer2..left..weight tensor(0.2847, device='cuda:0') tensor(0.0002, device='cuda:0')
layer2..left..bias tensor(0.0261, device='cuda:0') tensor(7.7771e-05, device='cuda:0')
layer2..right..weight tensor(0.0574, device='cuda:0') tensor(0.0002, device='cuda:0')
layer2..right..weight tensor(0.2861, device='cuda:0') tensor(0.0002, device='cuda:0')
layer2..right..bias tensor(0.0261, device='cuda:0') tensor(7.7771e-05, device='cuda:0')
...
layer4..left..weight tensor(0.2819, device='cuda:0') tensor(0.0020, device='cuda:0')
layer4..left..bias tensor(0.0155, device='cuda:0') tensor(0.0041, device='cuda:0')
fc.weight tensor(0.0233, device='cuda:0') tensor(0.0978, device='cuda:0')
fc.bias tensor(0.0338, device='cuda:0') tensor(0.3471, device='cuda:0')
查看变量——如学习率:
ipdb> opt.lr
0.005
然后修改学习率,同时更改优化器中的学习率,并将参数保存
ipdb> opt.lr = 0.001
ipdb> opt.lr
0.001
ipdb> for p in optimizer.param_groups: p['lr']=opt.lr
ipdb> model.save()
'checkpoints/resnet34_0417_14:55:38.pth'
然后c继续运行,会运行到之前89行的断点处
ipdb> c
20it [:, .13s/it]> /opt/user/dogcat/chapter6/main.py()train()
optimizer.zero_grad()
--> score = model(input)
loss = criterion(score,target)
然后调用s进入model(input)内部,即model.__call__(input)
然后一直向下运行,找到调用内部forward函数的地方:
ipdb> s
--Call--
> /home/home/anaconda3/lib/python3./site-packages/torch/nn/modules/module.py()__call__() --> def __call__(self, *input, **kwargs):
for hook in self._forward_pre_hooks.values(): ipdb> n
> /home/home/anaconda3/lib/python3./site-packages/torch/nn/modules/module.py()__call__()
def __call__(self, *input, **kwargs):
--> for hook in self._forward_pre_hooks.values():
hook(self, input) ipdb>
> /home/home/anaconda3/lib/python3./site-packages/torch/nn/modules/module.py()__call__()
hook(self, input)
--> if torch._C._get_tracing_state():
result = self._slow_forward(*input, **kwargs) ipdb>
> /home/home/anaconda3/lib/python3./site-packages/torch/nn/modules/module.py()__call__()
else:
--> result = self.forward(*input, **kwargs)
for hook in self._forward_hooks.values():
然后再调用s进入forward函数内部
然后向下运行,运行过第一层pre层后查看它们的输出的平均值和标准差
ipdb> s
--Call--
> /opt/user/dogcat/chapter6/models/resnet34.py()forward() ---> def forward(self, x):
x = self.pre(x) ipdb> n
> /opt/user/dogcat/chapter6/models/resnet34.py()forward()
def forward(self, x):
---> x = self.pre(x) ipdb>
> /opt/user/dogcat/chapter6/models/resnet34.py()forward() ---> x = self.layer1(x)
x = self.layer2(x) ipdb> x.data.mean(), x.data.std()
(tensor(0.2565, device='cuda:0'), tensor(0.3837, device='cuda:0'))
然后使用u跳回上一层,直到model(input)处:
ipdb> u
> /home/home/anaconda3/lib/python3./site-packages/torch/nn/modules/module.py()__call__()
else:
--> result = self.forward(*input, **kwargs)
for hook in self._forward_hooks.values(): ipdb> u
> /opt/user/dogcat/chapter6/main.py()train()
optimizer.zero_grad()
--> score = model(input)
loss = criterion(score,target)
然后清除所有断点:
ipdb> clear
Clear all breaks? y
Deleted breakpoint at /opt/user/dogcat/chapter6/main.py:
然后这就实现了在训练中间对参数进行更改然后再继续进行训练的操作
然后就能够使用命令c再继续运行
⚠️当然,这个时候要记得将之前创建的./tmp/debug文件夹删除,否则下次迭代又会进入debug模式
ipdb> c
30it [::, .41s/it]
总结
1)调试
所以当我们想要进入debug模式,修改程序中的某些参数值或者想要分析程序时,就可以在运行是添加参数:--debug-file=./tmp/debug
然后就能够在训练过程中通过创建./tmp/debug文件夹,这样程序就会进入调试模式
调试完成后就能够删除./tmp/debug文件夹并在ipdb调试接口输入c继续运行训练程序
2)退出程序
如果想要退出程序,也可以使用这种方法,先创建./tmp/debug文件夹进入调试模式,然后输入quit在退出debug的同时退出程序
这种退出程序的方法,与ctrl+c的方法相比更加安全,因为这能够保证数据加载的多进程程序也能正确地退出,并释放内存、显存等资源
pytorch和ipdb结合能够完成很多其他框架不能完成或很难实现的功能,主要有下面的几部分:
1)通过debug暂停程序:当程序进入debug模式之后,将不再执行GPU和CPU运算,但是内存和显存集相应的堆栈空间不会释放
2)通过debug分析程序,查看每个层的输出,查看网络的参数情况:通过u\d\s等命令,能够进入指定的代码,通过n可以进行单步执行,从而可以看见每一层的运算结果,便于分析网络的数值分布等信息
3)作为动态图框架,pytorch拥有python动态语言解释执行的优点,我们能够在运行程序时,通过ipdb修改某些变量的值或属性,这些修改能够立即生效。例如可以在训练开始不久后根据损失函数调整学习率,不必重启程序
4)如果在IPython中通过%run魔法方法运行程序,那么在程序异常退出时,可以使用%debug命令,直接进入debug模式,通过u和d调到报错的地方,查看对应的变量。然后找出原因后修改相应的代码即可。
因为有时模型训练好几个小时后,却在要保存模型之前,因为一个小小的拼写错误异常退出。这时候最好的办法就是利用%debug进入调试模式,在调试模式中直接运行model.save()保存模型
在ipython中,%pdb魔术方法能够使得程序出现问题后,不用手动输入%debug而自动进入调试模式,建议使用
pytorch调用cuDNN报错时,报错信息诸如CUDNN_STATUS_BAD_PARAM,从这些报错信息内容很难得到有用的帮助信息,最好先利用CPU运行代码,此时一般会得到相对友好的报错信息。
常见的错误有如下几种:
1)类型不匹配问题:如CrossEntropyLoss的输入target应该是一个LongTensor,而很多人输入FloatTensor
2)部分数据忘记从CPU转到GPU:例如当model存放与GPU时,输入input耶需要转移到GPU才能输入到model中
还有可能是把多个model存放在一个list对象,而在执行model.cuda()时,这个list中的对象是不会被转移到CUDA上的,正确的用法是使用ModuleList替代
3)Tensor形状不匹配:此类问题一般是输入数据形状不对,或是网络结构设计有问题,一般通过u命令跳到指定代码,查看输入和模型参数的形状即可得知
4)程序正常运行、没有报错,但是模型无法收敛的问题:例如二分类问题,交叉熵损失一直徘徊在0.69附近(ln2),或是数值出现溢出等问题
此时可以进入debug模式,用单步执行看看每一层输出的均值或方差,观察从哪一层开始出现数值异常。还要查看每个参数梯度的均值和方差,看看是否出现梯度消失或梯度爆炸的问题。
但是一般在激活函数前增加BatchNorm层、合理的参数初始化、使用Adam优化器,学习率设为0.001,基本上就能确保模型在一定程度上收敛
pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-在pytorch中使用的更多相关文章
- pytorch Debug —交互式调试工具Pdb (ipdb是增强版的pdb)-1-使用说明
初学时大多使用print或log调试程序,这在小规模的程序下很方便 但是更好的方法是一边运行一边检查里面的变量和方法 1.Pdb Pdb是一个交互式的调试工具,集成于Python标准库中 Pdb能让你 ...
- hdu 1024(最大和连续子序列增强版)
题意:最大和连续子序列的增强版,要求从一序列中取出若干段,这些段之间不能交叉,使得和最大并输出. 分析:用dp[i][j]表示前j个数取出i段得到的最大值,那么状态转移方程为dp[i][j]=max( ...
- Django之Django debug toolbar调试工具
一.安装Django debug toolbar调试工具 pip3 install django-debug-toolbar 如果出错命令为 pip install django_debug_tool ...
- Python的功能模块[4] -> pdb/ipdb -> 实现 Python 的单步调试
pdb / ipdb 模块 / pdb / ipdb Module pdb 和 ipdb 的主要作用是用于 Python 程序的单步调试,Python 的调试可参考链接. 下面是一个简单的使用示例 i ...
- 《zw版·delphi与halcon系列原创教程》zw版_THOperatorSetX控件函数列表 v11中文增强版
<zw版·delphi与halcon系列原创教程>zw版_THOperatorSetX控件函数列表v11中文增强版 Halcon虽然庞大,光HALCONXLib_TLB.pas文件,源码就 ...
- 将表里的数据批量生成INSERT语句的存储过程 增强版
将表里的数据批量生成INSERT语句的存储过程 增强版 有时候,我们需要将某个表里的数据全部或者根据查询条件导出来,迁移到另一个相同结构的库中 目前SQL Server里面是没有相关的工具根据查询条件 ...
- 最新GHOST XP系统下载旗舰增强版 V2016年
系统来自:系统妈:http://www.xitongma.com 深度技术GHOST xp系统旗舰增强版 V2016年3月 系统概述 深度技术ghost xp系统旗舰增强版集合微软JAVA虚拟机IE插 ...
- 最新深度技术GHOST XP系统旗舰增强版 V2016年
来自系统妈:http://www.xitongma.com 深度技术GHOST xp系统旗舰增强版 V2016年 系统概述 深度技术ghost xp系统旗舰增强版集合微软JAVA虚拟机IE插件,增强浏 ...
- WinNTSetup v3.8.7 正式版绿色增强版
最强系统安装利器:WinNTSetup 现已更新至 v3.8.7 正式版!这次更新修复调整了诸多问题,新版非常好用接近完美!WinNTSetup 现在已经自带BCDBoot 选项,并且完全支持Wind ...
随机推荐
- Asp.net Core IdentityServer4 入门教程(一):概念解析
目录 1.IdentityServer4 是什么 2.什么是OpenID和OAuth 2.0协议 3.IdentityServer4 可以用来做什么 其他 1.IdentityServer4 是什么 ...
- Spring Boot(十四)RabbitMQ延迟队列
一.前言 延迟队列的使用场景:1.未按时支付的订单,30分钟过期之后取消订单:2.给活跃度比较低的用户间隔N天之后推送消息,提高活跃度:3.过1分钟给新注册会员的用户,发送注册邮件等. 实现延迟队列的 ...
- 【Linux】Rsync的剖析与使用
目录 Rsync的工具剖析与使用 0.Rsync的介绍 1.Rsync的特性 2.Rsync的部署安装 3.搭建远程备份系统. Rsync的工具剖析与使用 0.Rsync的介绍 rsync是Linux ...
- java中变量的存储位置
1.寄存器:最快的存储区, 由编译器根据需求进行分配,我们在程序中无法控制. 2. 栈:存放基本类型的变量数据和对象的引用,但对象本身不存放在栈中,而是存放在堆(new 出来的对象)或者常量池中(字符 ...
- 【.NET Core项目实战-统一认证平台】第七章 网关篇-自定义客户端限流
[.NET Core项目实战-统一认证平台]开篇及目录索引 上篇文章我介绍了如何在网关上增加自定义客户端授权功能,从设计到编码实现,一步一步详细讲解,相信大家也掌握了自定义中间件的开发技巧了,本篇我们 ...
- 一统江湖的大前端(7)React.js-从开发者到工程师
目录 一. 前端打怪升级指南 1.1 我应该从哪个框架开始学? 1.2 一次转职 1.3 二次转职 1.4 转职-其他 二. 为什么你应该学习React 2.1 技术栈的延伸 2.2 组件化开发 2. ...
- Django学习之四:Django Model模块
目录 Django Model 模型 MODEL需要在脑子里记住的基础概念 区分清楚,必须不能混淆的 class Meta 内嵌元数据定义类 简单model创建实例 数据源配置 接着通过models在 ...
- document.getElementById(), getElementsByname(),getElementsByClassName(),getElementsByTagName()方法表示什么以及其意义
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- input 图片上传,第二次上传同一张图片失效
<input type="file" onchange="angular.element(this).scope().addPhoto(this,event)&qu ...
- input中只能写入数字int、float
input 属性 type="number" <input type="number" min="1" max="100&q ...