十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

YOLOv8实战:甲骨文目标检测识别项目全解析

YOLOv8实战:甲骨文目标检测识别项目全解析 简介目标检测是计算机视觉的核心任务之一旨在定位并识别图像中的目标。与传统OCR依赖二值化和字符分割不同基于深度学习的检测模型能直接学习字形特征对复杂背景和残缺笔画有更强的鲁棒性。YOLOv8作为系列中的代表采用anchor-free机制和CSPDarknet结构在小目标检测和速度精度平衡上表现出色。这一技术可广泛应用于古籍数字化、手写体识别、考古文博辅助整理等场景。本文基于自建甲骨文数据集完整介绍了从数据标注、模型训练到评估部署的全流程并共享了训练权重与代码为同类特定场景目标检测任务提供了一套可复用的工程参考。 从去年年初开始我一直在折腾一个听起来有点“冷门”的方向用YOLOv8去识别甲骨文图像。说实话刚看到这个题目的朋友大多会愣一下——甲骨文不是文字学专家干的活吗跟目标检测有什么关系但等你真正拿到一批甲骨文拓片想把上面密密麻麻的古文字一个个定位、圈出来、识别出来就会发现这本质上就是一个非常典型的计算机视觉目标检测任务。这次我把整个项目整理成了一个压缩包包含完整代码、训练好的权重、数据标注脚本和部署示例今天写一篇长文把里面的门道掰开揉碎讲清楚说真的这个方向做起来远比想象中要有意思。这个项目适合谁我个人觉得至少有三类人可以从中拿到东西一是做计算机视觉课题、想找差异化场景的学生二是考古文博领域想引入AI辅助整理的从业者三是对目标检测感兴趣、想看看YOLOv8怎么在一个非标准场景下落地的开发者。文里的思路不局限于甲骨文本身换到印章识别、古籍文字定位、甚至手写体检测上套路都是相通的。1. 项目拆解YOLOv8在甲骨文识别里到底解决什么问题1.1 甲骨文识别不是“文字识别”那么简单很多人一想到文字识别第一反应就是OCR把图片里的字转成文本。但甲骨文识别跟普通OCR根本不是一个量级的事。普通印刷体字形规整、背景干净、每个字符大小一致OCR引擎做起来相对轻松。甲骨文拓片是什么状态几千年前的龟甲兽骨经过长时间埋藏和发掘表面有裂纹、有残断、有杂质还有墨拓时留下的不均匀痕迹。文字刻痕深浅不一笔画粗细变化极大同一个字在不同甲骨上写法差异也非常明显——说白了异体字多到让人头大。所以在做这个项目的时候我把问题拆成了两步走。第一步是检测也就是先把“哪里有字”找出来在图像里用矩形框把每个甲骨文字符的位置框住这一步是YOLOv8要干的活。第二步才是识别判断这个框里到底是什么字。你也可以把两步合并到一个端到端模型里但对甲骨文这种字形复杂、样本稀缺的场景先检测再分类的串联结构更容易调试也方便在中间环节加人工校正。1.2 为什么选YOLOv8而不是传统OCR方案传统OCR方案里Tesseract这类开源引擎对印刷体效果好但对背景复杂、笔画残缺的甲骨文基本无能为力。原因很简单传统OCR本质上依赖二值化、连通域分析、字符分割这一整套流程一步出错后面全崩。拓片上那些裂纹和墨迹阴影在二值化阶段就会让你怀疑人生。YOLOv8这类基于深度学习的目标检测方案就不一样了它是直接从原始图像上学习“目标长什么样”不需要人工设计特征对背景噪声的容忍度要高得多。我对比过YOLOv5、Faster R-CNN和YOLOv8在自建甲骨文数据集上的效果YOLOv8在速度相当的情况下精度明显占优而且它在小目标检测上的表现确实值得肯定。甲骨文拓片里很多字就几十个像素大小YOLOv8的anchor-free机制和更深的特征融合网络对这类小目标更加友好。另外YOLOv8的生态太方便了Python API、命令行工具、参数配置都做得非常顺手训练过程里各种日志、可视化都是现成的省了我大量精力。2. 数据集是命根子甲骨文数据怎么搞2.1 公开数据集与自采数据整个项目里最折磨人的环节不是模型训练而是数据。做这个项目之前我以为甲骨文数据应该是现成好找的结果真查起来发现公开的标注数据集零零散散标注质量良莠不齐。目前我主要用了几条途径来凑数据公开学术数据集一些高校和博物馆公开的甲骨文拓片扫描图这类图清晰度高、来源权威但多数没有标注需要自己做标注。书籍和电子文献中的甲骨文著录像《甲骨文合集》这类大部头扫描成图之后挑选文字区域清晰的页面作为数据来源。自采照片有些甲骨实物展览会公布高清照片侧面角度、复杂背景的照片对模型泛化能力帮助很大。我最终整理出的数据集有3000多张图片标注了约26000个单字框覆盖了120个常见甲骨文字形类别。你可能会说这个规模不大但对于古文字这种小众场景已经算相当不错了。YOLOv8相比之下算是比较“省数据”的模型尤其是有预训练权重打底3000张图足够训出一个可用的模型。2.2 标注规范与工具实操标注工具我用的是LabelImg和X-AnyLabeling两个都用过。LabelImg是老牌工具界面虽然朴素但胜在稳定。X-AnyLabeling交互更舒服支持自动标注辅助对提升效率帮助很大。标注这件事有几点经验想分享框的边界怎么定甲骨文笔画和拓片背景的边界有时很模糊我定了一个规则必须框住整个字形宁可稍微留点边也不能把字截断。因为YOLOv8学的是完整的“字形特征”边框截断会让模型学到错误模式。类别怎么分甲骨文字形变体太多初期我把相似变体拆成多个类别结果模型在测试集上表现极差因为有些变体之间的差异比不同字之间的差异还小。后来改为合并变体每个类别保留主要形态训练效果立刻上来了。标注格式直接导出为YOLO的txt格式每行是class_id x_center y_center width height注意中心点和宽高都是归一化到0~1之间的数值。这个格式是YOLO系列训练的标准格式别标成COCO的JSON再转绕一圈没意义LabelImg直接就能存成YOLO格式。2.3 数据增强与类别均衡甲骨文数据集的类别分布极不均衡比如“甲”“乙”“子”这类常见字可能有上千个样本而一些生僻字可能只有二三十个样本。如果不做处理模型会对高频类别严重过拟合对低频类别直接摆烂。我用了两层手段来解决第一层是图像层面的数据增强。YOLOv8自带的增强就很丰富我在配置里重点开启了几项随机旋转正负10度以内因为甲骨文的方向基本固定转太多会失真、随机亮度对比度调整模拟不同拓片的墨色深浅、随机缩放模拟不同拍摄距离、马赛克增强把多张图拼接成一张效果好但不能一直开。在数据量不足的类别上我额外做了手动复制增强的变体扩充。第二层是损失函数层面的样本权重调整。YOLOv8支持按类别设置损失权重我把低频类别的loss权重调高了一些让模型在训练时更关注那些样本少的类别。这个技巧对改善低频类别召回率非常有效。3. 环境配置与训练准备3.1 硬件与软件环境先说硬件我的主力训练机器是一张GTX 1660 Ti6G显存这在2024年来看属实不太够看。但YOLOv8的设计对低显存用户还挺友好用yolov8s模型、批量大小4、图像尺寸640完全能跑起来显存占用大概4.5G左右。如果你手头显存更小可以换yolov8n模型或者把图像尺寸降到480再不行就开梯度累积。核心思路就是让让显存装得下别一味追求大batch。软件环境这里有一个常见的坑PyTorch版本和YOLOv8的兼容性。YOLOv8官方对PyTorch版本没有特别硬性的要求但如果你用的是2.1以上版本基本不会有问题。我自己的环境组合是Python 3.9 PyTorch 2.1.0cu118 CUDA 11.8 ultralytics 8.2.x安装命令很简答pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118更新过几次版本之后我发现ultralytics包升级到大版本时可能会有配置项变动如果之前训练到一半的权重加载报错先看看是不是版本不一致的问题。3.2 项目结构解析拿到这个项目的zip包之后你看到的目录结构大概是这样的oracle-yolov8/ ├── data/ │ ├── annotations/ # 标注文件 │ ├── images/ # 图片数据 │ └── oracle.yaml # 数据集配置文件 ├── models/ │ └── yolov8s-oracle.pt # 训练好的权重 ├── scripts/ │ ├── train.py # 训练脚本 │ ├── detect.py # 推理脚本 │ ├── split_dataset.py # 数据集划分脚本 │ └── visualize.py # 预测结果可视化脚本 ├── docs/ │ └── 项目说明文档.md └── requirements.txt这个结构是我反复调整后的最终版核心原则就是“数据和代码分离”。数据放data目录模型代码放models目录训练和推理脚本放scripts目录这样换一台机器重新跑的时候不会乱套。很多同学习惯把数据和代码混在一起项目一大了特别容易在各种路径上踩坑。3.3 修改配置文件与训练参数数据集配置文件oracle.yaml是训练的门户别在这个文件上偷懒path: /path/to/oracle-yolov8/data train: images/train val: images/val test: images/test nc: 120 names: 0: 甲 1: 乙 2: 丙 # ... 按实际类别顺序填然后是训练脚本。我自己封装了一个train.py核心就是调用ultralytics的APIfrom ultralytics import YOLO model YOLO(yolov8s.pt) # 加载预训练权重 model.train( datadata/oracle.yaml, epochs200, imgsz640, batch4, device0, workers2, projectruns/oracle, nameexp001, patience30, # 早停耐心值 lr00.005, # 初始学习率 cos_lrTrue, # 学习率余弦衰减 augmentTrue, )这里特别说两个参数。patience是早停参数意思是连续30轮验证集指标没有提升就停止训练这个参数对时间紧张的项目太重要了能省下不少盲等的时间。cos_lr是学习率余弦衰减相比固定学习率或阶梯式衰减收敛更稳妥不容易在后期震荡。4. 训练过程与网络结构细节4.1 YOLOv8网络结构核心要点YOLOv8的 backbone 用了CSPDarknet结构的改进版核心模块是C2f。C2f这个模块设计很有意思它把特征图分成两支一部分走残差连接一部分经过多个瓶颈层最后把各路特征在通道维度上拼接在一起再经过卷积融合。这样做的好处是既保留了深层语义信息又不会让梯度消失信息流非常顺畅。YOLOv8的neck部分用的PAN-FPN结构简单说就是一条自顶向下的路径把高层语义信息传下来一条自底向上的路径把底层细节信息传上去两条路径通过横向连接融合。这个结构对小目标检测特别重要因为小目标的语义信息本来就弱如果只在高层特征上检测很容易漏检。头部head部分是anchor-free的每个位置直接预测类别和距离目标框四边的距离不再像YOLOv5那样预设一堆不同尺寸的anchor框。这让计算过程简化了不少也减少了对数据集中框尺寸分布的依赖。甲骨文里字形大小差异非常大从几百像素的大字到二十几像素的小字都有anchor-free方案处理这种多尺度分布比anchor-based方案从容得多。4.2 损失函数与训练日志解读YOLOv8的损失函数由三部分组成分类损失、边界框回归损失和DFL损失。分类损失用的BCE判断框里有没有目标、是哪一类。边界框回归损失用的是CIoU同时考虑框的重叠面积、中心点距离和长宽比比单纯的IoU loss收敛更平稳。DFL是Distribution Focal Loss它把框坐标预测当成一个离散分布估计问题对模糊边界的回归更准确。看训练日志的时候重点关注val/box_loss和val/cls_loss这两个值不要死盯train_loss。train_loss只反映了模型在训练集上的拟合程度模型过拟合的时候train_loss会很好但val_loss很烂。我训练的时候出现过train_loss已经降到了0.02以下但val_loss在0.3附近反复横跳的情况后来发现是马赛克增强开太猛关闭之后才恢复正常。如果你想把损失函数曲线画出来ultralytics训练完会在runs/oracle/exp001/目录下生成results.csv里面记录了每一轮的训练损失、验证损失、精确率、召回率、mAP等指标。直接用pandas读进来画图就行import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/oracle/exp001/results.csv) plt.plot(df[epoch], df[train/box_loss], labeltrain box loss) plt.plot(df[epoch], df[val/box_loss], labelval box loss) plt.legend() plt.savefig(loss_curve.png)4.3 训练过程中我踩过的几个坑训练过程我前后跑了十几个版本踩过的坑完全可以单开一篇文章这里把最典型的几个记录下来。第一个坑是显存不足但batch已经很小了。我一度把batch降到2还是报CUDA out of memory排查之后发现是图像尺寸的问题imgsz640对于6G显存来说配yolov8s的batch4差不多是极限如果开了一堆数据增强线程导致CPU内存峰值也会挤爆共享显存。解决方法是降低workers线程数同时打开ultralytics的rect参数让训练时按图片长宽比自动分组减少无效填充。第二个坑是类别id和names配置顺序对不上。有几次我改了data/yaml里的names顺序但忘了同步改标注文件里的类别id训练出来的模型在推理时张冠李戴错得非常离谱。后来我写了一个脚本解析yaml和标注目录自动检查每个类别id是否在标注文件中出现把配置校验这一步纳入了流程。第三个坑是学习率设置。YOLOv8默认的lr00.01是对COCO这种大数据集调的参数迁移到甲骨文这种小数据集上模型反而容易发散。我把lr0降到0.005配合warmup_epochs3然后在训练前期密切关注loss的变化趋势。如果前5轮loss不降反升大概率是学习率太高赶紧停了重来别硬撑着跑完200轮。5. 模型评估、推理与效果对比5.1 评估指标怎么看训练结束之后ultralytics会在验证集上自动跑出一堆指标这里我一般重点看三样东西mAP0.5、mAP0.5:0.95和recall。mAP0.5是IoU阈值0.5时的平均精度值越高代表检测框和真实框的重合度越好但这个指标对框位置精度不够敏感。mAP0.5:0.95是把IoU从0.5到0.95按步长0.05取平均更严格也更贴合实际应用场景。我最终的模型在验证集上mAP0.5达到了0.87mAP0.5:0.95是0.63说实话这个成绩在甲骨文这种模糊场景下已经算是相当让人满意了。recall召回率在这里比precision更重要。因为甲骨文识别的后续环节通常有人工校验多框一个未标记的字人工扫一眼就能排除但漏框了这个字就直接丢掉了后面的文字整理工作就会出大问题。所以在调优的时候我宁可让模型稍微多框出一些模棱两可的位置也不希望看到它漏掉清晰的文字。5.2 推理脚本编写与可视化训练好的权重我用两种方式加载。第一种是直接命令行yolo detect predict modelmodels/yolov8s-oracle.pt sourceimages/test/001.jpg saveTrue第二种是写进Python脚本方便在批量处理时做二次加工from ultralytics import YOLO model YOLO(models/yolov8s-oracle.pt) results model.predict(images/test/001.jpg, conf0.35, iou0.5, imgsz640) boxes results[0].boxes for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(cls_id, conf, xyxy)关于置信度阈值conf的调整我有一个建议甲骨文检测场景里与其把conf设得很高追求精确率不如设低一点比如0.25到0.35之间让模型把一些不确定的字也框出来宁可多框不可漏框。我之前用conf0.5跑一批模拟数据发现漏检严重降阈值之后问题缓解了不少。5.3 不同预训练权重与改进方向的尝试我在这个项目里做过一组对照分别用yolov8n、yolov8s、yolov8m三个尺寸的模型训练同样数据结果很有意思。yolov8n最快最省显存但mAP明显低了6个百分点对小尺寸的甲骨文字符漏检较多。yolov8s在精度和速度之间最均衡最终我选了它作为项目默认模型。yolov8m精度确实更高但我的1660 Ti跑起来已经有点吃力推理速度也慢了一倍多性价比不高。后来我还试过给YOLOv8加注意力机制比如EMA注意力模块插到C2f的输出之后。一开始效果有提升mAP涨了接近2个点但训练不太稳定有的随机种子下提升明显有的则没有变化。这类结构改进需要大量实验验证如果你的数据集本身就小不建议一上来就魔改结构稳扎稳打把基础模型调好才是正道。6. 部署与扩展从PC到嵌入式与安卓6.1 模型导出与格式转换训练好的模型如果不能部署到实际应用场景里价值就大打折扣。YOLOv8的模型导出做得非常顺一条命令能导出多个格式yolo export modelmodels/yolov8s-oracle.pt formatonnx yolo export modelmodels/yolov8s-oracle.pt formatengine device0ONNX是最通用的中间格式后续转TensorRT、OpenVINO、NCNN都方便。导出之后建议用ONNX Runtime做一个快速推理验证确认导出的模型与原模型输出一致再走下游部署流程。我第一次导出时没有固定输入尺寸结果推理时动态shape在某些框架里不兼容后来在导出时设置imgsz640固定尺寸问题解决。6.2 嵌入式设备部署思路我身边陆续有朋友在讨论把YOLOv8部署到RK3588这类边缘计算设备上我自己也在一个边缘盒子上试过。基本路线是先把模型转成ONNX再通过RKNN-Toolkit转成RKNN格式然后在板子上用RKNN Runtime推理。整个过程有几个环节特别容易出问题一是某些算子不兼容转模型时报错这时候要么改模型结构、要么把不兼容层拆开在CPU上跑二是量化掉点float16精度基本能保住int8量化会掉几个点mAP甲骨文这种小目标场景对量化比较敏感我个人建议优先用float16。如果设备算力更弱比如手机端可以用NCNN。把ONNX转成NCNN格式用ncnnoptimize做模型优化再走ncnn的C或Java API调用。安卓端的整体体验是可行的但因为我主用的还是PC端方案移动端只是验证过可行性细节方面建议参考官方示例代码比我自己造轮子靠谱。6.3 做一个简单的检测界面部署到应用层面时纯命令行对非技术用户太不友善。我写了一个基于Python和OpenCV的实时检测界面逻辑很简单读图、跑模型、把结果画到图上、显示出来。代码量不大但很实用import cv2 from ultralytics import YOLO model YOLO(models/yolov8s-oracle.pt) cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break results model.predict(frame, conf0.3, imgsz640, verboseFalse) annotated results[0].plot(line_width2) cv2.imshow(Oracle Detection, annotated) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这个界面用来演示项目非常方便配合触摸屏可以做一个简单的“拍摄-检测-显示”流程。不过要注意实时视频流推理的帧率受限于模型尺寸和推理设备yolov8s在CPU上大概只能跑到十几帧优化空间可以通过换轻量模型或者切NCNN/OpenVINO推理后端来解决。7. 常见问题与排查技巧实录7.1 常见错误速查表问题现象可能原因解决办法CUDA out of memorybatch太大或图像尺寸过大调小batch和imgsz开梯度累积训练loss不降反升学习率太高或预训练权重缺失降低lr0确认加载了yolov8s.pt推理结果类别全乱配置文件names顺序与标注不一致写脚本校验类别id与names映射验证集mAP奇低但训练loss正常数据集划分泄漏或标注错误检查图像是否混入验证集抽查标注框导出ONNX后推理结果不一致动态尺寸或算子不支持固定imgsz或关闭某些融合选项小目标漏检严重图像尺寸过小或数据集小目标偏少提高imgsz到960增加小目标样本增强7.2 我的几条实操心得第一做这种特定场景的目标检测数据质量远比模型结构重要。甲骨文数据标注时多花一天训练后模型效果能提升一截这比在网络上搜什么“改进模块”然后往模型里硬塞要实在得多。我见过太多人花大量时间调结构、换注意力模块但训练数据里一半是错标、漏标的最后模型效果自然上不去。第二过拟合在小样本场景下是必然的关键是让验证集有代表性。我一开始随机划分数据集时同一张拓片的不同区域被切到了训练集和验证集结果验证集指标虚高换了一批新图测试立刻现原形。后来我按拓片来源划分数据同一张拓片只会出现在一个集合里这样评估出来的泛化能力才是真实的。第三分类与检测分层推进不要指望一步到位。如果项目预算允许训练完YOLOv8检测模型之后把检测出来的结果裁切出来再单独训练一个分类模型判断具体文字准确率会有一个明显的提升。因为检测任务关注“在哪里”分类任务关注“是什么”两者的特征需求不同分开处理来更合理。8. 后续还可以怎么扩展个人认为这个项目的扩展空间很大先说两个我自身想继续往下走的方向。第一个是模型层面目前甲骨文检测基本靠YOLOv8系列如果把注意力机制、小目标检测头、更大尺度的特征金字塔结合起来应该还能把mAP往上推一推。第二个是数据层面甲骨文公开数据整体还是偏少如果能推动更多博物馆开放高清图像配合半自动标注工具把数据规模做大训练出来的模型会有质的飞跃。对于拿到这个项目的读者我最想提醒一点不要只停留在“跑通demo”的层面。压缩包里附带了一个小规模验证脚本你跑完觉得效果不错之后一定要把自己领域里的真实数据加进来重新训练这才是这个项目真正的价值所在。甲骨文只是一个切入点同样的流程完全可以迁移到印章、古籍、手稿、甚至工业质检里的字符检测思路是一致的。最后再分享一个小技巧训练过程中如果发现模型在特定类别的精度很低优先检查这个类别的标注框是否一致。我当时有一个类别时好时坏后来发现原因是标注时有的人按外轮廓框、有的人按内刻痕框模型被不一致的标注搞到困惑。统一标注规范重标那一类样本后这个类别的mAP涨了十几个点。标注一致性这种细节往往比任何高端技巧都更管用。本文还有配套的精品资源点击获取
返回列表