问题
我在/home/joyner/yolo11/ultralytics目录下运行训练脚本。但是保存的模型在/home/joyner/yolov8/ultralytics/runs下面。按照常理来说应该是保存在当前目录下的run下面的。
分析
因为我没有修改代码,没有添加额外的参数。所有默认的目录是程序写定。在这之前,我想起来,我之前在这个机器上在两个目录下都安装了ultralytics的代码。先在/home/joyner/yolov8/,后在/home/joyner/yolo11下面。
现在的问题是保存的run文件在之前安装的代码的根目录下。这是为什么呢?
为了知道是在什么地方记录上一次安装了的代码的目录,下面开始debug。
debug
- 找到yolo的trainer部分
class YOLO(Model):"""YOLO (You Only Look Once) object detection model."""def __init__(self, model="yolo11n.pt", task=None, verbose=False):"""Initialize YOLO model, switching to YOLOWorld if model filename contains '-world'."""path = Path(model)if "-world" in path.stem and path.suffix in {".pt", ".yaml", ".yml"}: # if YOLOWorld PyTorch modelnew_instance = YOLOWorld(path, verbose=verbose)self.__class__ = type(new_instance)self.__dict__ = new_instance.__dict__else:# Continue with default YOLO initializationsuper().__init__(model=model, task=task, verbose=verbose)@propertydef task_map(self):"""Map head to model, trainer, validator, and predictor classes."""return {"classify": {"model": ClassificationModel,"trainer": yolo.classify.ClassificationTrainer,"validator": yolo.classify.ClassificationValidator,"predictor": yolo.classify.ClassificationPredictor,},"detect": {"model": DetectionModel,"trainer": yolo.detect.DetectionTrainer,"validator": yolo.detect.DetectionValidator,"predictor": yolo.detect.DetectionPredictor,},"segment": {"model": SegmentationModel,"trainer": yolo.segment.SegmentationTrainer,"validator": yolo.segment.SegmentationValidator,"predictor": yolo.segment.SegmentationPredictor,},"pose": {"model": PoseModel,"trainer": yolo.pose.PoseTrainer,"validator": yolo.pose.PoseValidator,"predictor": yolo.pose.PosePredictor,},"obb": {"model": OBBModel,"trainer": yolo.obb.OBBTrainer,"validator": yolo.obb.OBBValidator,"predictor": yolo.obb.OBBPredictor,},}
- 可以看到DetectionTrainer 继承了BaseTrainer,但是DetectionTrainer没有初始化函数,那我们就继续看BaseTrainer的初始化函数。
- BaseTrainer下的初始化发现了得save_dir关键词。我们在self.save_dir前后都输出关键参数的值。并在后面加上exit(1),只是debug,打印完参数结束了,而不是一直运行程序。
调试输出显示
self.args不包含任何保存的目录信息;
self.save_dir指向的就是
save_dir:/home/joyner/yolov8/ultralytics/runs/detect/train6
所以问题就是在get_save_dir这个函数上面。
- 继续查看get_save_dir这个函数
def get_save_dir(args, name=None):"""Returns the directory path for saving outputs, derived from arguments or default settings.Args:args (SimpleNamespace): Namespace object containing configurations such as 'project', 'name', 'task','mode', and 'save_dir'.name (str | None): Optional name for the output directory. If not provided, it defaults to 'args.name'or the 'args.mode'.Returns:(Path): Directory path where outputs should be saved.Examples:>>> from types import SimpleNamespace>>> args = SimpleNamespace(project="my_project", task="detect", mode="train", exist_ok=True)>>> save_dir = get_save_dir(args)>>> print(save_dir)my_project/detect/train"""if getattr(args, "save_dir", None):save_dir = args.save_direlse:from ultralytics.utils.files import increment_pathprint(f"args.project:{args.project}")print(f"ROOT.parent:{ROOT.parent}")print(f"TESTS_RUNNING:{TESTS_RUNNING}")print(f"RUNS_DIR:{RUNS_DIR}")project = args.project or (ROOT.parent / "tests/tmp/runs" if TESTS_RUNNING else RUNS_DIR) / args.taskprint(f"project:{project}")name = name or args.name or f"{args.mode}"save_dir = increment_path(Path(project) / name, exist_ok=args.exist_ok if RANK in {-1, 0} else True)print(f"save_dir:{save_dir}")return Path(save_dir)
然后继续输出关键参数的值,调试运行后输出为
args.project:None
ROOT.parent:/home/joyner/yolo11/ultralytics
TESTS_RUNNING:False
RUNS_DIR:/home/joyner/yolov8/ultralytics/runs
project:/home/joyner/yolov8/ultralytics/runs/detect
save_dir:/home/joyner/yolov8/ultralytics/runs/detect/train6
self.save_dir:/home/joyner/yolov8/ultralytics/runs/detect/train6
通过print的消息可以看到,是RUNS_DIR记录了之前的信息
继续查看RUNS_DIR是怎么记录的
- 查看RUNS_DIR的定义的代码
SETTINGS = SettingsManager() # initialize settings
print(f"SETTINGS:{SETTINGS}")
PERSISTENT_CACHE = JSONDict(USER_CONFIG_DIR / "persistent_cache.json") # initialize persistent cache
DATASETS_DIR = Path(SETTINGS["datasets_dir"]) # global datasets directory
WEIGHTS_DIR = Path(SETTINGS["weights_dir"]) # global weights directory
RUNS_DIR = Path(SETTINGS["runs_dir"]) # global runs directory
输出为
SETTINGS:JSONDict("/home/joyner/.config/Ultralytics/settings.json"):
{"settings_version": "0.0.6","datasets_dir": "/home/joyner/yolov8/datasets","weights_dir": "/home/joyner/yolov8/ultralytics/weights","runs_dir": "/home/joyner/yolov8/ultralytics/runs","uuid": "69cb628841752b831a1e86cef23499db0bf814ad5713fcf5d418e28e14f1ede4","sync": true,"api_key": "","openai_api_key": "","clearml": true,"comet": true,"dvc": true,"hub": true,"mlflow": true,"neptune": true,"raytune": true,"tensorboard": true,"wandb": false,"vscode_msg": true
}
可以看到save_dir是从本地一个文件里面读取的,而文件记录的是上一次安装目录。
总结
在ultralytics的8.3.49的版本中,如果第一次安装,就会记录在本地~/.config/Ultralytics/settings.json下。第二次安装不会改变这个目录的内容,就会从里面读取save_dir。
参考
https://github.com/ultralytics/ultralytics