简述问题
最近项目在使用yolov8,我个人习惯在pycharm中的console中逐行测试代码,但在pycharm的console中执行yolov8的示例代码报了完全看不懂的错误
具体的报错信息
报错代码
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "D:\python387\lib\multiprocessing\spawn.py", line 123, in spawn_main
exitcode = _main(fd, parent_sentinel)
File "D:\python387\lib\multiprocessing\spawn.py", line 136, in _main
prepare(preparation_data)
File "D:\python387\lib\multiprocessing\spawn.py", line 252, in prepare
_fixup_main_from_path(data['init_main_from_path'])
File "D:\python387\lib\multiprocessing\spawn.py", line 304, in _fixup_main_from_path
main_content = runpy.run_path(main_path,
File "D:\python387\lib\runpy.py", line 265, in run_path
code, fname = _get_code_from_file(run_name, path_name)
File "D:\python387\lib\runpy.py", line 234, in _get_code_from_file
with io.open_code(decoded_path) as f:
OSError: [Errno 22] Invalid argument: 'D:\\yolo\\<input>'
从报错信息看,它是在调用multiprocessing的模块中出现问题
而奇怪的是在cmd中调用python 命令行模式下执行相同代码却没有这种报错,反而是能正常调用的
最初以为是python的版本不兼容,换成了python3.10的版本依旧出现同样的错误,然后以为是pycharm的版本兼容问题,换了低版本的pycharm,依旧没用。
查看后台发现在调用后台时主进程同时启动多个子进程去进行训练,如果是熟悉multiprocessing的应该知道,multiprocessing调用pool时,一般将代码封装到函数或者类里面然后在__main__去调用,我试了一下,将代码放到__main__中去调用,然后整个脚本去运行,果然是能出结果的,而不放到__main__中,则会出现同样的错误,就是如下,第一种写法跟第二种写法的区别。但这也不是我想要的结果,我还是想逐行调试,查看每一步的输出,以达到跟cmd调用时逐行输入调试同样的效果。
# 第一种写法,这种写法会出现报错
from ultralytics import YOLO
model = YOLO("yolov8n.yaml") # build a new model from scratch
model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training)
model.train(data="coco128.yaml", epochs=1)
# 第二种写法,这种写法本质一样,但是不会出现报错
from ultralytics import YOLO
def main():
model = YOLO("yolov8n.yaml") # build a new model from scratch
model = YOLO("yolov8n.pt") # load a pretrained model (recommended for training)
# Use the model
model.train(data="coco128.yaml", epochs=3) # train the model
if __name__ == '__main__':
main()
没办法只能细看代码了。总结来说其实就是pycharm中的环境变量参数略有不同导致的。
具体问题出在prepare函数中的传参preparation_data,在cmd中打印这个preparation_data以及在pycharm中打印preparation_data他们的输出如下:
cmd中的python,preparation_data输出
{'log_to_stderr': False, 'authkey': b'\xb2h\xb73\xa1\xcbx\xd0\xdb\x9f20\xe2\xbfO\xc3\x0f|{\xc1\x9a\xf7\xb6G\xa1\x14d\x02\xd6\xa0\xe8\xf2', 'name': 'Process-24', 'sys_path': ['D:\\yolo', 'D:\\python387\\python38.zip', 'D:\\python387\\DLLs', 'D:\\python387\\lib', 'D:\\python387', 'D:\\python387\\lib\\site-packages'], 'sys_argv': [''], 'orig_dir': 'D:\\yolo', 'dir': 'D:\\yolo', 'start_method': 'spawn'}
pycharm console的preparation_data输出
{'log_to_stderr': False, 'authkey': b'\xa6;t~\xb3\\\x16hC=\xb4G\x8f\x81\xbaoNHqg\xb9j\xad\x0b~bq\xb2\xa7;F\xb1', 'name': 'Process-1', 'sys_path': ['D:\\Program Files\\PyCharm 2023.1.2\\plugins\\python\\helpers\\pydev', 'D:\\Program Files\\PyCharm 2023.1.2\\plugins\\python\\helpers\\third_party\\thriftpy', 'D:\\Program Files\\PyCharm 2023.1.2\\plugins\\python\\helpers\\pydev', 'D:\\yolo', 'D:\\Program Files\\PyCharm 2023.1.2\\plugins\\python\\helpers\\pycharm_display', 'D:\\python387\\python38.zip', 'D:\\python387\\DLLs', 'D:\\python387\\lib', 'D:\\python387', 'D:\\python387\\lib\\site-packages', 'D:\\Program Files\\PyCharm 2023.1.2\\plugins\\python\\helpers\\pycharm_matplotlib_backend', 'D:\\yolo'], 'sys_argv': ['D:/Program Files/PyCharm 2023.1.2/plugins/python/helpers/pydev/pydevconsole.py', '--mode=client', '--host=127.0.0.1', '--port=62180'], 'orig_dir': 'D:\\yolo', 'dir': 'D:\\yolo', 'start_method': 'spawn', 'init_main_from_path': 'D:\\yolo\\<input>'}
细看的话可以发现,pycharm中的preparation_data出现了’init_main_from_path’: ‘D:\yolo\’,跟报错信息出现的是一样的。重点就在于这个D:\yolo\,这不是个路径也不是个文件,那pycharm中定义这个东西到底有什么用?其实这个参数的作用是用于pycharm去准确定位主模块的路径位置,而代表console的输入来自输入流,而就是因为这个参数并不是指代具体的路径,导致这个参数本身并没有什么意义(就是定位主模块的路径位置,虽然另一个参数sys_path中的也会包含环境路径,但并不够具体。),而到了multiprocessing模块中就会调用这个参数的值,导致出现上述的报错。所以解决方案也很粗暴,直接把这个字典的值删掉或者修改multiprocessing的源码。
我这边直接修改multiprocessing的源码。
将:
elif 'init_main_from_path' in data:
_fixup_main_from_path(data['init_main_from_path'])
改为:
elif 'init_main_from_path' in data and '<input>' not in data['init_main_from_path']:
_fixup_main_from_path(data['init_main_from_path'])
其实我也只是回避了这个错误,这个问题更像是pycharm跟python的multiprocessing模块本身的兼容性出现问题。因为本身运行yolov8的代码时,并不需要这个参数,这个参数更像是pycharm中特有的参数值,回避这个问题后整体的代码也能顺利执行,并且得到跟cmd调用时同样的结果了。
暂时没有发现其他项目会有冲突,希望这种方法可以帮到看到这里的你,有问题可以在下面评论留言。