深度学习项目实战:基于PyTorch的图像分类与目标检测(YOLOv8)

一、项目概述

1.1 项目背景

目标检测是计算机视觉领域的核心技术之一,广泛应用于自动驾驶、安防监控、工业检测、医疗诊断等领域。YOLO(You Only Look Once)系列算法因其高效性和准确性成为目标检测的主流方案。

1.2 YOLOv8简介

特性

说明

单阶段检测

将目标检测作为回归问题处理,实现端到端训练

实时性能

在保持高精度的同时实现实时检测

模块化设计

支持多种模型尺寸(nano、small、medium、large、xlarge)

灵活部署

支持多种推理框架和硬件平台

易用性强

提供简洁的API和丰富的预训练模型

1.3 项目目标

• 掌握YOLOv8的核心原理和实现方法

• 完成从数据准备到模型部署的完整流程

• 实现图像分类和目标检测两个任务

• 学习模型优化和性能调优技巧

• 掌握深度学习项目的工程化实践

二、技术栈与环境配置

2.1 技术栈

组件

技术

深度学习框架

PyTorch 2.0+

计算机视觉库

OpenCV, Pillow

数据处理

NumPy, Pandas

可视化

Matplotlib, Seaborn

目标检测框架

Ultralytics YOLOv8

模型部署

ONNX, TensorRT

开发工具

Jupyter Notebook, VS Code

2.2 环境配置

创建虚拟环境并安装依赖:

# 创建虚拟环境
conda create -n yolo python=3.10 -y
conda activate yolo

#
安装PyTorch(根据CUDA版本选择)
pip install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu118

#
安装YOLOv8
pip install ultralytics

#
安装其他依赖
pip install opencv-python pillow numpy pandas matplotlib seaborn

#
验证安装
python -c "import torch; import ultralytics; print(torch.__version__)"

2.3 硬件要求

组件

要求

GPU

NVIDIA GPU(建议RTX 3060及以上)

内存

16GB RAM(推荐32GB)

存储

50GB可用空间(用于数据集和模型)

操作系统

Windows 10/11, Ubuntu 20.04+

三、YOLOv8架构详解

3.1 网络结构

YOLOv8采用CSPDarknet作为骨干网络,结合PANet和FPN进行特征融合,实现多尺度目标检测。

3.2 核心组件

组件

功能

C2f模块

改进的CSP模块,增强特征提取能力

SPPF模块

空间金字塔池化,提取多尺度特征

PANet

路径聚合网络,融合不同层级特征

解耦头

分离分类和回归任务,提高检测精度

Anchor-free

无锚框设计,简化模型结构

3.3 损失函数

YOLOv8采用多种损失函数的组合:

损失类型

函数

分类损失

BCE Loss(二元交叉熵)

回归损失

CIoU Loss(完整交并比)

DFL损失

分布焦点损失,提高边界框定位精度

四、项目结构设计

4.1 目录结构


yolov8_project/
├── data/                    #
数据目录
│   ├── images/             # 图像数据
│   │   ├── train/          # 训练集
│   │   ├── val/            # 验证集
│   │   └── test/           # 测试集
│   └── labels/             # 标注文件
│       ├── train/
│       ├── val/
│       └── test/
├── models/                  #
模型目录
│   ├── yolov8n.pt          # 预训练模型
│   ├── yolov8s.pt
│   ├── yolov8m.pt
│   └── yolov8l.pt
├── configs/                 #
配置文件
│   ├── data.yaml           # 数据集配置
│   └── train.yaml          # 训练配置
├── src/                     # 源代码
│   ├── train.py            # 训练脚本
│   ├── inference.py        # 推理脚本
│   ├── visualize.py        # 可视化脚本
│   └── utils.py            # 工具函数
├── outputs/                 # 输出目录
│   ├── runs/               # 训练结果
│   │   ├── detect/         # 检测结果
│   │   └── train/          # 训练日志
│   └── models/             # 导出模型
├── notebooks/               # Jupyter笔记本
│   ├── data_exploration.ipynb
│   └── model_analysis.ipynb
├── requirements.txt         #
依赖列表
└── README.md               # 项目说明

