
简介这份资源是一套基于Gradio搭建的YOLOv8目标检测服务实战项目面向具备一定Python基础、希望快速落地算法服务的学习者与开发者可用于课程设计、毕业项目或工程原型验证。压缩包共10个文件约14.09MB包含4个py源码文件、2个pyc编译文件、2个mp4演示视频、1个md说明文档以及1个onnx模型文件覆盖从模型加载、推理封装到Web界面交互的完整链路。项目以YOLODet推理模块与main入口为核心配合utils工具函数将YOLOv8模型封装为可交互的检测服务并附带运行效果录屏便于对照理解服务启动与检测流程。目前已有224人学习下载适合想掌握目标检测服务化部署、Gradio界面搭建与ONNX推理实践的读者参考可据此快速复现并二次开发自己的检测应用。1. 从一份 YOLOv8 检测服务源码说起Gradio 把模型变成能点的网页你手里可能已经有一份训练好的 YOLOv8 权重best.pt躺在runs/detect/train/weights/里命令行yolo predict也能跑出框。但同事、客户、导师不会用命令行他们要的是打开浏览器、拖一张图进去、几秒后看到框和置信度。这就是「基于 Gradio 搭建的 YOLOv8 目标检测服务」要解决的事用几十行 Python 把推理逻辑包成一个网页附带的项目源码和流程教程本质是把「模型 → 接口 → 界面」这条链路一次性打通。它适合三类人刚跑完 YOLOv8 训练想验证效果的学生、要把检测能力塞进内部工具的后端工程师、以及做毕业设计或课程项目需要交付可演示系统的开发者。读完你能拿到一条可复现的路径环境怎么配、Gradio 界面怎么接模型、参数怎么调、部署时哪里会翻车。下面按「先跑通最小服务 → 再拆解参数 → 最后处理踩坑」的顺序展开。2. 最小可运行服务Gradio 接 YOLOv8 的完整代码与逐行说明2.1 环境准备CPU 和 GPU 两条路怎么选先明确一件事Gradio 只是前端壳真正吃资源的是 YOLOv8 推理。如果你手头是 GTX1660Ti 这类显卡走 GPU 路线如果是纯 CPU 机器比如 Ubuntu20.04 的云主机也能跑只是单张图延迟从几十毫秒涨到几百毫秒。常见做法是先装 PyTorch再装 ultralytics 和 gradio。# 创建独立环境避免和系统 Python 打架 conda create -n yolo_gradio python3.10 -y conda activate yolo_gradio # GPU 版本CUDA 11.8 示例按自己驱动改 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 # CPU 版本没有显卡就用这条 # pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 核心依赖 pip install ultralytics gradio opencv-python pillow这里三个包的分工要清楚ultralytics提供 YOLO 类和推理接口gradio负责生成网页和文件上传组件opencv-python用于画框和格式转换。版本上不用刻意锁死ultralytics 8.x 系列 API 稳定gradio 4.x 和 5.x 的Interface用法基本一致。装完用python -c from ultralytics import YOLO; import gradio; print(ok)验证能打印 ok 就说明依赖没冲突。提示如果 pip 装 torch 特别慢先换国内镜像源再装别在超时上耗半小时。2.2 推理函数从上传图片到返回带框图Gradio 的核心是一个普通 Python 函数输入是图片输出也是图片。YOLOv8 的predict返回的Results对象里已经带了绘制好的图像直接取plot()就行不用自己写画框逻辑。import gradio as gr from ultralytics import YOLO import numpy as np # 加载模型只加载一次放在全局 model YOLO(best.pt) # 换成你自己的权重路径 def detect(image, conf_threshold, iou_threshold): image: gradio 传入的 numpy 数组 (H, W, 3)RGB conf_threshold: 置信度阈值 iou_threshold: NMS 的 IoU 阈值 if image is None: return None # YOLOv8 接受 numpy 数组内部会做 BGR/RGB 处理 results model.predict( sourceimage, confconf_threshold, iouiou_threshold, imgsz640, verboseFalse ) # results[0].plot() 返回 BGR 的 numpy 图转成 RGB 给 gradio annotated results[0].plot() annotated annotated[:, :, ::-1] # BGR - RGB return annotated逻辑说明model.predict的source可以直接吃 numpy 数组省去存临时文件的步骤。conf和iou作为函数参数暴露出来是为了后面在界面上加滑块。plot()画出来的图默认是 BGR 通道顺序而 Gradio 的 Image 组件按 RGB 显示所以必须做一次通道翻转否则颜色会发蓝——这是最常见的翻车点之一。参数说明imgsz640是推理分辨率和训练时保持一致效果最好如果训练用的是 1280这里也要改成 1280否则小目标检测精度会掉。verboseFalse只是关掉控制台刷屏不影响结果。2.3 界面组装滑块、示例图和启动参数有了推理函数用gr.Interface把输入输出拼起来。输入有两个图片和两个滑块输出一个带框图片。demo gr.Interface( fndetect, inputs[ gr.Image(typenumpy, label上传图片), gr.Slider(0.1, 0.9, value0.25, step0.05, label置信度阈值), gr.Slider(0.1, 0.9, value0.45, step0.05, labelIoU 阈值), ], outputsgr.Image(typenumpy, label检测结果), titleYOLOv8 目标检测服务, description上传图片调整阈值查看检测框, examples[[example.jpg, 0.25, 0.45]], # 可选放一张示例图 ) if __name__ __main__: demo.launch(server_name0.0.0.0, server_port7860)server_name0.0.0.0让服务监听所有网卡局域网内其他机器能访问只在本机用就写127.0.0.1。server_port默认 7860被占用就换一个。examples里的图片路径要真实存在否则启动时会报错。跑起来后浏览器打开http://本机IP:7860拖图进去就能看到框。注意gr.Image(typenumpy)传进来的是 RGB 数组如果你的模型训练时用的是 BGR比如 OpenCV 读图这里要手动转一下否则精度会异常。3. 参数调优与模型替换让服务适配你自己的数据集3.1 置信度与 IoU 阈值两个滑块背后的取舍界面上那两个滑块不是摆设它们直接决定检测结果的松紧。置信度阈值conf控制「多确定才算检测到」调低会冒出大量误检框调高会漏掉模糊目标。IoU 阈值控制 NMS 阶段「多重叠才算同一个目标」调低会抑制相邻目标调高会让同一物体出现多个框。参数典型范围调低的现象调高的现象建议起点conf0.1 ~ 0.9误检增多背景被框漏检增多小目标消失0.25iou0.1 ~ 0.9密集目标被合并同一目标重复框0.45实操建议先用默认 0.25 / 0.45 跑一批测试图统计漏检和误检哪个更严重。漏检多就把 conf 降到 0.15 试试误检多就升到 0.4。密集场景比如人群、货架把 iou 降到 0.3 左右能减少重复框。这两个值没有万能解跟你的数据集分布强相关。3.2 换成自己训练的权重路径、类别和 imgsz 对齐项目源码里默认加载的可能是yolov8n.pt这种官方权重类别是 COCO 的 80 类。你要用自己的数据改一行就够# 替换成自己训练产出的权重 model YOLO(runs/detect/train/weights/best.pt)但换权重之后有三件事必须对齐。第一类别名。best.pt里已经存了训练时的names字典plot()会自动用正确的类别名不用手动改。第二imgsz。训练时如果设的是 640推理也保持 640训练用 1280 而推理用 640小目标召回会明显下降。第三预处理。YOLOv8 训练时默认做了 letterbox 缩放predict内部会自动处理你不需要在 Gradio 函数里再手动 resize多此一举反而会引入形变。如果你用的是 labelme 标注再转 YOLO 格式的数据集确认data.yaml里的nc和names与权重一致。曾经遇到过一个血泪经验权重是 3 类但界面上显示的框标签全是错位的查了半天发现是data.yaml里 names 顺序和训练时不一致重新导出权重才解决。3.3 批量图片与视频输入Gradio 组件的替换方式单图检测跑通后很多人想直接支持视频或整个文件夹。Gradio 换组件就行推理函数稍作调整。def detect_video(video_path, conf_threshold): # video_path 是 gradio 传进来的临时文件路径 results model.predict( sourcevideo_path, confconf_threshold, streamTrue, # 视频必须开 stream否则内存爆 verboseFalse ) # 这里简化处理逐帧写出到临时视频实际项目用 cv2.VideoWriter for r in results: frame r.plot() # 省略写帧逻辑 return output_path关键点是streamTrue。视频如果不开流式ultralytics 会把所有帧读进内存再处理几分钟的视频就能把内存吃满。批量图片则可以把gr.Image换成gr.Files函数里循环调用model.predict返回一个 zip 或文件列表。注意 Gradio 对返回文件有格式要求图片列表要用gr.Gallery组件接收。4. 部署与排错Gradio 服务上线的五个真实坑4.1 坑一模型每次请求都重新加载首屏慢到怀疑人生现象第一次点检测等十几秒后面就快了但服务重启后又慢。原因YOLO(best.pt)写在了detect函数内部每次调用都重新加载权重。解决把模型加载提到函数外面作为全局变量服务启动时加载一次。如果显存紧张可以在launch前加torch.cuda.empty_cache()但别在每次推理后清反而拖慢速度。4.2 坑二局域网访问不了浏览器一直转圈现象本机127.0.0.1:7860能开同事的电脑打不开。原因launch()默认只绑127.0.0.1。解决改成server_name0.0.0.0。如果还不行检查服务器防火墙是否放行 7860 端口Ubuntu 上用sudo ufw allow 7860。另外公司网络如果有端口限制换 80 或 8080 这类常用端口试试。4.3 坑三上传大图后服务卡死或返回空白现象几 MB 的高清图上传后界面一直 loading最后报错或返回黑图。原因YOLOv8 默认会把输入缩放到imgsz但超大图在预处理阶段仍然占内存CPU 推理时尤其明显。解决在detect函数开头加一个尺寸检查超过 4000 像素的图先等比缩小。from PIL import Image import numpy as np def detect(image, conf_threshold, iou_threshold): if image is None: return None h, w image.shape[:2] max_side 2000 if max(h, w) max_side: scale max_side / max(h, w) image np.array(Image.fromarray(image).resize((int(w*scale), int(h*scale)))) # 后续推理不变4.4 坑四GPU 显存溢出报 CUDA out of memory现象跑几张图后报显存不足。原因Gradio 默认可能并发处理多个请求每个请求都占一份显存。解决在launch里限制并发demo.queue(max_size1)或者demo.launch(max_threads1)。另外推理完可以手动del results但 Python 的垃圾回收不一定及时最稳的还是限制并发数。如果显卡只有 4GB 显存imgsz降到 416 也能跑精度损失可接受。4.5 坑五中文标签显示成方块现象检测框上的类别名是中文时图上显示成方框乱码。原因OpenCV 的putText不支持中文而plot()底层用的就是它。解决两个办法。一是训练时类别名用英文显示时再映射成中文二是自己写画框逻辑用 PIL 的ImageDraw配合中文字体文件。from PIL import Image, ImageDraw, ImageFont def draw_chinese(image, boxes, labels): img Image.fromarray(image) draw ImageDraw.Draw(img) font ImageFont.truetype(SimHei.ttf, 20) # 字体文件放项目目录 for box, label in zip(boxes, labels): x1, y1, x2, y2 box draw.rectangle([x1, y1, x2, y2], outlinered, width2) draw.text((x1, y1-25), label, fillred, fontfont) return np.array(img)字体文件要随项目一起分发Linux 服务器上如果没有中文字体把SimHei.ttf或NotoSansCJK放到代码同级目录用相对路径加载。5. 进阶技巧用队列和身份验证把服务变成可交付的内部工具服务能跑之后下一步是让它「像个产品」。Gradio 自带队列和身份验证不用额外写后端。队列解决并发排队问题身份验证解决「不想让所有人随便访问」的问题。先看队列。默认情况下 Gradio 对每个请求开一个线程GPU 服务很容易被并发打爆。加上demo.queue()后请求会排队处理配合concurrency_count控制同时处理的数量。demo gr.Interface(...) demo.queue(concurrency_count1, max_size10) # 同时处理1个最多排10个 demo.launch(server_name0.0.0.0, server_port7860)concurrency_count1对单卡服务最稳max_size是队列上限超过就拒绝新请求。如果你的服务是 CPU 推理可以设成 2 或 4取决于核数。再看身份验证。Gradio 的launch支持auth参数传入用户名密码对即可。demo.launch( server_name0.0.0.0, server_port7860, auth(admin, your_password), # 浏览器会弹基础认证框 auth_message请输入账号密码 )这样打开网页会先弹一个 HTTP 基础认证框输入正确才能进界面。注意这是明文传输的 Basic Auth内网用没问题公网暴露一定要套 HTTPS否则密码等于裸奔。如果要做多用户管理Gradio 的auth不够用得换成 FastAPI 挂载 Gradio 或者用 Nginx 做前置认证。验证服务是否真的可用我一般做三步。第一步用curl测端口通不通curl -I http://127.0.0.1:7860返回 200 说明服务活着。第二步用一张训练集里的图跑一遍确认框的位置和标签正确。第三步用一张训练集外的图跑看泛化表现如果框乱飞说明模型过拟合或者阈值不对。这三步走完基本能判断这个服务能不能交付。最后说一个我自己的习惯每次改完推理函数先在本地用python app.py跑一遍确认没有语法错误和路径问题再传到服务器。服务器上只做部署不做调试。这样能省掉大量「在服务器上改一行等半天」的时间。另外权重文件不要提交到 Git用.gitignore排除部署时单独上传避免仓库膨胀。希望帮到你。本文还有配套的精品资源点击获取