search
arrow_back 返回
YOLO11训练自己的数据集

YOLO11训练自己的数据集

环境搭建

Anaconda3安装

Anaconda image 我下载的版本是Anaconda3-2024.10-1-Windows-x86_64

Pycharm安装

Pycharm image

安装Cuda

Cuda image 我下载的版本是cuda_12.9.0_576.02_windows

Cudnn安装

Cudnn image 我下载的版本是cudnn-windows-x86_64-8.9.7.29_cuda12-archive

安装完后进入Anaconda prompt创建虚拟环境

image

默认进入的是base环境,base环境的版本与下载的anaconda3版本有关,因此不建议直接使用,需要新建环境,在新建环境之前建议更改默认的pip源和conda源可加速下载速度

conda config --remove-key channels
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/main/
conda config --add channels https://mirrors.ustc.edu.cn/anaconda/pkgs/free/
conda config --add channels https://mirrors.bfsu.edu.cn/anaconda/cloud/pytorch/
conda config --set show_channel_urls yes
pip config set global.index-url https://mirrors.ustc.edu.cn/pypi/web/simple

创建一个名为yolov11,python版本为3.10的虚拟环境,回车后出现新建环境提醒输入y继续,耐心等待全部下载完成后自动安装

conda create -n yolov11 python=3.10

创建完之后输入下面命令进入yolov11环境

conda activate yolov11

输入下方命令即可安装pytorch,耐心等待安装完成

pip install torch==2.0.0+cu118 torchvision==0.15.1+cu118 --extra-index-url https://download.pytorch.org/whl/cu118

输入下面的指令通过pip安装其余库

pip install torch==2.0.0+cu118 torchvision==0.15.1+cu118 --extra-index-url https://download.pytorch.org/whl/cu118

安装ultralytics库

pip install ultralytics

源码下载

搭建好环境后,下载yolo11源码,源码仓库现在是Yolo26

Yolo源码仓库

可以在网盘下载

夸克网盘

下载完后使用Pycharm打开

修改解释器

image

项目有这些文件 image

先验证环境是否配好

yolo predict model=yolo11n.pt source='cat.jpg'

如下输出说明正常

image

训练自己的模型

数据集收集

因为这个检测我是要在RK3588上跑的,所以数据集直接用RK3588进行收集

image

数据集标注

数据集标注使用labelme软件进行标注 image

数据集转换

标注完数据集后,文件格式没有转换的话是LabelMe输出的.json文件,需要转换成yolo格式的文件,即.txt文件

image

在项目目录下创建一个json2yolo.py的脚本,脚本内容如下

import json
import os
import glob

# ================= 配置区域 =================
# 1. 你的 json 文件所在的文件夹路径 (注意路径中的斜杠)
json_dir = 'D:/your_path/json_labels'  

# 2. 转换后的 txt 文件保存路径 (建议新建一个文件夹)
txt_save_dir = 'D:/your_path/yolo_txt_labels' 

# 3. 类别映射字典 (务必与你之前设定的严格对应!)
class_mapping = {
    'solder_bridge': 0,
    'missing_comp': 1,
    'missing_solder': 2
}
# ============================================

if not os.path.exists(txt_save_dir):
    os.makedirs(txt_save_dir)

json_files = glob.glob(os.path.join(json_dir, '*.json'))

for json_file in json_files:
    with open(json_file, 'r', encoding='utf-8') as f:
        data = json.load(f)
    
    # 获取图像的绝对宽和高
    img_width = data['imageWidth']
    img_height = data['imageHeight']
    
    # 获取文件名(不含后缀)
    file_name = os.path.splitext(os.path.basename(json_file))[0]
    txt_file_path = os.path.join(txt_save_dir, file_name + '.txt')
    
    with open(txt_file_path, 'w') as txt_f:
        for shape in data['shapes']:
            label_name = shape['label']
            
            # 如果标注的名字不在我们设定的字典里,跳过或者报错
            if label_name not in class_mapping:
                print(f"警告: 文件 {file_name}.json 中发现未知类别 '{label_name}',已跳过。")
                continue
                
            class_id = class_mapping[label_name]
            
            # 解析 LabelMe 的两点坐标 (左上角和右下角)
            points = shape['points']
            x1, y1 = points[0]
            x2, y2 = points[1]
            
            # 确保坐标顺序正确
            xmin = min(x1, x2)
            xmax = max(x1, x2)
            ymin = min(y1, y2)
            ymax = max(y1, y2)
            
            # YOLO 格式数学转换:计算中心点和宽高,并归一化 (除以图片总宽高)
            x_center = ((xmin + xmax) / 2) / img_width
            y_center = ((ymin + ymax) / 2) / img_height
            width = (xmax - xmin) / img_width
            height = (ymax - ymin) / img_height
            
            # 写入 txt 文件,保留 6 位小数
            txt_f.write(f"{class_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")
            