五、数据集准备

5.1 数据集选择

数据集

说明

COCO

通用目标检测数据集,80个类别,11万张图像

VOC

PASCAL VOC数据集,20个类别,1.6万张图像

自定义数据集

根据具体应用场景收集和标注数据

5.2 数据标注

使用LabelImg或LabelStudio进行数据标注:

# 安装标注工具
pip install labelimg

#
启动标注工具
labelimg data/images/train data/labels/train

#
标注格式:YOLO格式
# 每行格式: class_id x_center y_center width height
#
坐标归一化到[0,1]

5.3 数据增强

增强类型

方法

几何变换

随机翻转、旋转、缩放、平移

颜色变换

亮度、对比度、饱和度调整

Mosaic增强

将4张图像拼接成一张

MixUp增强

两张图像混合

HSV增强

色调、饱和度、明度调整

5.4 数据集配置

创建data.yaml配置文件:

# 数据集配置
path: ../data  # 数据集根目录
train: images/train  # 训练集路径
val: images/val      # 验证集路径
test: images/test    # 测试集路径

# 类别定义
names:
  0: person
  1: car
  2: bicycle
  3: dog
  4: cat

#
数据集信息
nc: 5  # 类别数量

六、模型训练

6.1 训练脚本

from ultralytics import YOLO

#
加载预训练模型
model = YOLO('yolov8n.pt')  # yolov8s.pt, yolov8m.pt, yolov8l.pt

#
训练模型
results = model.train(
    data='configs/data.yaml',      #
数据集配置
    epochs=100,                    # 训练轮数
    imgsz=640,                     # 输入图像大小
    batch=16,                      # 批次大小
    device='0',                    # GPU设备
    workers=8,                     # 数据加载线程数
    name='yolov8n_custom',         # 实验名称
    patience=50,                   # 早停耐心值
    save=True,                     # 保存检查点
    plots=True,                    # 生成训练曲线
    verbose=True                   # 详细输出
)

#
验证模型
metrics = model.val()

#
导出模型
model.export(format='onnx')

6.2 训练参数说明

参数

说明

epochs

训练轮数,默认100

imgsz

输入图像大小,默认640

batch

批次大小,根据显存调整

lr0

初始学习率,默认0.01

weight_decay

权重衰减,默认0.0005

momentum

动量,默认0.937

warmup_epochs

预热轮数,默认3

mosaic

Mosaic增强概率,默认1.0

mixup

MixUp增强概率,默认0.0

6.3 训练监控

使用TensorBoard监控训练过程:

# 启动TensorBoard
tensorboard --logdir outputs/runs/train

#
或在代码中使用
from ultralytics import YOLO

model = YOLO('yolov8n.pt')
model.train(data='configs/data.yaml', tensorboard=True)

七、模型推理与部署

7.1 图像推理

from ultralytics import YOLO
import cv2

#
加载训练好的模型
model = YOLO('outputs/runs/train/yolov8n_custom/weights/best.pt')

#
单张图像推理
results = model('test_image.jpg')

#
批量推理
results = model(['image1.jpg', 'image2.jpg', 'image3.jpg'])

#
处理结果
for result in results:
    #
获取检测框
    boxes = result.boxes
    for box in boxes:
        #
获取类别
        cls_id = int(box.cls[0])
        cls_name = model.names[cls_id]
       
        #
获取置信度
        conf = float(box.conf[0])
       
        #
获取边界框坐标
        x1, y1, x2, y2 = box.xyxy[0]
       
        #
绘制结果
        cv2.rectangle(result.orig_img, (int(x1), int(y1)), (int(x2), int(y2)), (0, 255, 0), 2)
        cv2.putText(result.orig_img, f'{cls_name} {conf:.2f}',
                    (int(x1), int(y1)-10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
   
    #
保存结果
    cv2.imwrite('result.jpg', result.orig_img)

7.2 视频推理

from ultralytics import YOLO
import cv2

#
加载模型
model = YOLO('best.pt')

#
打开视频
cap = cv2.VideoCapture('input_video.mp4')

#
获取视频信息
fps = int(cap.get(cv2.CAP_PROP_FPS))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))

