用于个人记录,好记性不如烂笔头

其实整体训练的流程和V5差不多,只是V8不需要下载工程文件了,而是可以通过安装ultralytics,然后进行调用

pip install ultralytics

1.数据集

​ 数据集的制作方式和V5完全一致,唯一的区别是我们需要自己创建一个yaml的配置文件,该文件是为了让V8读取到数据。而这个yaml的格式是跟V5的类似的。

v5的操作链接如下,里面包含了数据集制作方式,和xml转txt的详细说明,可以参考一下:
YOLOv5单目标识别

本次我要识别的是一个数字“8”,图片和层级目录如下:
在这里插入图片描述
在这里插入图片描述

下面的图片是V5版本的数据的配置

在这里插入图片描述

而V8的yaml的配置如下

在这里插入图片描述

train: [F:\yolodata\8\train.txt]
val: [F:\yolodata\8\val.txt]


# number of classes
nc: 1

# class names
names: ['eight']

2.模型训练

准备好数据集以及配置文件后,就可以开启模型训练了。因为不需要下载工程文件了,所以我们创建一个v8_train.py文件,然后将要配置的参数写上即可

注意:需要自己去官方去下载预训练的模型,这里我用的yolo8s.pt

from ultralytics import YOLO


if __name__ == '__main__':
    model=YOLO(r"F:\yolodata\8\yolov8s.pt")
    model.train(
        data=r"F:\yolodata\8\eight.yaml",
        imgsz=320,
        device=0,
        epochs=10,
        name="eight8",
        batch=64,
        fliplr=0,#图像左右翻转(概率)
    )

当执行上面的代码后,当运行结束后,提示运行结果保存的位置在:Results saved to runs\detect\eight83。我这里运行的结果是保存在v8_train.py的同一个文件夹中的.

运行结果图片
在这里插入图片描述

这里我是把数据集,配置文件,训练的py,预训练的模型都放在一个文件夹,所以看起来有点乱,其实可以分成两个文件夹,数据集放到另一个文件夹。训练好的模型就在runs文件夹中
在这里插入图片描述

3.转onnx并推理

(1)输出结果解释
from ultralytics import YOLO


if __name__ == '__main__':
    model_path=r"F:\yolodata\8\runs\detect\eight83\weights\best.pt"
    model=YOLO(model_path)
    model.export(format='onnx',imgsz=320)# 自己模型的配置,我的图片大小是320的,官方的是640
    

​ 可以看到转成onnx后,onnx文件存放的位置也是在weights文件夹中,我们将onnx模型打开,他的输出是tensor: float32[1,5,2100],这里需要解释一下为什么他的输出会是这样的。我们对比一下官方的预训练模型

我们自己的模型如下
在这里插入图片描述

官方的模型如下

官服的输出是float32[1,84,8400]

from ultralytics import YOLO

if __name__ == '__main__':
    model_path=r"F:\yolodata\8\yolov8s.pt"
    model=YOLO(model_path)
    model.export(format='onnx',imgsz=640)#官方的数据集是640

在这里插入图片描述

解释如下:

​ 我们知道YOLO是有三个不同尺度的检测头(anchor),分别是80x80,40x40,20x20,这个三个size是怎么计算出来的呢,是因为yolo使用三个尺寸的下采样比例分别是8,16,32,官方使用640大小的图片,所以640分别除以8,16,32得到的就是80 40 20。

​ 由于特征图中的每个网格产生一个预测结果,(80x80+40x40+20x20)所以是8400个预测结果。官方使用的640x640的图片,而我们的图片大小是320x320,hw都分别都缩小了2倍,自然计算出来的结果就会少了2x2=4倍。8400/4=2100

与v5的不同,v5是每个网格会产生3个预测结果,计算出来是25200。

输出解释

tensor: float32[1,5,2100],代表什么呢?

1表示batch_size

5分别表示xywh和类别的得分,这里只有一个类,所以只有一个得分(官方的有80类所以是84)

2100表示检测框的数量

​ 如果我们把[1,5,2100]展开则是这样的:

​ ([[[x,x1,x2,x3…x2100],

​ [y,y1,y2,y3…y2100],

​ [w,w1,w2,w3…w2100],

​ [h,h1,h2,h3…h2100],

​ [s,s1,s2,s3…s2100]

​ ]]])

​ 所以我们只需要根据最后一行,将分数最大的那一列xywh拿出来即可

(2)推理

​ 从onnx中我们知道它的输入要求shape为(1, 3, 320, 320) float32类型,并且yolo在对图片处理中还进行了归一化处理,所以我们推理的时候也要对输入的图片做相应的处理

import numpy as np
import os
import onnxruntime as ort
import cv2



