用 YOLOv8 做试卷试题区域检测的环境与训练

前言

纸质或扫描试卷上的「试题分割」在工程上常先做目标检测:为每道大题或小题画矩形框,再按框裁图或送入 OCR。
本文说明如何用 Ultralytics YOLOv8 在本地完成环境配置与训练,不展开标注工具细节与 OCR 后处理。
依赖安装与训练命令使用 uv 管理虚拟环境与包版本。
Python 最低版本以你的 pyproject.tomlrequires-python 为准,建议使用 3.10+ 并与依赖声明保持一致。
CUDA 版 PyTorch 是否由 uv sync 直接解析到,取决于索引与平台;有独显时请对照 PyTorch 官网uv 文档 做补充配置。

依赖

安装 uv

若本机尚未安装 uv,可选用官方推荐方式或包管理器安装(任选其一即可,具体以 Astral 安装说明 为准)。

在已具备 Python 的环境中,用 pip 安装 uv 的示例命令如下。

1
python -m pip install uv

同步依赖

推荐在项目根目录通过 pyproject.toml 声明依赖(如 ultralyticsfastapiuvicorn 等)。
pyproject.toml 同级目录执行 uv sync,会创建或更新 .venv 并安装全部项目依赖,无需手写一长串 pip install

下面命令表示进入你的项目目录后一次性同步依赖。

1
2
cd your/project/backend
uv sync

若当前目录尚未初始化项目,可先创建 pyproject.toml 并写入 ultralytics 等依赖,再执行 uv sync 得到可训练环境。

依赖清单

按你给的项目依赖,可按职责归类如下。

训练核心

  • ultralytics>=8.4.41:YOLOv8 训练、验证、预测主包。

图像处理

  • opencv-python-headless>=4.13.0.92:无 GUI 环境下图像处理与解码。
  • pillow>=12.2.0:图片读写与基础处理。

API 服务

  • fastapi>=0.136.1:HTTP API 框架。
  • uvicorn[standard]>=0.46.0:ASGI 服务启动器。
  • python-multipart>=0.0.26:处理上传图片表单。

配置管理

  • pydantic-settings>=2.14.0:环境变量与配置管理。

下面是与该项目对齐的 pyproject.toml 片段。

1
2
3
4
5
6
7
8
9
10
11
12
13
[project]
name = "paper-training-backend"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = [
"fastapi>=0.136.1",
"opencv-python-headless>=4.13.0.92",
"pillow>=12.1.1",
"pydantic-settings>=2.14.0",
"python-multipart>=0.0.26",
"ultralytics>=8.4.41",
"uvicorn[standard]>=0.46.0",
]

写好依赖后执行 uv sync,再用 uv run 运行训练脚本即可。

检查 PyTorch 与 GPU

安装完成后建议用 uv run项目虚拟环境里执行 Python,避免误用系统全局解释器。

下面一小段用于确认 torchultralytics 已导入,并打印 CUDA 是否可用。

1
2
3
4
5
import torch
from ultralytics import YOLO

print("cuda available:", torch.cuda.is_available())
print("device count:", torch.cuda.device_count() if torch.cuda.is_available() else 0)

将上面脚本存为 check_cuda.py 后可用 uv run python check_cuda.py 执行;若仅为一次性检查,也可用 uv run python -c "import torch; print(torch.cuda.is_available())"

Python信息

激活虚拟环境

1
.venv\Scripts\activate

版本

1
python -V

位数

1
python -c "import platform; print(platform.architecture())"

路径

1
python -c "import sys; print(sys.executable)"

使用 GPU

若你按默认方式安装后训练仍走 CPU,通常是当前环境里的 torch 不是 CUDA 版本。
切换到 GPU 的关键是安装与你本机驱动匹配的 CUDA 版 torch,并在训练时指定 device=0device=cuda:0

  1. 先确认系统可识别 NVIDIA 显卡并且驱动正常。
  2. 执行 nvidia-smi,若命令不可用或无显卡信息,先完成驱动安装再继续。

下面命令用于检查显卡驱动状态。

1
nvidia-smi
  1. 在项目目录移除当前 torch 相关包,避免 CPU 版残留。
  2. 使用对应 CUDA 索引重新安装 torchtorchvisiontorchaudio

下面示例使用 cu124 索引,安装前请按你机器环境改成正确版本。

1
2
uv remove torch torchvision torchaudio
uv install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cu124
  1. 安装完成后再次检查 CUDA 是否可用。
  2. torch.cuda.is_available() 仍为 False,优先检查 CUDA 版本与驱动是否匹配。

下面命令用于验证 torch 是否识别 GPU 以及当前 CUDA 版本。

1
uv run python -c "import torch; print(torch.cuda.is_available(), torch.version.cuda); print(torch.cuda.get_device_name(0) if torch.cuda.is_available() else 'no gpu')"
  1. 训练时显式传入 device=0--device 0
  2. 若你使用训练脚本参数,建议同时保留 batch 可调,防止显存不足。

下面分别给出 CLI 与脚本两种训练写法。

1
2
uv run yolo detect train model=yolov8n.pt data=data/dataset/data.yaml device=0
uv run python training/train_yolo.py --data data/dataset/data.yaml --device 0

为了避免后续 uv sync 又装回 CPU 版,你可以在 pyproject.toml 中固定 torch 来源索引。
下面片段示例了 tool.uv.indextool.uv.sources 的常见写法。

1
2
3
4
5
6
7
8
9
[[tool.uv.index]]
name = "pytorch-cu124"
url = "https://download.pytorch.org/whl/cu124"
explicit = true

