CRNN笔记

article/2025/8/23 23:46:57

参考链接:

一文读懂CRNN+CTC文字识别 - 知乎

CTC loss - 知乎

1、背景

文字识别主流的两种算法

 1.1 基于CRNN+CTC

1.2 基于CNN+Seq2Seq+Attention

2、CRNN+CTC原理解析

CRNN+CTC结构图

 以下是根据paddleocr中以mobilenetv3为backbone的网络结构图

model                                           输入:256*3*32*100
BaseModel((backbone): MobileNetV3((conv1): ConvBNLayer((conv): Conv2D(3, 8, kernel_size=[3, 3], stride=[2, 2], padding=1, data_format=NCHW)(bn): BatchNorm())(blocks): Sequential((0): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(8, 8, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(8, 8, kernel_size=[3, 3], padding=1, groups=8, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(8, 8, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(1): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(8, 32, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(32, 32, kernel_size=[3, 3], stride=[2, 1], padding=1, groups=32, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(32, 16, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(2): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(16, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(40, 40, kernel_size=[3, 3], padding=1, groups=40, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(40, 16, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(3): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(16, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(40, 40, kernel_size=[5, 5], stride=[2, 1], padding=2, groups=40, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(40, 10, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(10, 40, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(40, 24, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(4): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(24, 64, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(64, 64, kernel_size=[5, 5], padding=2, groups=64, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(64, 16, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(16, 64, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(64, 24, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(5): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(24, 64, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(64, 64, kernel_size=[5, 5], padding=2, groups=64, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(64, 16, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(16, 64, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(64, 24, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(6): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(24, 120, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(120, 120, kernel_size=[3, 3], padding=1, groups=120, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(120, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(7): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(40, 104, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(104, 104, kernel_size=[3, 3], padding=1, groups=104, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(104, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(8): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(40, 96, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(96, 96, kernel_size=[3, 3], padding=1, groups=96, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(96, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(9): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(40, 96, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(96, 96, kernel_size=[3, 3], padding=1, groups=96, data_format=NCHW)(bn): BatchNorm())(linear_conv): ConvBNLayer((conv): Conv2D(96, 40, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(10): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(40, 240, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(240, 240, kernel_size=[3, 3], padding=1, groups=240, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(240, 60, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(60, 240, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(240, 56, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(11): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(56, 336, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(336, 336, kernel_size=[3, 3], padding=1, groups=336, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(336, 84, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(84, 336, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(336, 56, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(12): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(56, 336, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(336, 336, kernel_size=[5, 5], stride=[2, 1], padding=2, groups=336, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(336, 84, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(84, 336, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(336, 80, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(13): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(80, 480, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(480, 480, kernel_size=[5, 5], padding=2, groups=480, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(480, 120, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(120, 480, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(480, 80, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm()))(14): ResidualUnit((expand_conv): ConvBNLayer((conv): Conv2D(80, 480, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())(bottleneck_conv): ConvBNLayer((conv): Conv2D(480, 480, kernel_size=[5, 5], padding=2, groups=480, data_format=NCHW)(bn): BatchNorm())(mid_se): SEModule((avg_pool): AdaptiveAvgPool2D(output_size=1)(conv1): Conv2D(480, 120, kernel_size=[1, 1], data_format=NCHW)(conv2): Conv2D(120, 480, kernel_size=[1, 1], data_format=NCHW))(linear_conv): ConvBNLayer((conv): Conv2D(480, 80, kernel_size=[1, 1], data_format=NCHW)(bn): BatchNorm())))(conv2): ConvBNLayer((conv): Conv2D(80, 480, kernel_size=[1, 1], data_format=NCHW)       # 输出256 * 480 *1 *25,就是将图片编码为480*25的序列。(bn): BatchNorm())(pool): MaxPool2D(kernel_size=2, stride=2, padding=0))(neck): SequenceEncoder(                         # 输入neck的是256*480*1*25(encoder_reshape): Im2Seq()                    # 经过Im2Seq后,将图片输出为256*25*480的向量序列,25个时间序列,每个序列的维度为480(encoder): EncoderWithRNN((lstm): LSTM(480, 96, num_layers=2(0): BiRNN((cell_fw): LSTMCell(480, 96)(cell_bw): LSTMCell(480, 96))(1): BiRNN((cell_fw): LSTMCell(192, 96)(cell_bw): LSTMCell(192, 96)               #经过BILSTM后输出256*25*192))))(head): CTCHead(                                          #输入256*25*192,输出256*25*96,25是最大字符长度,96是字典的个数加上了sos,bos两个起始符(fc): Linear(in_features=192, out_features=96, dtype=float32))
)
CTCLOSS:最后一步ctcloss就是动态路径规划,设定一些规则,去掉重复的和空白的字符。
forward计算得到loss=每一条可以正确到达lable的路径的概率之和
每一条可以正确到达lable的路径的概率=这条路径的每个字符的概率乘积。
backward计算更新梯度,就是为了更新LSTM中的参数。反向算法:计算在t时刻,以第s个label 开始的后缀到正确结束点的概率和。


http://chatgpt.dhexx.cn/article/Ti7c549K.shtml

相关文章

ocr小白入门CRNN

什么是CRNN CRNN的整体框架图: CRNNCNNRNNCTC 1)CNN主要是为RNN提取特征; 2)RNN主要是将CNN输出的特征序列转换为输出; 3)CTC为翻译层,得到最终的预测结果,由于CTC适合不知道输入…

CRNN代码笔记

CRNN代码笔记 主要由五个模块组成: 数据集的加载与切分CRNN代码复现训练过程预测过程训练过程中对的评估 文章目录 CRNN代码笔记数据集的加载与切分RCNN模型构建训练部分训练辅助函数注意超参数设置判断cuda是否可用,是则基于GPU训练,否则用…

基于CRNN的文本识别

文章目录 0. 前言1. 数据集准备2.构建网络3.数据读取4.训练模型 0. 前言 至于CRNN网络的细节这里就不再多言了,网上有很多关于crnn的介绍,这里直接讲一下代码的实现流程 1. 数据集准备 CRNN是识别文本的网络,所以我们首先需要构建数据集&a…

CRNN论文翻译——中文版

文章作者:Tyan 博客:noahsnail.com | CSDN | 简书 翻译论文汇总:https://github.com/SnailTyan/deep-learning-papers-translation An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Applicatio…

CRNN论文笔记

0. 前言 在这篇论文《An End-to-End Trainable Neural Network for Image-based Sequence Recognition and Its Application to Scene Text Recognition》所讲述的内容便是大名鼎鼎的CRNN网络,中实现了端到端的文本识别。 论文地址 Github地址 该网络具有如下的特点: 1)该模…

CRNN详解

一.概述 常用文字识别算法主要有两个框架: CNNRNNCTC(CRNNCTC)CNNSeq2SeqAttention 本文介绍第一种方法。 CRNN是一种卷积循环神经网络结构,用于解决基于图像的序列识别问题,特别是场景文字识别问题。 文章认为文字识别是对序列的预测方法…

CRNN模型

介绍: 是目前较为流行的图文识别模型,可识别较长的文本序列, 它利用BLSTM和CTC部件学习字符图像中的上下文关系, 从而有效提升文本识别准确率,使得模型更加鲁棒。 CRNN是一种卷积循环神经网络结构,用于解决…

CRNN

CRNN详解:https://blog.csdn.net/bestrivern/article/details/91050960 https://www.cnblogs.com/skyfsm/p/10335717.html 1 概述 传统的OCR识别过程分为两步:单字切割和分类任务。现在更流行的是基于深度学习的端到端的文字识别,即我们不需…

论文阅读 - CRNN

文章目录 1 概述2 模型介绍2.1 输入2.2 Feature extraction2.3 Sequence modeling2.4 Transcription2.4.1 训练部分2.4.2 预测部分 3 模型效果参考资料 1 概述 CRNN(Convolutional Recurrent Neural Network)是2015年华科的白翔老师团队提出的,直至今日&#xff0c…

文本识别网络CRNN

文本识别网络CRNN 简介网络结构CNN层LSTM层CTC Loss 代码实现 简介 CRNN,全称Convolutional Recurrent Neural Network,卷积循环神经网络。 它是一种基于图像的序列识别网络,可以对不定长的文字序列进行端到端的识别。 它集成了卷积神经网络…

CRNN——文本识别算法

常用文字识别算法主要有两个框架: CNNRNNCTC(CRNNCTC)CNNSeq2SeqAttention 文章认为文字识别是对序列的预测方法,所以采用了对序列预测的RNN网络。通过CNN将图片的特征提取出来后采用RNN对序列进行预测,最后通过一个CTC的翻译层得到最终结果…

OCR论文笔记系列(一): CRNN文字识别

👨‍💻作者简介:大数据专业硕士在读,CSDN人工智能领域博客专家,阿里云专家博主,专注大数据与人工智能知识分享,公众号:GoAI的学习小屋,免费分享书籍、简历、导图等资料,更有交流群分享AI和大数据,加群方式公众号回复“加群”或➡️点击链接。 🎉专栏推荐:➡️点…

CRNN——卷积循环神经网络结构

CRNN——卷积循环神经网络结构 简介构成CNNMap-to-Sequence 图解RNNctcloss序列合并机制推理过程编解码过程 代码实现 简介 CRNN 全称为 Convolutional Recurrent Neural Network,是一种卷积循环神经网络结构,主要用于端到端地对不定长的文本序列进行识…

java bean的生命周期

文章转载来自博客园:https://www.cnblogs.com/kenshinobiy/p/4652008.html Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例&#xf…

Spring创建Bean的生命周期

1.Bean 的创建生命周期 UserService.class —> 无参构造方法(推断构造方法) —> 普通对象 —> 依赖注入(为带有Autowired的属性赋值) —> 初始化前(执行带有PostConstruct的方法) —> 初始…

Bean的生命周期(不要背了记思想)

文章内容引用自 咕泡科技 咕泡出品,必属精品 文章目录 1. 应付面试2 可以跟着看源码的图3 学习Bean 的生命周期之前你应该知道什么4 Bean 的完整生命周期 1. 应付面试 你若是真的为面试而来,请把下面这段背下来,应付面试足矣 spring的bean的…

简述 Spring Bean的生命周期

“请你描述下 Spring Bean 的生命周期?”,这是面试官考察 Spring 的常用问题,可见是 Spring 中很重要的知识点。 其实要记忆该过程,还是需要我们先去理解,本文将从以下两方面去帮助理解 Bean 的生命周期: 生…

【Spring源码】讲讲Bean的生命周期

1、前言 面试官:“看过Spring源码吧,简单说说Spring中Bean的生命周期” 大神仙:“基本生命周期会经历实例化 -> 属性赋值 -> 初始化 -> 销毁”。 面试官:“......” 2、Bean的生命周期 如果是普通Bean的生命周期&am…

Spring中bean的生命周期(易懂版)

bean的生命周期 写在前面的话bean的生命周期代码演示 bean的更完整的生命周期添加后置处理器的代码演示 写在前面的话 关于bean的生命周期有很多的文章,但是大多数都是长篇的理论,说来说去也不是很好理解,再次我就整理了一篇比较好理解的bea…

面试官:讲一下Spring Bean的生命周期?

1. 引言 “请你描述下 Spring Bean 的生命周期?”,这是面试官考察 Spring 的常用问题,可见是 Spring 中很重要的知识点。 其实要记忆该过程,还是需要我们先去理解,本文将从以下两方面去帮助理解 Bean 的生命周期&…