基于Yolov5+Deepsort+Pyqt的单目标跟踪器设计yolo.py:

parser

yolov5s.yaml



  • nc: 80 # number of classes
  • depth_multiple: 0.33 # model depth multiple 模型深度倍数 和number有关,要乘
  • width_multiple: 0.50 # layer channel multiple 层级通道倍数 和args有关,要乘
  • yolov5s.yaml
  • yolov5m.yaml
  • yolov5l.yaml
  • yolov5x.yaml

    yolov5n.yaml、yolov5l.yaml、yolov5m.yaml、yolov5s.yaml、yolov5x.yaml只有这两个倍数变化,模型越复杂,倍数越大。
  • [from, number, module, args]
  • [-1, 1, Focus, [64, 3]
    from=-1:从上一层过来的
  • [-1, 10], 1, Concat, [1]
    from=[-1,10]:从22层和10层过来
  • [-1, 3, C3, [128]]
    number=3,第2层有3个C3模块
  • module:
    conv:卷积层
    C3:
    SPP:
    nn.Upsample:
    Concat:
    Detect:
  • args:给module传的参数

    0-P1/2:第一层,P1,640x640输入的RGB图像-》320x320输出
    1-P2/4:第二层,P2,640x640输入的RGB图像-》160x160输出

流程图(FPN、PAN)

Model


cfg:配置文件
ch:channels,RGB三通道
nc:类别数

  • self.yaml.get('ch', ch) 优先使用yaml配置,否则使用默认值ch,体现配置优先级。
  • m = self.model[-1] 获取模型最后一层,预期为Detect层。YOLOv5 的检测头。
  • if isinstance(m, Detect): 确认最后一层是否为Detect类的实例,确保后续操作仅对检测头执行。
  • s = 256 # 2x min stride 设定基准输入尺寸 256x256(通常为最小下采样步长 stride 的 2 倍,用于计算特征图缩放比例)。
  • m.stride 通过前向传播一个 1xchx256x256 的零张量,获取各检测层的输出特征图尺寸。
  • m.anchors /= m.stride.view(-1, 1, 1) 将锚框尺寸归一化到特征图尺度(除以对应层的 stride)。
  • initialize_weights(self)初始化模型所有层的权重参数
  • self.info() 打印模型的结构摘要信息(如层数、参数数量、梯度占比等)。
    输出内容:
    各层的名称、类型、输入/输出维度。
    总参数量(可训练/不可训练)。
    浮点运算量(FLOPs)估算(如果实现)。
  • logger.info('') 输出一个空行到日志,用于分隔模型初始化日志与其他后续日志。

前向传播



x:输入图像张量
augment:是否启用数据增强(多尺度+翻转)
profile:是否启用性能分析

  • forward_once:单次前向传播
  • y, dt = [], [] # outputs
    y:存储每一层的输出结果。
    dt: 在性能分析模式下(profile=True),记录每一层的计算耗时。
  • for m in self.model: 遍历模型的所有层
  • m.f:表示当前层 m 的输入来源(默认为 -1,即来自前一层的输出)。
    如果 m.f 是整数(如 3),直接从 y[3] 获取输入(跳层连接)。
    如果 m.f 是列表(如 [2, 4, -1]),拼接多个层的输出作为输入(多分支结构)。

fuse


融合卷积层(Conv2d)和批归一化层(BatchNorm2d),目的是优化模型的计算效率
遍历模型的所有模块:for m in self.model.modules() 会遍历模型中的每一层。
检查模块类型:if type(m) is Conv and hasattr(m, 'bn') 判断当前模块是否是 Conv 类型(自定义的卷积层类),并且是否包含 bn(批归一化层)属性。
融合卷积和批归一化:调用 fuse_conv_and_bn(m.conv, m.bn) 将卷积层和批归一化层的参数合并为一个新的卷积层,并更新 m.conv。
移除批归一化层:delattr(m, 'bn') 删除原来的批归一化层。
更新前向传播方法:m.forward = m.fuseforward 将前向传播方法替换为融合后的版本(
fuseforward是专门为融合后的层设计的方法)。
打印模型信息:self.info() 输出融合后的模型结构信息。

NMS(Non-Maximum Suppression,非极大值抑制)

  • mode 参数:
    mode=True:表示需要添加 NMS 模块。
    mode=False:表示需要移除 NMS 模块。
  • present 变量:
    检查模型的最后一层是否是 NMS 类型(type(self.model[-1]) is NMS)。
    如果最后一层已经是 NMS,present 为 True;否则为 False。
  • 添加 NMS 模块(if mode and not present):
    如果 mode=True 且当前模型没有 NMS 模块(not present),则执行以下操作:
    创建一个新的 NMS() 模块实例 m。
    设置 m.f = -1(通常表示该模块的来源层,-1 可能表示“无”或“自动”)。
    设置 m.i 为当前最后一层的索引 +1(确保新模块的索引正确)。
    使用 add_module 方法将 NMS 模块添加到模型的末尾。
    调用 self.eval() 将模型切换到推理模式(因为 NMS 通常在推理时使用)。
  • 移除 NMS 模块(elif not mode and present):
    如果 mode=False 且当前模型包含 NMS 模块(present),则执行以下操作:
    直接通过切片 self.model[:-1] 移除最后一层(即 NMS 模块)。
  • 训练时:通常不需要 NMS,可以调用 model.nms(False) 移除 NMS 模块。
  • 推理时:需要 NMS 过滤冗余检测框,可以调用 model.nms(True) 添加 NMS 模块。

info打印

  • def info(self, verbose=False, img_size=640): model_info(self, verbose, img_size)
    self: 表示该方法属于某个类(通常是YOLOv5的模型类)。
    verbose=False: 一个布尔参数,控制是否打印详细信息。默认为 False,即只打印基本信息。
    img_size=640: 输入图像的尺寸,默认为 640(YOLOv5的默认输入分辨率)。
    调用 model_info(self, verbose, img_size) 函数,将当前模型实例、verbose 标志和 img_size 传递给它。
    model_info 函数的作用是分析模型的结构和参数,并打印相关信息,例如:
    模型的层数、参数数量、计算量(FLOPs)。
    各层的详细信息(如果 verbose=True)。
    输入尺寸对模型的影响。
赞赏