[tool.uv.sources]
torch = [{ index = "pytorch-cu124" }]
torchvision = [{ index = "pytorch-cu124" }]
torchaudio = [{ index = "pytorch-cu124" }]

添加后执行 uv sync,即可按该索引解析 torch 系列包。

实现

数据目录

YOLOv8 检测任务约定「图片」与「标签」分 train / val(可选 test),标签为与图片同名的 .txt 文件。
推荐将数据放在 data/dataset/ 下,与 data.yaml 同层。

下面给出一份通用目录骨架示例。

1
2
3
4
5
6
7
8
data/dataset/
data.yaml
images/
train/
val/
labels/
train/
val/

若你不沿用该路径,也可采用任意根目录名,只要与 data.yamlpathtrainval 一致即可。

1
2
3
4
5
6
7
datasets/exam_questions/
images/
train/
val/
labels/
train/
val/

images/trainlabels/train主文件名一一对应(扩展名分别为图片格式与 .txt),验证集同理。

标注格式

每个 labels/*.txt 中一行表示一个框,共 5 个数字:class_id x_center y_center width height,且均为相对整张图的 0~1 归一化 坐标。
class_id 从 0 开始;若只检测「题目块」一类,可始终为 0

下面是一行标签的示例含义说明(数值为虚构示例,仅演示格式)。

1
0 0.512 0.305 0.42 0.08

表示类别 0 的一个框,中心约在图像正中偏上,宽高约为图宽高的 42% 与 8%。
标注可用 Label Studio、CVAT、labelImg 等工具,导出为 YOLO 格式后复制到上面对应目录。

数据集配置

在数据集根目录旁或项目内新建 data.yaml,声明路径、类别数与类别名。
path 建议写绝对路径或相对于你运行命令时的当前目录的明确相对路径,避免训练时找不到图片。
可先准备一个 data.yaml 模板,再按实际路径与类别修改。

下面示例中 nc 为类别数,names 为类别名列表;单类检测时 nc: 1 即可。

1
2
3
4
5
6
7
path: datasets/exam_questions
train: images/train
val: images/val

nc: 1
names:
0: question

多类时增大 nc 并按顺序列出 names

训练

使用预训练权重可加快收敛,例如 yolov8n.pt(nano,速度快)、yolov8s.pt 等。
推荐在项目中提供 training/train_yolo.py 调用 Ultralytics API,并用 uv run 固定解释器与依赖版本。
脚本默认在有 CUDA 时使用 device=0,否则使用 CPU,并会打印警告,避免无 GPU 时误传 device=0 直接报错。

下面命令在项目根目录执行,使用默认数据配置与训练超参(可用 --epochs--imgsz--batch--model--device 等覆盖)。

1
2
cd your/project/backend
uv run python training/train_yolo.py --data data/dataset/data.yaml

建议在训练脚本里通过 projectname 统一管理输出目录,最佳权重一般为 weights/best.pt;若对接 API,可复制到固定路径或通过环境变量配置模型路径。

若你更习惯官方 CLI,也可在已 uv sync 的环境中用下面等价方式启动训练(注意当前工作目录与 data.yaml 路径要一致)。

下面命令与脚本默认超参类似,将 data.yaml 换成你的实际路径即可。

1
uv run yolo detect train model=yolov8n.pt data=data/dataset/data.yaml epochs=100 imgsz=640 batch=16 device=0

无 GPU 时请传 device=cpu 或依赖 train_yolo.py 的自动回退,并把 batch 调小以免内存不足。
未使用自定义脚本时,Ultralytics 默认产物多在 runs/detect/train/ 下的 weights/best.pt

验证与预测

训练结束后可用同一 data.yaml 在验证集上算 mAP,用于对比不同实验。

1
uv run yolo detect val model=data/runs/detect/paper_train/weights/best.pt data=data/dataset/data.yaml

对单张扫描卷预测并保存画框结果时,指定图片路径与保存目录即可(模型路径按你实际 runs 目录调整)。

1
uv run yolo detect predict model=data/runs/detect/paper_train/weights/best.pt source=path/to/page.jpg save=True

若项目提供 FastAPI 推理接口,可在服务目录执行 uv run python -m uvicorn app.main:app --reload --host 0.0.0.0 --port 8000,Windows 下若遇包路径问题可设置 PYTHONPATH 为当前目录或编写启动脚本统一处理。
若需部署到边缘设备,可在官方文档中查阅 export 为 ONNX、TensorRT 等格式的用法,本文不展开。

验证

环境是否就绪:在项目目录执行 uv sync 无报错,且 uv run python training/train_yolo.py --data ... 能跑通、loss 正常下降、无「找不到图片或标签」路径报错。
数据是否规范:随机打开几张 labels 中的 .txt,确认坐标均在 0~1 且 train/val 文件名成对存在。
训练是否过拟合:对比 trainval 的指标曲线,若验证集明显变差可减少轮数或增强数据增强强度。

总结

  1. 安装 uv,在项目目录执行 uv sync,用 uv run python 运行脚本与检查 GPU。
  2. images/{train,val}labels/{train,val} 组织数据(推荐使用 data/dataset/),标签为 YOLO 归一化格式。
  3. 编写或复制 data.yaml,指向数据根目录并声明 ncnames
  4. 使用 uv run python training/train_yolo.py --data data/dataset/data.yaml(或 uv run yolo detect train ...),根据显存调整 batchimgsz
  5. uv run yolo detect val / predict 或 API 检查指标与框是否贴合试题区域,再进入裁图或 OCR 流程。

试卷反光、装订线、跨栏排版会增加漏检与框粘连,需要在数据采集与标注阶段尽量覆盖真实版式,必要时增加类别或改用更大模型。