YOLOV8解读及推理代码

本文详细解析YOLOV8的升级点,如新架构、Ancher-Free检测头和优化的损失函数,提供训练和推理代码示例。
摘要由CSDN通过智能技术生成

YOLOV8

前言

YOLOv8并非一个全新的目标检测网络,而是在YOLOv5的基础上进行了升级。其主要升级包括:

  • 新的骨干网络
  • 创新的Ancher-Free检测头
  • 新的损失函数

性能对比

下表展示了在COCO Val 2017数据集上官方进行测试的mAP、参数量和FLOPs的结果。

模型YOLOv5params(M)FLOPs@640 (B)YOLOv8params(M)FLOPs@640 (B)
n28.0(300e)1.94.537.3 (500e)3.28.7
s37.4 (300e)7.216.544.9 (500e)11.228.6
m45.4 (300e)21.249.050.2 (500e)25.978.9
l49.0 (300e)46.5109.152.9 (500e)43.7165.2
x50.7 (300e)86.7205.753.9 (500e)68.2257.8

可以看出,相较于YOLOv5,YOLOv8在精度上取得了显著提升。然而,N/S/M模型的参数量和FLOPs相应地也有相当的增加。此外,大多数模型相较于YOLOv5,在推理速度上都略有下降。

在这里插入图片描述

新的骨干网络

YOLOv8引入了一系列关键的改进,特别是在骨干网络方面:

  • 第一个卷积层的kernel由6x6缩减为3x3,以提高特征提取的精度和效率。
  • 所有的C3模块都被替换为C2f模块,结构更为复杂,引入了更多的跳层连接和额外的Split操作,以促进信息的更好传递。
  • 删除了Neck模块中的两个卷积连接层,以简化网络结构。
  • 在Backbone中,C2f的block数由3-6-9-3调整为3-6-6-3,以优化网络的深度和复杂度。
    在这里插入图片描述

新的 Ancher-Free 检测头

在YOLOv8中,Head部分经历了一系列重大变化,从原先的耦合头演变为解耦头,并且从YOLOv5的Anchor-Based设计转变为Anchor-Free设计。这一变化带来了以下关键特点:

  • 解耦设计: Head部分不再采用之前的紧密耦合结构,而是进行了解耦,使分类和回归分支更为独立。
  • Anchor-Free设计: 与YOLOv5的Anchor-Based设计不同,YOLOv8的Head部分摒弃了之前的objectness分支,转而实现了Anchor-Free设计,从而简化了模型结构。
  • 回归分支创新: Head部分的回归分支采用了Distribution Focal Loss中提出的积分形式表示法,这一创新提高了模型对目标定位和边界框回归的效果。

这些变化共同构成了YOLOv8 Head部分的新特征,使其在目标检测任务中更具灵活性和性能。

在这里插入图片描述

新的损失函数

YOLOv8的损失函数计算涉及两个主要分支:分类分支和回归分支,不再包含之前的objectness分支。这两个分支的损失通过一定的权重比例进行加权。

  • 分类分支: 仍然使用二元交叉熵(BCE Loss)来处理目标分类问题。
  • 回归分支: 引入Distribution Focal Loss的积分形式表示法,同时还采用了CIoU Loss。这种设计使得回归分支更加精细化,有助于提高目标的定位和边界框回归的准确性。

通过这样的损失函数设计,YOLOv8在训练过程中能够更好地优化模型参数,使其在目标检测任务中取得更好的性能。

环境配置

conda create -n yolov8_env python==3.9
pip install ultralytics
conda activate yolov8_env
git clone https://github.com/ultralytics/ultralytics

训练

基于python脚本

from ultralytics import YOLO

# 加载模型
# model = YOLO("yolov8n.yaml")  # 从头开始构建新模型
model = YOLO("yolov8n.pt")  # 加载预训练模型(建议用于训练)

# 使用模型
model.train(data="ultralytics/ultralytics/datasets/VOC_lw.yaml", epochs=100,batch=16,patience=0)  # 训练模型
metrics = model.val()  # 在验证集上评估模型性能

基于命令行

yolo task=detect mode=train model=yolov8n.yaml data=ultralytics/ultralytics/datasets/VOC.yaml

推理

pt模型推理

results = model("https://ultralytics.com/images/bus.jpg")  # 对图像进行预测

onnx模型推理

  1. pt模型转onnx
yolo export model=best.pt format=onnx opset=12
  1. 基于ultralytics进行onnx推理
from ultralytics import YOLO
import os
# Load a model 
model = YOLO('best.onnx')  # load an official model

# Predict with the model
# results = model('62.png')  # predict on an image
path = "climb/images"
img_list = [os.path.join(path,dir) for dir in os.listdir(path)]
for im in img_list:  
    model.predict(im, save=True, imgsz=640, conf=0.40)
  1. onnx推理
import numpy as np
import cv2

import logging


