背景
本来开开心心(误)在Ubuntu上调代码,后来在某一次操作后突然发现自己代码开始报Segment Fault错误,而且电脑设置是可以产生core文件的,所以每次都会产生一个名字类似core_Python_*
的core文件,但是自己往常对于Segment Fault的认知还是停留在访问了不该访问的内存这里,而且往常调试core文件需要使用gdb,并且需要得到可执行文件,对于Python产生的core文件就不知道如何处理了,所以就展开了折腾之路。
问题描述
问题如背景所述,
环境参数如下:
Ubuntu 20.04
torch 1.9.0 pypi_0 pypi
torchaudio 0.10.0 py38_cu113 pytorch
torchvision 0.11.0 py38_cu113 pytorch
tensorflow 2.8.0 pypi_0 pypi
问题解决
本身正常的思路应该是回退,找到导致出错的步骤,但是由于自己本来以为是TensorFlow和cuda的问题,一通操作加reboot
后已经回退不回去了。只能用笨方法找错了。
由于不会调试Python的core文件,所以只能用VS Code的debug工具一步步执行,发现出错点就在TensorFlow的import语句行,由于本身安装的cuda-toolkit是使用PyTorch网站上的conda安装语句直接安装的,所以TensorFlow找不到libcudart.so.11.0
,本以为是这个原因,后来修改了LD_LIBRARY_PATH
后,这个动态库找到了,但是Segment Fault问题仍未解决。
后来在类似问题解决方案中发现有可能是TensorFlow和某些库冲突,所以就把问题行之前的所有import语句按顺序执行,终于定位到了问题,就是import torchvision后再import tensorflow导致的错误。而自己当时导致出错的语句就是import了某个模块,而这个.py
文件中就有torchvision相关语句。
找到问题之后我已经可以很容易复现错误了,只需要执行如下代码,对应之前提到的版本,就可复现错误。
import torchvision
import tensorflow
就会出现Segment fault
错误。
找到问题就想要解决问题,看看是版本问题还是环境的库路径问题,找到了一个相关问题,在这个链接中有人提了一个issue,提到了Torch和TensorFlow之间的冲突导致的Segment Fault问题,从开发者的评论来看,应该是有和**RTLD_GLOBAL**
有关,但知识所限,我还不太清楚,暂且记录一下,有机会再来补充。
更快地找到Python问题行
后来查找问题时,发现了更快地找到问题行的两种方式,列举如下:
利用python3的faulthandler
将以下两行代码加到文件首行
import faulthandler
# 启用代码
faulthandler.enable()
# 后边正常写其他代码
然后在命令行按如下格式启动执行,其实就是在原有的执行方式中加上-X faulthandler
即可。
python -X faulthandler your_script.py
之后可以看到这样的输出,从而快速定位出错行
利用gdb调试Python
本来自己对于gdb的认知停留在调试C++可执行文件和C++的core文件上,后来了解到也可以这样调试Python。记录如下:
gdb python
(gdb) run /path/to/your_script.py
## wait for Segment fault ##
(gdb) backtrace
## stack trace of the py code
当然我在参考链接中看到原作者比较容易地定位到了错误,但是我调试时显示调用堆栈比较多,报错信息有399行,以我现有的知识确实暂时无法找到报错行,暂且记录一下吧。
暂时的解决方案
暂时的解决方案就是在这个项目中不再使用TensorFlow了,把相关代码使用PyTorch代码代替,也只能算是权宜之计了。
启示
学会定位问题
后续复盘的时候,发现是因为import了某个Python模块,里面有from torchvision.transforms import transforms
的语句,才会导致后来import TensorFlow时出现错误,但当时只觉得是TensorFlow库的原因,没想到库的冲突问题,浪费了较多时间。
记住上一步
有时候做了某一步后开始出现错误,就要努力找到这一步的内容,就这次情况而言,其实是import某个模块导致的冲突,不太明显,但是如果知道这一步的话排查问题就会更快一点。
以上,特此记录,分享,交流,进步~