print("转换完成!请前往输出文件夹检查 .txt 文件。")

然后点击右上角的运行

image

转换成功 image

随便打开一个,显示的是坐标文件,说明没有问题 image

数据集划分

训练自己的yolov11检测模型,数据集需要划分为训练集、验证集和测试集,这里提供一个参考代码,划分比例为8:1:1,也可以按照自己的比例划分,获取的数据集划分过了则不用重复划分,即在项目目录创建一个dataset.py脚本,在代码最后替换成自己的路径

import os
import shutil
import random
 
# random.seed(0)  #随机种子,可自选开启
def split_data(file_path, label_path, new_file_path, train_rate, val_rate, test_rate):
	images = os.listdir(file_path)
	labels = os.listdir(label_path)
	images_no_ext = {os.path.splitext(image)[0]: image for image in images}
	labels_no_ext = {os.path.splitext(label)[0]: label for label in labels}
	matched_data = [(img, images_no_ext[img], labels_no_ext[img]) for img in images_no_ext if img in labels_no_ext]
 
	unmatched_images = [img for img in images_no_ext if img not in labels_no_ext]
	unmatched_labels = [label for label in labels_no_ext if label not in images_no_ext]
	if unmatched_images:
		print("未匹配的图片文件:")
		for img in unmatched_images:
			print(images_no_ext[img])
	if unmatched_labels:
		print("未匹配的标签文件:")
		for label in unmatched_labels:
			print(labels_no_ext[label])
 
	random.shuffle(matched_data)
	total = len(matched_data)
	train_data = matched_data[:int(train_rate * total)]
	val_data = matched_data[int(train_rate * total):int((train_rate + val_rate) * total)]
	test_data = matched_data[int((train_rate + val_rate) * total):]
 
	# 处理训练集
	for img_name, img_file, label_file in train_data:
		old_img_path = os.path.join(file_path, img_file)
		old_label_path = os.path.join(label_path, label_file)
		new_img_dir = os.path.join(new_file_path, 'train', 'images')
		new_label_dir = os.path.join(new_file_path, 'train', 'labels')
		os.makedirs(new_img_dir, exist_ok=True)
		os.makedirs(new_label_dir, exist_ok=True)
		shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
		shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
	# 处理验证集
	for img_name, img_file, label_file in val_data:
		old_img_path = os.path.join(file_path, img_file)
		old_label_path = os.path.join(label_path, label_file)
		new_img_dir = os.path.join(new_file_path, 'val', 'images')
		new_label_dir = os.path.join(new_file_path, 'val', 'labels')
		os.makedirs(new_img_dir, exist_ok=True)
		os.makedirs(new_label_dir, exist_ok=True)
		shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
		shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
	# 处理测试集
	for img_name, img_file, label_file in test_data:
		old_img_path = os.path.join(file_path, img_file)
		old_label_path = os.path.join(label_path, label_file)
		new_img_dir = os.path.join(new_file_path, 'test', 'images')
		new_label_dir = os.path.join(new_file_path, 'test', 'labels')
		os.makedirs(new_img_dir, exist_ok=True)
		os.makedirs(new_label_dir, exist_ok=True)
		shutil.copy(old_img_path, os.path.join(new_img_dir, img_file))
		shutil.copy(old_label_path, os.path.join(new_label_dir, label_file))
	print("数据集已划分完成")
 
if __name__ == '__main__':
	file_path = r"f:\data\JPEGImages"  # 图片文件夹
	label_path = r'f:\data\labels'  # 标签文件夹
	new_file_path = r"f:\VOCdevkit"  # 新数据存放位置
	split_data(file_path, label_path, new_file_path, train_rate=0.8, val_rate=0.1, test_rate=0.1)

点击运行 image

分好了,把分好后的文件夹复制到项目目录

image

8:1:1是标准的做法,但是会浪费一部分数据给测试,更推荐做8:2划分,即训练:验证=8:2,只需要把脚本最后的比例改一下就行了

image

训练模型

在项目路径创建一个.yaml文件,这是专门写给 YOLO 系统的数据集导航地图

image

项目目录创建一个训练脚本yolo11_train.py

epochs是训练轮数,可以由少变多看训练效果,workers和batch根据电脑性能进行调整,如果运行吃力则相应降低,最好为2的n次方。没有显卡则把device=0修改为device=‘cpu’

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO
if __name__ == '__main__':
  model = YOLO('D:/OKay/Yolo/Yolo11/YOLOv11/ultralytics-8.3.23/ultralytics/cfg/models/11/yolo11.yaml')
  model.load('yolo11n.pt')  #注释则不加载
  results = model.train(
    data='D:/OKay/Yolo/Yolo11/YOLOv11/ultralytics-8.3.23/pcba_data.yaml',  #数据集配置文件的路径
    epochs=200,  #训练轮次总数
    batch=16,  #批量大小,即单次输入多少图片训练
    imgsz=640,  #训练图像尺寸
    workers=8,  #加载数据的工作线程数
    device= 0,  #指定训练的计算设备,无nvidia显卡则改为 'cpu'
    optimizer='SGD',  #训练使用优化器,可选 auto,SGD,Adam,AdamW 等
    amp= True,  #True 或者 False, 解释为:自动混合精度(AMP) 训练
    cache=False  # True 在内存中缓存数据集图像,服务器推荐开启
)