img_path=r"F:\yolodata\8\Frames\155.png"
onn_path=r"F:\yolodata\8\runs\detect\eight83\weights\best.onnx"
provider=ort.get_available_providers()[1 if ort.get_device() == 'GPU' else 0]

ort_session=ort.InferenceSession(
                                onn_path,
                                providers=[provider])
# 图片处理
img=cv2.imread(img_path)
img_dst=img[np.newaxis,:,:,:].astype(np.float32)
img_dst=img_dst.transpose(0,3,1,2)/255.0
# print(img.shape,img.dtype) # (1, 3, 320, 320)  float32

# 推理
resluts=ort_session.run(output_names=["output0"],
                        input_feed={"images":img_dst})

# print(resluts[0].shape) # (1, 5, 2100)
best_index=resluts[0][:,-1,:].argmax() # 1750


position=resluts[0][:,:,best_index]
cx,cy,ww,hh,ss=position[0][0],position[0][1],position[0][2],position[0][3],position[0][4]
new_img=cv2.imread(img_path)
cv2.putText(new_img,str(round(ss,3)),(int(cx-ww/2),int(cy-hh/2)-5),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,255),2)
cv2.rectangle(new_img,(int(cx-ww/2),int(cy-hh/2)),(int(cx+ww/2),int(cy+hh/2)),(0,0,255),2)

