从零构建水下生物检测模型:YOLOv5实战指南
水下世界的神秘与复杂一直吸引着科学家和探险家。在这个充满未知的领域,人工智能技术正逐渐成为探索海洋生物多样性的重要工具。本文将带你一步步完成从环境配置到模型部署的完整流程,使用YOLOv5构建一个能够识别螃蟹、鱼类、水母等常见水下生物的目标检测系统。
1. 环境准备与数据集处理
1.1 搭建深度学习环境
构建YOLOv5模型的第一步是配置合适的开发环境。推荐使用Python 3.8+和PyTorch 1.7+的组合,这是经过验证的稳定搭配。以下是关键组件的安装步骤:
conda create -n yolo_env python=3.8 conda activate yolo_env pip install torch==1.8.1+cu111 torchvision==0.9.1+cu111 -f https://download.pytorch.org/whl/torch_stable.html pip install opencv-python matplotlib tqdm pandas seaborn注意:CUDA版本需要与你的NVIDIA显卡驱动兼容。使用nvidia-smi命令查看支持的CUDA版本。
常见环境问题解决方案:
- CUDA版本不匹配:重新安装对应版本的PyTorch
- 显存不足:减小batch_size或使用更小的模型变体(yolov5s)
- 依赖冲突:建议使用conda或venv创建独立环境
1.2 数据集结构与格式转换
假设你已经获得了标注好的水下生物数据集,通常会有两种常见格式:
VOC格式:
Annotations/ ├── image1.xml ├── image2.xml └── ... JPEGImages/ ├── image1.jpg ├── image2.jpg └── ...YOLO格式:
images/ ├── image1.jpg ├── image2.jpg └── ... labels/ ├── image1.txt ├── image2.txt └── ...如果原始数据是VOC格式,可以使用以下Python脚本转换为YOLO格式:
import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_file, classes): tree = ET.parse(xml_file) root = tree.getroot() size = root.find('size') w = int(size.find('width').text) h = int(size.find('height').text) yolo_lines = [] for obj in root.iter('object'): cls = obj.find('name').text if cls not in classes: continue cls_id = classes.index(cls) xmlbox = obj.find('bndbox') b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text)) bb = convert((w,h), b) yolo_lines.append(f"{cls_id} {' '.join([str(a) for a in bb])}\n") return yolo_lines def convert(size, box): dw = 1./size[0] dh = 1./size[1] x = (box[0] + box[1])/2.0 y = (box[2] + box[3])/2.0 w = box[1] - box[0] h = box[3] - box[2] x = x*dw w = w*dw y = y*dh h = h*dh return (x,y,w,h)2. YOLOv5模型配置
2.1 下载与准备YOLOv5
从官方仓库克隆最新代码:
git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txtYOLOv5提供了多个预训练模型变体,根据硬件条件选择:
| 模型类型 | 参数量(M) | 推理速度(ms) | mAP@0.5 | 适用场景 |
|---|---|---|---|---|
| yolov5n | 1.9 | 6.3 | 28.0 | 移动端/嵌入式 |
| yolov5s | 7.2 | 6.4 | 37.4 | 入门级GPU |
| yolov5m | 21.2 | 8.2 | 45.4 | 中等配置 |
| yolov5l | 46.5 | 10.1 | 49.0 | 高性能GPU |
| yolov5x | 86.7 | 12.1 | 50.7 | 服务器级 |
对于水下生物检测,建议从yolov5s开始,在验证集上评估后再决定是否需要更大模型。
2.2 自定义数据集配置
创建数据集描述文件underwater.yaml:
# 训练和验证图像路径 train: ../underwater_dataset/train/images val: ../underwater_dataset/valid/images # 类别数量 nc: 6 # 类别名称 names: ['crab', 'fish', 'jellyfish', 'shrimp', 'small_fish', 'starfish']关键参数说明:
nc: 类别数量,与你的数据集一致names: 类别标签,顺序与标注文件中的class_id对应- 路径建议使用相对路径,便于项目迁移
3. 模型训练与调优
3.1 启动训练过程
基础训练命令:
python train.py --img 640 --batch 16 --epochs 100 --data underwater.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --name underwater_detection常用训练参数解析:
--img: 输入图像尺寸,保持640x640的默认值即可--batch: 根据GPU显存调整,显存不足时减小此值--epochs: 训练轮数,水下生物检测通常需要100-300轮--weights: 预训练权重,使用官方提供的yolov5s.pt可以加速收敛--name: 实验名称,用于区分不同训练运行
3.2 训练监控与问题排查
训练开始后,YOLOv5会自动生成以下监控文件:
runs/train/underwater_detection/ ├── weights/ # 保存的模型权重 ├── events.out.tfevents # TensorBoard日志 ├── results.png # 训练指标可视化 ├── train_batch0.jpg # 训练批次示例 └── val_batch0_labels.jpg # 验证集标注可视化常见训练问题及解决方案:
损失不下降
- 检查学习率是否合适(默认0.01)
- 确认数据标注是否正确
- 尝试更小的模型或增加数据增强
显存不足(OOM)
- 减小batch_size(如从16降到8)
- 使用更小的模型变体(yolov5n)
- 尝试混合精度训练(添加
--device 0 --half)
过拟合
- 增加数据增强参数(添加
--augment True) - 提前停止训练(观察验证集指标)
- 使用更大的数据集
- 增加数据增强参数(添加
3.3 高级训练技巧
数据增强策略:
修改data/hyps/hyp.scratch-low.yaml中的增强参数:
hsv_h: 0.015 # 色调增强 hsv_s: 0.7 # 饱和度增强 hsv_v: 0.4 # 明度增强 degrees: 10.0 # 旋转角度 translate: 0.1 # 平移比例 scale: 0.9 # 缩放比例 shear: 0.0 # 剪切变换 perspective: 0.0 # 透视变换 flipud: 0.0 # 上下翻转概率 fliplr: 0.5 # 左右翻转概率 mosaic: 1.0 # mosaic增强概率 mixup: 0.0 # mixup增强概率学习率调度:
YOLOv5默认使用余弦退火学习率调度。可以通过修改train.py中的优化器配置进行调整:
optimizer = torch.optim.SGD(pg0, lr=hyp['lr0'], momentum=hyp['momentum'], nesterov=True) lf = lambda x: ((1 + math.cos(x * math.pi / epochs)) / 2) * (1 - hyp['lrf']) + hyp['lrf'] # cosine scheduler = torch.optim.lr_scheduler.LambdaLR(optimizer, lr_lambda=lf)4. 模型评估与部署
4.1 性能评估指标
训练完成后,使用验证集评估模型性能:
python val.py --weights runs/train/underwater_detection/weights/best.pt --data underwater.yaml --img 640关键评估指标解读:
- mAP@0.5: IoU阈值为0.5时的平均精度,主要指标
- mAP@0.5:0.95: IoU阈值从0.5到0.95的平均精度,更严格
- Precision: 查准率,预测为正样本中实际为正的比例
- Recall: 查全率,实际正样本中被预测为正的比例
水下生物检测的典型性能目标:
| 类别 | 合理mAP@0.5 | 优秀mAP@0.5 |
|---|---|---|
| 螃蟹 | 0.65-0.75 | >0.80 |
| 鱼类 | 0.70-0.80 | >0.85 |
| 水母 | 0.60-0.70 | >0.75 |
| 虾类 | 0.55-0.65 | >0.70 |
4.2 模型导出与优化
将PyTorch模型导出为ONNX格式,便于跨平台部署:
python export.py --weights runs/train/underwater_detection/weights/best.pt --include onnx --img 640 --dynamic导出后的模型可以使用ONNX Runtime进行加速推理:
import onnxruntime as ort ort_session = ort.InferenceSession("best.onnx") outputs = ort_session.run(None, {"images": processed_image})模型量化减小模型大小,提升推理速度:
from onnxruntime.quantization import quantize_dynamic, QuantType quantize_dynamic("best.onnx", "best_quant.onnx", weight_type=QuantType.QUInt8)4.3 实际应用示例
使用训练好的模型进行实时检测:
import cv2 import torch model = torch.hub.load('ultralytics/yolov5', 'custom', path='runs/train/underwater_detection/weights/best.pt') cap = cv2.VideoCapture('underwater_video.mp4') while cap.isOpened(): ret, frame = cap.read() if not ret: break results = model(frame) rendered_frame = results.render()[0] cv2.imshow('Underwater Detection', rendered_frame) if cv2.waitKey(1) == ord('q'): break cap.release() cv2.destroyAllWindows()对于边缘设备部署,可以考虑使用TensorRT进一步优化:
trtexec --onnx=best.onnx --saveEngine=best.trt --fp165. 进阶优化策略
5.1 类别不平衡处理
水下数据集中常见类别不平衡问题,例如鱼类样本远多于海星。解决方法:
重采样策略:
- 过采样稀有类别
- 欠采样常见类别
损失函数加权: 修改YOLOv5的损失计算,为稀有类别分配更高权重:
# 在utils/loss.py中修改ComputeLoss类 class ComputeLoss: def __init__(self, model, autobalance=False): self.cls_weight = torch.tensor([1.0, 1.0, 2.0, 1.5, 1.0, 2.0]) # 各类别权重 # ...其余初始化代码- 数据增强侧重: 对稀有类别使用更强的数据增强
5.2 水下图像增强
水下图像常受颜色失真和模糊影响,预处理方法:
def underwater_image_enhancement(image): # 颜色校正 image = cv2.cvtColor(image, cv2.COLOR_BGR2LAB) l, a, b = cv2.split(image) clahe = cv2.createCLAHE(clipLimit=3.0, tileGridSize=(8,8)) l = clahe.apply(l) image = cv2.merge((l,a,b)) image = cv2.cvtColor(image, cv2.COLOR_LAB2BGR) # 去模糊 kernel = np.array([[-1,-1,-1], [-1,9,-1], [-1,-1,-1]]) image = cv2.filter2D(image, -1, kernel) return image5.3 模型融合与集成
提升模型鲁棒性的高级技术:
TTA(Test-Time Augmentation):
python detect.py --weights best.pt --source test_images/ --augment模型融合: 训练多个不同初始化的模型,融合预测结果:
models = [ torch.hub.load('ultralytics/yolov5', 'custom', path='model1.pt'), torch.hub.load('ultralytics/yolov5', 'custom', path='model2.pt'), torch.hub.load('ultralytics/yolov5', 'custom', path='model3.pt') ] def ensemble_predict(image): results = [model(image) for model in models] # 实现加权框融合算法(WBF) return final_results- 多尺度训练与测试: 在训练时使用不同输入尺寸,提升模型尺度不变性:
python train.py --img 320 640 --multi-scale