刚读研的时候看到老师用pdb debug觉得很酷,不知道怎么用,下来后自己试了试,我感觉很好用!(1、可能是因为debug的文件夹都比较熟悉了所以觉得pdb好用,建议还是可以用vscode调试;2、亲身体验在Linux使用pdb调试打印model时显示不完整,不利于查看,在vscode的终端pdb调试能完整的看到model)
1、应用场景
用于Linux系统下Python文件的debug。
- 直接调试Python文件(此时我们的文件夹就全是Python文件,需要调试的Python文件不在一些执行脚本里面)。
- shell脚本里带有Python文件时(我们实现一些功能的时候,会写一个shell脚本即.sh文件,里面可能包括一些变量、路径之类的,也包括我们要运行的Python文件。运行的时候我们运行.sh文件,如果脚本里有运行Python文件的命令,那自然而然里面的Python文件也被运行到了)。
2、两种方式调试
- 非侵入式方法
python -m pdb xxx.py 如果还有后续的参数,直接加在它后面。
如果是要调试Pytorch的神经网络,如下命令:
torchrun -m pdb xxx.py : 注意调试的时候使用一个GPU, 一个线程来调试最好。 - 侵入式方法
需要在运行的文件中增加一行
import pdb;pdb.set_trace()
3、基本操作
- 查看源代码:
l
查看当前位置前后11行。ll
,查看当前函数的所有代码 - 运行下一行:
n
就是往下运行一行 - 添加断点:
b /mnt/database/xxx.py:100
在/mnt/database/xxx.py路径下的xxx.py文件的第100行打断点 - 清除断点:
cl
- 打印变量值:
p A
打印变量名为A的值(若是想打印这个A的shape之类的属性值都可以,即p A.shape
,就会把A的shape打印出来,打印其他属性操作是一样的) - 进入函数:
s
如果我们运行到某一行,这一行调用了一个函数,我们就可以使用s,然后就可以跳到那个函数里面去 - 执行下一行:
r
如果在函数中,直接运行到函数返回处 - 直接跳转到指定行:
j 100
跳到第100行 - 跳到断点处:
c
先使用b打断点,然后使用c就可以直接跳到断点处 - 持续执行直到运行到指定行:
unt 100
假如我现在在第20行,使用该命令我可以一直往下执行到第100行 - 在函数中时打印函数的参数和参数的值:
a
- 退出pdb调试:
q
- 如果要重新开始下一次调试:(即保留断点设置和debugger设置):
restart
4、例子解释
- 我使用的是wenet中写好的run.sh脚本(wenet是一个做语音识别的开源工具),对网络训练的时候进行debug
- shell脚本内容(看下我代码里的注释)
#!/bin/bash
. ./path.sh || exit 1;
export CUDA_VISIBLE_DEVICES="0"
export NCCL_DEBUG=INFO
num_nodes=1
node_rank=0
data=/mnt/database/luody/wenet-main/examples/aishell/s0/data1
data_url=www.openslr.org/resources/33
nj=16
dict=data/dict/lang_char.txt
data_type=raw
num_utts_per_shard=1000
train_set=train
train_config=/mnt/database/luody/wenet-main/examples/aishell/s0/conf/train_conformer.yaml
cmvn=true
dir=/mnt/database/luody/wenet-main/examples/aishell/s0/exp/conformer_auto_weight
checkpoint=
average_checkpoint=true
decode_checkpoint=$dir/final.pt
average_num=1
. tools/parse_options.sh || exit 1;
mkdir -p $dir
INIT_FILE=$dir/ddp_init
init_method=file://$(readlink -f $INIT_FILE)
echo "$0: init method is $init_method"
num_gpus=$(echo $CUDA_VISIBLE_DEVICES | awk -F "," '{print NF}')
# Use "nccl" if it works, otherwise use "gloo"
dist_backend="gloo"
world_size=`expr $num_gpus \* $num_nodes`
echo "total gpus is: $world_size"
cmvn_opts=
$cmvn && cp data/${train_set}/global_cmvn $dir
$cmvn && cmvn_opts="--cmvn ${dir}/global_cmvn"
i=0
gpu_id=$(echo $CUDA_VISIBLE_DEVICES | cut -d',' -f$[$i+1])
rank=`expr $node_rank \* $num_gpus + $i`
##################################################
# 注意看这里,原本脚本是运行python文件,即直接python wenet/bin/train.py,但是我们想要调试它,就应该是 python -m pdb wenet/bin/train.py
########################################################3
python -m pdb wenet/bin/train.py --gpu $gpu_id \
--config $train_config \
--data_type $data_type \
--symbol_table $dict \
--train_data /mnt/database/luody/wenet-main/examples/aishell/s0/data/$train_set/data.list \
--cv_data /mnt/database/luody/wenet-main/examples/aishell/s0/data/dev/data.list \
${checkpoint:+--checkpoint $checkpoint} \
--model_dir $dir \
--ddp.init_method $init_method \
--ddp.world_size $world_size \
--ddp.rank $rank \
--ddp.dist_backend $dist_backend \
--num_workers 1 \
$cmvn_opts \
--pin_memory
现在我们直接copy上面的代码到终端即可,终端会自动给我们运行
粘贴到终端后的界面如下
接下来就可以开始调试啦
l
:显示当前所在位置的上下文代码
n
:运行一行
b
:打断点(在/mnt/database/luody/wenet_kd_test/wenet/bin/train.py文件的第126行打断点)
c
:跳到断点处(跳到了第126行)
s
:进入函数(train.py文件中有一个函数,我们要进入这个函数用s
,s
后可以看到跳到了executor.py文件的train函数部分)
p
:打印参数以及参数的一些属性(打印参数的shape)
q
:退出调试
5、总结
熟能生巧、多用