CLASSES = ['banner']
colors = np.random.uniform(0, 255, size=(len(CLASSES), 3))

def draw_bounding_box(img, class_id, confidence, x, y, x_plus_w, y_plus_h):
    label = f'{CLASSES[class_id]} ({confidence:.2f})'
    color = colors[class_id]
    cv2.rectangle(img, (x, y), (x_plus_w, y_plus_h), color, 2)
    cv2.putText(img, label, (x - 10, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

class BannerDetector:
    def __init__(self, model_path = None):
        # logging.info(f"start init model")
        self.model: cv2.dnn.Net = cv2.dnn.readNetFromONNX(model_path)
        self.img_det_size = 640


    
    def __call__(self , image, score_threshold = 0.9):
        blob = self.img_process(image)
        self.model.setInput(blob)
        outputs = self.model.forward()
        
        outputs = np.array([cv2.transpose(outputs[0])])
        rows = outputs.shape[1]

        boxes = []
        scores = []
        class_ids = []

        for i in range(rows):
            classes_scores = outputs[0][i][4:]
            (minScore, maxScore, minClassLoc, (x, maxClassIndex)) = cv2.minMaxLoc(classes_scores)
            if maxScore >= 0.25:
                box = [
                    outputs[0][i][0] - (0.5 * outputs[0][i][2]), outputs[0][i][1] - (0.5 * outputs[0][i][3]),
                    outputs[0][i][2], outputs[0][i][3]]
                boxes.append(box)
                scores.append(maxScore)
                class_ids.append(maxClassIndex)

        result_boxes = cv2.dnn.NMSBoxes(boxes, scores, score_threshold, 0.45, 0.5)
        detections = []
        # logging.info(f"result_boxes is : {result_boxes}")
        for i in range(len(result_boxes)):
            index = result_boxes[i]
            box = boxes[index]
            print(box)
            x1,y1,x2,y2 = round(box[0] * self.scale), round(box[1] * self.scale),round((box[0] + box[2]) * self.scale), round((box[1] + box[3]) * self.scale)   
            box = [x1,y1,x2,y2]
            detection = {
                'class_id': class_ids[index],
                'class_name': CLASSES[class_ids[index]],
                'confidence': scores[index],
                'box': box,
                'scale': self.scale}
            detections.append(detection)
            print(detection)
            draw_bounding_box(image, class_ids[index], scores[index], x1,y1,x2,y2)
        cv2.imwrite('image.jpg', image)
        
 
        return detections


    
    def img_process(self, img):     
        img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
        original_image: np.ndarray = img
        [height, width, _] = original_image.shape
        length = max((height, width))
        logging.info(f"img shape:{height,width}")
        image = np.zeros((length, length, 3), np.uint8)
        image[0:height, 0:width] = original_image
        self.scale = length / self.img_det_size

        blob = cv2.dnn.blobFromImage(image, scalefactor=1 / 255, size=(640, 640), swapRB=True)
        return blob
if __name__ == '__main__':
    image = cv2.imread("1.jpg")
    import time,copy
    model = BannerDetector(model_path="model/banner.onnx")
    bboxes = model(image, score_threshold=0.5)
    cv_image_copy = copy.deepcopy(image)
YOLOv8的训练代码解读如下: train.py是YOLOv8项目中的一个主要文件,它包含了训练模型所需的核心功能和逻辑。在train.py中,主要涉及的函数是train()函数。 train()函数是整个训练过程的入口函数,它接收一些参数,如模型、数据集、优化器等,并执行训练循环。在训练循环中,首先加载训练数据集,并通过数据增强方法对图像进行增强,以提高模型的泛化能力和鲁棒性。然后,将增强后的图像输入到模型中进行前向传播,得到预测结果。接着,计算预测结果与真实标签之间的损失,使用损失函数计算损失值,并根据损失值来更新模型的参数。这个过程不断迭代,直到达到预设的训练轮数或达到停止训练的条件。 train.py还涉及了其他一些模块和文件,如checkpoints、data、dataset、loss、utils等。checkpoints目录存储了训练过程中保存的模型权重文件,这些文件可以用于恢复训练或进行推理。data目录包含了存储类别信息和训练数据列表的文件,classes.txt文件存储了物体类别的名称,train.txt文件包含了训练数据集的文件路径列表。dataset模块提供了数据加载器,用于加载训练数据并进行预处理。loss模块包含了损失函数的实现,用于计算模型预测结果与真实标签之间的差异。utils模块包含了一些辅助函数和工具类,用于在训练过程中进行日志记录、模型保存等操作。 需要注意的是,由于train.py函数涉及的篇幅较大,本博客只提供了部分核心内容的讲解。如果你想详细了解train.py的完整代码,你可以查看网盘地址中的代码文件(提取码:wbqu)。 请注意,我在回答中使用了引用和引用中的相关内容来支持我的回答。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

江小皮不皮

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值