hubconf.py
目录
[2.def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):](#2.def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):)
[3.def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None):](#3.def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None):)
[4.if name == 'main':](#4.if name == 'main':)
1.所需的库和模块
python
import torch
2.def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):
python
# 这段代码定义了一个名为 _create 的函数,它用于创建或加载 YOLO 模型。
# 定义了一个函数 _create ,它接受七个参数。
# 1.name (str) :模型的名称或者模型权重文件的路径。如果是模型名称,如 'yolov5s' ,则会加载预训练的权重;如果是路径,如 'path/to/best.pt' ,则会加载该路径下的权重文件。
# 2.pretrained (bool) :是否加载预训练的权重。默认为 True 。
# 3.channels (int) :输入图像的通道数。默认为 3,适用于常规的 RGB 图像。
# 4.classes (int) :模型预测的类别数。默认为 80,适用于 COCO 数据集。
# 5.autoshape (bool) :是否应用 YOLO 的 autoshape 功能,该功能允许模型自动处理不同大小和格式的输入。默认为 True 。
# 6.verbose (bool) :是否打印详细信息。默认为 True 。
# 7.device (str or torch.device or None) :指定模型运行的设备,如 'cpu' 或 'cuda:0' 。如果没有指定,则会自动选择设备。
def _create(name, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True, device=None):
# 创建或加载 YOLO 模型。
"""Creates or loads a YOLO model
Arguments:
name (str): model name 'yolov3' or path 'path/to/best.pt'
pretrained (bool): load pretrained weights into the model
channels (int): number of input channels
classes (int): number of model classes
autoshape (bool): apply YOLO .autoshape() wrapper to model
verbose (bool): print all information to screen
device (str, torch.device, None): device to use for model parameters
Returns:
YOLO model
"""
# 这部分代码是 _create 函数的导入部分,它从不同的模块导入了必要的类和函数。
# 从 pathlib 模块导入 Path 类,这个类用于处理文件系统路径。
from pathlib import Path
from models.common import AutoShape, DetectMultiBackend
from models.experimental import attempt_load
# 从 models.yolo 模块导入 ClassificationModel 、 DetectionModel 和 SegmentationModel 类。 这些类分别代表 YOLO 用于 分类 、 检测 和 分割 的模型。
from models.yolo import ClassificationModel, DetectionModel, SegmentationModel
from utils.downloads import attempt_download
from utils.general import LOGGER, check_requirements, intersect_dicts, logging
from utils.torch_utils import select_device
# 这些导入语句为 _create 函数提供了处理文件路径、加载和创建模型、下载模型文件、记录日志和选择设备等所需的工具和类。这些工具和类是构建和运行 YOLO 模型的基础。
# 这段代码是 _create 函数的一部分,它负责根据提供的参数设置日志级别、检查依赖、处理模型路径,并尝试加载或创建 YOLO 模型。
# 如果 verbose 参数为 False ,则设置日志记录器 LOGGER 的日志级别为 WARNING ,这意味着只有警告及以上级别的日志信息会被输出。
if not verbose:
LOGGER.setLevel(logging.WARNING)
# 调用 check_requirements 函数来检查运行模型所需的依赖是否满足, exclude 参数指定不需要检查的依赖。
# def check_requirements(requirements=ROOT / 'requirements.txt', exclude=(), install=True, cmds=''): -> 用于检查是否安装了满足YOLO要求的依赖项。如果某些依赖项未安装或版本不兼容,函数会尝试自动安装它们。
check_requirements(exclude=('opencv-python', 'tensorboard', 'thop'))
# 将 name 参数转换为 Path 对象,以便使用 pathlib 模块提供的方法来处理路径。
name = Path(name)
# 如果 name 不包含文件扩展名( suffix )且不是一个目录,则为其添加 .pt 扩展名,否则保持 name 不变。这用于确定模型权重文件的路径。
path = name.with_suffix('.pt') if name.suffix == '' and not name.is_dir() else name # checkpoint path
# 开始一个 try-except 块,用于捕获并处理在加载模型过程中可能发生的异常。
try:
# 调用 select_device 函数来确定模型将运行在哪个设备上,这可以是 CPU 或 GPU。
# def select_device(device='', batch_size=0, newline=True):
# -> 根据用户提供的参数选择使用 CPU、单个 GPU 或多个 GPU,并返回一个对应的 PyTorch 设备对象。返回一个 PyTorch 设备对象,用于指定后续计算应该在哪个设备上执行。
# -> return torch.device(arg)
device = select_device(device)
# 如果 pretrained 为 True , channels 为 3, classes 为 80,则尝试加载预训练的 YOLO 模型。
if pretrained and channels == 3 and classes == 80:
# 内部的 try-except 块,用于捕获在加载预训练模型时可能发生的异常。
try:
# 尝试使用 DetectMultiBackend 类来加载模型,这个类支持多种后端, path 是模型路径, device 是设备, fuse 决定是否应用 autoshape 。
# class DetectMultiBackend(nn.Module):
# -> DetectMultiBackend 类实现了一个多后端检测模型,能够支持多种不同的模型格式和推理引擎。
# -> def __init__(self, weights='yolo.pt', device=torch.device('cpu'), dnn=False, data=None, fp16=False, fuse=True):
model = DetectMultiBackend(path, device=device, fuse=autoshape) # detection model
# 如果 autoshape 为 True ,则根据模型类型应用 AutoShape 包装器。
if autoshape:
# 如果模型是预训练的且模型类型为 ClassificationModel ,则发出警告,因为 AutoShape 与分类模型不兼容。
if model.pt and isinstance(model.model, ClassificationModel):
LOGGER.warning('WARNING ⚠️ YOLO ClassificationModel is not yet AutoShape compatible. ' # 警告⚠️YOLO ClassificationModel 尚不兼容 AutoShape。
'You must pass torch tensors in BCHW to this model, i.e. shape(1,3,224,224).') # 您必须将 BCHW 中的 torch 张量传递给此模型,即形状(1,3,224,224)。
# 如果模型是预训练的且模型类型为 SegmentationModel ,则发出警告,因为 AutoShape 与分割模型不兼容。
elif model.pt and isinstance(model.model, SegmentationModel):
LOGGER.warning('WARNING ⚠️ YOLO SegmentationModel is not yet AutoShape compatible. ' # 警告⚠️YOLO SegmentationModel 尚不兼容 AutoShape。
'You will not be able to run inference with this model.') # 您将无法使用该模型进行推理。
# 如果模型不是分类或分割模型,则应用 AutoShape 包装器。
else:
# class AutoShape(nn.Module):
# -> AutoShape 类实现了一个输入鲁棒性的模型包装器,用于处理不同格式的输入数据(如 OpenCV、NumPy、PIL 或 PyTorch 张量),并执行预处理、推理和非最大抑制(NMS)。
# -> def __init__(self, model, verbose=True):
model = AutoShape(model) # for file/URI/PIL/cv2/np inputs and NMS
# 如果在尝试加载预训练模型时发生异常,则捕获异常并继续执行。
except Exception:
# 如果预训练模型加载失败或不是预训练模型,则尝试使用 attempt_load 函数来加载任意模型, fuse 参数设置为 False 。
# def attempt_load(weights, device=None, inplace=True, fuse=True):
# -> 用于加载一个或多个预训练的模型权重,并创建一个模型集合( Ensemble )。如果只有一个模型,直接返回该模型。返回最终构建的模型集合( Ensemble )。
# -> return model[-1] / return model
model = attempt_load(path, device=device, fuse=False) # arbitrary model
# 这段代码负责根据提供的参数配置环境,并尝试加载预训练的 YOLO 模型。如果预训练模型加载失败或不兼容,它会回退到加载任意模型。这个过程涉及到日志级别设置、依赖检查、路径处理和异常处理。
# 这段代码是 _create 函数的继续部分,它处理非预训练模型的创建和权重加载。
# 这个 else 块与之前的 if pretrained and channels == 3 and classes == 80: 条件块相对应。如果条件不满足,即不加载预训练模型或者模型的通道数和类别数不是默认值,将执行这里的代码。
else:
# 查找与模型名称相对应的 .yaml 配置文件。 Path(__file__).parent 获取当前文件的父目录路径, / 'models' 进入 models 子目录, rglob 递归搜索所有匹配的 .yaml 文件, f'{path.stem}.yaml' 使用模型权重文件的名称(不含扩展名)来匹配配置文件名, [0] 选择搜索结果的第一个文件,即配置文件的路径。
cfg = list((Path(__file__).parent / 'models').rglob(f'{path.stem}.yaml'))[0] # model.yaml path
# 使用找到的配置文件 cfg 和指定的输入通道数 channels 以及类别数 classes 创建一个 DetectionModel 实例。
model = DetectionModel(cfg, channels, classes) # create model
# 如果 pretrained 参数为 True ,则尝试加载预训练权重。
if pretrained:
# 使用 attempt_download 函数尝试下载模型权重文件(如果它是一个 URL),然后使用 torch.load 加载权重文件到指定的 device 。
# def attempt_download(file, repo='ultralytics/yolov5', release='v7.0'): -> 尝试从 GitHub 仓库的发布资产中下载文件,如果本地找不到该文件。返回文件的路径,以字符串形式。 -> return str(file)
ckpt = torch.load(attempt_download(path), map_location=device) # load
# model.state_dict()
# 在 PyTorch 中, model.state_dict() 是一个模型( model )对象的方法,它用于返回模型中所有参数和缓存的字典,包括权重和偏差。
# 参数 :无参数。
# 返回值 :
# 返回一个包含模型参数的 OrderedDict ,其中的键是参数的名称,值是对应的张量(tensor)。
# 详细说明 :
# state_dict 是一个有序字典( OrderedDict ),其中包含了模型中所有参数的名称和对应的张量。
# 这个字典可以用于保存模型的状态,以便以后可以重新加载模型的状态。
# 参数名称(键)通常是按照它们在模型中定义的顺序排列的。
# 这个函数通常用于保存模型的权重到文件中,或者在加载模型时从文件中恢复权重。
# model.state_dict() 是 PyTorch 模型序列化和反序列化过程中的一个关键部分,它允许用户轻松地保存和加载模型的参数。
# 从权重文件中提取模型的状态字典,并确保其数据类型为浮点数(FP32)。
csd = ckpt['model'].float().state_dict() # checkpoint state_dict as FP32
# 使用 intersect_dicts 函数找到预训练权重和新模型权重之间的交集,忽略 anchors 。
# def intersect_dicts(da, db, exclude=()): -> 计算两个字典 da 和 db 中具有匹配键和形状的元素的交集,同时排除指定的键。 -> return {k: v for k, v in da.items() if k in db and all(x not in k for x in exclude) and v.shape == db[k].shape}
csd = intersect_dicts(csd, model.state_dict(), exclude=['anchors']) # intersect
# torch.nn.Module.load_state_dict(state_dict, strict=True)
# load_state_dict() 是 PyTorch 中 torch.nn.Module 类(即所有神经网络模型的基类)的一个方法,用于加载模型的参数。这个方法将传入的状态字典(state dictionary)中的参数加载到模型中,使得模型的权重和偏差与状态字典中的相匹配。
# 参数 :
# state_dict :一个包含模型参数的字典对象。通常由 torch.save() 保存的模型参数或通过 model.state_dict() 获取。
# strict :(可选)一个布尔值,默认为 True 。如果为 True ,则要求状态字典中的每个键都必须与模型中的参数匹配。如果为 False ,则忽略不匹配的键。
# 返回值 :无返回值。该方法直接修改模型的参数。
# 使用场景 :
# 当你从文件中加载模型权重或者在训练过程中恢复模型状态时。
# load_state_dict() 方法是 PyTorch 中管理和迁移模型权重的重要工具,特别是在模型保存、加载和迁移学习场景中。
# 将预训练权重加载到模型中, strict=False 允许忽略模型和预训练权重中不匹配的键。
model.load_state_dict(csd, strict=False) # load
# 如果预训练权重中的类别数与 classes 参数相匹配。
if len(ckpt['model'].names) == classes:
# 将预训练权重中的类别名称赋值给模型的 names 属性。
model.names = ckpt['model'].names # set class names attribute
# 如果 verbose 参数为 False ,则将日志级别重置为 INFO 。
if not verbose:
LOGGER.setLevel(logging.INFO) # reset to default
# 将模型移动到指定的 device 上,并返回模型实例。
return model.to(device)
# 这段代码处理了非预训练模型的创建和(如果需要)预训练权重的加载。它还负责设置日志级别,并确保模型被移动到正确的设备上。这个过程确保了模型可以根据用户提供的参数被正确地创建和配置。
# 这段代码是 _create 函数中异常处理的部分,它用于捕获并处理在模型创建或加载过程中发生的任何异常。
# 这个 except 块捕获所有类型的 Exception 异常,并将异常对象赋值给变量 e 。
except Exception as e:
# 定义一个变量 help_url 并赋值为一个字符串,这个字符串是一个 URL,指向 YOLOv5 GitHub 仓库中的 Issue #36 页面,用户可以在这里寻求帮助。
help_url = 'https://github.com/ultralytics/yolov5/issues/36'
# 使用 f-string(格式化字符串字面量)创建一个新的字符串 s ,它包含 异常信息 e 、一些额外的提示信息,以及 help_url 。 f'{e}' 将异常对象 e 转换为字符串, force_reload=True 是一个提示,建议用户尝试使用这个参数强制重新加载模型。
s = f'{e}. Cache may be out of date, try `force_reload=True` or see {help_url} for help.' # 缓存可能已过期,请尝试"force_reload=True"或查看{help_url}寻求帮助。
# 抛出一个新的 Exception 异常,异常信息为字符串 s 。 from e 指定了原始异常 e 作为新异常的上下文,这样在异常链中可以追踪到原始异常。
raise Exception(s) from e
# 这段代码在发生异常时提供了额外的错误信息和帮助链接,并且重新抛出异常,使得调用者可以捕获并处理这个异常。这种做法有助于调试和用户支持,因为它提供了关于如何解决问题的直接线索。
# _create 函数是一个用于创建或加载 YOLO 模型的通用函数,支持预训练权重的加载、多种输入格式的处理以及日志级别的设置。通过这个函数,用户可以根据需要创建或加载 YOLO 模型,并进行进一步的操作。
3.def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None):
python
# 这段代码定义了一个名为 custom 的函数,它是一个包装器(wrapper)函数,用于创建或加载一个模型。
# 这是函数定义的开始。函数名为 custom ,它接受四个参数。
# 1.path :一个字符串,默认值为 'path/to/model.pt' ,表示模型文件的路径。
# 2.autoshape :一个布尔值,默认为 True ,表示是否自动调整输入数据的形状以匹配模型的期望输入。
# 3._verbose :一个布尔值,默认为 True ,表示是否在执行过程中输出详细信息。下划线前缀通常表示这是一个内部参数,不建议外部用户直接修改。
# 4.device :一个可选参数,用于指定模型运行的设备,如CPU或GPU。默认值为 None ,意味着将使用默认设备。
def custom(path='path/to/model.pt', autoshape=True, _verbose=True, device=None):
# YOLO custom or local model YOLO 自定义或本地模型。
# 调用了一个名为 _create 的函数 ,并将 custom 函数接收到的参数传递给 _create 函数。
# _create 函数的参数与 custom 函数的参数相对应,但是 verbose 参数在 _create 函数中没有下划线前缀,这表明它可能是一个公开的参数,供外部用户使用。
return _create(path, autoshape=autoshape, verbose=_verbose, device=device)
# 这个 custom 函数是一个包装器,它提供了一个简单的接口来调用 _create 函数。 custom 函数允许用户指定模型文件的路径、是否自动调整输入数据的形状、是否输出详细信息以及模型运行的设备。通过设置默认参数,它使得用户在不提供任何参数的情况下也能使用默认配置来创建或加载模型。这个函数的设计意图可能是为了简化模型创建或加载的过程,同时提供一定的灵活性以适应不同的使用场景。
4.if name == 'main':
python
# 这段代码是一个Python脚本,它使用命令行参数解析和图像处理库来加载一个模型并对一系列图像进行推理。
# 检查当前脚本是否作为主程序运行。如果是,那么下面的代码块将被执行。
if __name__ == '__main__':
# 导入 argparse 模块,这是一个用于解析命令行参数的库。
import argparse
# 从 pathlib 模块导入 Path 类,它提供了面向对象的文件系统路径表示。
from pathlib import Path
# 导入 numpy 库,并将其别名设置为 np ,这是一个用于数值计算的库。
import numpy as np
# 从 PIL 库导入 Image 模块,它用于图像处理。
from PIL import Image
# 从 utils.general 模块导入 cv2 和 print_args 函数。 cv2 是OpenCV库的别名, print_args 用于打印参数。
from utils.general import cv2, print_args
# Argparser
# 创建一个新的 ArgumentParser 对象,用于处理命令行参数。
parser = argparse.ArgumentParser()
# 向解析器添加一个名为 --model 的命令行参数,它接受一个字符串类型的值,默认值为 'yolo' ,帮助信息为 'model name' 。
parser.add_argument('--model', type=str, default='yolo', help='model name') # 模型名称。
# 解析命令行参数,并将解析结果存储在 opt 变量中。
opt = parser.parse_args()
# vars(object)
# vars() 函数在 Python 中用于获取对象的属性字典。这个字典包含了对象的大部分属性,但不包括方法和其他一些特殊的属性。对于用户自定义的对象, vars() 返回的字典包含了对象的 __dict__ 属性,这是一个包含对象所有属性的字典。
# 参数说明 :
# object :要获取属性字典的对象。
# 返回值 :
# 返回指定对象的属性字典。
# 注意事项 :
# vars() 对于内置类型(如 int 、 float 、 list 等)返回的是一个包含魔术方法和特殊属性的字典,这些属性通常是不可访问的。
# 对于自定义对象, vars() 返回的是对象的 __dict__ 属性,如果对象没有定义 __dict__ ,则可能返回一个空字典或者抛出 TypeError 。
# 在 Python 3 中, vars() 也可以用于获取内置函数的全局变量字典。
# vars() 函数是一个内置函数,通常用于调试和访问对象的内部状态,但在处理复杂对象时应该谨慎使用,因为直接修改对象的属性可能会导致不可预测的行为。
# 打印解析后的参数。 vars(opt) 将 opt 对象转换为字典。
# def print_args(args: Optional[dict] = None, show_file=True, show_func=False): -> 打印函数的参数。这个函数可以显示当前函数的参数,或者如果提供了参数字典,也可以显示任意函数的参数。
print_args(vars(opt))
# Model
# 创建一个模型实例,使用 _create 函数。参数包括 模型名称 、 是否预训练 、 输入通道数 、 类别数 、 是否自动调整形状 和 是否输出详细信息 。
model = _create(name=opt.model, pretrained=True, channels=3, classes=80, autoshape=True, verbose=True)
# 这一行被注释掉了,它显示了如何使用 custom 函数来创建模型实例。
# model = custom(path='path/to/model.pt') # custom
# Images
# 定义一个包含不同类型图像源的列表,包括 文件名 、 Path对象 、 URI 、 OpenCV图像 、 PIL图像 和 Numpy数组 。
imgs = [
'data/images/zidane.jpg', # filename
Path('data/images/zidane.jpg'), # Path
'https://ultralytics.com/images/zidane.jpg', # URI
cv2.imread('data/images/bus.jpg')[:, :, ::-1], # OpenCV
Image.open('data/images/bus.jpg'), # PIL
np.zeros((320, 640, 3))] # numpy
# Inference
# 对图像列表进行批量推理,指定输出图像的大小为320。
results = model(imgs, size=320) # batched inference
# Results
# 打印推理结果。
results.print()
# 保存推理结果。
results.save()
# 这个脚本是一个完整的图像推理流程,它首先解析命令行参数,然后加载一个模型,接着对一系列图像进行推理,并打印和保存结果。这个脚本展示了如何使用不同的图像源进行批量推理,并处理推理结果。