精华内容
下载资源
问答
  • 场景文本识别模型综述

    千次阅读 2019-11-25 12:36:45
    大多数自然场景文字识别算法使用合成数据进行训练。两个常用的合成数据集是 MJSynth(MJ) 和 SynthText(ST) ,分别包含890万和550万张训练样本。 图1 不同比例的训练数据集(MJ+ST)与算法识别性能 结论: 自然场景...

    一、数据集的分析

    (一) 训练数据集

    大多数自然场景文字识别算法使用合成数据进行训练。两个常用的合成数据集是 MJSynth(MJ) 和 SynthText(ST) ,分别包含890万和550万张训练样本。

    不同比例的训练数据集(MJ+ST)与算法识别性能

    图1 不同比例的训练数据集(MJ+ST)与算法识别性能

    结论:

    • 自然场景文字识别算法的性能随着数据量的增多而改善。
    • 在不同训练数据集下训练的模型,彼此不具有可比性。
    • 数据的多样性比数据量更加重要。
    • 当真实训练数据与评测数据分布相近时,在真实数据上Fine-tuning可以改善识别算法的性能;反之效果可能适得其反。

    (二) 测试数据集

    自然场景文字识别领域的评测数据集主要包括2类:一类是规则文本数据集,如 IIIT5K,SVT,IC03 和 IC13;另一类是不规则文本数据集(以弯曲、透视变换为主要特点),如IC15,SVT-P 和 CUTE80 。

    图2 6种自然场景文字识别算法的性能比较(相同训练集)

    结论:

    • 部分自然场景文字识别评测数据集(IC03, IC13和IC15)存在样本数量差异。特别地,IC03训练集与IC13测试集存在215张重合文字样本。
    • 测试集样本数量的差异会影响对识别算法性能的评估。

    二、模型结构的分析

    本文将自然场景文字识别模型分为4个模块阶段(Stage),包括:

    • 变换处理阶段(Transformation stage)
    • 特征提取阶段(Feature Extraction stage)
    • 序列建模阶段(Sequence Modeling stage)
    • 预测阶段(Prediction stage)
      本文探究了不同阶段的不同设计实现对算法识别性能、速度和参数存储量的影响:
    图3 自然场景文字识别模型24种实现方法的识别性能,速度和参数存储量比较

    结论:最佳模型结构:TPS + ResNet + BiLSTM + Attntion Mechanism

    (一)Transformation Stage

    表1 Transformation Stage 2种方法(None和TPS)的准确率,速度和参数存储量分析

    图4 图2 加入TPS后正确识别的图片

    图5 Transformation Stage的准确率、速度和参数存储量分析

    结论:

    • TPS变换的引入可以改善自然场景文字识别器的识别性能。
    • TPS变换适用于识别不规则文本。
    • 引入TPS变换带来的识别性能的改善,以增加少量时间和增加少量参数作为代价。

    (二)Feature Extraction Stage

    表2 Feature Extraction Stage 3种实现方法(VGG,RCNN和ResNet)的准确率、速度和参数存储量分析


    图6 加入ResNet后正确识别的图片

    图7 Feature Extraction Stage的准确率、速度和参数存储量分析

    结论:

    • 具有更复杂的特征提取模块的自然场景文字识别器的识别性能更好。
    • 更复杂的特征提取模块具有更好的特征表达能力,适用于识别具有复杂字体和背景的文字样本。
    • 对于速度而言,特征提取阶段的不同实现方法没有明显差异;对于参数存储量而言,ResNet的高识别性能以最大的参数存储空间作为代价。

    (三)Sequence Modeling Stage

    表4 Sequence Modeling Stage 2种实现方法(None和BiLSTM)的准确率、速度和参数存储量分析


    图8 加入BiLSTM后正确识别的图片

    图9 Sequence Modeling Stage的准确率、速度和参数存储量分析

    结论:

    • BiLSTM的引入可以改善自然场景文字识别器的识别性能。
    • BiLSTM适用于识别包含无关字符的文字样本。
    • 引入BiLSTM带来的识别性能的改善,以增加少量时间和增加少量参数作为代价。

    (四)Prediction Stage

    表 Prediction Stage 两种实现方法(CTC和Attn)的准确率、速度和参数存储量分析

    图 加入Attention Mechanism后正确识别的图片

    图 Prediction Stage的准确率、速度和参数存储量分析
    **结论:** - 对于自然场景文字识别(英文)的Prediction Stage来说,Attention Mechanism的识别性能优于CTC算法。 - 因为Attention Mechanism含有字符级隐式语言建模,所以适用于识别含有遮挡的文字样本。 - 对于速度而言,Attention Mechanism明显慢于CTC;对于参数存储量而言,二者没有明显差别。

    (五)准确率和速度的权衡分析

    图 准确率和速度的权衡分析
    表 不同模块改变对准确率和速度的影响

    结论:

    • ResNet、BiLSTM和TPS的引入略微增加了时间(1.3ms ->10.9ms),却很好地改善了识别性能(69.5% ->82.9%)。
    • Attention Mechanism的引入增加了大量的时间(10.9ms-> 27.6ms),却带来了很少的识别性能改善(82.9% ->84.0%)。
    • 权衡准确率和速度,自然场景文字识别模型最优的模块改善路径为:ResNet -> BiLSTM -> TPS -> Attention Mechanism。

    (六)准确率和参数存储量的权衡分析

    图 准确率和参数存储量的权衡分析
    表 不同模块改变对准确率和参数存储量的影响


    结论:

    • RCNN是一个轻量级的特征提取模块,具有较好的准确率-参数存储量权衡优势;相反,引入ResNet占用了大量的参数。
    • 权衡准确率和参数存储量,自然场景文字识别模型最优的模块改善路径为:RCNN -> Attention Mechanism -> TPS -> BiLSTM –> ResNet。

    三、 总结及讨论

    本文是第一篇对自然场景文字识别算法性能比较的公平性进行详细分析讨论的文章。本文通过大量的实验分析,总结并提出了丰富实用的结论和工程建议,同时也引发了相关研究者对于自然场景文字识别领域更多的思考。
    本文的主要贡献有:
    (1)首次公开指出了自然场景文字识别算法性能比较的公平性的问题;
    (2)系统全面的探讨了训练和评测数据集、模型结构(如主干网)对自然场景文字识别算法性能的影响;
    (3)把自然场景文字识别整体流程划分为四个不同的模块,并总结了一个高性能的识别技术路线;
    (4)分析了自然场景文字识别算法的不同阶段及不同实现对识别算法性能、速度和参数存储量的影响。

    展开全文
  • 场景文字识别-Attention类别 计算机视觉(PaddleCV)应用 文字 图片识别 营业执照识别 车牌识别 票据识别模型概述使用Attention 识别图片中单行英文字符,用于端到端的自然场景文本识别。模型说明## 代码结构```├──...

    场景文字识别-Attention

    类别 计算机视觉(PaddleCV)

    应用 文字 图片识别 营业执照识别 车牌识别 票据识别

    模型概述

    使用Attention 识别图片中单行英文字符,用于端到端的自然场景文本识别。

    模型说明

    ## 代码结构

    ```

    ├── data_reader.py # 下载、读取、处理数据。

    ├── crnn_ctc_model.py # 定义了OCR CTC model的网络结构。

    ├── attention_model.py # 定义了OCR attention model的网络结构。

    ├── train.py # 用于模型的训练。

    ├── infer.py # 加载训练好的模型文件,对新数据进行预测。

    ├── eval.py # 评估模型在指定数据集上的效果。

    └── utils.py # 定义通用的函数。

    ```

    ## 简介

    本章的任务是识别图片中单行英文字符,这里我们分别使用CTC model和attention model两种不同的模型来完成该任务。

    这两种模型的有相同的编码部分,首先采用卷积将图片转为特征图, 然后使用`im2sequence op`将特征图转为序列,通过`双向GRU`学习到序列特征。

    两种模型的解码部分和使用的损失函数区别如下:

    - CTC model: 训练过程选用的损失函数为CTC(Connectionist Temporal Classification) loss, 预测阶段采用的是贪婪策略和CTC解码策略。

    - Attention model: 训练过程选用的是带注意力机制的解码策略和交叉信息熵损失函数,预测阶段采用的是柱搜索策略。

    训练以上两种模型的评估指标为样本级别的错误率。

    ## 数据

    数据的下载和简单预处理都在`data_reader.py`中实现。

    ### 数据示例

    我们使用的训练和测试数据如`图1`所示,每张图片包含单行不定长的英文字符串,这些图片都是经过检测算法进行预框选处理的。

    7f2bedbd077d01de79adfc9113a128af.png

    图 1

    在训练集中,每张图片对应的label是汉字在词典中的索引。 `图1` 对应的label如下所示:

    ```

    80,84,68,82,83,72,78,77,68,67

    ```

    在上边这个label中,`80` 表示字符`Q`的索引,`67` 表示英文字符`D`的索引。

    ### 数据准备

    **A. 训练集**

    我们需要把所有参与训练的图片放入同一个文件夹,暂且记为`train_images`。然后用一个list文件存放每张图片的信息,包括图片大小、图片名称和对应的label,这里暂记该list文件为`train_list`,其格式如下所示:

    ```

    185 48 00508_0215.jpg 7740,5332,2369,3201,4162

    48 48 00197_1893.jpg 6569

    338 48 00007_0219.jpg 4590,4788,3015,1994,3402,999,4553

    150 48 00107_4517.jpg 5936,3382,1437,3382

    ...

    157 48 00387_0622.jpg 2397,1707,5919,1278

    ```

    文件train_list

    上述文件中的每一行表示一张图片,每行被空格分为四列,前两列分别表示图片的宽和高,第三列表示图片的名称,第四列表示该图片对应的sequence label。

    最终我们应有以下类似文件结构:

    ```

    |-train_data

    |- train_list

    |- train_imags

    |- 00508_0215.jpg

    |- 00197_1893.jpg

    |- 00007_0219.jpg

    | ...

    ```

    在训练时,我们通过选项`--train_images` 和 `--train_list` 分别设置准备好的`train_images` 和`train_list`。

    >**注:** 如果`--train_images` 和 `--train_list`都未设置或设置为None, reader.py会自动下载使用[示例数据](http://paddle-ocr-data.bj.bcebos.com/data.tar.gz),并将其缓存到`$HOME/.cache/paddle/dataset/ctc_data/data/` 路径下。

    **B. 测试集和评估集**

    测试集、评估集的准备方式与训练集相同。

    在训练阶段,测试集的路径通过train.py的选项`--test_images` 和 `--test_list` 来设置。

    在评估时,评估集的路径通过eval.py的选项`--input_images_dir` 和`--input_images_list` 来设置。

    **C. 待预测数据集**

    预测支持三种形式的输入:

    第一种:设置`--input_images_dir`和`--input_images_list`, 与训练集类似, 只不过list文件中的最后一列可以放任意占位字符或字符串,如下所示:

    ```

    185 48 00508_0215.jpg s

    48 48 00197_1893.jpg s

    338 48 00007_0219.jpg s

    ...

    ```

    第二种:仅设置`--input_images_list`, 其中list文件中只需放图片的完整路径,如下所示:

    ```

    data/test_images/00000.jpg

    data/test_images/00001.jpg

    data/test_images/00003.jpg

    ```

    第三种:从stdin读入一张图片的path,然后进行一次inference.

    ## 模型训练与预测

    ### 训练

    使用默认数据在GPU单卡上训练:

    ```

    env CUDA_VISIBLE_DEVICES=0 python train.py

    ```

    使用默认数据在CPU上训练:

    ```

    env OMP_NUM_THREADS=python train.py --use_gpu False --parallel=False

    ```

    使用默认数据在GPU多卡上训练:

    ```

    env CUDA_VISIBLE_DEVICES=0,1,2,3 python train.py --parallel=True

    ```

    默认使用的是`CTC model`, 可以通过选项`--model="attention"`切换为`attention model`。

    执行`python train.py --help`可查看更多使用方式和参数详细说明。

    图2为使用默认参数在默认数据集上训练`CTC model`的收敛曲线,其中横坐标轴为训练迭代次数,纵轴为样本级错误率。其中,蓝线为训练集上的样本错误率,红线为测试集上的样本错误率。测试集上最低错误率为22.0%.

    6c116986be73e1959df80628031a4206.png

    图 2

    图3为使用默认参数在默认数据集上训练`attention model`的收敛曲线,其中横坐标轴为训练迭代次数,纵轴为样本级错误率。其中,蓝线为训练集上的样本错误率,红线为测试集上的样本错误率。测试集上最低错误率为16.25%.

    f63bbc06812599bfa49770a192e84a2f.png

    图 3

    ## 测试

    通过以下命令调用评估脚本用指定数据集对模型进行评估:

    ```

    env CUDA_VISIBLE_DEVICES=0 python eval.py \

    --model_path="./models/model_0" \

    --input_images_dir="./eval_data/images/" \

    --input_images_list="./eval_data/eval_list"

    ```

    执行`python train.py --help`可查看参数详细说明。

    ### 预测

    从标准输入读取一张图片的路径,并对齐进行预测:

    ```

    env CUDA_VISIBLE_DEVICES=0 python infer.py \

    --model_path="models/model_00044_15000"

    ```

    执行上述命令进行预测的效果如下:

    ```

    ----------- Configuration Arguments -----------

    use_gpu: True

    input_images_dir: None

    input_images_list: None

    model_path: /home/work/models/fluid/ocr_recognition/models/model_00052_15000

    ------------------------------------------------

    Init model from: ./models/model_00052_15000.

    Please input the path of image: ./test_images/00001_0060.jpg

    result: [3298 2371 4233 6514 2378 3298 2363]

    Please input the path of image: ./test_images/00001_0429.jpg

    result: [2067 2067 8187 8477 5027 7191 2431 1462]

    ```

    从文件中批量读取图片路径,并对其进行预测:

    ```

    env CUDA_VISIBLE_DEVICES=0 python infer.py \

    --model_path="models/model_00044_15000" \

    --input_images_list="data/test.list"

    ```

    ## 预训练模型

    |模型| 错误率|

    |- |:-: |

    |[ocr_ctc_params](https://paddle-ocr-models.bj.bcebos.com/ocr_ctc.zip) | 22.3% |

    |[ocr_attention_params](https://paddle-ocr-models.bj.bcebos.com/ocr_attention.zip) | 15.8%|

    >在本文示例中,均可通过修改`CUDA_VISIBLE_DEVICES`改变当前任务使用的显卡号。

    展开全文
  • 论文题目是Attention-based Extraction of Structured ...一些不错的文章:Elijha:Attention和Transformer0 Abstract整个的模型由CNN、RNN和注意力机制组成(CRNN将注意力机制换成了CTC),并取得了不错的成绩:We ...

    论文题目是Attention-based Extraction of Structured Information from Street View Imagery。

    源代码在attention_ocr。

    一些不错的文章:Elijha:Attention和Transformer


    0 Abstract

    整个的模型由CNN、RNN和注意力机制组成(CRNN将注意力机制换成了CTC),并取得了不错的成绩:

    We present a neural networks model --- based on Convolutional Neural networks, Recurrent Neural Networks and a novel attention mechanism --- which achieves 84.2% accuracy on the challenging French Street Name Signs (FSNS) dataset, significantly outperforming the previous state of the art (Smith'16), which achieved 72.46%.

    论文还比较了CNN网络深度对准确率的影响,发现深度越深并不代表准确率越高,第1节论文认为这是由于文字特征偏少的缘故:

    Surprisingly, we find that deeper is not always better (in terms of accuracy, as well as speed).

    1. Introduction

    和以往别的文本识别模型不同,论文提出的模型不仅仅是将给定图片的所有文本提取出来,而是一个更难的情况,只将其中有用的部分提取出来(意味着选择性忽略掉了一部分信息):

    In this paper, we concentrate not just on transcribing all the text in a given image, but instead on the harder problem of extracting a subset of useful pieces of information.

    论文使用的数据集是French Street Name Signs (FSNS),这个数据集之后论文会详细介绍,与一般的数据集有些许不同。

    论文比较了文本识别与图片分类在准确率与深度关系上的不同,文本识别的准确率随着深度的增加先增加,之后下降,而图片分类的准确率随着深度的增加而增加:

    Interestingly, we find that for all three networks, the accuracy initially increases with depth, but then starts to decrease. This is in contrast to models trained on the ILSVRC Imagenet dataset, which is comparable in size to FSNS. For image classification, accuracy tends to increase with depth monotonically.

    论文认为这是任务的难易程度决定的,图片分类需要的特征更多更复杂:

    We believe the difference is that image classification needs very complicated features, which are spatially invariant, whereas, for text extraction, it hurts to use to use such features.

    我个人理解的深度学习的精髓在于浅层特征排列组合成高级特征。图片分类的高级特征特别复杂,比如判断图片为一只猫这种高级特征可能是由猫腿、猫头等次高级特征组成,但猫头这种次高级特征也比一个字符也难的很多,因此我非常认同论文认为OCR需要的特征比较简单这个观点。

    论文认为该论文主要有三点贡献:

    1. 提出了一种新奇的基于注意力模型的架构,使用端到端训练,准确率/速度/泛化性等都非常好;
    2. 在一个新的、更复杂的数据集上表现良好,证明算法的通用性;
    3. 研究了不同深度的CNN网络对速度和准确率的影响,并给出配置的相关建议;

    2. Methods

    模型大致为:使用CNN处理图片,然后用注意力模型加权处理(即对重点部位给予注意力),将结果送进RNN,得到最终结果。

    f018e26a7999c79b708cbfe3140074dd.png

    python/model.py表明了模型的创建方式:

    """Functions to build the Attention OCR model.
    Usage example:
      ocr_model = model.Model(num_char_classes, seq_length, num_of_views)
      data = ... # create namedtuple InputEndpoints
      endpoints = model.create_base(data.images, data.labels_one_hot)
      # endpoints.predicted_chars is a tensor with predicted character codes.
      total_loss = model.create_loss(data, endpoints)
    """

    2.1 CNN-based feature extraction

    论文使用了三种CNN模型:inception-v2(参考深入解读Inception V2之Batch Normalization(附源码))、 inception-v3(参考深入解读Inception V3)、 inception-resnet-v2(参考深入解读Inception V4(附源码))。这三种模型提取特征的能力都非常强,inception-v2稍微弱于另外两个:

    We find that inception-v3 and inception-resnet-v2 perform comparably, and both significantly outperform inception-v2.

    另外论文也比较了预训练与随机初始化的区别,发现没有明显的差别:

    We also compared the effects of pre-training on Imagenet vs. training from random initialization, and found no notable difference, so only report results using the latter.

    有关这个话题的深入探讨,可以看看何凯明的最新文章,我写的介绍在[论文阅读]何凯明:预训练是否需要?。

    feature map的表示方法为

    ,其中,
    表示位置,
    表示通道channel。

    c6ab53509d1d343c8587755d46bc5489.png

    从图1抽出feature map的图就好理解了,四个不同视角的图在宽度方向进行组合。

    对应的代码位于python/model.py中类model中类方法create_base():

    views = tf.split(
        value=images, num_or_size_splits=self._params.num_views, axis=2)
    
    nets = [
        self.conv_tower_fn(v, is_training, reuse=(i != 0))
        for i, v in enumerate(views)
    ]

    参数是由外部传入的,传入的函数位于python/datasets/fsns.py,这个参数定义了不同视角的数量,即四个:

    DEFAULT_CONFIG = {
        ...
        'num_of_views': 4,
        ...
    }

    而conv_tower_fn()也是类model的类函数,每次都会调用inception_v3得到一个module,

    net, _ = inception.inception_v3_base(
                images, final_endpoint=mparams.final_endpoint)

    而inception.inception_v3_base()定义在slim/nets/inception_v3.py,final_endpoint为:

    'conv_tower_fn':
            ConvTowerParams(final_endpoint='Mixed_5d')

    因为nets最终是一个包含4个'Mixed_5d'的feature map,每个feature map的大小是17 x 17 x 768。

    2.2 RNN

    因为CNN得到的结果是多个channel的feature map,但RNN需要的输入量却是序列矩阵,因此需要一个算法将两者联立起来。论文使用的Attention Model机制,关于Attention Model的介绍可参考一文看懂 Attention 机制,你想知道的都在这里了。Enjoy。

    因为是seq2seq,所以序列都是一个一个产生的,这里理解

    就是代表字符产生的顺序,当遇到一个截止符号就会停止产生下一个字符。

    RNN部分还是很常见的类型,有输入

    ,有输出
    ,有中间的隐藏变量
    。这篇论文最重要的注意力机制掩膜
    在下一节2.3节中会详细阐述,这里将其视为一个黑箱模型。

    求解CNN输出向量

    ,是
    维向量。求解公式为:
    ,得到的是一个实数。在第
    步,
    组成了一个
    维向量。

    之后就可以由CNN输出向量

    求解RNN输入

    是上一个预测字符的one-hot向量,比如:

    eabbba21f86990ab69bde2abe2ba3350.png

    上一个预测字符为'e',假设字母表为['a', 'b', 'c', 'd', 'e', 'f'],那么该向量为[0, 0, 0, 0, 1, 0]。

    有了输入和中间状态,就可以得到输出和下一时刻的中间状态了:

    最终的输出结果还要加上CNN输出向量

    ,这里
    维向量。

    最后使用greedy decoding求出所需字符即可:

    这里的

    只是代表字符集合的意思,即从字符集合里挑出一个字符作为最终的字符。

    对应的调用代码位于python/model.py中类model中类方法create_base():

    chars_logit = self.sequence_logit_fn(net, labels_one_hot)

    这个函数主要的代码为:

    layer_class = sequence_layers.get_layer_class(mparams.use_attention,
                                                        mparams.use_autoregression)
    layer = layer_class(net, labels_one_hot, self._params, mparams)
    return layer.create_logits()

    主要调用了python/sequence_layers.py里面的get_layer_class()函数:

    if use_attention and use_autoregression:
        layer_class = AttentionWithAutoregression
    elif use_attention and not use_autoregression:
        layer_class = Attention
    elif not use_attention and not use_autoregression:
        layer_class = NetSlice
    elif not use_attention and use_autoregression:
        layer_class = NetSliceWithAutoregression
    else:
        raise AssertionError('Unsupported sequence layer class')

    可以看到设置为:

    'sequence_logit_fn':
            SequenceLogitsParams(
              use_attention=True,
              use_autoregression=True,
              num_lstm_units=256,
              weight_decay=0.00004,
              lstm_state_clip_value=10.0)

    use_autoregression对应的是2.5节提到的autoregressive connections,因此函数最终调用的是AttentionWithAutoregression()类,而该类继承了类Attention,而类Attention继承了python/sequence_layers.py里面的类SequenceLayerBase,因此layer.create_logits()调用的函数为该类下面的函数:

    def create_logits(self):
        """Creates character sequence logits for a net specified in the constructor.
    
        A "main" method for the sequence layer which glues together all pieces.
    
        Returns:
          A tensor with shape [batch_size, seq_length, num_char_classes].
        """
        with tf.variable_scope('LSTM'):
          first_label = self.get_input(prev=None, i=0)
          decoder_inputs = [first_label] + [None] * (self._params.seq_length - 1)
          lstm_cell = tf.contrib.rnn.LSTMCell(
              self._mparams.num_lstm_units,
              use_peepholes=False,
              cell_clip=self._mparams.lstm_state_clip_value,
              state_is_tuple=True,
              initializer=orthogonal_initializer)
          lstm_outputs, _ = self.unroll_cell(
              decoder_inputs=decoder_inputs,
              initial_state=lstm_cell.zero_state(self._batch_size, tf.float32),
              loop_function=self.get_input,
              cell=lstm_cell)
    
        with tf.variable_scope('logits'):
          logits_list = [
              tf.expand_dims(self.char_logit(logit, i), dim=1)
              for i, logit in enumerate(lstm_outputs)
          ]
    
        return tf.concat(logits_list, 1)

    首先建立lstm_cell,初始化方法使用了orthogonal_initializer()函数,这个函数的作用是生成随机正交矩阵:

    Generates orthonormal matrices with random values.

    方法是使用SVD分解,首先需要产生一个随机矩阵:

    flat_shape = (shape[0], np.prod(shape[1:]))
    w = np.random.randn(*flat_shape)

    np.prod可参考numpy.prod,作用是将大于2维的shape强制转换为二维的shape(不太明白为什么不直接报错?),得到一个flat后的shape,之后使用随机指令(参考numpy.random.randn)生成标准正态分布的随机矩阵。

    之后使用SVD指令来生成正交矩阵:

    u, _, v = np.linalg.svd(w, full_matrices=False)
    w = u if u.shape == flat_shape else v

    np.linalg.svd参考numpy.linalg.svd,参数full_matrices表示u、v不一定是方块矩阵,这样,u、v其中必有一个的维度是和flat_shape的维度是相等的,做一个判断即可,最后的reshape是为了还原之前的np.prod()操作。

    然后通过self.unroll_cell()得到输出,而self.unroll_cell()调用的是类Attention里面的函数:

    def unroll_cell(self, decoder_inputs, initial_state, loop_function, cell):
        return tf.contrib.legacy_seq2seq.attention_decoder(
            decoder_inputs=decoder_inputs,
            initial_state=initial_state,
            attention_states=self._net,
            cell=cell,
            loop_function=self.get_input)

    OK,函数已经指向了legacy_seq2seq,主要的代码文件是seq2seq.py,那就好好读一读这个文件吧。

    注释里讲了该类的作用:

    First, we run the cell on a combination of the input and previous
    attention masks:
      cell_output, new_state = cell(linear(input, prev_attn), prev_state).
    Then, we calculate new attention masks:
      new_attn = softmax(V^T * tanh(W * attention_states + U * new_state))
    and then we calculate the output:
      output = linear(cell_output, new_attn).

    注意此时高度和宽度已经通过代码net = self.pool_views_fn(nets)(具体解释在本文2.4节)合并为一个维度了,所以这里有:

    attention_states: 3D Tensor [batch_size x attn_length x attn_size]

    这里attention_states就是输入的Tensor,而attn_length为4*height*width,attn_size为通道数。

    注意这里hidden对应的是公式

    ,而hidden_features对应的是公式
    ,代码通过卷积的方式来进行这个操作,注意这里num_heads为1:
    # To calculate W1 * h_t we use a 1-by-1 convolution, need to reshape before.
    hidden = array_ops.reshape(attention_states,
                                   [-1, attn_length, 1, attn_size])
    hidden_features = []
    v = []
    attention_vec_size = attn_size  # Size of query vectors for attention.
    for a in xrange(num_heads):
       k = variable_scope.get_variable(
              "AttnW_%d" % a, [1, 1, attn_size, attention_vec_size], dtype=dtype)
       hidden_features.append(nn_ops.conv2d(hidden, k, [1, 1, 1, 1], "SAME"))
       v.append(
              variable_scope.get_variable(
                "AttnV_%d" % a, [attention_vec_size], dtype=dtype))

    里面最重要的函数为attention(),作用在于使用RNN输出的下一状态

    求解attention的下一状态和图像的乘积
    默认为
    )。

    分析函数attention(),首先求

    y = Linear(query, attention_vec_size, True)(query)
    y = array_ops.reshape(y, [-1, 1, 1, attention_vec_size])
    y = math_ops.cast(y, dtype)
    # Attention mask is a softmax of v^T * tanh(...).
    s = math_ops.reduce_sum(v[a] * math_ops.tanh(hidden_features[a] + y),
            [2, 3])

    之后求解

    a = nn_ops.softmax(math_ops.cast(s, dtype=dtypes.float32))
    # Now calculate the attention-weighted vector d.
    a = math_ops.cast(a, dtype)

    然后求attention的下一状态和图像的乘积

    d = math_ops.reduce_sum(
                  array_ops.reshape(a, [-1, attn_length, 1, 1]) * hidden, [1, 2])
    ds.append(array_ops.reshape(d, [-1, attn_size]))

    之后就进入解码的循环:

    for i, inp in enumerate(decoder_inputs):

    而decoder_inputs定义为,这里self._params.seq_length指的是解码的最大长度:

    decoder_inputs = [first_label] + [None] * (self._params.seq_length - 1)

    循环体内先求RNN的输入

    ,其中input_size表示的及时
    input_size = inp.get_shape().with_rank(2)[1]
    ...
    inputs = [inp] + attns
    inputs = [math_ops.cast(e, dtype) for e in inputs]
    x = Linear(inputs, input_size, True)(inputs)

    然后求解RNN:

    # Run the RNN.
    cell_output, state = cell(x, state)

    然后对state求解注意力矩阵:

    # Run the attention mechanism.
    if i == 0 and initial_state_attention:
      with variable_scope.variable_scope(
        variable_scope.get_variable_scope(), reuse=True):
          attns = attention(state)
    else:
      attns = attention(state)

    最后求解输出,表示的公式是

    ,貌似代码里没有softmax?
    with variable_scope.variable_scope("AttnOutputProjection"):
            cell_output = math_ops.cast(cell_output, dtype)
            inputs = [cell_output] + attns
    output = Linear(inputs, output_size, True)(inputs)

    2.3 Spatial attention

    经典的注意力机制是:

    利用了图像内容

    和中间状态
    来得到注意力机制掩膜

    论文认为这种做法是排列不变的,即如果打散了像素的排列(shuffle洗牌机制,跟扑克牌洗牌一样的意思,得到的牌是随机排列的),得到的注意力机制掩膜

    依然是相同的,原因是
    函数:
    is applied elementwise to its vector argument.

    为了让模型知道往哪看,论文在经典的注意力机制上加了两部分内容

    论文说

    是坐标
    处的one-hot向量,这等价于加了一个偏置:

    3bbc3dbc5c4f55b010625b63ccab7b31.png

    对应的调用代码位于python/model.py中类model中类方法create_base():

    nets = [self.encode_coordinates_fn(net) for net in nets]

    这个函数的解释很好的说明了函数的用途,:

    Adds one-hot encoding of coordinates to different views in the networks.
    For each "pixel" of a feature map it adds a onehot encoded x and y coordinates.

    分析函数,首先使用tf.meshgrid()函数构造表示位置的两个的矩阵:

    x, y = tf.meshgrid(tf.range(w), tf.range(h))

    之后增加对每个坐标的注意力:

    w_loc = slim.one_hot_encoding(x, num_classes=w)
    h_loc = slim.one_hot_encoding(y, num_classes=h)

    返回的是卷积输出与坐标注意力的concatenation:

    loc = tf.concat([h_loc, w_loc], 2)
    loc = tf.tile(tf.expand_dims(loc, 0), [batch_size, 1, 1, 1])
    return tf.concat([net, loc], 3)

    另外一篇论文添加的

    ,这可以简单理解为该时刻注意的地方和上一次注意的地方相关,但论文认为在多行文字识别中,有时会从上一行的末尾调到该行的开头,这是一个big jump,这个是很难捕捉到的(即上一时刻注意的地方和这一时刻注意的地方关系不大):
    However, in multiline text recognition problems, we sometimes have to make a big jump to the left side of the line below, which cannot be captured by this approach.

    2.4 Handling multiple views

    FSNS每个图片包含四个视角,每个视角都是

    的图像。论文会将这四个视角的图片拼接起来:
    We then concatenate these horizontally to create a single input feature map.

    如图所示:

    c6ab53509d1d343c8587755d46bc5489.png

    对应的调用代码位于python/model.py中类model中类方法create_base()::

    net = self.pool_views_fn(nets)

    与论文不同的是,代码是在高度方向堆叠的,不过代码也说明了在高度方向或宽度方向堆叠是不重要的:

    Combines output of multiple convolutional towers into a single tensor.
    It stacks towers one on top another (in height dim) in a 4x1 grid.
    The order is arbitrary design choice and shouldn't matter much.

    最后会把高度和宽度合为一个维度:

    net = tf.concat(nets, 1)
    batch_size = net.get_shape().dims[0].value
    feature_size = net.get_shape().dims[3].value
    return tf.reshape(net, [batch_size, -1, feature_size])

    2.5 Training

    论文的目标是最大化

    ,但好像
    的计算方法没有给出,暂且认为是交叉熵吧,具体看了源代码再说吧。

    论文使用了autoregressive connections来计算损失函数,而不是CTC loss,这样做能提高6%的准确率,速度也提升了1倍:

    Our training method allows us to use autoregressive connections easily, which is not possible when using CTC loss, which was used by the previous state of the art model on FSNS.

    论文另外写了些网络参数的设置,一些数据增强的方法可以看看。从训练时间上来看,这个用了40台机器还需要训练10个小时,不知道是不是因为没有pretrain的原因。


    3. Datasets

    3.1 FSNS dataset

    每个图片有4个展开图,每个展开图是

    大小的彩色图片。

    0a2c48c8c862442380aba6a8ddddee3a.png

    图片label最多有37个字符。

    3.2 Street View Business Names Dataset

    每个图片的大小是

    ,这个数据集是比FSNS难的,关键点在于文本可能只占据了图片的一小部分(如果我去做第一个是去做文本检测,再搞文本识别,多做了一步):
    This dataset is significantly more challenging than FSNS, as storefronts have a lot more variation, and richer contextual information, compared to the street name signs. Moreover, the business name can be a small fraction of the entire image.

    74d3e7d82468e2d05d22ddb19b62f6be.png

    4. Experimental Results

    4.1 Accuracy on FSNS

    最终的准确率有84.2%,较之前最高的72.46%提高了12个比分点,还是非常高的:

    Which archives 84.2% accuracy on the challenging French Street Name Signs (FSNS) dataset, significantly outperforming the previous state of the art (Smith'16), which achieved 72.46%.

    另外注意力机制引入位置信息(参考2.2节)也能提高0.9个百分点的准确率:

    Finally, we see that our novel location-aware attention helps by 0.9% over standard attention.

    这说明位置信息还是很有用的,毕竟是二维的图像,位置隐含的信息很多。

    4.2 The effect of depth on FSNS

    计算最复杂的部分就是CNN部分了,论文对CNN的数量等做了研究。随着CNN深度的增加,准确率先升后降:

    We see that the accuracy improves for a while, and then starts to drop as the depth increases. This trend hold for all three models.

    论文认为由两个原因:

    1. Character recognition does not benefit from the high-level features that are needed for image classification;
    2. The spatial resolution of the image features used as input for attention decreases after every max pooling operation, which limits the precision of the attention mask on a particular character;

    第一个原因好理解,特征抽象到一定程度就没有用了。第二个原因在于max pool的影响,比如非常细小的字符如'l'、'1'等经过max pool后会消失的很惨,在实践过程中我也经常发现往往是这类比较细小的字符不能识别出来。

    相同的,感受野也不需要很大,我理解成字符本身很小,很小的感受野就知道该字符与下一个应该attention的字符:

    We don't see any dependency between accuracy and the theoretical receptive field of the neurons in the last convolutional layer, but the effective field of view can be much smaller.

    之后比较了不同的模型,最终选择了inception-v3。

    4.3 Visualization of attention on FSNS

    深度学习大家都说是一个黑盒,所以能可视化还是很牛逼的(我在工作中也尽量这样,第一方便自己debug,也方便老大等别人直观的看到自己的工作成果)。

    不太理解saliency map是什么意思,其组成为

    表示的是预测字符
    的对数。

    attention map就好理解了,不过其尺寸和最后一层feature map的尺寸,是图片尺寸经过pool操作得到的,所以要在图片上绘制注意力图需要将注意力图上采样,即等比例放大:

    Additionly, we visualize the attention map
    by upsampling with nearest-neighbor interpolation to the size of the input.

    之后分析注意力图像的时候提到了一点,因为训练样本是在一个小区间内('Rue'这三个字符才会连续出现),所以导致网络也收敛到一个小区间去了,在预测'ue'的时候会在图像边缘出现绿条:

    Since 'Rue' is the most common beginning of a street name in this dataset, the model can predict the string 'Rue' without paying attention to the image for the next three iterations. This phenomenon is represented by the vertical green bars, which show that the model is just paying attention to the edge of the image, which has no informative content.

    按理说,这种情况'u'和'e'上下一个字符的注意力应该更强些,出现在边缘这个很难理解。

    4.4 Error Analysis on FSNS

    主要分析了一下各种错误类型,一定程度上有助于算法debug。

    4.5 Results on internal datasets

    使用了另外一个数据集进行测试。


    5. Conclusions And Future Work

    之后的工作一方面是在训练RNN上找到更精致的方法,比如scheduled sampling,或者hybrid ML/RL方法。另外,也会去探寻寻找结构化信息的方法。


    测试驱动编程

    最终写一个感觉不错的方法,即代码里广泛使用的测试驱动编程。

    测试代码为:

    cd research/attention_ocr/python
    CUDA_VISIBLE_DEVICES=1 python -m unittest discover -p  '*_test.py'

    最前面的CUDA_VISIBLE_DEVICES=1是设置训练的显卡,如果是单卡的话需要设置CUDA_VISIBLE_DEVICES=0,不写这个也行。

    如果想进行单个测试:

    cd research/attention_ocr/python
    CUDA_VISIBLE_DEVICES=1 python -m unittest datasets/fsns_test.py

    unittest是基于Java的流行测试框架JUint,是一个单元测试工具,利用unittest可以以更加结构化的方式编写大型且周详的测试集。

    其中蕴含的一个思想就是单元测试。单元测试只对程序的各个部分建立测试。*_test.py表示会调用所有符合这种格式的测试文件,在attention_ocr/python有这么多测试文件:

    data_provider_test.py demo_inference_test.py metrics_test.py model_test.py sequence_layers_test.py

    因为Python是没有编译步骤的,所以只需要编辑和运行即可,在Python中运行程序就是测试的部分。所以这段代码其实也是一个测试代码。

    另外一个需要介绍的就是测试驱动编程了。测试驱动编程指的是先测试再编码。这种第一个好处是可以明确需求,因为先写测试代码本身的意思就是将抽象的需求转换成逻辑性非常强的代码。第二个好处就是为改变而计划,一般来说,写代码的bug是层出不穷的,但我认为debug需要避免的一个点就是改好了一个bug而引起了更多的bug(有点像庸医治驼背,直接用板凳把背压平,驼背是好了,但人却over了),防止这个的一个措施就是先写测试文件,这样程序改了哪运行下测试文件就知道有没有引起别的bug了。

    另外再写一写测试驱动编程的四个步骤吧:

    1. 明确特性。将特性记录下来,为其编写测试;
    2. 编写特性的骨架代码。此时测试允许有失败,这表明测试可以失败(不能失败表示这个测试代码是用不了的):在试图让测试成功前,先要看到它失败!
    3. 为特性的骨架编写哑代码(dummy code)。能满足测试要求就行;
    4. 重构代码,使其完成应有的功能;

    (以上单元测试部分等参考Python基础教程(第2版·修订版))。

    unittest的更多知识可以参考单元测试,一种常见的运行方法是:

    python -m unittest mydict_test

    其中参数m表示mod,意思是run library module as a script (terminates option list)。

    另外可以看到attention_ocr里的测试代码还有discover方法,这个可以参考python自动化-unittest批量执行用例(discover),表示的是unittest模块中的TestLoader类中的discover方法来批量执行用例。参数p表示匹配脚本名称的规则。

    【已完结】

    展开全文
  • CRNN 1) 端到端可训练(把CNN和...5) 性能好,而且模型小(参数少) 网络结构 架构包括三部分: 1) 卷积层,从输入图像中提取特征序列; 2) 循环层,预测每一帧的标签分布; 3) 转录层,将每一帧的预测...

    CRNN

    1) 端到端可训练(把CNN和RNN联合训练)

    2) 任意长度的输入(图像宽度任意,单词长度任意)

    3) 训练集无需有字符的标定

    4) 带字典和不带字典的库(样本)都可以使用

    5) 性能好,而且模型小(参数少)


    网络结构

    这里写图片描述

    架构包括三部分:
    1) 卷积层,从输入图像中提取特征序列;
    2) 循环层,预测每一帧的标签分布;
    3) 转录层,将每一帧的预测变为最终的标签序列。

    在CRNN的底部,卷积层自动从每个输入图像中提取特征序列。在卷积网络之上,构建了一个循环网络,用于对卷积层输出的特征序列的每一帧进行预测。采用CRNN顶部的转录层将循环层的每帧预测转化为标签序列。虽然CRNN由不同类型的网络架构(如CNN和RNN)组成,但可以通过一个损失函数进行联合训练。

    2.1. 特征序列提取

    在CRNN模型中,通过采用标准CNN模型(去除全连接层)中的卷积层和最大池化层来构造卷积层的组件。这样的组件用于从输入图像中提取序列特征表示。在进入网络之前,所有的图像需要缩放到相同的高度。然后从卷积层组件产生的特征图中提取特征向量序列,这些特征向量序列作为循环层的输入。具体地,特征序列的每一个特征向量在特征图上按列从左到右生成。这意味着第i个特征向量是所有特征图第i列的连接。在我们的设置中每列的宽度固定为单个像素。

    由于卷积层,最大池化层和元素激活函数在局部区域上执行,因此它们是平移不变的。因此,特征图的每列对应于原始图像的一个矩形区域(称为感受野),并且这些矩形区域与特征图上从左到右的相应列具有相同的顺序。如图2所示,特征序列中的每个向量关联一个感受野,并且可以被认为是该区域的图像描述符。
    这里写图片描述

    2.2. 序列标注

    一个深度双向循环神经网络是建立在卷积层的顶部,作为循环层。循环层预测特征序列x=x1,…,xT中每一帧xt的标签分布yt。循环层的优点是三重的。首先,RNN具有很强的捕获序列内上下文信息的能力。对于基于图像的序列识别使用上下文提示比独立处理每个符号更稳定且更有帮助。以场景文本识别为例,宽字符可能需要一些连续的帧来完全描述(参见图2)。此外,一些模糊的字符在观察其上下文时更容易区分,例如,通过对比字符高度更容易识别“il”而不是分别识别它们中的每一个。其次,RNN可以将误差差值反向传播到其输入,即卷积层,从而允许我们在统一的网络中共同训练循环层和卷积层。第三,RNN能够从头到尾对任意长度的序列进行操作。
    这里写图片描述

    传统的RNN单元在其输入和输出层之间具有自连接的隐藏层。每次接收到序列中的帧xt时,它将使用非线性函数来更新其内部状态ht,该非线性函数同时接收当前输入xt和过去状态ht−1作为其输入:ht=g(xt,ht−1)。那么预测yt是基于ht的。以这种方式,过去的上下文{{xt′}t′

    2.3. 转录

    http://blog.csdn.net/quincuntial/article/details/77679463

    展开全文
  • 本文基于tensorflow、keras/pytorch实现对自然场景的文字检测及端到端的OCR中文文字识别Special Notes原项目里会遗漏各种模型数据,可以在这个百度云盘里找到:Chinese_ocr-ctpn+crnn 。可以使用 demo.py 跑起来整个...
  • 本文介绍图像文本识别(OCR)领域的最新技术进展。首先介绍应用背景,包括面临的...然后介绍最近三年来出现的各种文本边框检测模型、文字内容识别模型、端到端图文识别模型。最后介绍图文识别领域的大型公开数据集。
  • [转]场景文字识别数据集

    千次阅读 2018-12-29 15:18:52
    1.中文数据集 CTW data(Chinese Text in ...清华大学与腾讯共同推出了中文自然文本数据集(Chinese Text in the Wild,CTW)——一个超大的街景图片中文文本数据集,为训练先进的深度学习模型奠定了基础。目前,该...
  • 最近在学习自然场景下的文字识别,有一个比较新的模型EAST,所以学习一下。 论文原地址:https://arxiv.org/abs/1704.03155v2 源码:https://github.com/argman/EAST 模型特点及优势 该模型直接预测全图像...
  • 实现功能文字方向检测 0、90、180、270度检测文字检测 后期将切换到keras版本文本检测 实现keras端到端的文本检测及识别不定长OCR识别环境部署Bash##GPU环境sh setup.sh## CPU环境sh setup-cpu.sh##CPU python3环境...
  • 在本教程中,您将学习如何使用OpenCV通过EAST文本检测器检测自然场景图像中的文本。OpenCV的EAST文本检测器是一种深度学习模型,基于新颖的架构和训练模式。它的优势是(1)可以以13 FPS的速度、几乎实时地在720p...
  • 自然场景文字定位是文字识别中非常重要的一部分。与通用的物体检测相比,文字定位更具挑战性,文字在长宽比、尺度和方向上有更大范围的变化。针对这些问题,本文介绍一种融合文字片段及金字塔网络的场景文字定位方法...
  • GitHub:... |-angle 基于VGG分类模型文字方向检测预测 |-bash 环境安装 |----setup-python3.sh 安装python3环境 |----setup-python3-cpu.sh 安装CPU环境...
  • 摘要 本文介绍图像文本识别(OCR)领域的最新技术进展。...然后介绍最近三年来出现的各种文本边框检测模型、文字内容识别模型、端到端图文识别模型。最后介绍图文识别领域的大型公开数据集。 应用概述 OCR...
  • 阿里的印刷文字识别,实际就是光学字符识别(OCR),它包括自然场景图片的中英文文字检测和识别,比如门店、菜单、路牌等,以及常见的证件类检测和关键区域文字识别:身份证、银行卡、驾驶证、营业执照等。...
  • 译者按: 作为 OCR的 经典模型之一,CRNN在自然场景的文本识别方面应用很广,各种变体层出不穷。CRNN主要应用在文字识别的本身,属于OCR后端任务(前段是CTPN 文字区域识别) 摘要 基于图像的序列识别一直是计算机...
  • 自然场景OCR检测(YOLOv3+CRNN)

    千次阅读 2020-08-25 20:02:55
    目前的主流自然场景OCR模型:文字检测+文字识别 文字检测:解决的问题是哪里有文字,文字的范围有多大。 主要方法: 1.CTPN:水平文字检测,四个自由度,类似物体检测(常用成熟基础)。 2.目标检测:如YOLO、SSD、...
  • 为了提高了静态图像中自然场景分类的识别精度,采用一种基于加权优化的聚类方法。将文本领域的文字激活力矩阵方法应用到图像分类领域,将视觉词汇的数目减少使得运行时间减少,并降低了对存储内存的占用。在特征编码...
  • 「R Talk 」是「北京智源—旷视智能模型设计与图像感知联合实验室」推出的一个深度...近日,旷视科技云服务事业部算法负责人姚聪博士应邀在雷锋网 AI 研习社做了一次主题为自然场景文字检测与识别的线上报告:《Scen...
  • 想象“语音识别”这样的场景,机器通过一定的算法将语音转换为文字,显然这个过程是及其容易出错的。例如,用户发音“Recognize Speech”,机器可能会正确地识别文字为“Recognizespeech”,但是也可以不小心错误地...
  • 1. 什么是语音交互? 语音交互(VUI)指的是人类与设备通过自然语音进行信息的传递。一次完整的语音交互需要经历ASR→NLP→Skill→TTS的流程: ... 解码,即通过声学和语言模型将语音数据识别文字。 ...
  • 103976个英文单词

    2018-12-31 16:44:49
    生成好的103976个英文单词,每行一个。用于自然场景英文文字模型生成和训练识别
  • 这项任务要求模型可以识别图片中的物体、理解物体间的关系,并用一句自然语言表达出来。 应用场景:比如说用户在拍了一张照片后,利用Image Caption技术可以为其匹配合适的文字,方便以后检索或省去用...
  • 文本分类是很多应用场景的基础,某些垃圾邮件识别,舆情分析,情感识别,新闻自动分类,智能客服机器人的合并分类等等。此处分为两个部分: 第1部分:基于scikit学习机器学习的Python库,对比几个传统机器学习方法...
  • 这项任务要求模型可以识别图片中的物体、理解物体间的关系,并用一句自然语言表达出来。应用场景:比如说用户在拍了一张照片后,利用Image Caption技术可以为其匹配合适的文字,方便以后检索或省去用户手动配字;...
  • 本项目基于yolo3 与crnn 实现中文自然场景文字检测及识别 darknet 优化版本:https://github.com/chineseocr/darknet-ocr.git 训练代码(master分支) ocr训练数据集 ocr ctc训练数据集(压缩包解码:chineseocr) ...

空空如也

空空如也

1 2 3 4
收藏数 66
精华内容 26
关键字:

自然场景文字识别模型