----与智者为伍 为创新赋能----
导读
记录直接在YOLOv8的官方仓库上直接配置和训练yolov5的全过程。
本项目基于ultralytics及yolov5等进行综合参考,致力于让yolo系列的更加高效和易用。
目前主要做了以下的工作:
为什么这个仓库取名为ultralytics,而不是yolov8,结合这个issue,笔者认为主要有以下几个方面的原因:
issue链接:https://github.com/ultralytics/ultralytics/issues/179
结合上面的讨论,自然而然会有这个想法,既然ultralytics要建一个集成训练框架,那么能否直接在ultralytics仓库上直接配置和训练yolov5呢,笔者做了下面一系列的尝试:
models/common.py
中,加入了yolov5所需的网络结构 class C3(nn.Module):
# CSP Bottleneck with 3 convolutions
def __init__(self, c1, c2, n=1, shortcut=True, g=1, e=0.5): # ch_in, ch_out, number, shortcut, groups, expansion
super().__init__()
c_ = int(c2 * e) # hidden channels
self.cv1 = Conv(c1, c_, 1, 1)
self.cv2 = Conv(c1, c_, 1, 1)
self.cv3 = Conv(2 * c_, c2, 1) # optional act=FReLU(c2)
self.m = nn.Sequential(*(Bottleneck(c_, c_, shortcut, g, e=1.0) for _ in range(n)))
def forward(self, x):
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))
最后一通操作下来,已经可以根据yolov5s.yaml去读取网络结构了,但是在跑的时候还是报错。
报错信息如下:
于是针对"train_args"
做了一个全局搜索,发现了下面的结果:
可以看到,之前训练出来的v8的权重内包含了"train_args"
的信息。顺着程序运行的流程,相应地发现了yolo/engine/model
中的"__init__(self)"
函数,
def __init__(self, model='yolov8n.yaml', type="v8") -> None:
"""
Initializes the YOLO object.
Args:
model (str, Path): model to load or create
type (str): Type/version of models to use. Defaults to "v8".
"""
self.type = type
self.ModelClass = None # model class
self.TrainerClass = None # trainer class
self.ValidatorClass = None # validator class
self.PredictorClass = None # predictor class
self.model = None # model object
self.trainer = None # trainer object
self.task = None # task type
self.ckpt = None # if loaded from *.pt
self.ckpt_path = None
self.cfg = None # if loaded from *.yaml
self.overrides = {} # overrides for trainer object
self.init_disabled = False # disable model initialization
# Load or create new YOLO model
{'.pt': self._load, '.yaml': self._new}[Path(model).suffix](model)
读取模型和配置是在"__init__"
的最后一行:
# Load or create new YOLO model
{'.pt': self._load, '.yaml': self._new}[Path(model).suffix](model)
而def _load(self, weights: str):
中实际读取模型权重的实现是self.model = attempt_load_weights(weights)
。可以看到,相比于yolov5,v8读取权重的函数attempt_load_weights
,多了下面这行
args = {**DEFAULT_CONFIG_DICT, **ckpt['train_args']} # combine model and default args, preferring model args
那么,能否直接将v5的项目中,将相应的函数补充过来给v8做适配呢,自然是可以的,当笔者将model.py的_load
函数中这行代码:
self.model = attempt_load_weights(weights)
替换为下面这行时:
self.model = attempt_load(weights)
重新运行了一遍,发现又出现了下面的问题:
错误信息为AttributeError: 'Model' object has no attribute 'args'
,既然是Model定义和配置上的问题,那么就没有再往下修改的必要了,还是等官方团队的更新和修改吧,等等党永远不亏。
根据官方的文档介绍,还有对代码的分析,目前v8项目是支持检测、分类和分割的。设定是通过"task"
进行区分任务,又通过mode
来设置是训练还是检测的模式,如下使用:
yolo task=detect mode=train model=yolov8n.yaml epochs=1 ...
... ... ...
segment predict yolov8n-seg.pt
classify val yolov8n-cls.pt
def attempt_load_weights(weights, device=None, inplace=True, fuse=False):
# Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
from ultralytics.yolo.utils.downloads import attempt_download
model = Ensemble()
for w in weights if isinstance(weights, list) else [weights]:
ckpt = torch.load(attempt_download(w), map_location='cpu') # load
args = {**DEFAULT_CONFIG_DICT, **ckpt['train_args']} # combine model and default args, preferring model args
ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
...
def attempt_load(weights, device=None, inplace=True, fuse=True):
# Loads an ensemble of models weights=[a,b,c] or a single model weights=[a] or weights=a
from models.yolo import Detect, Model
model = Ensemble()
for w in weights if isinstance(weights, list) else [weights]:
ckpt = torch.load(attempt_download(w), map_location='cpu') # load
ckpt = (ckpt.get('ema') or ckpt['model']).to(device).float() # FP32 model
...
参考
[1].https://github.com/isLinXu/YOLOv8_Efficient.
[2].https://github.com/isLinXu/model-metrics-plot.
来源:新机器视觉
申明:感谢原创作者的辛勤付出。本号转载的文章均会在文中注明,若遇到版权问题请联系我们处理。
----与智者为伍 为创新赋能----
联系邮箱:uestcwxd@126.com
QQ:493826566