OCR 性能优化:从认识 BiLSTM 网络结构开始
摘要: 想要对 OCR 进行性能优化,首先要了解清楚待优化的 OCR 网络的结构,本文从动机的角度来推演下基于 Seq2Seq 结构的 OCR 网络是如何一步步搭建起来的。
本文分享自华为云社区《OCR性能优化系列(一):BiLSTM网络结构概览》,原文作者:HW007。
OCR 是指对图片中的印刷体文字进行识别,最近在做 OCR 模型的性能优化,用 Cuda C 将基于 TensorFlow 编写的 OCR 网络重写了一遍,最终做到了 5 倍的性能提升。通过这次优化工作对 OCR 网络的通用网络结构和相关的优化方法有较深的认识,计划在此通过系列博文记录下来,也作为对自己最近工作的一个总结和学习笔记。
想要对 OCR 进行性能优化,首先要了解清楚待优化的 OCR 网络的结构,在本文中我将尝试着从动机的角度来推演下基于 Seq2Seq 结构的 OCR 网络是如何一步步搭建起来的。
读懂此文的前提只需要了解在矩阵乘法中矩阵的维度变化规律,即 n*p 的矩阵乘以 p*m 的矩阵等于 n*m 的矩阵。如果知道 CNN 和 RNN 网络的结构,对机器学习模型的构造套路有点了解的话更好。
首先给出从本文要剖析的 OCRBILSTM 网络总体结构如下图:
接下来我将从这张图的右上角(模型的输出端)向左下角(模型的输入端)逐步解释每一个结构的动机及其作用。
1. 构造最简单的 OCR 网络
首先考虑最简单情况下的 OCR 识别场景,假设输入是只含有一个文字图片,图片的高和宽均为 32 个像素,即 32*32 的矩阵,为了方便将其拉长便可得到一个 1*1024 的矩阵。在输出方面,由于文字的特殊性,我们只能将所有的文字进行标号,最后输出所识别的文字的编号便好,由此得到我们的输出是一个 1*1 的矩阵,矩阵元素的内容就是所识别的文字的编号。
怎么得到这个 1*1 的矩阵呢?根据概率统计的套路,我们假设全世界存在 10000 个文字,将其表为 1~1000 号,那么这 10000 个元素都有概率成为我们的输出,因此我们如果先算出这 10000 个文字作为该输入图片的识别结果的概率的话,再挑概率最大的那个输出便可以了。于是问题被转变成如何从一个 1*1024 的矩阵(X)中得到一个 1*10000 的矩阵(Y)。在这里便可以上机器学习模型结构中最常见的线性假设套路了,假设 Y 和 X 是之间是线性相关的,这样便可得到最简单且经典的线性模型:Y = AX + B。 其中称 X(维度:1*1024)为输入,Y(维度:1*10000)为输出,A 和 B 均为该模型的参数,由矩阵乘法可知 A 的维度应该是 1024*1000,B 的维度应该是 1*10000。至此,只有 X 是已知的,我们要计算 Y 的话还需要知道 A 和 B 的具体值。在机器学习的套路中,作为参数的 A 和 B 的值在一开始是随机设定的,然后通过喂大量的 X 及其标准答案 Y 来让机器把这两个参数 A、B 慢慢地调整到最优值,此过程称为模型的训练,喂进去的数据称为训练数据。训练完后,你便可以拿最优的 A 乘以你的新输入 X 在加上最优的 B 得到相应的 Y 了,使用 argMax 操作来挑选 Y 这 1*10000 个数中最大的那个数的编号,就是识别出来的文字的编号了。
现在,再回头去看图 1 中右上角的那部分,相信你能看懂两个黄色的 384*10000 和 1*10000 的矩阵的含义了。图中例子和上段文字描述的例子的区别主要在于图中的输入是 1 张 1*1024 的图片,上段文字中的是 27 张 1*384 的图片罢了。至此,你已经了解如何构造一个简单地 OCR 网络了。接下来我们就开始对这个简单地网络进行优化。
2. 优化策略一:减少计算量
在上面的文字描述的例子中,我们每识别一个文字就要做一次 1*1024 和 1024*10000 的矩阵乘法计算,这里面计算量太大了,是否有一些计算是冗余的呢?熟悉 PCA 的人应该马上能想到,其实将 32*32 的文字图片拉长为 1*1024 的矩阵,这个文字的特征空间是 1024 维,即便每维的取值只有 0 和 1 两种,这个特征空间可表示的值都有 2^1024 种,远远大于我们所假设的文字空间中所有文字个数 10000 个。为此我们可以用 PCA 或各种降维操作把这个输入的特征向量降维到小于 10000 维,比如像图中的 128 维。
3. 优化策略二:考虑文字间的相关性
(提醒:在上图中为了体现出 batch Size 的维度,是按 27 张文字图片来画的,下文中的讨论均只针对 1 张文字图片,因此下文中维度为 1 的地方均对应着图中的 27)
也许你已经注意到了,图中与黄色的 384*10000 矩阵相乘的“位置图像特征”的维度没有直接用一个 1*384,而是 1*(128+128+128)。其实这里隐含着一个优化,这个优化是基于文字间的关联假设的,简单地例子就是如果前面一个字是“您”,那其后面跟着的很可能是“好”字,这种文字顺序中的统计规律应该是可以用来提升文字图片的识别准确率的。那怎么来实现这个关联呢?
在图中我们可以看到左侧有一个 10000*128 的参数矩阵,很容易知道这个参数就像一个数据库,其保存了所有 10000 个文字图片经过加工后的特征(所谓加工便是上面提到的降维,原始特征应该是 10000*1024 的),照图中的结构,我需要输入当前识别的这个字的前一个字的识别结果 (识别工作是一个字接一个字串行地识别出来的)。然后选择出上个字对应的特征矩阵 1*128,再经过一些加工转换后当做 1*384 的输入中的前 1/3 部分内容。
同理,1*384 里靠后的两个 1*128 又代表什么含义呢?虽然在句子中,前面一个字对后面一个字的影响很大,即使当前要预测的字在图片中很模糊,我也可以根据前面的字将其猜出来。那是否可以根据其前 k 个字或者后 k 个字猜出来呢?显然答案是肯定的。因此靠后的两个 1*128 分别代表的是句子图片里文字“从前到后(Forward)”和“从后到前(Backward)”的图片特征对当前要识别的字的影响,因此图中在前面加了个“双向 LSTM 网络”来生成这两个特征。
至此,改良版的 OCR 网络轮廓基本出来了,还有一些细节上的问题需要解决。不知你是否注意到,按上面所述,1*384 中包含了 3 个 1*128 的特征,分别代表着前一个字对当前字的影响、图片中的整个句子中各个文字从前到后(Forward)的排序对当前文字的影响、图片中的整个句子中各个文字从后到前(Backward)的排序对当前文字的影响。
但是他们的特征长度都是 128!!!一个字是 128,一个句子也是 128?对于不同的文字图片中,句子的长度还可能不一样,怎么可能都用一个字的特征长度就表示了呢?
如何表示一个可变长的句子的特征呢?乍一看的确是个很棘手的问题,好在它有一个很粗暴简单的解决办法,就是加权求和,又是概率统计里面的套路,管你有几种情况,所有的情况的概率求和后都得等于 1。看到在这里不知道是否被震撼到,“变化”和“不变”这样看起来水火不容的两个东西就是这么神奇地共存了,这就是数学的魅力,让人不禁拍手赞绝!
下图以一个实际的例子说明这种神奇的方式的运作方式。当我们要对文字片段中的“筷”字进行识别时,尽管改字已近被遮挡了部分,但根据日常生活中的一些经验知识积累,要对该位置进行补全填空时,我们联系上下文,把注意力放在上文中的“是中国人”和下文中的“吃饭”上。这个加权系数的机制便是用来实现这种注意力机制的。至于“日常生活中的经验”这种东西就是由“注意力机制网络”通过大量的训练数据来学习得到的。也就是图 1 中的那 32 个 alpha 的由来。注意力网络在业界一般由 GRU 网络担任,由于篇幅原因,在此不展开了,下回有机会再细说。看官们只需知道在图一的右边还应该有个“注意力网络”来输出 32 个 alpha 的值便好。
版权声明: 本文为 InfoQ 作者【华为云开发者社区】的原创文章。
原文链接:【http://xie.infoq.cn/article/49fa0b446f7dc6185326b15ff】。文章转载请联系作者。
评论