当前位置:   article > 正文

RCNN+CTC(CNN+RNN+CTC)复现细节记录

cnn+ctc

由于比赛的原因,接触了图像文字识别,即是对输入的图片,识别其中的文字。然而对于现实世界中随机的一张图片,首先需要文字检测,即检测出图片中文字的所在文字,然后再进行文字识别,由于比赛给出的数据不用考虑文字检测部分,所以此篇文章主要介绍文字识别算法CRNN。

CRNN算法思想很简单,架构模型为CNN+RNN,CNN用于提取图片的特征,然后转换成特征序列,作为RNN的序列输入,RNN网络用于预测序列,RNN生成的序列经过CTC与label进行校正,CTC的原理很复杂,所幸的是tensorFlow中对此算法进行封装,tf.nn.ctc_loss,所以就不深入了解CTC算法了。

虽然看着CRNN此算法很简单,但是也算是首次接触,还是遇见了数不尽的坑,其中最大的问题,就是不论是调整学习率还是CNN/RNN结构,或者label的表示方式,输出结果总是类似,两个序列之间的编辑距离不会变化,(在知乎对此问题的提问)debug期间,对着代码排查了好几遍,原以为是什么地方理解错误,最后主要发现是优化函数选择问题,论文中建议使用Adadelta优化函数,我当时手欠打成了Adam优化函数。

完整代码见:https://github.com/skloisMary/TensorFlow-CRNN

整个流程包括可概括成五步:

文件作用
extract.py提取图片标签中的字符,unique之后所有的字符构成字典,并把字典写入map.json文件中
TFrecorde.pyTFRecord是谷歌推荐的一种二进制文件格式,将数据集保存成tfrecorde文件
Model.py定义模型,train/test
run.py主程序
inference.py使用新数据,引用模型

1. tf.nn.ctc_loss函数

作用:处理输出标签和真实标签之间的CTC损失

  1. tf.nn.ctc_loss(
  2. labels,
  3. inputs,
  4. sequence_length,
  5. preprocess_collapse_repeated=False,
  6. ctc_merge_repeated=True,
  7. ignore_longer_outputs_than_inputs=False,
  8. time_major=True
  9. )

输入参数:

  • labels 是一个int32类型的稀疏张量SparseTensorlabels.indices[i, :] == [b, t] 表示label.value[i]保存着(batch b, time t)的id,label.values[i] must take on value in [0, num_labels]
  • inputs: 通常是RNN输出的标签预测值logits,是一个3-D浮点型张量,如果time_major为True(默认),那么inputs的shape形状为[max_time, batch_size, num_classes],如果time_major为False,那么inputs的shape形状为[ batch_size, max_time, num_classes]
  • sequence_lenght: 一个1-D int32的向量,size为[batch_size],vector中的每个值表示序列的长度,max_time_step.
  • preprocess_collapse_repeated,布尔值,默认为False. 是否预处理,将重复的label合并
  • ctc_merge_repeated, 布尔值,默认为True
  • ignore_longer_outputs_than_inputs,布尔值,默认为False。如果输入inputs长度小于输出预测序列的长度,那么默认情况下,会报错Not enough time for target transition sequence, 可以将此参数设定为True,会自动忽略此错误,使之变成一个warning,或者扩展设定的最大宽度大小.
  • time_major,参数inputs张量的shape定义形式。

输出:

  • 一个1-D浮点性张量,size为[batch_size],里面取值为负log概率(negative log probabilities)

2. tf.nn.ctc_beam_search_decoder函数

作用:此函数对作为输入传进来的logits进行解码

  1. tf.nn.ctc_beam_search_decoder(
  2. inputs,
  3. sequence_length,
  4. beam_width=100,
  5. top_paths=1,
  6. merge_repeated=True
  7. )

输入参数:

  • inputs:  logits, 一个3-D浮点性张量,shape形状为[max_time, batch_size, num_classes]
  • sequence_length: 一个1-D int32的向量,size为[batch_size],vector中的每个值表示序列的长度
  • merge_repeated: 布尔值,默认为True。在输出的beams中,合并重复的类别。也就是说,在一个beam中,如果连续的输出是一样的,只有第一个被保留下来。举例为,假如序列为[ABB*B*B],其中*表示空格,设定merge_repeated为True, 那么返回的值AB,如果设定merge_repeated为False,那么返回的值为ABBB

输出:

  • 一个元组(decoded, log_probability)
  • decoded: 一个top_paths(默认为1)长度的list,也就是只包含一个元素的list, decoded[j]是一个稀疏张量,保存着解码的输出decoded[0].indices: 索引矩阵;decoded[0].value: 值向量,向量中保存的是解码的类别;decoded[j].dense_shape:shape向量
  • log_probability: 一个浮点型的矩阵,大小为(batch_size * top_maths), top_maths默认为1, 包含序列的log-probabilities

3. tf.edit_distance函数

作用:计算两个序列之间的编辑距离(Levenshtein distance),所谓编辑距离就是针对两个字符串的差异程度的量化测量,量测方式是至少需要多少次的处理才能将一个字符串变成另一个字符串

  1. tf.edit_distance(
  2. hypothesis,
  3. truth,
  4. normalize=True,
  5. name='edit_distance'
  6. )

输入参数:

  • hypothesis: 稀疏张量,为标签输出序列
  • truth: 稀疏张量,为真实标签序列
  • normalize: 布尔值,如果为True,归一化编辑距离

输出:

  • 一个稠密张量

参考:

[1]. Tensorflow API, tf.nn._ctc_loss

[2]. Tensorflow API, tf.nn.ctc_beam_search_decoder

[3]. Tensorflow API, tf.edit_distance

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/577273
推荐阅读
  

闽ICP备14008679号