深度学习项目实战:基于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.cls0)
cls_name = model.namescls_id
获取置信度
conf = float(box.conf0)
获取边界框坐标
x1, y1, x2, y2 = box.xyxy0
绘制结果
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 = results0.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))
训练损失
axes0, 0.plot(df'epoch', df'train/box_loss', label='Box Loss')
axes0, 0.plot(df'epoch', df'train/cls_loss', label='Cls Loss')
axes0, 0.plot(df'epoch', df'train/dfl_loss', label='DFL Loss')
axes0, 0.set_xlabel('Epoch')
axes0, 0.set_ylabel('Loss')
axes0, 0.set_title('Training Loss')
axes0, 0.legend()
验证损失
axes0, 1.plot(df'epoch', df'val/box_loss', label='Box Loss')
axes0, 1.plot(df'epoch', df'val/cls_loss', label='Cls Loss')
axes0, 1.plot(df'epoch', df'val/dfl_loss', label='DFL Loss')
axes0, 1.set_xlabel('Epoch')
axes0, 1.set_ylabel('Loss')
axes0, 1.set_title('Validation Loss')
axes0, 1.legend()
mAP指标
axes1, 0.plot(df'epoch', df'metrics/mAP50(B)', label='mAP@50')
axes1, 0.plot(df'epoch', df'metrics/mAP50-95(B)', label='mAP@50-95')
axes1, 0.set_xlabel('Epoch')
axes1, 0.set_ylabel('mAP')
axes1, 0.set_title('Mean Average Precision')
axes1, 0.legend()
精确率和召回率
axes1, 1.plot(df'epoch', df'metrics/precision(B)', label='Precision')
axes1, 1.plot(df'epoch', df'metrics/recall(B)', label='Recall')
axes1, 1.set_xlabel('Epoch')
axes1, 1.set_ylabel('Score')
axes1, 1.set_title('Precision and Recall')
axes1, 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 = results0.plot()
保存结果
if output_path:
cv2.imwrite(str(output_path), annotated_image)
print(f'结果已保存到: {output_path}')
return results0
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 = results0.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 = results0.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()
十一、项目数据已上传,下载地址: