PaddleOCR Enhanced CTC Loss 全解析Focal-CTC、A-CTC 与 C-CTC 的改进原理与实战配置【免费下载链接】PaddleOCR飞桨多语言OCR工具包实用超轻量OCR系统支持80种语言识别提供数据标注与合成工具支持服务器、移动端、嵌入式及IoT设备端的训练与部署 Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80 languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR本文围绕 PaddleOCR 中基于 CTCLoss 的三条改进路线展开Focal-CTC难例挖掘、A-CTC多任务学习与 C-CTC度量学习系统讲解每个改进的数学动机、源码实现、超参选择以及在 PP-OCRv2 中的应用结论。读完本文你将理解 EnhancedCTCLoss 的内部结构与参数含义掌握 Center 初始化与tools/export_center.py的完整使用流程并能够在自己的识别任务上直接复用 ch_PP-OCRv2_rec_enhanced_ctc_loss.yml 等配置进行训练实验。在 OCR 识别领域CRNN 是工业界广泛使用的文字识别算法训练阶段采用 CTCLoss 计算网络损失推理阶段采用 CTCDecode 获得解码结果。尽管 CRNN 已被实际业务证明能获得可靠的识别效果用户对准确率的要求却永无止境。PaddleOCR 团队以 CTCLoss 为切入点分别从难例挖掘Hard Example Mining、多任务学习Multi-task Learning与度量学习Metric Learning三个角度探索了 CTCLoss 的改进融合方案最终提出EnhancedCTCLoss包含 Focal-CTC Loss、A-CTC Loss、C-CTC Loss 三个组成部分。下面逐一展开。1. Focal-CTC Loss以难例挖掘思路改进 CTC1.1 Focal Loss 的原理回顾Focal Loss 出自论文《Focal Loss for Dense Object Detection》最初用于解决 one-stage 目标检测中正负样本比例严重失衡的问题。该损失函数降低了大量简单负样本在训练中所占的权重本质上是一种困难样本挖掘Hard Example Mining。其损失函数形式如下$$ \begin{equation} L_{fl}\left{ \begin{array}{cl} -\alpha(1 - y^{})^{\gamma}logy^{} , y 1 \ -(1 - \alpha)y^{\gamma}log(1 - y^{}), y 0 \ \end{array} \right. \end{equation} $$其中y 是经过激活函数的输出取值在 0-1 之间。它是在原始交叉熵损失的基础上增加了调制系数 $(1 - y)^\gamma$ 与平衡因子 $\alpha$。当 $\alpha 1, y 1$ 时其损失函数与交叉熵损失的对比见上图。从上图可以看到当 $\gamma 0$ 时调整系数 $(1-y)^\gamma$ 赋予易分类样本损失一个更小的权重使网络更关注困难的、错分的样本。调整因子 $\gamma$ 用于调节简单样本权重降低的速率$\gamma 0$ 时即为交叉熵损失函数$\gamma$ 增大时调整因子的影响也随之增大。实验发现 $\gamma 2$ 是最优值。平衡因子 $\alpha$ 用来平衡正负样本本身的比例不均论文中 $\alpha$ 取 0.25。1.2 从 Focal Loss 到 Focal-CTC对于经典的 CTC 算法假设某个特征序列 $(f_1, f_2, \dots, f_t)$ 经过 CTC 解码之后结果等于 label 的概率为 $y$则 CTC 解码结果不等于 label 的概率即为 $(1-y)$。不难发现CTCLoss 值与 $y$ 存在如下关系$$ L_{CTC} -log(y^{}) $$结合 Focal Loss 的思想——赋予困难样本较大的权重、简单样本较小的权重可使网络更加聚焦于困难样本的挖掘进一步提升识别准确率。由此 PaddleOCR 提出了Focal-CTC Loss其定义如下$$ L_{Focal_CTC} \alpha * (1 - y^{})^{\gamma} * L_{CTC} $$实验中 $\gamma$ 取值为 2、$\alpha 1$。也就是说一个样本的 CTC loss 越大即解码结果越不确定、越困难$(1-y)^\gamma$ 越接近 1权重保持较大反之 CTC loss 越小简单样本调制因子迅速衰减权重被压低。1.3 源码实现Focal-CTC 的实现位于 ppocr/losses/rec_ctc_loss.py。CTCLoss类通过use_focal_loss开关控制是否启用 Focal 调制其核心逻辑如下底层调用nn.CTCLoss(blank0, reductionnone)先得到每个样本的原始 CTC loss不做 reduce当use_focal_lossTrue时将原始 loss 代入weight exp(-loss)再计算weight 1 - weight并取平方得到 $(1-y)^2$ 形式的调制因子最后loss loss * weight并做mean()归约返回{loss: loss}。从源码可以看出$\alpha 1$ 意味着调制因子仅包含 $(1-y)^\gamma$ 一项不额外引入类别平衡项这是 CTC 序列任务与目标检测任务在样本分布上的差异所决定的。2. A-CTC Loss以 ACE Loss 做辅助监督的多任务学习2.1 ACE Loss 的优势A-CTC Loss 是 CTC Loss ACE Loss 的简称。其中 ACE Loss 出自论文《Aggregation Cross-Entropy for Sequence Recognition》。与 CTCLoss 相比ACE Loss 主要有两点优势ACE Loss 能够解决 2-D 文本的识别问题CTCLoss 只能处理 1-D 文本ACE Loss 在时间复杂度和空间复杂度上优于 CTC Loss。上图总结了前人对各类 OCR 识别算法的优劣对比。虽然 ACE Loss 如上图所述可以处理 2D 预测且在内存占用与推理速度方面具备优势但在实践中发现单独使用 ACE Loss 的识别效果并不如 CTCLoss。因此 PaddleOCR 团队尝试将 CTCLoss 与 ACELoss 结合以 CTCLoss 为主、ACELoss 作为辅助监督 loss——这一多任务学习方案收到了效果在内部实验数据集上相比单独使用 CTCLoss识别准确率可提升约 1%。2.2 公式与超参A-CTC Loss 定义如下$$ L_{A-CTC} L_{CTC} \lambda * L_{ACE} $$实验中 $\lambda 0.1$。ACE loss 实现代码见 ppocr/losses/ace_loss.py。2.3 源码实现在 ppocr/losses/ace_loss.py 中ACELoss的实现思路是对预测结果在类别维度做softmax沿时间维度axis1对概率做聚合求和并除以时间步数N得到聚合分布aggregation_preds将 labelbatch[3]也按时间步归一化首位置填充div - length表示 blank/多余部分使用soft_labelTrue的CrossEntropyLoss计算聚合分布与归一化标签之间的损失返回{loss_ace: loss}。这种先聚合时间维、再算交叉熵的做法绕开了 CTC 的前向-后向对齐算法使得损失可以天然适配 2D 预测同时计算复杂度更低作为辅助监督信号可以弥补 CTC 主损失在长序列上的不足。3. C-CTC Loss以 Center Loss 拉大类间距离3.1 中文识别的痛点与 Center LossC-CTC Loss 是 CTC Loss Center Loss 的简称。其中 Center Loss 出自论文《A Discriminative Feature Learning Approach for Deep Face Recognition》最早用于人脸识别任务用于增大类间距离、减小类内距离是度量学习Metric Learning领域一种较早且常用的算法。在中文 OCR 识别任务中通过对 badcase 分析发现中文识别的一大难点是相似字符多、容易误识。由此想到借鉴度量学习的思想增大相似字符的类间距从而提高识别准确率。但需要注意的是度量学习主要用于图像识别领域训练数据的标签是固定值而 OCR 识别本质上是序列识别任务特征与 label 之间并不存在显式的对齐关系因此两者如何结合是一个值得探索的方向。PaddleOCR 团队尝试了 Arcmargin、Cosmargin 等方法最终发现CenterLoss 有助于进一步提升识别准确率。C-CTC Loss 定义如下$$ L_{C-CTC} L_{CTC} \lambda * L_{center} $$实验中设置 $\lambda 0.25$。Center Loss 实现代码见 ppocr/losses/center_loss.py。3.2 Center 的初始化随机初始化无效值得一提的是在 C-CTC Loss 中选择随机初始化 Center 并不能带来明显提升。PaddleOCR 采用的 Center 初始化方法如下基于原始的 CTCLoss训练得到一个网络 N挑选出训练集中识别完全正确的部分组成集合 G将 G 中的每个样本送入网络进行前向计算提取最后一个 FC 层的输入即 feature及其经过 argmax 计算的结果即 index之间的对应关系将相同 index 的 feature 进行聚合计算平均值得到各自字符的初始 center。3.3 使用 export_center.py 提取 Center以配置文件 configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml 为例Center 提取命令如下python tools/export_center.py -c configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec.yml -o Global.pretrained_model./output/rec_mobile_pp-OCRv2/best_accuracy运行完成后会在 PaddleOCR 主目录下生成train_center.pkl。从 tools/export_center.py 的源码可以看到该流程的具体实现先用build_dataloader(config, Eval, ...)构建数据加载器并将 Eval 数据集指向训练集config[Eval][dataset][name] config[Train][dataset][name]等确保用训练数据计算 Center关键步骤是设置config[Architecture][Head][return_feats] True让 CTCHead 在输出预测的同时返回 FC 层输入的特征通过build_model构建模型并用load_model加载预训练权重调用program.get_center(model, eval_dataloader, post_process_class)聚合特征计算每个字符的平均特征作为初始 Center最后序列化到train_center.pkl。在 ppocr/losses/center_loss.py 中CenterLoss.__init__默认用paddle.randn([num_classes, feat_dim])初始化 centers当传入center_file_path时会校验文件存在性并从 pkl 中逐键加载覆盖对应索引的 center。前向计算时将特征 reshape 为[-1, feat_dim]对预测做argmax得到伪标签再通过平方展开计算特征与各 center 之间的 L2 距离矩阵用 mask 选出对应类别的距离并求均值返回{loss_center: loss}——整体逻辑即为拉近特征与其所属类别 center 的距离。4. 统一融合方案 EnhancedCTCLoss将上述三种思路统一融合即为EnhancedCTCLoss统一实现见 ppocr/losses/rec_enhanced_ctc_loss.py。EnhancedCTCLoss继承自nn.Layer构造参数与含义如下参数默认值含义use_focal_lossFalse是否启用 Focal-CTC 调制难例挖掘use_ace_lossFalse是否叠加 ACE Loss 辅助监督多任务学习ace_loss_weight0.1ACE Loss 的权重 $\lambda$use_center_lossFalse是否叠加 Center Loss度量学习center_loss_weight0.05Center Loss 的权重 $\lambda$num_classes6625类别数字符集大小Center 矩阵的行数feat_dim96特征维度FC 层输入维度Center 矩阵的列数init_centerFalse是否使用预提取的 Center 初始化center_file_pathNonetrain_center.pkl的路径在前向__call__中总损失按如下顺序累加loss L_CTC center_loss_weight * L_center 若 use_center_loss ace_loss_weight * L_ace 若 use_ace_loss最终返回{enhanced_ctc_loss: loss}。注意CTCLoss与CenterLoss之间共享同一个CTCHead的特征输出CenterLoss要求predicts为(features, predicts)的元组形式这正是配置中需要打开return_feats: true的原因。仓库中已经提供了一套完整可用的组合配置configs/rec/ch_PP-OCRv2/ch_PP-OCRv2_rec_enhanced_ctc_loss.yml。与基础版配置相比它主要做了以下改动Head下新增return_feats: true使 CTCHead 同时输出特征与预测供 CenterLoss 使用Loss由单个CTCLoss改为CombinedLoss其中CTCLoss的use_focal_loss: false、weight: 1.0CenterLoss的weight: 0.05、num_classes: 6625、feat_dim: 96center_file_path留空填入上一步生成的train_center.pkl路径即可使用预提取 Center配置中还以注释形式保留了 ACE Loss 的接入方式ACELoss权重 0.1便于在自有数据集上尝试三路融合Train.dataset.transforms中的KeepKeys.keep_keys增加了label_ace字段用于在启用 ACE Loss 时提供聚合标签输出目录相应改为./output/rec_mobile_pp-OCRv2_enhanced_ctc_loss。5. 实验结论与使用建议对于上述三种方案PaddleOCR 团队基于百度内部数据集进行了训练与评测实验结果如下表所示algorithmFocal_CTCA_CTCC-CTCgain0.3%0.7%1.7%基于上述实验结论PP-OCRv2 采用了 C-CTC 策略。值得说明的是PP-OCRv2 处理的是6625 个中文字符的识别任务字符集较大、形似字较多因此 C-CTC 方案在该任务上带来的提升较大但若切换到其他 OCR 识别任务结论可能会有所不同。建议读者结合自身任务特点做针对性尝试难例较多、长尾样本明显的任务优先尝试 Focal-CTCuse_focal_loss: true它几乎零成本接入只需要在 CTCLoss 上打开开关希望引入 2D 监督信息或加速收敛的任务尝试叠加 ACE Lossuse_ace_loss: trueace_loss_weight: 0.1但需注意单独使用 ACELoss 效果不及 CTCLoss务必保持 CTC 为主字符集大、相似字符多的中文/多语言任务优先尝试 C-CTCuse_center_loss: true并严格按照先训 CTCLoss 基线 → 用tools/export_center.py提取 Center → 用train_center.pkl初始化再训练的三步流程执行随机初始化 Center 不会带来明显收益追求极限精度可尝试三者组合的 EnhancedCTC 方案并以 ch_PP-OCRv2_rec_enhanced_ctc_loss.yml 为模板在自己的数据集上分别调节center_loss_weight、ace_loss_weight与 Focal 的 $\gamma$ 超参。由于不同任务的字符集规模、形似字密度与数据分布差异较大建议以基线 CTCLoss 为参照在验证集上对比各方案的准确率增益选择最适合自身业务的组合。【免费下载链接】PaddleOCR飞桨多语言OCR工具包实用超轻量OCR系统支持80种语言识别提供数据标注与合成工具支持服务器、移动端、嵌入式及IoT设备端的训练与部署 Awesome multilingual OCR toolkits based on PaddlePaddle (practical ultra lightweight OCR system, support 80 languages recognition, provide data annotation and synthesis tools, support training and deployment among server, mobile, embedded and IoT devices)项目地址: https://gitcode.com/paddlepaddle/PaddleOCR创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考