以调用YOLO为例,在PyCharm 中使用相对路径导入包

当我们从GitHub上下载了一些包,需要调用时,或者当需要在电脑里运行多个版本的某程序,以便后续进行不同版本的模型测试和魔改时,如果是通过将你需要的包的路径添加到系统里的方式,会很麻烦,因为每次换版本都要修改系统里的路径,有没有较为快捷的方法,例如在调用YOLO时,只需要下载好各版本的YOLO放在本地,调用的时候只需要使用类似 from  ./yolo8 import YOLO,或 from ./yolo11 import YOLO便可调用yolov8和yolov11。下面便提供一种方案:

例1,

以自写程序为例,首先,我们创建一个符合Python包规范的目录结构:

my_project/

│── main.py

└── my_package/

    ├── __init__.py

    ├── module1.py

    ├── module2.py

    └── subpackage/

        ├── __init__.py

        └── module3.py

文件内容实现

1. 基础模块文件

my_package/module1.py

def greet():

    return "Hello from module1"

my_package/module2.py

from .module1 import greet  # 相对导入同目录下的module1

def greet_twice():

    return greet() + " and " + greet()

my_package/subpackage/module3.py

from ..module1 import greet  # 相对导入上级目录的module1

def greet_from_sub():

    return "Subpackage says: " + greet()

2. 主程序文件

main.py

from my_package.module2 import greet_twice

from my_package.subpackage.module3 import greet_from_sub

print(greet_twice())

print(greet_from_sub())

3.运行结果

当运行main.py时,输出应该是:

Hello from module1 and Hello from module1

Subpackage says: Hello from module1

例2,

以YOLO为例。首先,下载好不同版本的yolo放在本地(文件名中可以有下划线但是不能有横杠,如ultralytics-main,import的时候会识别不到,但是ultralytics_main则可以。),如下图:

下载好官方训练好的模型yolo8n.pt或者yolo11n.pt,链接https://github.com/ultralytics/ultralytics,在主程序yolo_test.py中写入如下代码:

from ultralytics_main_v11.ultralytics.models.yolo import YOLO

# 如果models文件夹下有 __init__.py, 也可以使用from ultralytics_main_v11.ultralytics.models import YOLO

model = YOLO(r'./yolov11n.pt')

results = model(r"./bus.jpg", conf=0.05, device='cpu', save=True)

运行便可,运行后,主文件夹中会出现新文件夹runs,里面有测试的结果。后续如果需要对yolo结构进行修改,则只需要在对应的文件夹(如ultralytics_main_v8)下修改便可。

注意:在下载的文件包如ultralytics_main_v11中,有很多多代码都有相互调用

(如from ultralytics.models.yolo import YOLO),这时应把所有这样的调用代码都改成相对路径(如from ultralytics_main_v11.ultralytics.models.yolo import YOLO),否则调用的是系统默认的也就是已安装的那个版本的YOLO,例如系统里装的是YOLOv8,则只有主文程序使用相对路径调用YOLOv11的程序,YOLOv11中的子程序中的调用包的代码并没有改成相对路径,则会报错:ImportError: cannot import name 'YOLOE' from 'ultralytics.models',因为子程序调用的是YOLOv8的程序,YOLOv8中并无YOLOE的模块。


另外,修改好所有文件的相对路径之后,此时如果使用

from ultralytics_main_v11.ultralytics import YOLO
model_yaml = r"./yolov11s.yaml"
data_yaml = r"./data.yaml"
pre_model = r"./yolov11n.pt"
model = YOLO(model_yaml, task='detect').load(pre_model)

# 训练参数
results = (model.train( data=data_yaml, device=0, epochs=2,imgsz=640, batch=32,workers=2))

的方式调用模型和数据,则可正常运行,如果是通过

from ultralytics_main_v11.ultralytics.models.yolo import YOLO


model = YOLO(r'./yolo11n.pt')

results = model(r"./bus.jpg", conf=0.05, device=0, save=True)

来调用官方下载的预训练模型,如yolov11n.pt,仍然会报错,因为官方在保存.pt 文件时,使用 torch.save() 保存对象,如果保存的是类的实例(例如模型),会将该类的 模块路径和类名 一起序列化。例如:

from ultralytics.nn.task import DetectionModel

model = DetectionModel(...)

torch.save(model, 'model.pt')

这会在 .pt 文件中记录类的完整路径 ultralytics.nn.task.DetectionModel。所以,即使你没有直接写依赖,它也会在反序列化时寻找原始模块结构。这时只需要在脚本开头写上

import sys

sys.path.insert(0, './ ultralytics_main_v11')

则可正常运行。

(如果改用 state_dict 保存模型则不会保存路径依赖

保存时:

torch.save(model.state_dict(), 'model_weights.pt')

加载时:

model = YourModelClass()  # 定义好模型结构

model.load_state_dict(torch.load('model_weights.pt'))

另外2:使用相对路径调用yolo时,有可能会出现所有的输出都会打印两遍的情况,因为这种自定义路径加载的方式有可能 使 logging 被初始化多次,解绝的办法是:

方法一:在程序开始位置清理所有日志器(包括子模块)YOLOv8 的日志器可能在内部被多次注册(比如模型加载一次,推理又注册一次),而且是 自定义的 logger,需要逐个处理:

import logging


# 清理所有 Logger(包括 ultralytics 子模块的)

for name in logging.root.manager.loggerDict:

logging.getLogger(name).handlers.clear()

注意这段代码必须在模型加载,也就是

from ultralytics_main_v11.ultralytics.models.yolo import YOLO

之后。

方法二:手动设置 ultralytics logger 的级别与 handler

找到 ultralytics/yolo/utils/__init__.py 或 ultralytics/utils/__init__.py(可能在你项目的 ultralytics_main_v11/ 下面),它里面有类似:

LOGGER = logging.getLogger("ultralytics")

你可以在你程序最前面这样加(避免重复 handler):

import logging


ultra_logger = logging.getLogger("ultralytics")

ultra_logger.handlers.clear()

ultra_logger.propagate = False  # 防止向上冒泡

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值