
1. 项目概述当YOLOv5遇见甲骨文最近在整理一个挺有意思的私人项目核心是把目标检测领域的“万金油”YOLOv5给搬到了考古文字识别这个相对小众但极具挑战的场景里。具体来说就是构建一个能自动从复杂的文本考古图像中定位并识别出甲骨文字符的系统。这活儿听起来像是计算机视觉和古文字学的交叉做起来也确实踩了不少坑但也收获了一套比较完整的从数据准备到模型部署的实战经验。甲骨文作为现存最古老的成熟汉字体系其研究价值不言而喻。但传统的考释工作高度依赖专家的肉眼和经验效率是瓶颈。一张拓片或照片上字符形态各异、笔画粘连、背景复杂可能有泥土纹理、龟甲裂纹干扰人工逐字标注和识别工作量巨大。我们这个系统的目标就是尝试用AI来当个“初级助手”先把图像里的字符一个个框出来检测再判断它可能是哪个字识别为研究者提供一个初步的、可批量处理的参考结果。为什么选YOLOv5原因很直接它足够成熟、社区资源丰富、从nnano到xextra large的全系列模型为我们提供了从轻量级到高精度的灵活选择。在考古数字化场景下计算资源可能天差地别——有的在博物馆现场用边缘设备如Jetson Nano做实时展示有的则在实验室用服务器做高精度批量处理。YOLOv5系列正好能覆盖这些需求。整个项目流程涉及数据采集与标注、模型选型与训练、性能优化以及最后的系统集成下面我就把各个环节的关键细节和心得捋一捋。2. 核心思路与方案选型背后的考量做这个项目首要问题不是直接上模型而是想清楚我们要解决的核心矛盾是什么。甲骨文图像检测识别难点非常具体目标尺度差异大同一张图像里字符大小可能因为书写位置、拍摄距离而相差数倍。目标形态极其多样同一个字在不同时期的刻写风格、磨损程度下外观差异可以很大。背景干扰复杂龟甲兽骨本身的纹理、裂纹、污渍以及拍摄时的光照不均、阴影都会和字符笔画混淆。数据稀缺且标注成本高高质量的、带 bounding box 和字符类别标注的甲骨文图像数据集非常少专家标注耗时费力。基于这些难点我们的技术选型思路就很明确了为什么是“检测识别”两步走而不是端到端最初也考虑过直接用端到端的文本检测识别框架如 DBNet CRNN。但甲骨文是单字离散的不同于现代文本的行序列。先检测出每个字符的独立位置再对每个裁剪出的字符小图进行分类结构更清晰也便于后续针对“检测”和“分类”两个子任务分别优化。比如检测模型可以更关注定位的鲁棒性而分类模型可以更专注于字形特征的提取。为什么是YOLOv5系列做检测全系列覆盖从 YOLOv5n 到 YOLOv5x模型参数量、计算量和精度梯度明显。我们可以用小模型n/s做快速原型验证和轻量部署用大模型l/x追求极限精度这种灵活性对于探索性项目至关重要。成熟的训练生态YOLOv5 的代码库非常友好数据格式YOLO格式、训练脚本、评估指标一目了然社区里针对各种奇怪问题的解决方案也很多能极大降低工程门槛。平衡速度与精度在考古场景不一定需要每秒100帧的实时性但对精度要求较高漏检、误检直接影响研究结果。YOLOv5系列在COCO等通用数据集上表现出的良好平衡给了我们信心。识别分类部分如何考虑检测框出来的字符区域就是一张张小图像。识别本质是一个图像分类任务。但甲骨文字类别多上千类样本少每类可能只有几个到几十个样本。因此我们考虑了几种方案训练一个全新的CNN分类网络如ResNet、EfficientNet。问题数据量太小极易过拟合。使用预训练模型进行微调Fine-tuning。这是更可行的主流方案。利用在ImageNet等大型数据集上预训练好的模型其浅层卷积核已经学会了提取通用图像特征边缘、纹理我们只需要用甲骨文数据去微调其深层网络使其适应甲骨文笔画的特定模式。更进阶的可以考虑度量学习如Triplet Loss或小样本学习来应对极端类别不均衡的情况。在初期我们选择方案2作为基础。注意这里有一个关键决策点。甲骨文图像很多是灰度或单通道的拓片。而常见的预训练模型如PyTorch Torchvision里的大多是在RGB三通道ImageNet上训练的。直接输入单通道图像需要调整网络输入层或者将单通道图像复制成三通道。我们测试发现对于笔画结构特征复制成三通道并微调的效果已经不错且改动最小。3. 数据准备从原始拓片到模型可读的格式数据是AI模型的燃料在考古领域更是如此。我们的数据源主要来自已公开的甲骨拓片图库、著录扫描件以及部分高清拍摄照片。3.1 数据收集与预处理来源优先选择清晰度高、背景相对干净的图像。避免使用经过多次翻拍、压缩严重或水印干扰大的图片。预处理流程灰度化与二值化很多拓片本就是黑白彩色照片也先转为灰度图。然后尝试自适应阈值二值化如OpenCV的cv2.adaptiveThreshold将字符前景与背景分离。这一步能有效减少后续模型学习的干扰。去噪使用形态学操作如开运算、闭运算去除小的斑点噪声灰尘和填补笔画中的细小断裂。但必须谨慎避免过度操作导致笔画变形或字符粘连。尺寸归一化将所有训练图像缩放到统一的尺寸如640x640。这是YOLOv5训练的标准输入尺寸。缩放时保持原图宽高比并进行填充padding防止字符变形。3.2 数据标注一项需要耐心和专业知识的工作这是整个项目最耗时、也最关键的环节。我们使用LabelImg、CVAT等标注工具。标注规范Bounding Box框住整个字符尽量紧贴笔画外缘但不必过于精确到像素级适当留一点边缘有利于模型学习。类别标签给每个框赋予一个字符类别标签。这里依赖甲骨文字典如《甲骨文编》为每个可释读的字分配一个唯一ID。对于未释读或存疑的字可以暂时归为“未知”类或根据字形特征给予临时编号。标注心得多人协作与校验最好由至少两位有一定甲骨文基础的人员进行标注并交叉校验以减少主观误差。处理模糊与残缺字对于笔画模糊或残缺不全的字如果大部分结构可辨则正常标注如果完全无法辨认则不标注避免引入噪声。数据增强策略甲骨文数据量小必须做数据增强。除了YOLOv5自带的Mosaic、随机翻转、色彩抖动等我们特别增加了针对性的增强模拟磨损随机添加椒盐噪声、高斯模糊模拟拓片不清或照片模糊。模拟光照随机调整亮度、对比度模拟不同拍摄条件。弹性形变轻微的仿射变换或弹性形变模拟载体龟甲不平整造成的字形扭曲。3.3 数据集划分与YOLO格式我们将标注好的数据按大约 7:2:1 的比例划分为训练集、验证集和测试集。确保每个字符类别在三个集合中都有分布分层采样。 YOLOv5需要的标注格式是每个图像对应一个.txt文件每行代表一个目标class_id x_center y_center width height坐标和宽高都是相对于图像宽度和高度的归一化值0-1之间。这个格式需要从标注工具导出的XML或JSON格式转换而来。4. YOLOv5模型训练与调优实战数据准备好后就进入核心的模型训练阶段。我们以YOLOv5s为例详细走一遍流程。4.1 环境配置与代码准备# 克隆 YOLOv5 官方仓库 git clone https://github.com/ultralytics/yolov5 cd yolov5 pip install -r requirements.txt # 安装依赖环境主要是PyTorch、TorchVision以及一些工具库。建议使用Python 3.8和PyTorch 1.7。4.2 配置文件调整YOLOv5通过.yaml文件管理数据和模型配置。数据配置文件 (data/guwen.yaml)# 甲骨文数据配置 path: ../datasets/guwen # 数据集根目录 train: images/train # 训练集图像路径 val: images/val # 验证集图像路径 test: images/test # 测试集图像路径 # 类别数量 nc: 1500 # 假设我们有1500个可识别的甲骨文字类 # 类别名称列表 names: [字_1, 字_2, 字_3, ... , 字_1500]模型配置文件直接使用models/yolov5s.yaml其中的nc参数会自动被数据配置覆盖。4.3 启动训练python train.py --img 640 --batch 16 --epochs 300 --data data/guwen.yaml --cfg models/yolov5s.yaml --weights yolov5s.pt --name guwen_det_s--img 640: 输入图像尺寸。--batch 16: 批次大小根据GPU内存调整。甲骨文检测目标相对稀疏可以尝试稍大的batch size。--epochs 300: 迭代轮次。由于数据量可能不大需要足够轮次让模型收敛但也要防止过拟合后期需要看验证集损失。--weights yolov5s.pt: 加载预训练权重。强烈建议使用预训练权重这能极大加速收敛并提升最终性能。--name guwen_det_s: 本次训练运行的名称用于保存结果。4.4 关键超参数调优心得YOLOv5有很多超参数在data/hyps/hyp.scratch.yaml中定义。对于甲骨文场景我调整了几个关键点hsv_h,hsv_s,hsv_v(色彩空间增强)由于甲骨文图像色彩信息不关键甚至主要是灰度可以降低这些增强的强度避免无意义的颜色扰动。我通常把它们调低到0.015以下。degrees(旋转角度)甲骨文字符方向基本是固定的虽然有少数倒书、侧书所以旋转增强的范围不宜过大设置degrees: 0.0或很小的值如±5度。translate(平移)可以适当保留模拟字符在图像中的位置变化。scale(缩放)非常重要甲骨文字符大小不一需要模型能适应尺度变化。可以保持或略微增大缩放增强的范围。mosaic: 马赛克增强对于小目标检测很有效建议开启默认是1.0。它能帮助模型学习在复杂上下文中定位目标。4.5 训练监控与评估训练开始后TensorBoard或YOLOv5自带的日志会记录各项指标。关键指标train/box_loss,train/obj_loss,train/cls_loss: 训练损失关注其下降趋势。val/box_loss,val/obj_loss,val/cls_loss: 验证损失是判断过拟合的关键。如果验证损失开始上升而训练损失继续下降可能就是过拟合了。metrics/mAP_0.5和metrics/mAP_0.5:0.95这是核心评估指标。mAP_0.5是IoU阈值为0.5时的平均精度mAP_0.5:0.95是在多个IoU阈值0.5到0.95步长0.05下的平均mAP后者更严格。对于考古检测我们更关心召回率Recall即尽量别漏掉字符所以也会密切关注metrics/recall。过拟合应对数据增强这是对抗过拟合的第一道防线确保增强策略足够多样。早停Early Stopping监控验证集mAP如果连续多个epoch不再提升则停止训练。权重衰减Weight Decay在优化器如Adam中设置适当的权重衰减参数。DropOutYOLOv5中默认没有大量使用DropOut但如果模型较小如v5n且数据很少可以考虑在分类头等部分添加。4.6 全系列模型对比实验我们分别训练了YOLOv5n, s, m, l, x五个模型。对比结果如下表所示模型参数量 (M)mAP0.5 (Val)mAP0.5:0.95 (Val)推理速度 (ms/img on V100)模型大小 (MB)适用场景建议YOLOv5n1.90.7230.421~1.23.8移动端/嵌入式设备演示对实时性要求极高可接受一定精度损失。YOLOv5s7.20.8150.523~2.014.4平衡之选。适合大多数研究场景的本地服务器或高性能PC精度和速度兼顾。YOLOv5m21.20.8560.581~3.541.5追求更高精度计算资源较充裕。适合作为后端服务的核心检测模块。YOLOv5l46.50.8720.602~5.889.3精度优先用于生成高置信度的基准结果或关键资料处理。YOLOv5x86.70.8830.618~9.1166.7极限精度探索。资源消耗大通常用于学术研究中的性能上限评估。从结果看YOLOv5s到YOLOv5m的精度提升比较明显之后边际效益递减。对于甲骨文检测YOLOv5s或YOLOv5m往往是性价比最高的选择。v5n虽然快但在一些复杂背景或小字符上漏检较多v5l/x精度提升有限但推理时间和资源消耗成倍增加。5. 字符识别模块的构建与融合检测模型给我们提供了字符的位置框接下来需要对每个框内的图像进行识别。5.1 识别模型选型与训练我们采用微调预训练CNN模型的方式。以EfficientNet-B0为例它兼顾了精度和效率。数据准备使用训练好的YOLOv5模型如v5m在训练集图像上推理裁剪出所有检测到的字符区域并适当向外扩展一些像素作为上下文。将这些裁剪图根据其标注的类别保存到以类别ID命名的文件夹中。这就构成了一个分类数据集。注意这里用的是模型检测结果而非完美标注框。这引入了“噪声”但更贴近实际应用场景模型检测框不可能完美。这也迫使分类模型要学会容忍一定程度的定位偏差和背景残留反而能提升系统的整体鲁棒性。模型微调import torch import torchvision.models as models import torch.nn as nn # 加载预训练的EfficientNet-B0 model models.efficientnet_b0(pretrainedTrue) # 修改最后的分类层输出类别数改为我们的甲骨文字类别数如1500 num_ftrs model.classifier[1].in_features model.classifier[1] nn.Linear(num_ftrs, 1500) # 定义损失函数和优化器 criterion nn.CrossEntropyLoss() optimizer torch.optim.Adam(model.parameters(), lr0.001) # 训练循环简略 for epoch in range(num_epochs): # ... 训练和验证步骤 # 重点使用学习率预热和余弦退火调度 scheduler.step()训练技巧输入处理将单通道字符图像复制三份变为“伪RGB”图像再归一化。学习率策略使用学习率预热Warmup和余弦退火Cosine Annealing有助于稳定训练并找到更优解。类别不平衡处理甲骨文字频差异巨大有的字常见有的字极罕见。可以使用加权交叉熵损失Weighted CrossEntropyLoss根据每个类别的样本数倒数来设置权重让模型更多关注稀有字。5.2 检测与识别的流水线集成训练好检测和识别两个模型后需要将它们串联起来形成一个完整的系统。import cv2 import torch from yolov5_detector import YOLOv5Detector # 假设封装好的检测类 from classifier import OracleCharacterClassifier # 假设封装好的分类类 class OracleOCRSystem: def __init__(self, det_model_path, cls_model_path, devicecuda): self.detector YOLOv5Detector(det_model_path, device) self.classifier OracleCharacterClassifier(cls_model_path, device) self.conf_threshold 0.25 # 检测置信度阈值 self.iou_threshold 0.45 # NMS的IoU阈值 def predict(self, image_path): # 1. 检测 img cv2.imread(image_path) detections self.detector.predict(img, self.conf_threshold, self.iou_threshold) # detections: list of [x1, y1, x2, y2, conf, cls_id] (检测框) results [] for det in detections: x1, y1, x2, y2, conf, _ det # 2. 裁剪字符区域可适当padding char_patch img[int(y1):int(y2), int(x1):int(x2)] # 3. 预处理缩放、归一化等以适应分类器输入 processed_patch self.classifier.preprocess(char_patch) # 4. 识别 cls_id, cls_conf, cls_name self.classifier.predict(processed_patch) # 5. 组装结果 results.append({ bbox: [x1, y1, x2, y2], det_conf: conf, char: cls_name, cls_conf: cls_conf, final_score: conf * cls_conf # 一个简单的综合评分 }) # 6. 后处理按某种规则如从左到右从上到下排序结果 sorted_results self._sort_results(results, img.shape) return sorted_results这个流水线清晰地将检测和识别解耦便于单独调试和更新任一模块。6. 系统优化与部署考量模型训练好流水线跑通只是第一步。要让系统真正可用还需要一系列优化。6.1 性能优化技巧模型剪枝与量化如果部署在资源受限的边缘设备上可以对YOLOv5检测模型进行剪枝移除不重要的神经元或通道和量化将FP32权重转换为INT8。PyTorch提供了相关的工具如Torch Pruning, Torch Quantization。量化通常能显著减少模型大小和加速推理且精度损失可控。TensorRT加速对于NVIDIA GPU部署使用TensorRT将PyTorch模型转换并优化能获得数倍的推理速度提升。YOLOv5官方也提供了导出到ONNX并进而用TensorRT加速的脚本。批处理Batch Inference当需要处理大量图片时尽量使用批处理而不是单张推理能充分利用GPU并行计算能力大幅提升吞吐量。6.2 部署方案选择本地API服务使用FastAPI或Flask将上述OracleOCRSystem类封装成RESTful API。方便与其他系统如数字博物馆网站、研究数据库集成。from fastapi import FastAPI, File, UploadFile app FastAPI() ocr_system OracleOCRSystem(...) # 初始化系统 app.post(/predict/) async def predict_image(file: UploadFile File(...)): image_data await file.read() # ... 解码图像调用 ocr_system.predict return {results: predictions}桌面应用使用PyQt、Tkinter或更现代的ElectronPython后端构建一个带GUI的桌面工具方便研究人员本地使用上传图片并可视化检测识别结果。移动端/嵌入式部署对于YOLOv5n这类小模型可以尝试使用PyTorch Mobile、TensorFlow Lite或NVIDIA的JetPack SDK针对Jetson系列部署到移动设备或边缘计算盒子上用于现场文物展示或快速筛查。6.3 持续改进与迭代一个实用的系统不是一蹴而就的。主动学习Active Learning系统在实际使用中可以将置信度低的预测结果例如检测框得分低或分类得分低保存下来交由专家进行复核和标注。将这些新标注的数据加入训练集重新训练模型能有效提升系统在“困难样本”上的表现。错误分析定期分析系统在测试集上的错误案例。是检测漏了还是框不准或者是分类错了针对不同类型的错误可以采取不同策略。例如如果小字符漏检多可以尝试在训练时增加小目标数据增强如复制粘贴小目标或者使用更专注于小目标的检测头改进。7. 实战中遇到的典型问题与解决实录在开发和测试过程中我们遇到了不少坑。这里记录几个典型问题及其排查思路。7.1 训练时mAP平均精度始终为0或极低可能原因1数据标注格式错误。这是最常见的原因。检查YOLO格式的txt文件确保坐标是归一化的0-1且类别ID从0开始连续编号。一个快速检查方法是写个脚本可视化几个标注框看是否和图像对齐。可能原因2类别数nc设置错误。在数据配置文件.yaml中nc必须等于你数据集中实际类别的数量且names列表的长度要等于nc。可能原因3学习率过高或过低。使用预训练权重时初始学习率不宜过大。可以尝试使用YOLOv5默认的超参数--hyp hyp.scratch.yaml或者将学习率调低一个数量级试试。可能原因4数据本身问题。图像路径错误、图像损坏、或者训练集和验证集没有正确分离有重叠。检查train.py输出的数据集统计信息确认图像和标签数量匹配。7.2 模型推理时漏检严重尤其漏小字符解决方案检查输入分辨率YOLOv5默认输入是640x640。如果原始图像中字符已经非常小下采样到640后可能只有几个像素点。尝试增大训练和推理时的--img参数如1280但会显著增加计算量和内存消耗。调整锚框AnchorYOLOv5会针对你的数据集自动计算合适的锚框尺寸。在训练命令中加入--noautoanchor可以禁用自动计算使用默认锚框。但更好的方法是让模型自己计算。确保你的训练数据覆盖了各种尺度的字符。数据增强确保使用了Mosaic增强并可以尝试专门针对小目标的增强如随机将小字符复制粘贴到图像的不同位置。降低置信度阈值推理时通过--conf参数降低检测置信度阈值默认0.25让更多候选框进入后续处理。但要注意这会增加误检。7.3 分类模型将不同字混淆特别是字形相似的字可能原因这是甲骨文识别固有的难点如“人”与“入”“月”与“夕”等。解决方案特征工程在输入分类模型前可以尝试一些预处理来强化区别特征。例如计算字符的骨架细化或者提取Hu矩等形状特征与图像特征融合后再输入网络。但这增加了复杂性。模型层面使用更强大的网络如EfficientNet-B3, B4或者引入注意力机制如SE Block, CBAM让模型更关注字符间的细微差异部分。数据层面对于易混淆字对在数据集中可以有意地增加它们的样本数量或者在训练时给它们更高的损失权重。后处理引入语言模型或上下文信息。甲骨文卜辞有一定文例可以利用前后字符的关系对分类结果进行校正。这属于更高级的集成应用。7.4 推理速度慢无法满足实时性或批量处理需求分析用torch.cuda.Event()或Python的time模块对流水线的每个步骤检测前处理、检测推理、NMS、裁剪、分类前处理、分类推理进行计时找到瓶颈。优化如果检测是瓶颈考虑换用更小的YOLOv5模型n, s或进行量化、TensorRT加速。如果分类是瓶颈考虑使用更轻量的分类网络如MobileNetV3或者将分类模型也进行量化。批处理对于批量图片一定要用批处理。将多张图片堆叠成一个batch输入检测模型能极大提升GPU利用率。异步处理在Web服务中可以使用异步框架如FastAPI的async/await或消息队列避免推理请求阻塞。构建这样一个跨领域的应用系统最大的体会是“没有银弹”。YOLOv5提供了强大的检测基础但将其成功应用于甲骨文这样的特定领域需要大量针对性的细节调整和问题解决。从数据标注的规范性到增强策略的针对性再到模型调试的耐心每一步都直接影响最终效果。这个项目目前还是一个持续优化的过程但已经能够为甲骨文的数字化整理提供一个有一定可用性的自动化工具原型。未来考虑引入更先进的视觉TransformerViT模型进行检测和识别或者利用无监督、半监督学习来缓解数据标注压力都是值得探索的方向。