ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO数字识别检测系统:模型对比到FastAPI服务与LLM集成实践

YOLO数字识别检测系统:模型对比到FastAPI服务与LLM集成实践 这次我们来看一个可以把目标检测、后端服务和大语言模型真正串起来的项目数字识别检测系统。它没有把“数字识别”当成一个孤立 Demo而是把 YOLOv8 / v10 / v11 / v12以及标题中提到的 v26 新迭代版本放进同一个检测任务里做横向对比再用 FastAPI 把这套模型包装成可调用的推理服务最后接入千问、DeepSeek 这类大语言模型对识别结果做结构化输出和二次校验。如果你正在做全栈项目练手或者想搞清楚“同一份数据集上多个 YOLO 版本到底差多少”这篇文章可以直接收藏。我们会先过一遍核心能力和硬件门槛再走完整条链路环境准备、模型训练、效果评估、服务启动、API 调用、批量任务、大模型集成、常见问题排查。先说结论这个项目的关键不是把数字识别做到 100% 准确而是帮你建立一套“目标检测模型 后端服务化 大模型增强”的完整工作流。只要这条链路通了以后换成车牌识别、仪表读数、工业字符检测都是同一套思路。1. 核心能力速览先看一张总表方便你快速判断这个项目适不适合自己。能力项说明项目类型目标检测 全栈应用 大语言模型集成检测目标数字识别可扩展到仪表读数、车牌数字、印刷体数字、手写数字等模型版本YOLOv8 / v10 / v11 / v12标题中的 v26 可按同一流程验证推理框架以 Ultralytics 训练和推理流程为主线后端服务FastAPI 独立推理服务前端展示Web 上传图片并展示检测框大模型集成千问DashScope 兼容接口、DeepSeek 兼容接口批量任务支持图片目录批处理结果落 JSON / CSV硬件要求GPU 优先CPU 可跑但推理耗时差异明显启动方式训练脚本 API 服务命令是否支持 API支持可接入现有业务系统适合场景模型对比学习、仪表数字识别、全栈项目实践、LLM 结果增强这里先说明一点不同 YOLO 版本的权重文件和配置方式以各官方仓库为准。本文给出的命令和代码是通用模板实际项目里需要根据你的数据路径、模型文件名和端口号做替换。显存占用不会有“一个固定值”它和模型尺寸、输入分辨率、batch 大小、是否开启半精度推理都有关系。后面第 9 节会专门讲怎么观察和压低显存。2. 适用场景与使用边界这个项目适合谁我觉得有三类人第一类是正在做目标检测课程设计或毕设的同学需要在同一份数据集上横向对比几个 YOLO 版本画 mAP 曲线、耗时对比表格。第二类是前后端工程师想找一个有 AI 能力的全栈项目练手把模型训练、接口封装、前端展示、LLM 调用串起来。第三类是实际业务里要做数字识别的人比如电表水表读数、仪表盘数字、印刷体字符识别可以先拿这套系统做验证。这个项目不适合什么场景如果你的业务需要毫秒级响应比如工业质检流水线上的实时检测那么直接用本地推理服务的方案还不够需要做 TensorRT 量化、模型剪枝、多进程并发优化。如果只是识别一张图里的简单数字杀鸡用牛刀直接用 OCR 或传统图像处理可能更快。使用边界必须说清楚车牌识别涉及个人隐私和公共安全实际部署要确认授权和合规要求。仪表读数可能涉及生产数据或商业数据不要随意把图片发到外部大模型 API。训练数据不能使用未经授权的版权图片或他人数据集。大模型调用会产生费用密钥要保存在服务端不要放到前端页面。用大模型做结果解析时不要把 YOLO 的输出当成绝对正确要保留置信度和人工复核入口。3. 环境准备与前置条件3.1 系统与软件版本目标检测环境主要涉及 Python、PyTorch、CUDA、GPU 驱动这几样。建议按下面的清单检查一遍检查项建议操作系统Windows 10 / 11、Ubuntu 20.04 / 22.04Python3.8 及以上推荐 3.10GPUNVIDIA 独显优先显存 6G 以上体验更稳CUDA与 PyTorch 版本匹配建议 cu118 / cu121 / cu124 及以上磁盘空间至少 20G 剩余模型权重和数据集会占不少空间端口后端 API 默认建议 8000前端开发服务器常用 5173 或 3000如果你没有 NVIDIA GPU也不是完全不能跑。CPU 推理可以跑通流程但训练会比较难受。从项目验证的角度可以先下载预训练权重在 CPU 上对几张测试图片做推理确认流程正确后再找 GPU 机器做完整训练。3.2 创建虚拟环境并安装依赖强烈建议使用虚拟环境避免和系统 Python 环境冲突。下面是通用安装命令# 创建虚拟环境 python -m venv .venv source .venv/bin/activate # Windows 下执行: .venv\Scripts\activate # 安装基础依赖 pip install --upgrade pip pip install ultralytics pip install fastapi uvicorn python-multipart requests pip install openai如果你有requirements.txt直接执行pip install -r requirements.txt注意安装ultralytics时会自动安装对应版本的 PyTorch。如果你本机已经装好了带 CUDA 的 PyTorch建议先确认版本再安装避免覆盖。3.3 验证 CUDA 是否可用安装完成后跑一个快速检查import torch print(torch.__version__) print(torch.cuda.is_available()) print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else CPU)如果torch.cuda.is_available()返回 False说明 PyTorch 没有检测到 CUDA。先检查驱动和 CUDA 版本是否匹配或者重新安装对应 CUDA 版本的 PyTorch。4. YOLO 系列模型差异与选型既然是深度对比就要知道这几个版本的核心差异。以下内容是公开技术资料的通用总结具体细节以官方论文和仓库为准。版本核心设计思路在数字识别场景的侧重YOLOv8anchor-free 检测头C2f 模块支持检测 / 分割 / 分类生态成熟文档多适合快速搭建基线YOLOv10端到端 NMS-free 训练同时使用一对多和一对一监督推理流程更简洁适合追求部署效率YOLOv11引入 C3k2、C2PSA 等结构anchor-free 主线延续精度与速度相对均衡新项目常用候选YOLOv12注意力机制升级区域级递归置信度设计适合关注注意力机制对精度提升的验证v26 新迭代版本迭代较快结构细节以官方仓库为准建议先用同一套测试流程验证谨慎直接替换生产选型建议数据量小、快速跑通基线选 YOLOv8n 或 YOLOv8s。想要简化部署流程不想在 NMS 后处理上花太多心思试 YOLOv10n。需要精度和速度平衡YOLOv11s 比较稳妥。想看看注意力机制在数字这一类小目标上有没有帮助YOLOv12 值得跑一轮。至于 v26建议在测试环境里单独跑数据对比清楚了再决定是否上生产。数字识别的特点是小目标多、边缘清晰、类别数量少0-9 共 10 类。这种情况下模型结构的差异通常不会造成“能不能识别”的差距而是体现在小数字和模糊数字上的 mAP 差异。所以对比实验要重点看每个数字类别的 AP而不是只看整体 mAP。5. 模型训练与评估验证5.1 准备数字识别数据集先准备数据集。数字识别检测数据集的标注格式推荐使用 YOLO 格式images/train/0001.jpg images/train/0001.txt images/val/0002.jpg images/val/0002.txt每个 txt 文件一行一个目标格式是class_id x_center y_center width height如果是数字识别类别可以设计为 0-9path: ./numdet_dataset train: images/train val: images/val names: 0: 0 1: 1 2: 2 3: 3 4: 4 5: 5 6: 6 7: 7 8: 8 9: 9如果你要识别的是仪表数字可能还要增加小数点、正负号、单位字符等类别。车牌数字场景则要结合车牌字符集设计类别。数据集标注工具可以用 LabelImg、X-AnyLabeling、CVAT 等标注完成后导出为 YOLO 格式。标注质量直接决定模型上限。数字区域框不要太大也不要太小尽量贴近数字边缘。如果一张图里有多个数字全部标出来漏标会导致训练时把漏标区域当成背景影响收敛。5.2 训练脚本安装好 ultralytics 之后训练命令非常简单。先训练 YOLOv8nyolo detect train modelyolov8n.pt datanum_det.yaml epochs100 imgsz640 batch16也可以用 Python 脚本from ultralytics import YOLO model YOLO(yolov8n.pt) model.train( datanum_det.yaml, epochs100, imgsz640, batch16, device0, nameyolov8n_numdet, )训练完成后权重保存在runs/detect/yolov8n_numdet/weights/best.pt。5.3 多版本对比评估这是整个项目最有价值的地方用同一个数据集、同一套验证逻辑对比多个模型。评估脚本可以这样写from ultralytics import YOLO model_configs [ yolov8n.pt, yolov10n.pt, yolov11n.pt, yolov12n.pt, ] for cfg in model_configs: try: model YOLO(cfg) metrics model.val(datanum_det.yaml, splitval) print(f{cfg} mAP50-95: {metrics.box.map:.4f}) print(f{cfg} mAP50: {metrics.box.map50:.4f}) print(f{cfg} Precision:{metrics.box.mp:.4f}) print(f{cfg} Recall: {metrics.box.mr:.4f}) except Exception as e: print(f{cfg} 评估失败: {e})需要说明的是不同版本的预训练权重下载地址和可用性会有差异跑之前确认网络能正常下载权重文件。评估之后还要看每个数字类别的 AP。Ultralytics 会在runs/detect/val目录下生成混淆矩阵、类别 AP 曲线、PR 曲线等可视化结果。对比时要关注哪个版本在“5”和“8”这类容易混淆的数字上表现更好。哪个版本对模糊数字或倾斜数字更鲁棒。推理速度差异是否明显。模型文件大小和显存占用差异。5.4 损失曲线训练日志目录下会有results.png里面包含 train/val loss、precision、recall、mAP 曲线。如果你用的是自己写的训练闭环也可以用脚本把results.csv画成损失函数曲线图方便写对比报告和博客。这里可以用 pandas 读日志再画图不过不强制。6. 全栈系统部署与服务启动训练出best.pt后下一步就是把模型包装成服务。这里用 FastAPI 做一个轻量识别接口。6.1 推理服务代码from fastapi import FastAPI, UploadFile, File from ultralytics import YOLO import cv2 import numpy as np app FastAPI() model YOLO(runs/detect/yolov8n_numdet/weights/best.pt) app.post(/detect) async def detect(image: UploadFile File(...)): img_bytes await image.read() nparr np.frombuffer(img_bytes, np.uint8) img cv2.imdecode(nparr, cv2.IMREAD_COLOR) results model(img, verboseFalse)[0] boxes results.boxes.xyxy.cpu().tolist() confs results.boxes.conf.cpu().tolist() cls_ids results.boxes.cls.cpu().tolist() class_names results.names detections [] for box, conf, cls_id in zip(boxes, confs, cls_ids): detections.append({ class: class_names[int(cls_id)], class_id: int(cls_id), confidence: round(float(conf), 4), bbox: [round(v, 2) for v in box], }) return {count: len(detections), detections: detections}6.2 启动服务uvicorn main:app --host 0.0.0.0 --port 8000启动后输出会显示Uvicorn running on http://0.0.0.0:8000浏览器访问http://127.0.0.1:8000/docs可以看到 FastAPI 自动生成的 Swagger 接口文档这里就可以直接测试/detect接口。6.3 前端页面全栈项目可以配一个轻量前端。最简单的做法是写一个 HTML 页面通过fetch上传图片到/detect再把返回的检测框画在 Canvas 上。如果你想做得复杂一点可以用 Vue 3 Vite 搭管理后台这类“企业级后台管理系统全栈项目”的工程化套路适合放到简历里。不过核心逻辑不变前端发送图片后端返回 JSON前端负责画框和展示置信度。7. 推理接口 API 与批量任务7.1 curl 测试服务启动后直接测接口curl -X POST http://127.0.0.1:8000/detect \ -F imagetest_images/test_digit_01.jpg返回示例{ count: 2, detections: [ { class: 3, class_id: 3, confidence: 0.9052, bbox: [120.4, 80.2, 145.7, 110.3] }, { class: 7, class_id: 7, confidence: 0.8874, bbox: [210.1, 85.4, 238.9, 112.6] } ] }7.2 Python 客户端调用import requests resp requests.post( http://127.0.0.1:8000/detect, files{image: open(test_images/test_digit_01.jpg, rb)}, timeout30, ) data resp.json() print(data)7.3 批量任务批量识别目录下所有图片from pathlib import Path import requests import json input_dir Path(./test_images) output_dir Path(./results_json) output_dir.mkdir(exist_okTrue) images list(input_dir.glob(*.jpg)) list(input_dir.glob(*.png)) print(f共找到 {len(images)} 张图片) results {} for img_path in images: try: resp requests.post( http://127.0.0.1:8000/detect, files{image: open(img_path, rb)}, timeout30, ) resp.raise_for_status() results[img_path.name] resp.json() print(f已处理: {img_path.name}) except Exception as e: print(f失败: {img_path.name}, 原因: {e}) with open(output_dir / all_results.json, w, encodingutf-8) as f: json.dump(results, f, ensure_asciiFalse, indent2)批量任务要注意几点每次请求之间可以加一个极短的间隔避免把本地服务打满。如果图片数量很大建议在requests.post外层加 retry 逻辑。每张图的结果写入单独的 JSON 文件比最后一次性写大文件更稳。批量任务最好记录每个文件的处理状态成功、失败、超时、无检测结果。8. 大语言模型集成千问与 DeepSeek为什么要接大模型YOLO 检测输出的是坐标、类别、置信度用户不一定能直接看懂。大模型可以把这些结构化结果变成自然语言描述、报表、异常提示甚至根据置信度决定哪些结果需要人工复核。下面给出一种常见的接入方式实际 API 地址、模型名称、密钥获取方式以官方最新文档为准。8.1 千问Qwen接入示例千问可以通过 DashScope 的 OpenAI 兼容模式调用from openai import OpenAI client OpenAI( api_keyyour-dashscope-api-key, base_urlhttps://dashscope.aliyuncs.com/compatible-mode/v1 ) system_prompt 你是数字识别结果解析助手。 请根据 YOLO 模型输出的检测结果生成一段可读的识别说明。 如果存在低置信度检测结果请明确提醒人工复核。 user_content 图片中检测到以下数字区域 1. 数字 3置信度 0.9052坐标 [120.4, 80.2, 145.7, 110.3] 2. 数字 7置信度 0.8874坐标 [210.1, 85.4, 238.9, 112.6] 3. 数字 8置信度 0.4521坐标 [310.2, 90.1, 338.5, 118.4] 请整理成识别报告并标记出置信度较低的结果。 resp client.chat.completions.create( modelqwen-plus, messages[ {role: system, content: system_prompt}, {role: user, content: user_content}, ], temperature0.3, ) print(resp.choices[0].message.content)8.2 DeepSeek 接入示例DeepSeek 兼容 OpenAI 风格接口from openai import OpenAI client OpenAI( api_keyyour-deepseek-api-key, base_urlhttps://api.deepseek.com/v1 ) resp client.chat.completions.create( modeldeepseek-chat, messages[ {role: user, content: 请将以下 YOLO 检测结果整理为 CSV 格式\n user_content} ], temperature0.2, ) print(resp.choices[0].message.content)8.3 在识别服务中集成大模型你可以把大模型调用直接合入 FastAPI 接口让/detect返回检测结果之后再调用 LLM 生成自然语言摘要app.post(/detect_with_llm) async def detect_with_llm(image: UploadFile File(...)): detect_result await detect(image) llm_summary llm_format_result(detect_result) return { detect_result: detect_result, llm_summary: llm_summary, }建议大模型调用超时时间设短一点比如 15 到 30 秒。不要因为 LLM 服务不稳定导致整个识别接口超时。更合理的做法是YOLO 返回结果立刻入库LLM 摘要通过异步任务生成前端先显示检测框摘要生成后再刷新。8.4 调用大模型的注意事项第一密钥不要硬编码在代码里。用环境变量export DASHSCOPE_API_KEYyour-key export DEEPSEEK_API_KEYyour-key第二YOLO 输出和 LLM 输出都要保存原始日志方便追溯。第三如果图片内容涉及隐私或商业数据不要直接发送到外部大模型接口。本地化部署大语言模型是另一个方向但会涉及更多资源开销不在本文展开。9. 资源占用与性能观察9.1 显存观察方法Linux 推荐用nvidia-smi实时查看显存nvidia-smi watch -n 1 nvidia-smiWindows 可以用任务管理器查看 GPU 显存使用或者用nvidia-smi也行。Python 代码里查看 PyTorch 分配的峰值显存import torch torch.cuda.reset_peak_memory_stats() # 这里执行推理或训练 peak_memory torch.cuda.max_memory_allocated() / 1024**2 print(f峰值显存: {peak_memory:.2f} MB)9.2 影响性能的因素同样是数字识别输入分辨率从 640 降到 320推理速度通常会明显提升但小数字的检测精度可能会下降。模型从 n 系列换到 x 系列精度可能提升显存占用和耗时也会成倍增加。batch 从 1 提到 16训练吞吐量提升但显存占用也随之上升。开启半精度推理可以降低显存占用model YOLO(best.pt) results model.predict(test.jpg, halfTrue)CPU 推理可以跑但在批量处理场景下GPU 的吞吐优势非常明显。如果目标机器只有 CPU建议把 batch 设为 1并且降低imgsz。9.3 不同 YOLO 版本运行速度对比做对比实验时可以统计每个模型推理一张图片的平均耗时import time from ultralytics import YOLO model_configs [yolov8n.pt, yolov8s.pt, yolov10n.pt, yolov11n.pt] test_img test_images/test_digit_01.jpg repeat 20 for cfg in model_configs: model YOLO(cfg) # 先 warmup model.predict(test_img, verboseFalse) start time.time() for _ in range(repeat): model.predict(test_img, verboseFalse) avg_cost (time.time() - start) / repeat print(f{cfg} 平均推理耗时: {avg_cost * 1000:.2f} ms)这里没有给出特定硬件上的具体数据因为这个结果严重依赖 GPU 型号、CPU 型号、输入图片大小。建议你在自己机器上跑完再记录数据。10. 常见问题与排查方法问题现象可能原因排查方式解决方案ModuleNotFoundError: No module named ultralytics依赖没有安装或虚拟环境没激活检查当前 Python 环境激活虚拟环境后重新安装依赖训练时提示找不到数据集YAML 路径配置错误打印data.yaml里的绝对路径改成绝对路径或相对项目根目录的路径torch.cuda.is_available()返回 FalsePyTorch 与 CUDA 版本不匹配执行检查脚本查看 CUDA 版本重新安装匹配的 PyTorchCUDA out of memory显存不足观察nvidia-smi显存占用降低 batch、imgsz 或换小模型下载权重文件超时网络原因或源不可用查看下载日志使用代理或提前手动下载权重放到缓存目录启动uvicorn main:app报错main.py 文件不存在或代码有语法错误查看报错日志确认文件路径和 Python 语法浏览器访问http://127.0.0.1:8000打不开服务未启动或端口被占用查看终端日志使用netstat -ano查端口换端口启动或重启服务接口返回 500图片解析失败或模型路径错误查看 FastAPI 日志确认传参格式检查模型路径批量任务处理到一半卡住某个请求超时或进程假死查看日志、检查服务状态增加 timeout 和重试机制分批处理识别出大量误检训练数据标注质量差或类别不平衡看混淆矩阵和每类 AP补齐标注数据增加困难样本大模型调用返回超时网络问题或接口参数错误单独测试 LLM API增加超时时间和重试逻辑11. 最佳实践与使用建议第一第一次跑训练先不要追求精度。用 yolov8n、epochs 50、imgsz 320、batch 4先确认整个流程能跑通。流程通了再逐步增加训练轮数和分辨率。第二数据集、模型权重、输出结果分目录管理。我建议按下面的结构组织numdet_project/ ├── data/ │ ├── images/ │ └── labels/ ├── models/ ├── runs/ ├── scripts/ └── results/第三训练日志要保留。Ultralytics 会自动生成results.csv建议把它拷贝到固定的目录防止训练过程中被覆盖。对比模型时把这些 CSV 汇总到一张表里写博客或者做汇报都方便。第四模型文件命名要带版本信息。不要只叫best.pt建议改成yolov8n_numdet_20250201.pt这种格式。换模型时不会搞混。第五接口服务要加访问控制。如果部署在公网一定要加 token 或者 basic auth。最简单的做法是在 FastAPI 里加一个依赖from fastapi import Header, HTTPException API_TOKEN your-secret-token async def verify_token(x_token: str Header(...)): if x_token ! API_TOKEN: raise HTTPException(status_code401, detailInvalid token)第六批量任务一定要有日志和失败重试。一张图处理失败不要中断整个队列记录失败原因最后统一重试。第七涉及人脸、车牌、声音、版权素材等场景必须确认授权。数字识别本身不敏感但如果你把识别系统扩展到车牌、身份证或人脸就要严格遵守隐私保护要求不能在未授权的情况下收集和处理数据。第八大模型生成的内容不能直接对外发布。YOLO 的检测框和置信度是客观结果LLM 生成的描述是主观加工发布前要做人工复核特别是涉及业务报表的场景。12. 总结与下一步这个项目最值得尝试的点是用一套代码同时跑通 YOLOv8、v10、v11、v12以及后续新版本的对比实验并且把结果服务化、接入大模型。你不需要一开始就把所有模型都训练完先拿 YOLOv8n 跑通全链路再逐个换成其他版本对比数据就有了。最先要验证的功能不是模型精度而是/detect接口能不能稳定返回检测结果。接口通了后面的大模型集成、批量任务、前端展示都可以在上面扩展。最容易踩的坑有三个数据集标注格式写错、CUDA 和 PyTorch 版本不匹配、大模型 API 密钥配错。这三个问题在日志里都有明确报错按第 10 节的排查表逐项查就行。后续可以扩展的方向包括接入更多新版本模型、把前端做成上传即识别的交互页面、增加批量任务的进度条、接入本地部署的大语言模型、把识别结果导出为 Excel 报表。往工程化方向走可以用 Docker 把训练和服务环境打包做到一键部署。往智能化方向走可以让大模型根据置信度和数字序列规则自动判断哪些检测结果可信形成一个“模型识别 规则校验 大模型解释”的完整闭环。建议收藏备用动手跑一轮再说。
返回列表