2021SC@SDUSC
目录
一、前情回顾
1.1 PP-OCR文字识别策略
策略的选用主要是用来增强模型能力和减少模型大小。下面是PP-OCR文字识别器所采用的九种策略:
- 轻主干,选用采用 MobileNetV3 large x0.5 来权衡精度和效率;
- 数据增强,BDA (Base Dataaugmented)和TIA (Luo et al. 2020);
- 余弦学习率衰减,有效提高模型的文本识别能力;
- 特征图辨析,适应多语言识别,进行向下采样 feature map的步幅修改;
- 正则化参数,权值衰减避免过拟合;
- 学习率预热,同样有效;
- 轻头部,采用全连接层将序列特征编码为预测字符,减小模型大小;
- 预训练模型,是在 ImageNet 这样的大数据集上训练的,可以达到更快的收敛和更好的精度;
- PACT量化,略过 LSTM 层;
1.2 本文介绍策略
在之前系列文章中,已经陆续介绍了PP-OCR文字识别模型中的轻主干策略、轻头部策略、数据增强策略、余弦学习率衰减策略以及特征图辨析策略。同时在各个策略的介绍过程中,穿插了包括PP-OCR文字识别模型的组织网络构建、常用以及最新数据增强算法实现、学习率介绍与学习率衰减常用策略、CRNN文字识别策略介绍等知识的介绍。
由于之前的介绍可能过于笼统,仍有部分细节没有展开讲述,本篇及之后陆续发布的文章,会对之前的策略介绍进行补充(与之前介绍策略的文章的发布顺序没有太大关系,在哪个部分有新的认识就会补充哪里,欢迎大家指正)。
在上次的文章中,我们介绍了特征图辨析,结合CRNN网络结构,进行了 feature map的步幅修改,在CRNN最终标签生成时,利用了CTC loss作为对齐方式。本篇文章将会详细介绍CTC算法,并结合代码介绍CTC算法在PP-OCR中的应用。
二、CTC介绍
2.1 CTC是什么
CTC,Connectionist Temporal Classification,用来解决输入序列和输出序列难以一一对应的问题。
CTC是一种Loss计算方法,用CTC代替Softmax Loss,训练样本无需对齐。CTC特点:
- 引入blank字符,解决有些位置没有字符的问题
- 通过递推,快速计算梯度
2.2 为什么选用CTC
基于文本识别算法的两种框架(之前也介绍过)如下图:
选用第一种框架,是由于相比于attention,CTC结合CRNN具有以下优点:
- 从效果上来看,通用OCR场景CTC的识别效果优于Attention,因为带识别的字典中的字符比较多,常用中文汉字三千字以上,如果训练样本不足的情况下,对于这些字符的序列关系挖掘比较困难。中文场景下Attention模型的优势无法体现。而且Attention适合短语句识别,对长句子识别比较差。
- 从训练和预测速度上,Attention的串行解码结构限制了预测速度,而CTC网络结构更高效,预测速度上更有优势。
根据上一篇文章介绍的CRNN OCR,第一种框架为CTC结合CRNN。整个网络,包含CNN和RNN层,然后根据RNN网络结果进一步CTC loss处理获取最终标签(结果)。
框架选择的CTC loss与其他算法的优劣比较:
- 对于RNN层,如果使用常见的Softmax cross-entropy loss,则每一列输出都需要对应一个字符元素。那么训练时候每张样本图片都需要标记出每个字符在图片中的位置,再通过CNN感受野对齐到Feature map的每一列,获取该列输出对应的Label才能进行训练。
- 在实际情况中,标记这种对齐样本非常困难(除了标记字符,还要标记每个字符的位置),工作量非常大。另外,由于每张样本的字符数量不同,字体样式不同,字体大小不同,导致每列输出并不一定能与每个字符一一对应。
- CTC提出一种对不需要对齐的Loss计算方法,用于训练网络,被广泛应用于文本行识别和语音识别中。
2.3 CTC算法原理实现
流程
首先,再讲一下CRNN流程(如下图):先通过CNN提取文本图片的Feature map,然后输入到LSTM中。LSTM的每一个时间片后接softmax,输出一个后验概率矩阵。
具体细节及过程
先通过CNN提取文本图片的Feature map,然后将每一个channel作为 D = 512 的时间序列输入到LSTM中.
补充定义:
- CNN Feature map:Feature map的每一列作为一个时间片输入到LSTM中。设Feature map大小为m·T。
- LSTM:LSTM的每一个时间片后接softmax,输出 y 是一个后验概率矩阵,LSTM可以表示为:y = NETw(X):
- 空白blank符号:blank表示当前列对应的图像位置没有字符。
- β变换:中间有空白格的就不消除重复。LSTM的结果y经过β变换之后可以获得结果,β变换显然不是单对单映射
CTC怎么做
对于LSTM给定输入 X 的情况下,输出为 L 的概率为:
对于任意一条路径 Π 有 :
举例,T = 12时
在实际情况中,T会设置的非常大(>=20),且路径非常多,无法通过逐条求和直接计算
P( l | x)。因此需要快速计算方法。
在CTC的训练过程,本质上是通过梯度 调整LSTM的参数 W ,使得对于输入样本为
时使得
取得最大。
CTC借用了HMM的“向前—向后”(forward-backward)算法来计算,这样对LSTM的输出y求导之后,再根据y对LSTM里面的权重参数w进行链式求导,就可以使用梯度下降的方法来更新参数。
2.4 CRNN和CTC总结
核心就是将CNN/LSTM/CTC三种方法结合:
- 首先CNN提取图像卷积特征
- 然后LSTM进一步提取图像卷积特征中的序列特征
- 最后引入CTC解决训练时字符无法对齐的问题
三、CTC代码实现
3.1 代码位置
3.2 关键代码
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import paddle
from paddle import nn
class CTCLoss(nn.Layer):
def __init__(self, **kwargs):
super(CTCLoss, self).__init__()
self.loss_func = nn.CTCLoss(blank=0, reduction='none')
def forward(self, predicts, batch):
predicts = predicts.transpose((1, 0, 2))
N, B, _ = predicts.shape
preds_lengths = paddle.to_tensor([N] * B, dtype='int64')
labels = batch[1].astype("int32")
label_lengths = batch[2].astype('int64')
loss = self.loss_func(predicts, labels, preds_lengths, label_lengths)
loss = loss.mean() # sum
return {'loss': loss}
总结
由于之前系列文章的介绍可能过于笼统,仍有部分细节没有展开讲述,本篇及之后陆续发布的文章,将会对之前的策略介绍进行补充(与之前介绍策略的文章的发布顺序没有太大关系,在哪个部分有新的认识就会补充哪里)欢迎大家指正。