也可以使用命令行执行训练

yolo task=detect mode=train model=yolo11n.yaml pretrained=yolo11n.pt data=data.yaml epochs=200 imgsz=640 device=0 optimizer='SGD' workers=8 batch=64 amp=False cache=False

训练开始

image

内存炸了,训练过程中pycharm闪退了,改用终端训练,总共要训练200轮

image

训练完成

image

模型测试

项目目录创建一个测试脚本yolov11_predict.py

from ultralytics import YOLO
# 加载训练好的模型,改为自己的路径
model = YOLO('runs/detect/train5/weights/best.pt')  #修改为训练好的路径
source = 'D:/OKay/Yolo/test.png' #修改为自己的图片路径及文件名
# 运行推理,并附加参数
model.predict(source, save=True)

image

测试测试集上各类别的精度及总体精度,创建一个yolo11_val.py脚本

import warnings
warnings.filterwarnings('ignore')
from ultralytics import YOLO

if __name__ == '__main__':
    model = YOLO('runs/detect/train5/weights/best.pt')
    model.val(data='D:/OKay/Yolo/Yolo11/YOLOv11/ultralytics-8.3.23/pcba_data.yaml',
              split='val',  # <--- 关键修改在这里
              imgsz=640,
              batch=16,
              iou=0.6,
              conf=0.001,
              workers=8,
              )

由于前面使用的是8:2的划分,所以没有单独的测试集,直接用验证验证集的数据

image

image

数据分析

混淆矩阵

混淆矩阵数据表明,模型在当前验证集上实现了零误检(False Positive)与零漏检(False Negative),呈现出极高的分类与定位精度。从绝对值混淆矩阵的统计结果来看,验证集内共包含76个连锡(solder_bridge)、38个漏件(missing_comp)以及40个漏焊(missing_solder)真实样本。模型对上述三个类别的预测数量与真实标签数量完全对应,所有预测结果均集中于矩阵对角线。相应的归一化混淆矩阵(Normalized Confusion Matrix)显示各类别对角线数值均为 1.00,背景(background)类别与其他缺陷类别交叉项均为0。该组数据证实模型对各类PCBA缺陷特征具有优异的提取与判别能力,未发生类别混淆现象。

image

image

精确率与召回率曲线

精确率-召回率曲线进一步量化了模型的综合检测性能。在当前验证集下,连锡、漏件与漏焊三个单独类别的 P-R 曲线以及全类别平均曲线均呈现出理想的直角形态,紧贴坐标平面右上方(坐标为 1.0, 1.0 的区域)。在交并比(IoU)阈值设为 0.5 的标准下,模型全类别的平均精度均值(mAP@0.5)高达 0.995。此项指标反映出模型在维持极高预测精确率的同时,也达到了满分的召回率,验证了模型在复杂区域特征定位上的高可靠性。

image

置信度相关曲线

置信度综合曲线(包含 F1-Confidence, Precision-Confidence, Recall-Confidence)的结果显示,模型对其输出的预测框具有极高的确定性。其中,F1-置信度曲线表明,当推理阶段的置信度阈值(Confidence Threshold)设定为 0.878 时,所有类别的 F1 综合得分达到最高值 1.00。此外,精确率和召回率在极宽的置信度区间(约 0.05 至 0.90)内均保持在 1.0 满分状态,直至置信度超过 0.95 之后才出现召回率的断崖式下降。该分布特性说明模型预测得分普遍且稳定地处于高位,抗背景噪声干扰的能力极强,非常适合在实际工程中采用较高的阈值进行严格筛选。

image

image

image

综合上述多维度评估指标,本次训练的 YOLOv11 模型在 PCBA 缺陷检测的验证集上表现卓越,各项性能指标均触及理论上限。鉴于验证集数据表现出 100% 的准确率,模型具备了坚实的落地基础。针对后续工程实践,提出两点建议:首先,需警惕当前数据集分布可能带来的过拟合(Overfitting)风险,建议引入未参与模型迭代的全新批次产线实拍数据进行交叉验证,以评估其实际泛化能力。

评论

Cover
晴天 周杰伦
OKayFlow 正在共享键鼠中... 将鼠标向左大跨度甩回,或在主电脑上按 Scroll Lock 键强制退出
OKayFlow
工具箱

工具箱