# 显示两张图片
combined_img=np.hstack((img,new_img))
cv2.imshow("combined_img",combined_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码执行后图片显示效果如下
在这里插入图片描述

(2)多目标检测模型的推理

如果是多目标的模型,比如这里我的模型是可以检测19种目标的模型,那么推理就如下面一样

import cv2
import numpy as np
import onnxruntime as ort

# 类别字典
class_dict = {
    0: 'forward_scissors', 1: 'reverse_scissors', 2: 'call', 3: 'fist', 4: 'like',
    5: 'little_finger', 6: 'middle_finger', 7: 'ok', 8: 'one', 9: 'palm',
    10: 'rock', 11: 'stop', 12: 'three2', 13: 'three3', 14: 'three_gun',
    15: 'three', 16: 'thumb_index', 17: 'two_up_inverted', 18: 'two_up'
}

# img_path = r"E:\All_Data\test\1\gesture12.jpg"
img_path = r"E:\All_Data\test\1\gesture11.jpg"
onn_path = r"E:\All_Data\test\1\best(2).onnx"
provider = ort.get_available_providers()[1 if ort.get_device() == 'GPU' else 0]

ort_session = ort.InferenceSession(onn_path, providers=[provider])

# 图片处理
img = cv2.imread(img_path)
img = cv2.resize(img, (640, 480)) # 因为模型导出的时候是(1,3,640,480) BCHW
img1 = img[:, :, ::-1] # YOLO模型训练的时候加载数据默认是PIL去实现的,所以默认是RGB
img_dst = img[np.newaxis, :, :, :].astype(np.float32)
img_dst = img_dst.transpose(0, 3, 1, 2) / 255.0

# 推理
results = ort_session.run(output_names=["output0"], input_feed={"images": img_dst})

# 获取最佳检测结果
output = results[0][0]  # 形状(23, 6300)
print(output[4:23,:].shape) # (19, 6300)

scores = np.max(output[4:23, :], axis=0)  # 获取每个框的最大类别分数
best_index = np.argmax(scores)  # 最高分数的索引
position = output[:, best_index]  # 最佳框的信息

# 解析坐标和置信度
cx, cy, ww, hh = position[0:4]
class_probs = position[4:23]  # 类别概率
class_id = np.argmax(class_probs)  # 最高概率的类别ID
confidence = class_probs[class_id]  # 置信度分数

# 获取类别名称
class_name = class_dict.get(class_id, f"Unknown_{class_id}")

# 计算框的坐标
x1 = int(cx - ww / 2)
y1 = int(cy - hh / 2)
x2 = int(cx + ww / 2)
y2 = int(cy + hh / 2)

# 在图像上绘制结果
new_img = img.copy()
cv2.rectangle(new_img, (x1, y1), (x2, y2), (0, 0, 255), 2)

label = f"{class_name}: {confidence:.2f}"

(font_width, font_height), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
cv2.rectangle(new_img, (x1, y1 - font_height - 10), (x1 + font_width, y1), (0, 0, 255), -1)

# 在框上方显示类别和置信度
cv2.putText(new_img, label, (x1, y1 - 10),
            cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2)
cv2.imshow("Detection Result", new_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

4.YOLOv8参数说明

model.train()参数说明**

参考链接:https://blog.csdn.net/qq_42452134/article/details/135168930

参数 (Key) 默认值 (Value) 描述 (Description)
model 如果预训练就指向预训练模型 模型文件路径,例如 yolov8n.pt, yolov8n.yaml
data 执行数据集地址 数据文件路径,例如 coco128.yaml
epochs 100 训练的周期数
time None 训练的小时数,如果提供了此参数将覆盖周期数
patience 50 早停训练等待的最大无改善周期数
batch 16 每批次的图像数量(-1 表示自动批次)
imgsz 640 输入图像的尺寸
save TRUE 是否保存训练检查点和预测结果
save_period -1 每 x 个周期保存一次检查点(如果小于 1 则禁用)
cache FALSE 是否使用数据加载的缓存,可选 True/ram, disk 或 False
device None 运行设备,例如 cuda device=0 或 device=0,1,2,3 或 device=cpu
workers 8 数据加载的工作线程数(如果使用DDP则每个RANK)
project None 项目名称
name None 实验名称
exist_ok FALSE 是否覆盖已存在的实验
pretrained TRUE 是否使用预训练模型(布尔值)或从其中加载权重的模型(字符串)
optimizer ‘auto’ 使用的优化器,选项包括 [SGD, Adam, Adamax, AdamW, NAdam, RAdam, RMSProp, auto]
verbose FALSE 是否打印详细输出
seed 0 随机种子,用于可重复性
deterministic TRUE 是否启用确定性模式
single_cls FALSE 将多类别数据作为单一类别训练
rect FALSE 矩形训练,每批次根据最小填充整理
cos_lr FALSE 使用余弦学习率调度器
close_mosaic 10 在最后几个周期禁用马赛克增强(0 为禁用)
resume FALSE 从最后一个检查点恢复训练
amp TRUE 自动混合精度(AMP)训练
fraction 1 训练集中用于训练的数据集比例(默认为 1.0,即全部图像)
profile FALSE 在训练期间用于日志记录器的 ONNX 和 TensorRT 速度分析
freeze None 在训练期间冻结前 n 层,或冻结层索引列表
lr0 0.01 初始学习率(例如 SGD=1E-2, Adam=1E-3)
lrf 0.01 最终学习率(初始学习率 * 最终学习率)
momentum 0.937 SGD 动量/Adam beta1
weight_decay 0.0005 优化器权重衰减 5e-4
warmup_epochs 3 热身周期数(小数也可)
warmup_momentum 0.8 热身期间的初始动量
warmup_bias_lr 0.1 热身期间的初始偏置学习率
box 7.5 边界框损失增益
cls 0.5 类别损失增益(根据像素缩放)
dfl 1.5 DFL 损失增益
pose 12 姿态损失增益(仅姿态)
kobj 2 关键点对象损失增益(仅姿态)
label_smoothing 0 标签平滑(小数表示比例)
nbs 64 标称批次大小
overlap_mask TRUE 训练期间遮罩是否重叠(仅限分割训练)
mask_ratio 4 遮罩下采样比率(仅限分割训练)
dropout 0 是否使用 dropout 正则化(仅限分类训练)
val TRUE 训练期间是否进行验证/测试
plots FALSE 训练/验证期间是否保存图表和图像

model.export()参数说明

参考链接:https://blog.csdn.net/qq_42761751/article/details/140825169

Argument Type Default Description
format str ‘torchscript’ 导出模型的目标格式,例如 ‘onnx’、‘torchscript’、‘tensorflow’ 或其他格式,用于定义与各种部署环境的兼容性
imgsz int or tuple 640 模型输入的期望图像大小。可以是整数,或者用于特定尺寸的元组(高度,宽度)
keras bool FALSE 启用导出为Keras格式的TensorFlow SavedModel,提供与TensorFlow服务和API的兼容性
optimize bool FALSE 在导出到TorchScript时应用移动设备优化,可能会减少模型大小并提高性能
half bool FALSE 启用FP16(半精度)量化,减少模型大小,并可能在支持的硬件上加速推理
int8 bool FALSE 启用INT8量化,进一步压缩模型并加速推理,精度损失最小,主要适用于边缘设备
dynamic bool FALSE 允许 ONNX 和 TensorRT 导出支持动态输入尺寸,提高处理不同图像尺寸的灵活性
simplify bool FALSE 通过 onnxslim 简化 ONNX 导出的模型图,可能提高性能和兼容性
opset int None 指定 ONNX opset 版本,以确保与不同的 ONNX 解析器和运行时兼容。如果未设置,将使用最新支持的版本
workspace float 4 设置 TensorRT 优化的最大工作空间大小(以 GiB 为单位),以平衡内存使用和性能
nms bool FALSE 为 CoreML 导出添加非极大值抑制(NMS),这是准确和高效检测后处理的关键
batch int 1 指定导出模型的批量推理大小或在预测模式下导出模型将同时处理的最大图像数量

完结!!!

在这里插入图片描述

Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