本章节将介绍yolov8算法训练过程中的第一步:加载默认训练参数以及超参的配置文件default.yaml。
Yolov8 训练的入口文件为train.py,文件结构如下图所示:
1. 执行train函数,函数默认配置参数为cfg=DEFAULT_CFG ,其中DEFAULT_CFG是从模块ultralytics.yolo.utils导入的,是一个全局变量
from ultralytics.yolo.utils import DEFAULT_CFG, LOGGER, RANK, colorstr
2. 获取配置文件的路径
在ultralytics/yolo/utils目录下的init.py文件中,首先获取文件绝对路径,然后通过FILE.parents[2]获取上2层目录,最后拼接目录获取到yaml配置文件的绝对路径。
FILE = Path(__file__).resolve() #__file__表示当前文件的文件名;.resolve()获取绝对路径;获取文件绝对路径
ROOT = FILE.parents[2] # YOLO
DEFAULT_CFG_PATH = ROOT / 'yolo/cfg/default.yaml'
3. 配置文件的加载解析及处理代码如下所示
DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH) #加载完成后是字典
for k, v in DEFAULT_CFG_DICT.items():
if isinstance(v, str) and v.lower() == 'none': #
DEFAULT_CFG_DICT[k] = None
DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
下面将逐函数讲解:
3.1 通过yaml_load()函数加载配置文件
DEFAULT_CFG_DICT = yaml_load(DEFAULT_CFG_PATH) #加载完成后是字典
DEFAULT_CFG_DICT是字典类型,此时的数值为配置文件中的键值对,内容如下(部分):
3.1.1 yaml_laod()函数实现如下:
def yaml_load(file='data.yaml', append_filename=False):
"""
Load YAML data from a file.
Args:
file (str, optional): File name. Default is 'data.yaml'.
append_filename (bool): Add the YAML filename to the YAML dictionary. Default is False.
Returns:
(dict): YAML data and file name.
"""
print("---------->yaml_load:{}".format(file))
with open(file, errors='ignore', encoding='utf-8') as f:
s = f.read() # string
# Remove special characters
if not s.isprintable(): #移除所有的非打印字符
s = re.sub(r'[^\x09\x0A\x0D\x20-\x7E\x85\xA0-\uD7FF\uE000-\uFFFD\U00010000-\U0010ffff]+', '', s)
# Add YAML filename to dict and return
return {**yaml.safe_load(s), 'yaml_file': str(file)} if append_filename else yaml.safe_load(s)
通过open()打开并读取yaml文件,移除所有的非打印字符。
最后通过yaml.safe_load()完成配置文件的加载。关于yaml文件的使用请参考如下文章python 之yaml库使用总结。
3.2 对加载后的yaml配置文件进行处理,将键的值为字符串‘none’的值重新赋值为None.
for k, v in DEFAULT_CFG_DICT.items():
if isinstance(v, str) and v.lower() == 'none': #
DEFAULT_CFG_DICT[k] = None
在Python中,`None`是一个特殊的常量,用于表示空值或无值的情况。`None`是一个特殊的Python对象,其类型是`NoneType`。`None`不占据任何空间,也不包含任何值。
3.3 获取所有默认配置的键
DEFAULT_CFG_KEYS = DEFAULT_CFG_DICT.keys()
3.4 将加载后的配置字典转换为一个有命名空间的对象(SimpleNamespace),便于后续的存储和访问。
DEFAULT_CFG = IterableSimpleNamespace(**DEFAULT_CFG_DICT)
其中IterableSimpleNamespace是一个子类,继承自SimpleNamespace类。
关于SimpleNamespace的介绍,请参考文章python之SimpleNamespace()使用总结。
3.4.1 IterableSimpleNamespace类的实现如下
import torch
import yaml
from types import SimpleNamespace
class IterableSimpleNamespace(SimpleNamespace):
"""
Ultralytics IterableSimpleNamespace is an extension class of SimpleNamespace that adds iterable functionality and
enables usage with dict() and for loops.
"""
def __iter__(self):
"""Return an iterator of key-value pairs from the namespace's attributes."""
return iter(vars(self).items())
def __str__(self):
"""Return a human-readable string representation of the object."""
return '\n'.join(f'{k}={v}' for k, v in vars(self).items())
def __getattr__(self, attr):
"""Custom attribute access error message with helpful information."""
name = self.__class__.__name__
raise AttributeError(f"""
'{name}' object has no attribute '{attr}'. This may be caused by a modified or out of date ultralytics
'default.yaml' file.\nPlease update your code with 'pip install -U ultralytics' and if necessary replace
{DEFAULT_CFG_PATH} with the latest version from
https://github.com/ultralytics/ultralytics/blob/main/ultralytics/yolo/cfg/default.yaml
""")
def get(self, key, default=None):
"""Return the value of the specified key if it exists; otherwise, return the default value."""
return getattr(self, key, default)
至此,将默认配置yaml文件被加载到内存中,并最终转换为一个具有命名空间的全局变量DEFAULT_CFG。此时在启动训练代码时,默认的超参及普通参数配置文件default.yaml被加载并传递到函数中。
总结,本文章详细介绍了yolov8默认配置文件default.yaml如何被加载并处理成训练函数(train)所需要的参数的过程。