Phi-3-mini-4k-instruct-gguf赋能课程设计:自动生成Multisim电路仿真报告
2026/4/13 6:29:09
基于YOLO算法的目标检测毕设实战:从模型选型到部署优化
很多做毕设的同学拿到“目标检测”题目后,第一反应是“YOLO 听起来很酷”,第二反应是“怎么跑不通?”——训练 loss 炸掉、mAP 算出来 0.01、Jetson 上推理 2 s 一张图……本文把我自己踩过的坑写成一份“通关攻略”,照着做,基本能把项目从“能跑”升级到“能看、能讲、能答辩”。
python train.py --img 640 --batch 16 --epoch 300一把梭,结果 loss 从 10 飞到 100,NaN 结束。mAP@0.5,对mAP@0.5:0.95和AR@100一问三不知,老师质疑“指标这么单一,可信吗?”.pt文件 40 MB,网页一加载,用户手机直接发烫。一句话:学术 demo 与工业落地之间,差了一“整套工程化”。
| 维度 | YOLOv5 | YOLOv8 | YOLO-NAS |
|---|---|---|---|
| 精度 (COCO) | 37.4 | 53.9 | 54.1 |
| 速度 (V100 FP16) | 2.9 ms | 1.2 ms | 1.1 ms |
| 易用性 | 社区最大,文档多 | Ultralytics 官方统一 API | 需要 Deci 平台,代码开源但不完全 |
| 训练自定义数据 | 一键脚本 | 同 v5,支持更多增强 | 需转换格式,步骤多 |
| 导出 ONNX | 官方支持 | 官方支持 | 支持,但节点名不友好 |
| 量化/剪枝生态 | 丰富 | 更丰富 | 刚起步 |
结论:
下文全部以YOLOv8为例,其他版本命令基本通用。
conda create -n yolo python=3.9 conda activate yolo pip install ultralytics==8.0.200 # 锁定版本,防止 API 漂移dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml两行就够:
train: ./images/train val: ./images/val nc: 3 names: ['cat', 'dog', 'person']提醒:标签文件一定用YOLO 格式(class x_center y_center width height),全部归一化到 0-1,Win 下不要用 Excel 打开再保存,会偷偷把空格变 Tab!
# train.py from ultralytics import YOLO def main(): model = YOLO("yolov8n.pt") # 加载预训练权重,迁移学习 model.train( data="dataset/data.yaml", epochs=150, # 先少跑,看曲线再决定是否加长 imgsz=640, batch=32, # 显存不足就调小 optimizer="AdamW", # 比 SGD 收敛快 cos_lr=True, # 余弦退火 augment=True, # 官方默认已开 cache=False, # 数据集大就关,省显存 device=0, # 单卡 project="runs/det", name="exp", exist_ok=False ) if __name__ == "__main__": main()跑完后runs/exp/weights/best.pt自动保存最高 mAP 模型。
# eval.py from ultralytics import YOLO model = YOLO("runs/exp/weights/best.pt") metrics = model.val() # 默认用 data.yaml 里的 val print("mAP50:", metrics.box.map50) print("mAP50-95:", metrics.box.map)答辩常问:
- “为什么 mAP50 高但 mAP50-95 低?” → 说明框定位不准,需增加回归 loss 权重或更多小目标增强。
- “AR 代表什么?” → 查全率,越高漏检越少,安全场景必须关注。
# export.py model = YOLO("best.pt") model.export(format="onnx", imgsz=640, half=True, simplify=True)得到best.onnx,节点名干净,兼容 TensorRT 8.x。
# infer.py import cv2, onnxruntime as ort import numpy as np class YoloInfer: def __init__(self, onnx_path, conf_thres=0.5, nms_thres=0.45): self.conf = conf_thres self.nms = nms_thres providers = ['CUDAExecutionProvider', 'CPUExecutionProvider'] self.ort = ort.InferenceSession(onnx_path, providers=providers) self.input_name = self.ort.get_inputs()[0].name def preprocess(self, img): # 等比缩放 + 灰条 h0, w0 = img.shape[:2] r = 640 / max(h0, w0) h, w = int(h0*r), int(w0*r) img_res = cv2.resize(img, (w, h)) dw, dh = (640-w)//2, (640-h)//2 pad = np.full((640, 640, 3), 114, np.uint8) pad[dh:dh+h, dw:dw+w] = img_res # HWC→CHW & 归一化 blob = pad[:,:,::-2].transpose(2,0,1)[None]/255.0 return blob.astype(np.float repertoire="32") def __call__(self, img): blob = self.preprocess(img) outs = self.ort.run(None, {self.input_name: blob})[0] # 后处理:置信度过滤 + NMS boxes, scores, cls = self.postprocess(outs) return boxes, scores, cls def postprocess(self, preds): # preds shape: [1, 8400, 4+1+nc] preds = preds[0] xywh, conf, cls = np.split(preds, [4, 5], axis=1) conf = conf.ravel() mask = conf > self.conf xywh, conf, cls = xywh[mask], conf[mask], cls[mask] # 转 xyxy x, y, w, h = xywh.T x1, y1, x2, y2 = x-w/2, y-h/2, x+w/2, y+h/2 boxes = np.stack([x1,y1,x2,y2], axis=1) # NMS idx = cv2.dnn.NMSBoxes(boxes.tolist(), conf.tolist(), self.conf, self.nms) return boxes[idx], conf[idx], cls[idx]把预处理、后处理都封装到类里,主流程只剩三行,老师看你代码结构直接加分。
model.export(format=engine, int8=True, data="calib/"),给出 100 张校准图即可。/upload,/infer,/result,Docker 镜像 300 MB,树莓派 4B 也能跑。python utils/verify_labels.py提前扫描,出现“空格分隔”“坐标>1”直接抛异常。oversample=1.5,mAP 可涨 3-5 点。.engine文件持久化,开机直接加载。cache=True会全载入内存,图片大就关;推理阶段batch=1稳。ultralytics==8.0.200,onnxruntime-gpu==1.16,升级前 diff 看 changelog。imgsz降到 320,看速度/精度交换比,写进答辩 PPT;毕设不是“跑通就行”,而是“能讲清楚为什么这样做”。把这篇笔记当 checklist,一步步打钩,最终你交上去的不只是代码,还有一份可以复现、可以量化的工程报告。祝你答辩顺利,早日把 YOLO 装进自己的简历!