背景
最近在服务器上训练一个基于 ultralytics 的YOLO分割项目,项目目录里已经有一份自己的 ultralytics 源码。

按直觉来说,在项目根目录执行 python train.py,Python 应该优先使用当前项目里的源码。
但实际运行时却出现了很奇怪的问题:
-
平时单独测试
import ultralytics时,路径显示的是自己项目里的包 -
真正训练,尤其是多卡 DDP 启动后,报错却来自虚拟环境里自带的的
site-packages/ultralytics -
自定义参数在训练中失效,提示"不是有效参数"(比如自己项目是最新的v26,之前虚拟环境中的
ultralytics版本不支持v26,没法识别一些参数)
这说明:主进程和训练子进程实际加载的不是同一份代码。
现象
训练时报错类似下面这样:
bash
'angle' is not a valid YOLO argument
'end2end' is not a valid YOLO argument
'rle' is not a valid YOLO argument
但这些参数明明是自己项目里已经支持的。
进一步查看 traceback,会发现报错来自:
bash
.../site-packages/ultralytics/...
而不是项目目录里的:
bash
Project/Det_Seg/ultralytics-main/ultralytics/...
原因分析
问题的根因是:Python 导包路径优先级导致同名包冲突。
虽然项目目录下也有一个 ultralytics,但是在某些启动方式下,尤其是 DDP 多卡训练 时,子进程实际优先加载了环境中已经安装好的 ultralytics,也就是 site-packages 里的版本。
这样就出现了两个后果:
第一,项目里的自定义修改没有生效。
第二,环境包不认识自定义参数,于是直接报错。
不是模型配置错了,而是运行时根本没用到自己项目的那份代码。
如何确认是不是导包错了
最简单的方法是在 Python 里打印实际导入路径:
bash
import ultralytics
print(ultralytics.__file__)
如果输出的是:
bash
Project/Det_Seg/ultralytics-main/ultralytics/__init__.py
说明当前解释器用的是本地项目代码。
如果输出的是:
bash
.../site-packages/ultralytics/__init__.py
那就是加载错了。
解决方案
最直接有效的方法是手动把项目根目录加入 PYTHONPATH:
bash
export PYTHONPATH=/Project/Det_Seg/ultralytics-main:$PYTHONPATH
| 组成部分 | 作用 |
|---|---|
export |
将变量设置为环境变量,使其对当前终端会话以及由它启动的所有子进程(如 Python 解释器)都生效。 |
PYTHONPATH |
这是一个 Python 解释器启动时会读取的特定环境变量,专门用于指定额外的模块搜索路径。 |
= |
赋值操作符。 |
/Project/Det_Seg/ultralytics-main |
你想要添加的绝对路径。这通常是你自己的项目目录或某个库的源代码目录。 |
:$PYTHONPATH |
这部分至关重要。它将原有的 PYTHONPATH 变量的值追加在后面,确保你不会覆盖掉之前可能已经设置好的其他路径。 |
这行命令的作用是:
-
把自己的项目路径加入 Python 模块搜索路径
-
并且放在更靠前的位置
-
这样
import ultralytics时会优先找到项目里的源码,而不是环境里安装的同名包
设置完之后,再次验证:
bash
python -c "import ultralytics; print(ultralytics.__file__)"
如果输出已经指向项目目录,就说明生效了。
在本地开发环境里,很多时候当前工作目录恰好能让 Python 找到项目源码,所以问题不明显。
但到了服务器上,尤其是多卡训练、tmux、远程 shell、DDP 子进程这些场景下,导包路径可能和想象的不一样。这时项目里虽然有源码,但真正运行时未必会优先使用它。
PYTHONPATH的好处在于,它是显式指定路径优先级,能让主进程和子进程都更稳定地加载同一份代码。
适用场景
这个方法特别适合下面几类问题:
-
项目目录和环境里有同名 Python 包
-
本地改过第三方库源码,但运行时总是不生效
-
单进程正常,多进程/DDP 报参数无效
-
服务器上
python train.py和预期跑的代码不一致 -
不方便立刻重新打包安装 editable package
实战经验
原本还尝试过用:
bash
pip install -e .
把本地项目安装成 editable 模式。
但服务器网络环境有问题,安装过程中又遇到了依赖下载失败、DNS 解析失败等问题,导致更麻烦。
相比之下,直接设置:
bash
export PYTHONPATH=/Project/Det_Seg/ultralytics-main:$PYTHONPATH
简单、直接、立刻生效,特别适合先把训练跑起来。
推荐的使用方式
最稳妥的方式是在进入项目目录后,先执行:
bash
cd /Project/Det_Seg/ultralytics-main
export PYTHONPATH=$(pwd):$PYTHONPATH
python train.py
这样写比硬编码路径更方便迁移。
可选补充:写进启动脚本
如果每次都要手动执行比较麻烦,可以写一个启动脚本,比如 run.sh:
bash
#!/bin/bash
cd /Project/Det_Seg/ultralytics-main
export PYTHONPATH=$(pwd):$PYTHONPATH
python train.py
然后:
bash
bash run.sh