街景字符识别赛题实战:从数据预处理到模型调优的完整指南
1. 街景字符识别赛题到底在考什么第一次接触这个赛题的人很容易把它当成普通的OCR任务来处理觉得无非就是检测加识别套个开源框架跑一遍就完事了。但真正打过几轮之后你会发现这个赛题的设计其实相当刁钻它考察的东西远比能不能识别出字符要深得多。1.1 从任务本质说起街景字符识别英文通常叫Street View Text Recognition核心场景是给定一张在街道上拍摄的自然场景图片图片中可能包含一个或多个由数字和字母组成的文本串比如门牌号、路牌编号、商铺招牌上的编号等要求算法定位出文本区域并识别出具体的字符内容。这个任务之所以难难在自然场景四个字。跟扫描文档不同街景图片里的文字会受到各种干扰光照不均、透视变形、遮挡、模糊、字体多样、背景复杂。你在实验室里用印刷体训练出来的模型直接拿到街景数据上跑效果往往惨不忍睹。这个赛题通常给出的数据格式是每张图片对应一个JSON标注文件里面包含该图片中所有文本区域的边界框坐标和对应的文本内容。评估指标一般是准确率也就是完全识别正确的样本占总样本的比例。注意是完全正确一个字符错了整张图就算错这对精度的要求非常高。1.2 为什么值得认真做很多人觉得学习赛嘛随便跑跑就行了。但我个人的经验是这个赛题麻雀虽小五脏俱全它几乎涵盖了工业级OCR项目的完整流程数据探索、标注解析、模型选型、训练调优、后处理、结果集成。你在这个赛题上踩过的坑在实际项目中一个都不会少。而且这个赛题的另一个好处是数据量适中单卡就能跑不需要动辄八卡起步。对于想入门计算机视觉实战的人来说性价比极高。1.3 整体技术路线概览解决这个赛题主流思路无非两条一是检测加识别的两阶段方案二是端到端的单阶段方案。两阶段方案就是先用检测模型比如DBNet、EAST把文本区域框出来再用识别模型比如CRNNCTC、SVTR对每个框做字符识别。端到端方案则是用一个模型直接输出文本内容比如基于Transformer的架构。两种方案各有优劣后面我会详细拆解。但不管选哪条路有几个核心环节是绕不开的数据预处理、数据增强、模型选择、损失函数设计、学习率调度、后处理策略。每一个环节都有讲究每一个环节都可能成为你上分的瓶颈或者突破口。2. 数据理解与预处理的关键细节我见过太多人一上来就开始搭模型结果训练了半天loss不降回头一看数据都没搞清楚。这个赛题的数据有几个容易踩坑的地方我逐一拆解。2.1 标注格式解析与常见陷阱赛题给出的标注通常是JSON格式每张图对应一个标注项。标注里包含图片文件名、文本区域的四个顶点坐标、以及对应的文本内容。看起来很简单对吧但实际操作中你会遇到这些问题第一标注框可能是倾斜的。四个顶点不一定构成一个正矩形可能是任意四边形。如果你直接用外接正矩形去裁剪会引入大量背景噪声影响识别精度。第二有些图片中文本区域非常小。小到你可能在可视化的时候都看不清。这类样本在训练中容易被模型忽略但在评估时又确实存在需要特别处理。第三标注中可能存在空文本或者特殊字符。你需要确认字符集的范围是只包含数字还是数字加字母还是包含更多字符。字符集的大小直接影响分类头的设计。提示拿到数据后第一件事不是写模型而是写一个可视化脚本随机抽取几十张图把标注框画上去肉眼检查一遍。这一步花不了多少时间但能帮你避免后面大量的返工。2.2 数据分布分析与策略制定可视化之后你需要做几个统计文本长度的分布、文本区域大小的分布、字符类别的分布、图片分辨率的分布。这些统计直接决定了你后续的策略。比如如果文本长度集中在4到6个字符那你用固定长度的识别头就够了。如果长度变化很大从1到20都有那你就需要考虑CTC或者Attention这类能处理变长序列的解码方式。再比如如果小目标占比很高那你在检测阶段就需要特别关注多尺度特征融合或者在数据增强时注意不要过度缩小图片。我当时的做法是画了几张分布图发现文本长度主要集中在5到8之间但有一小部分特别长的样本。针对这种情况我最终选择了CTC解码因为它对变长序列的处理更加自然。2.3 数据增强的取舍与实操数据增强是上分的关键手段之一但不是越多越好。你需要根据赛题数据的特点来选择增强方式。对于街景字符识别我推荐以下几种增强随机旋转模拟拍摄角度变化但角度不要太大一般控制在正负10度以内随机缩放模拟不同距离拍摄的效果颜色抖动调整亮度、对比度、饱和度模拟不同光照条件随机裁剪注意裁剪后要保证文本区域完整模糊处理模拟运动模糊或失焦不推荐的增强翻转水平翻转会让文字变成镜像除非你的识别模型能处理镜像文字否则不要用、大角度旋转超过15度后文字可读性急剧下降。这里有个细节很多人忽略增强操作要和标注框同步变换。如果你只对图片做了旋转标注框没跟着转那训练数据就是错的。建议使用支持同步变换的增强库或者自己写变换逻辑时格外小心。3. 模型选型与方案对比这是整个项目最核心的决策点。选错了方向后面再怎么调优都是事倍功半。3.1 两阶段方案检测加识别两阶段方案是最经典也最稳妥的路线。检测阶段负责定位文本区域识别阶段负责读取字符内容。检测模型选择DBNet是目前最主流的选择它的优势在于可微分二值化能端到端训练而且对不规则形状的文本区域处理得比较好。EAST也不错速度更快但对长文本的检测效果稍逊。如果你的数据中文本区域大多是水平矩形那用EAST就够了如果倾斜和弯曲的比较多DBNet更合适。识别模型选择CRNNCTC是经典组合结构简单训练稳定对变长文本友好。SVTR是近几年比较新的方案基于Transformer架构精度更高但训练成本也更大。如果你追求精度且算力充足可以试试SVTR如果追求性价比和稳定性CRNNCTC是不会错的选择。两阶段方案的优点是模块化每个阶段可以独立优化出了问题也容易定位。缺点是检测和识别之间的误差会累积检测框不准会直接影响识别结果。3.2 端到端方案一步到位端到端方案试图用一个模型直接完成检测和识别省去中间环节。代表性的方法有基于Transformer的架构比如把检测和识别统一到一个序列生成框架里。这种方案的理论上限更高因为它可以联合优化检测和识别避免误差累积。但实际落地时有几个问题训练数据需求更大、训练时间更长、调参更困难。对于学习赛这种数据量有限的场景端到端方案未必比两阶段方案效果好。我个人的建议是如果你是第一次做这个赛题先从两阶段方案入手把baseline跑通再考虑要不要换端到端。3.3 方案对比与选择建议对比维度两阶段方案端到端方案实现难度中等较高训练成本较低较高精度上限高理论上更高调试难度低模块化高耦合性强适合人群入门到进阶进阶到高级数据需求中等大注意不要盲目追求最新最复杂的方案。在数据量有限的情况下一个调优充分的CRNN往往比一个没调好的Transformer效果更好。4. 训练调优与上分技巧实录这部分是我踩坑最多、也收获最大的环节。很多技巧看起来不起眼但实际效果非常明显。4.1 学习率调度与优化器选择学习率是训练中最敏感的超参数。我试过固定学习率、余弦退火、阶梯下降、OneCycle等多种策略最终发现对于这个赛题余弦退火配合热重启效果最稳定。具体设置初始学习率设为1e-3用AdamW优化器权重衰减设1e-4。训练过程中每5个epoch做一次余弦退火最低降到1e-6。如果发现loss震荡可以适当降低初始学习率。另外一个技巧是warmup。前500到1000个step用线性增长的方式把学习率从很小的值升到初始值能有效避免训练初期的震荡。这个技巧在Transformer类模型上尤其重要但对CNN模型也有帮助。4.2 损失函数设计与调优识别阶段最常用的损失函数是CTC Loss。它的好处是不需要对齐标注直接输入序列和标签就能算loss。但CTC有几个需要注意的地方第一CTC要求输入序列长度大于等于标签长度。如果你的文本区域裁剪得太窄特征图的时间步数不够CTC会报错。解决办法是保证裁剪后的图像有足够的宽度或者在模型里加一个自适应池化层。第二CTC容易出现blank占主导的情况导致模型倾向于输出空序列。可以通过调整blank的权重或者使用focal loss来缓解。如果你用的是Attention解码那损失函数就是交叉熵。这时候需要注意标签平滑一般设0.1就够了太高反而会损害精度。4.3 模型集成与后处理策略单模型的天花板是有限的想要进一步上分模型集成是必经之路。常用的集成方式有权重平均把多个epoch的模型权重取平均简单有效多模型投票训练多个不同初始化的模型推理时取多数投票TTA测试时增强对测试图片做多种变换分别推理后融合结果后处理方面有几个实用技巧第一置信度过滤。对于识别置信度低于阈值的样本可以考虑用语言模型或者规则进行纠正。比如门牌号通常都是数字如果识别结果里出现了字母大概率是错的。第二长度约束。如果你知道文本长度的大致分布可以对识别结果做长度约束过滤掉明显不合理的输出。第三字符集约束。如果赛题明确说明只包含数字那识别结果里出现字母就可以直接判定为错误需要重新解码。4.4 常见问题速查表问题现象可能原因解决思路loss不下降学习率过大/过小调整学习率加warmuploss震荡严重batch size太小增大batch size或梯度累积过拟合数据量不足/模型太大加数据增强加正则化减小模型识别结果重复字符CTC解码问题检查blank标签设置小目标识别差特征图分辨率不够加FPN用更高分辨率输入检测框不准回归损失权重不合理调整损失权重加IoU损失5. 实操流程完整复盘说了这么多理论最后我把整个实操流程串一遍方便你直接照着做。5.1 环境搭建与数据准备环境方面Python 3.8以上PyTorch 1.10以上另外需要OpenCV、NumPy、Pandas、Matplotlib这些基础库。如果要用DBNet可以装一个开源的OCR工具箱省去自己写检测模型的麻烦。数据准备阶段先把标注解析成统一的格式建议用一个DataFrame来管理包含图片路径、文本框坐标、文本内容、文本长度等字段。然后划分训练集和验证集比例大概8比2。注意要按文本长度分层抽样保证验证集的分布和训练集一致。5.2 检测模型训练要点如果选择两阶段方案先训练检测模型。DBNet的训练相对简单主要注意几点输入分辨率不要太小建议至少736x736学习率用1e-3配合余弦退火训练epoch数一般50到100就够了。训练完成后在验证集上评估检测的召回率和精确率。如果召回率偏低说明有些文本区域没检测到可以降低二值化阈值如果精确率偏低说明误检太多可以提高阈值。5.3 识别模型训练要点识别模型的训练是重头戏。输入是检测框裁剪出来的文本区域图像统一缩放到高度32或48宽度按比例缩放。标签就是文本内容对应的字符索引序列。训练时注意几点batch size尽量大至少64以上学习率用1e-3配合warmupCTC Loss的blank标签设为0训练epoch数一般100到200。如果验证集准确率停滞不前可以尝试以下操作增大输入分辨率、加深网络、加Attention机制、换用更强的backbone。5.4 推理与提交推理阶段先把检测模型跑一遍得到所有文本框然后对每个框做识别最后按赛题要求的格式输出结果。注意处理边界情况没有检测到文本框的图片、识别结果为空的情况、置信度过低的情况。提交前一定要在本地做一次完整的验证确保格式正确、没有遗漏、没有多余的字符。6. 几个容易被忽略的提分细节最后分享几个我在实战中总结的、文档里不会写的细节。第一个是数据清洗。赛题数据里难免有一些标注错误或者模糊不清的样本这些样本留着只会干扰训练。我的做法是先用一个baseline模型跑一遍训练集把loss特别高的样本挑出来人工检查确认是标注问题的就直接剔除。第二个是字符集顺序。字符集的索引顺序会影响模型的收敛速度。建议把出现频率高的字符放在前面blank放在0的位置。这个细节看起来微不足道但实测能加快收敛。第三个是验证集的选择。不要随便切一部分训练集当验证集要确保验证集的分布和测试集尽可能一致。如果测试集里长文本比较多验证集也要相应调整。第四个是模型保存策略。不要只保存最后一个epoch的模型要保存验证集上表现最好的那个。另外建议保存多个checkpoint方便后续做模型集成。第五个是推理时的batch处理。推理时把图片按宽度排序后分批能减少padding提高推理速度。这个技巧在图片数量多的时候效果很明显。提示以上所有技巧都不是孤立的需要根据你的实际情况组合使用。不要一次性把所有技巧都用上那样出了问题你都不知道是哪个环节导致的。建议每次只改一个变量观察效果后再决定下一步。