#
创建视频写入器
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
out = cv2.VideoWriter('output_video.mp4', fourcc, fps, (width, height))

#
逐帧处理
while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
   
    #
推理
    results = model(frame)
   
    #
绘制结果
    annotated_frame = results[0].plot()
   
    #
写入视频
    out.write(annotated_frame)
   
    #
显示
    cv2.imshow('YOLOv8 Detection', annotated_frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
out.release()
cv2.destroyAllWindows()

7.3 模型部署

将模型导出为ONNX格式进行部署:

from ultralytics import YOLO

#
加载模型
model = YOLO('best.pt')

#
导出为ONNX
model.export(format='onnx', dynamic=True, simplify=True)

#
导出为TensorRT
model.export(format='engine', half=True)

#
导出为CoreML
model.export(format='coreml')

八、可视化与评估

8.1 训练曲线可视化

import matplotlib.pyplot as plt
import pandas as pd
from pathlib import Path

#
读取训练日志
results_csv = 'outputs/runs/train/yolov8n_custom/results.csv'
df = pd.read_csv(results_csv)

#
绘制损失曲线
fig, axes = plt.subplots(2, 2, figsize=(12, 10))

#
训练损失
axes[0, 0].plot(df['epoch'], df['train/box_loss'], label='Box Loss')
axes[0, 0].plot(df['epoch'], df['train/cls_loss'], label='Cls Loss')
axes[0, 0].plot(df['epoch'], df['train/dfl_loss'], label='DFL Loss')
axes[0, 0].set_xlabel('Epoch')
axes[0, 0].set_ylabel('Loss')
axes[0, 0].set_title('Training Loss')
axes[0, 0].legend()

#
验证损失
axes[0, 1].plot(df['epoch'], df['val/box_loss'], label='Box Loss')
axes[0, 1].plot(df['epoch'], df['val/cls_loss'], label='Cls Loss')
axes[0, 1].plot(df['epoch'], df['val/dfl_loss'], label='DFL Loss')
axes[0, 1].set_xlabel('Epoch')
axes[0, 1].set_ylabel('Loss')
axes[0, 1].set_title('Validation Loss')
axes[0, 1].legend()

# mAP
指标
axes[1, 0].plot(df['epoch'], df['metrics/mAP50(B)'], label='mAP@50')
axes[1, 0].plot(df['epoch'], df['metrics/mAP50-95(B)'], label='mAP@50-95')
axes[1, 0].set_xlabel('Epoch')
axes[1, 0].set_ylabel('mAP')
axes[1, 0].set_title('Mean Average Precision')
axes[1, 0].legend()

#
精确率和召回率
axes[1, 1].plot(df['epoch'], df['metrics/precision(B)'], label='Precision')
axes[1, 1].plot(df['epoch'], df['metrics/recall(B)'], label='Recall')
axes[1, 1].set_xlabel('Epoch')
axes[1, 1].set_ylabel('Score')
axes[1, 1].set_title('Precision and Recall')
axes[1, 1].legend()

plt.tight_layout()
plt.savefig('training_curves.png', dpi=300)

8.2 混淆矩阵

from ultralytics import YOLO
import matplotlib.pyplot as plt

#
加载模型
model = YOLO('best.pt')

#
验证并生成混淆矩阵
results = model.val(conf=0.25, iou=0.6, plots=True)

#
混淆矩阵会自动保存到 outputs/runs/val/confusion_matrix.png

8.3 PR曲线

# 验证模型并生成PR曲线
results = model.val(plots=True)

# PR
曲线会自动保存到 outputs/runs/val/PR_curve.png

九、项目实战案例

9.1 案例1:交通标志检测

实现交通标志的实时检测,用于自动驾驶辅助系统。

参数

配置

数据集

GTSDB(德国交通标志检测基准数据集)

类别数

43个交通标志类别

模型

YOLOv8n(轻量级,适合实时应用)

输入尺寸

640x640

训练轮数

100 epochs

mAP@50

0.92

推理速度

2ms/帧(RTX 3090)

9.2 案例2:工业缺陷检测

实现产品表面缺陷的自动检测,用于质量控制。

参数

配置

数据集

自定义工业缺陷数据集

类别数

5类缺陷(划痕、凹陷、污渍、裂纹、气泡)

模型

YOLOv8s(平衡精度和速度)

输入尺寸

1024x1024

训练轮数

150 epochs

mAP@50

0.88

推理速度

8ms/帧(RTX 3090)

9.3 案例3:行人检测

实现行人的实时检测,用于安防监控。

参数

配置

数据集

COCO行人数据 + 自定义数据

类别数

1类(行人)

模型

YOLOv8m(高精度)

输入尺寸

640x640

训练轮数

200 epochs

mAP@50

0.95

推理速度

5ms/帧(RTX 3090)

十、优化与扩展

10.1 模型优化

优化方法

说明

模型量化

将FP32模型量化为INT8,减少模型大小

模型剪枝

移除不重要的权重,减少计算量

知识蒸馏

用大模型指导小模型训练

神经架构搜索

自动搜索最优网络结构

10.2 性能优化

优化方法

说明

混合精度训练

使用FP16加速训练,减少显存占用

梯度累积

模拟大批次训练

分布式训练

多GPU并行训练

数据加载优化

使用多线程预加载数据

10.3 部署优化

部署平台

优化方案

TensorRT加速

NVIDIA GPU专用推理引擎

ONNX Runtime

跨平台推理框架

OpenVINO

Intel CPU优化推理

CoreML

Apple设备部署

附录:完整代码示例

A.1 完整训练脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
YOLOv8
完整训练脚本
"""

from ultralytics import YOLO
import torch
from pathlib import Path

def train_model():
    """
训练YOLOv8模型"""
   
    #
检查GPU
    device = '0' if torch.cuda.is_available() else 'cpu'
    print(f'Using device: {device}')
   
    #
加载预训练模型
    model = YOLO('yolov8n.pt')
   
    #
训练配置
    config = {
        'data': 'configs/data.yaml',
        'epochs': 100,
        'imgsz': 640,
        'batch': 16,
        'device': device,
        'workers': 8,
        'name': 'yolov8n_custom',
        'patience': 50,
        'save': True,
        'plots': True,
        'verbose': True,
        'lr0': 0.01,
        'weight_decay': 0.0005,
        'warmup_epochs': 3,
        'mosaic': 1.0,
        'mixup': 0.0,
        'hsv_h': 0.015,
        'hsv_s': 0.7,
        'hsv_v': 0.4
    }
   
    #
训练模型
    results = model.train(**config)
   
    #
验证模型
    metrics = model.val()
   
    #
打印结果
    print(f'mAP50: {metrics.box.map50:.4f}')
    print(f'mAP50-95: {metrics.box.map:.4f}')
    print(f'Precision: {metrics.box.mp:.4f}')
    print(f'Recall: {metrics.box.mr:.4f}')
   
    #
导出模型
    model.export(format='onnx')
   
    return model, results

if __name__ == '__main__':
    model, results = train_model()

A.2 完整推理脚本

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
YOLOv8
完整推理脚本
"""

from ultralytics import YOLO
import cv2
import argparse
from pathlib import Path

class YOLODetector:
    """YOLOv8
检测器"""
   
    def __init__(self, model_path, conf_threshold=0.5, iou_threshold=0.45):
        """
       
初始化检测器
       
        Args:
            model_path:
模型路径
            conf_threshold: 置信度阈值
            iou_threshold: IOU阈值
        """
        self.model = YOLO(model_path)
        self.conf_threshold = conf_threshold
        self.iou_threshold = iou_threshold
        self.class_names = self.model.names
   
    def detect_image(self, image_path, output_path=None):
        """
       
检测单张图像
       
        Args:
            image_path:
输入图像路径
            output_path: 输出图像路径
        """
        #
读取图像
        image = cv2.imread(str(image_path))
        if image is None:
            raise ValueError(f'
无法读取图像: {image_path}')
       
        #
推理
        results = self.model(
            image,
            conf=self.conf_threshold,
            iou=self.iou_threshold,
            verbose=False
        )
       
        #
绘制结果
        annotated_image = results[0].plot()
       
        #
保存结果
        if output_path:
            cv2.imwrite(str(output_path), annotated_image)
            print(f'
结果已保存到: {output_path}')
       
        return results[0]
   
    def detect_video(self, video_path, output_path=None):
        """
       
检测视频
       
        Args:
            video_path:
输入视频路径
            output_path: 输出视频路径
        """
        #
打开视频
        cap = cv2.VideoCapture(str(video_path))
        if not cap.isOpened():
            raise ValueError(f'
无法打开视频: {video_path}')
       
        #
获取视频信息
        fps = int(cap.get(cv2.CAP_PROP_FPS))
        width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
        height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
        total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))
       
        #
创建视频写入器
        if output_path:
            fourcc = cv2.VideoWriter_fourcc(*'mp4v')
            out = cv2.VideoWriter(str(output_path), fourcc, fps, (width, height))
       
        #
逐帧处理
        frame_count = 0
        while cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break
           
            #
推理
            results = self.model(
                frame,
                conf=self.conf_threshold,
                iou=self.iou_threshold,
                verbose=False
            )
           
            #
绘制结果
            annotated_frame = results[0].plot()
           
            #
写入视频
            if output_path:
                out.write(annotated_frame)
           
            #
显示进度
            frame_count += 1
            if frame_count % 30 == 0:
                print(f'
处理进度: {frame_count}/{total_frames} ({frame_count/total_frames*100:.1f}%)')
           
            #
显示
            cv2.imshow('YOLOv8 Detection', annotated_frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
       
        #
释放资源
        cap.release()
        if output_path:
            out.release()
        cv2.destroyAllWindows()
       
        print(f'
视频处理完成: {frame_count} ')
   
    def detect_webcam(self):
        """
检测摄像头实时画面"""
        #
打开摄像头
        cap = cv2.VideoCapture(0)
        if not cap.isOpened():
            raise ValueError('
无法打开摄像头')
       
        while True:
            ret, frame = cap.read()
            if not ret:
                break
           
            #
推理
            results = self.model(
                frame,
                conf=self.conf_threshold,
                iou=self.iou_threshold,
                verbose=False
            )
           
            #
绘制结果
            annotated_frame = results[0].plot()
           
            #
显示
            cv2.imshow('YOLOv8 Webcam Detection', annotated_frame)
            
            #
q退出
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
       
        cap.release()
        cv2.destroyAllWindows()

def main():
    """
主函数"""
    parser = argparse.ArgumentParser(description='YOLOv8
目标检测')
    parser.add_argument('--model', type=str, default='best.pt', help='
模型路径')
    parser.add_argument('--source', type=str, help='
输入源(图像/视频/摄像头)')
    parser.add_argument('--output', type=str, help='
输出路径')
    parser.add_argument('--conf', type=float, default=0.5, help='
置信度阈值')
    parser.add_argument('--iou', type=float, default=0.45, help='IOU
阈值')
    parser.add_argument('--webcam', action='store_true', help='
使用摄像头')
   
    args = parser.parse_args()
   
    #
创建检测器
    detector = YOLODetector(
        model_path=args.model,
        conf_threshold=args.conf,
        iou_threshold=args.iou
    )
   
    #
检测
    if args.webcam:
        detector.detect_webcam()
    elif args.source:
        source_path = Path(args.source)
        if source_path.is_file():
            if source_path.suffix.lower() in ['.jpg', '.jpeg', '.png', '.bmp']:
                detector.detect_image(source_path, args.output)
            elif source_path.suffix.lower() in ['.mp4', '.avi', '.mov']:
                detector.detect_video(source_path, args.output)
        else:
            raise ValueError(f'
不支持的输入源: {args.source}')
    else:
        print('
请指定输入源(--source)或使用摄像头(--webcam')

if __name__ == '__main__':
    main()

十一、项目数据已上传,下载地址:

https://download.csdn.net/download/m0_67097444/92942078

更多推荐