PyTorch版YOLOv5与YOLOv7多进程推理模型加载路径错误咨询
多进程加载YOLOv5与YOLOv7推理的路径冲突及相关问题解答
我需要在同一项目中通过多进程(支持CPU或GPU)分别加载PyTorch版YOLOv5与YOLOv7进行推理,但出现模型加载路径错误。报错显示加载YOLOv5时,torch.load从YOLOv7的models.common模块中找不到'C3'属性。
项目结构
project_root/ ├── yolov5/ │ ├── models/ │ │ ├── common.py │ │ └── yolo.py │ └── utils/ ├── yolov7/ │ ├── models/ │ │ ├── common.py │ │ └── yolo.py │ └── utils/ └── inference.py
核心代码(inference.py)
import torch import multiprocessing as mp import sys import os def load_yolov5(): # 设置路径 sys.path.insert(0, './yolov5') from models.common import C3 # 确保能找到YOLOv5的C3 model = torch.load('./yolov5/yolov5s.pt', map_location='cpu') print("YOLOv5加载成功") # 推理逻辑... def load_yolov7(): # 设置路径 sys.path.insert(0, './yolov7') from models.common import Conv # 确保能找到YOLOv7的模块 model = torch.load('./yolov7/yolov7.pt', map_location='cpu') print("YOLOv7加载成功") # 推理逻辑... if __name__ == '__main__': # 设置环境变量尝试解决路径问题 os.environ['PYTHONPATH'] = './yolov5:./yolov7' p1 = mp.Process(target=load_yolov5) p2 = mp.Process(target=load_yolov7) p1.start() p2.start() p1.join() p2.join()
完整报错栈
Traceback (most recent call last): File "<string>", line 1, in <module> File "/usr/lib/python3.8/multiprocessing/spawn.py", line 116, in spawn_main exitcode = _main(fd, parent_sentinel) File "/usr/lib/python3.8/multiprocessing/spawn.py", line 125, in _main prepare(preparation_data) File "/usr/lib/python3.8/multiprocessing/spawn.py", line 236, in prepare _fixup_main_from_path(data['init_main_from_path']) File "/usr/lib/python3.8/multiprocessing/spawn.py", line 287, in _fixup_main_from_path main_content = runpy.run_path(main_path, File "/usr/lib/python3.8/runpy.py", line 265, in run_path return _run_module_code(code, init_globals, run_name, File "/usr/lib/python3.8/runpy.py", line 94, in _run_module_code _run_code(code, mod_globals, init_globals, File "/home/user/project/inference.py", line 10, in <module> load_yolov5() File "/home/user/project/inference.py", line 8, in load_yolov5 model = torch.load('./yolov5/yolov5s.pt', map_location='cpu') File "/home/user/.local/lib/python3.8/site-packages/torch/serialization.py", line 713, in load return _load(opened_zipfile, map_location, pickle_module, **pickle_load_args) File "/home/user/.local/lib/python3.8/site-packages/torch/serialization.py", line 1049, in _load result = unpickler.load() AttributeError: Can't get attribute 'C3' on <module 'models.common' from '/home/user/project/yolov7/models/common.py'>
问题解答
1. 为何torch.serialization的load函数设置断点后无法调试?
torch.load底层依赖Python的pickle模块反序列化模型,pickle加载时直接执行类/函数的导入逻辑,且多进程spawn模式下,子进程是重新启动解释器加载主模块,断点无法被子进程继承。- 反序列化过程中大量操作由C扩展实现,Python调试器无法跟踪C层代码,导致断点无法触发。
2. 为何设置环境变量仍无法找到正确路径获取'C3'属性?
- 环境变量
PYTHONPATH优先级低于sys.path.insert(0, ...),且多进程spawn模式下,子进程会重新执行主模块代码,两个进程的sys.path会互相干扰:比如YOLOv7进程先将./yolov7插入sys.path头部,导致YOLOv5进程加载时,Python优先从YOLOv7的models.common导入,而该模块没有C3类(YOLOv7用的是命名不同的同类结构模块)。 torch.load反序列化时,会根据模型保存时的模块路径查找类,当两个YOLO版本的模块同名时,必然出现路径混淆。
3. 如何实现两模型多进程(单GPU环境下亦可)推理?
- 方案1:重命名模块目录避免冲突
将yolov5的models目录改为yolov5_models,yolov7的改为yolov7_models,修改各自代码中的导入路径,确保模块名唯一,从根源避免路径混淆。 - 方案2:子进程内严格隔离sys.path
在每个子进程函数中,先清空sys.path,再仅添加当前YOLO版本的路径,彻底隔离两个版本的导入环境:def load_yolov5(): sys.path = [] # 清空原有路径 sys.path.insert(0, './yolov5') sys.path.insert(0, os.path.dirname(os.path.abspath(__file__))) # 确保能加载自身模块 from models.common import C3 model = torch.load('./yolov5/yolov5s.pt', map_location='cpu') # 推理逻辑 - 方案3:单GPU下用线程+锁控制推理
单GPU环境下可改用线程代替进程,提前加载好两个模型,推理时加锁避免GPU资源冲突:import threading lock = threading.Lock() def infer_yolov5(img): with lock: results = model_v5(img) return results def infer_yolov7(img): with lock: results = model_v7(img) return results - 方案4:用torch.hub加载官方预训练模型
直接调用官方实现的torch.hub.load加载模型,官方已处理好模块隔离:model_v5 = torch.hub.load('ultralytics/yolov5', 'yolov5s', pretrained=True) model_v7 = torch.hub.load('WongKinYiu/yolov7', 'yolov7', pretrained=True)
4. 同一项目能否混用不同版本的YOLO?
完全可以,但必须解决模块命名冲突和路径隔离问题:
- 要确保不同YOLO版本的核心模块(如
models.common)不会被Python解释器混淆,要么重命名模块目录,要么在加载时严格隔离sys.path。 - 不同YOLO版本的依赖库可能存在版本差异,建议用虚拟环境隔离,或确保项目依赖同时兼容两个版本的YOLO(比如PyTorch版本满足两者要求)。
内容的提问来源于stack exchange,提问作者season
相关产品推荐
相关产品推荐

