手写OCR识别

  • 一:官方支持的数据格式?
    • 1.官方文档
      • 1.1 PaddleOCR 支持两种数据格式:
      • 1.2 训练数据的默认存储路径
      • 1.3 自定义数据集的准备
        • 1.3.1 通用数据集
        • 1.3.2 lmdb数据集
          • 1.3.2.1 lmdb基本函数:
          • 1.3.2.2 创建一个 lmdb 环境:
          • 1.3.2.3 修改数据库内容:
          • 1.3.2.4 查询数据库内容:
          • 1.3.2.5 完整的demo如下:
          • 1.3.2.6 将图片和对应的文本标签存放到lmdb数据库:
          • 1.3.2.7 从lmdb数据库中读取图片数据:
        • 1.3.3文字标签数字化(涉及到解码部分,训练输入的数据不用编码,按一般格式输入即可):
    • 2.FAQ中的相关问题
      • 2.1 Q:对于图片中的密集文字,有什么好的处理方法?
      • 2.2 Q:文本行较紧密的情况下如何准确检测?
      • 2.3 Q:文档场景中,使用DB模型会出现整行漏检的情况应该怎么解决?
      • 2.4 Q: 弯曲文本(如略微形变的文档图像)漏检问题
      • 2.5 Q: 如何识别文字比较长的文本?
      • 2.6 Q: 使用预训练模型进行预测,对于特定字符识别识别效果较差,怎么解决?
      • 2.7 Q: 在使用训练好的识别模型进行预测的时候,发现有很多重复的字,这个怎么解决呢?
      • 2.8 Q: 模型独立性—— 只想要识别票据中的部分片段,重新训练它的话,只需要训练文本检测模型就可以了吗?问文本识别,方向分类还是用原来的模型这样可以吗?
      • 2.9 Q: 遇到中英文识别模型不支持的字符,该如何对模型做微调?
      • 2.10 Q: 特殊字符(例如一些标点符号)识别效果不好怎么办?
      • 2.11 Q: 单张图上多语种并存识别(如单张图印刷体和手写文字并存),应该如何处理?
      • 2.12 Q: 如何更换文本检测/识别的backbone?
      • 2.13 Q: 参照文档做实际项目时,是重新训练还是在官方训练的基础上进行训练?具体如何操作?
      • 2.14 Q: 为什么在checkpoints中load下载的预训练模型会报错?
      • 2.15 Q: 如何对检测模型finetune,比如冻结前面的层或某些层使用小的学习率学习?
      • 2.16 Q: 在识别模型中,为什么降采样残差结构的stride为(2, 1)?
      • 2.17 Q: 训练识别时,如何选择合适的网络输入shape?
      • 2.18 Q: 识别模型框出来的位置太紧凑,会丢失边缘的文字信息,导致识别错误
      • 2.19 Q: 文本识别训练不加LSTM是否可以收敛?
      • 2.20 Q: 文本识别中LSTM和GRU如何选择?
      • 2.21 Q: 对于CRNN模型,backbone采用DenseNet和ResNet_vd,哪种网络结构更好?
      • 2.22 Q: 如何根据不同的硬件平台选用不同的backbone?
      • 2.23 Q: 文字识别模型模型的输出矩阵需要进行解码才能得到识别的文本。代码中实现为preds_idx = preds.argmax(axis=2),也就是最佳路径解码法。这是一种贪心算法,是每一个时间步只将最大概率的字符作为当前时间步的预测输出,但得到的结果不一定是最好的。为什么不使用beam search这种方式进行解码呢?
      • 2.24 Q: PP-OCR检测效果不好,该如何优化?
      • 2.25 Q: DB有些框太贴文本了反而去掉了一些文本的边角影响识别,这个问题有什么办法可以缓解吗?
      • 2.26 Q: 训练模型和测试模型的检测结果差距较大
      • 2.27 Q: 某个类别的样本比较少,通过增加训练的迭代次数或者是epoch,变相增加小样本的数目,这样能缓解这个问题么?
      • 2.28 Q: 如何调试数据读取程序?
      • 2.29 Q: 中文文本检测、文本识别构建训练集的话,大概需要多少数据量
      • 2.30 Q: config yml文件中的ratio_list参数的作用是什么?
      • 2.31 Q: 怎么加速训练过程呢?
      • 2.32 一些特殊场景的数据识别效果差,但是数据量很少,不够用来finetune怎么办?
      • 2.33 如何合成手写中文数据集?
      • 2.34 PaddleOCR默认不是200个step保存一次模型吗?为啥文件夹下面都没有生成
      • 2.35 PaddleOCR在训练的时候一直使用cosine_decay的学习率下降策略,这是为什么呢?
      • 2.36 Cosine学习率的更新策略是怎样的?训练过程中为什么会在一个值上停很久?
      • 2.37 之前的CosineWarmup方法为什么不见了?
      • 2.38 训练识别和检测时学习率要加上warmup,目的是什么?
      • 2.39 训练过程中,训练程序意外退出/挂起,应该如何解决?
      • 2.40 训练程序启动后直到结束,看不到训练过程log?
      • 2.41 配置文件中的参数num workers是什么意思,应该如何设置?
    • 3.程序中的相关内容
      • 4.搞清楚各种配置文件yml对应关系
  • 二:CRNN网络设计
    • 2.1 网络结构
    • 2.2 输入数据大小
    • 2.3 处理过程
  • 三:PaddleOCR使用的骨干网
  • 四:CAISA-HWDB数据格式及转换
    • 4.1 官网描述
      • 4.1.1 类别
        • 4.1.1.1 Feature Data
        • 4.1.1.2 Character Sample Data
        • 4.1.1.3 Textline (Page) Data——使用
        • 4.1.1.4 Competition Test Data
      • 4.1.2 数据集的划分
    • 4.2 读取 gnt 解码为 字+img
    • 4.3 读取 dgrl 解码为多行手写文本的图片+ 相应的VOC格式的xml文件
    • 4.4 数据量
      • 4.4.1 训练
      • 4.4.2 验证
      • 4.4.2 分布
  • 五:使用单字训练还是文本行训练?——文本行
    • 5.1 提取单行文本+标签
  • 六:格式转换
  • 七:数据增广处理
    • 7.1 印刷体数据集
    • 7.2 场景文本数据集
    • 7.3 数字+英文
  • 八:环境配置
    • 8.1 CUDA版本以及Cudnn版本
  • 九: 训练
    • 9.2 训练命令
    • 9.2 模型转换——转Inference模型测试
  • 十: 使用训练117epoch-best acc参数的测试
    • 10.1 关于单行文本中文本弯曲问题
    • 10.2 英文识别能力——
    • 10.3 印刷体数字识别能力——
    • 10.4 针对印刷字体的识别能力
      • 10.4.1 测试1
      • 10.4.2 测试2
    • 10.5 针对场景文字的识别能力
    • 10.6 针对手写印刷体共存
      • 10.6.1 手写印刷体大小不一
        • 10.6.1.1 共存,距离过近——除去识别模型本身的识别精度问题,无法识别是裁剪的问题
      • 10.6.2 官方给的手写印刷共存的处理思路,关键在于分类和两个识别模型
    • 10.7 针对常规难题的测试(基于117左右-best)
      • 10.7.1 连笔
      • 10.7.2 书写不水平
      • 10.7.3 字迹潦草
      • 10.7.4 相似字的识别
      • 10.7.5 带表格线和不带表格线
      • 10.7.6 多行文字的识别能力
        • 10.7.6.1 测试1
        • 10.7.6.2 测试2
    • 10. 使用test数据集中的图片测试(117左右best)
      • 10. .1 006-P18_3.jpg
      • 10. .2 006-P19_3.jpg
      • 10. .3 013-P16_0.jpg
      • 10. .4 020-P16_0.jpg
  • 十一: 问题总结
  • 十一: 几点想法
    • 1.手写体 场景文字 均衡数据及分布 一起训练???
    • 2.finetune的操作,怎样固定层数???
    • 3.和不同手写人的数据分布有关吗,一段时间内输入的都是同一个人的数据,并没有穿插其他人的
  • 附录一 : 好的参考
  • 附录二: 代码组织结构

蓦然回首,那人却在灯火阑珊处。
此文从20220421开始着手,
至20220425为初稿,
从基础理论看起,
以官方文档为根本,
经过自己的一番摸索,
也倒是大致了解了整个过程,
最后却发现最有用的却是已经被官方总结好了
放在这里让后来人少走弯路。
虽然自己摸爬滚打许多天不如一篇官方文章,
但是,
真的没有收获吗?
我觉得未必。

编辑记录
————————————————
20220421 起稿
20220425 21:49 一稿发布
20220426 编辑
20220427 已成功能够开始训练,涉及到手写体数据库格式转换和配置过程后面补齐
20220428 摸索服务器训练
20220502 尝试使用epoch31的训练数据识别(epoch: [31/500], iter: 10105, lr: 0.000993, loss: 7.327022, acc: 0.558589,)
20220503 修补训练数据集的生成与配置使用;测试训练模型的识别能力
202205__ 有使用epoch117数据识别,应该为第10节的测试
202205__ 未完待续…
20220512 搞清train与test数据的相关性——不同作者书写,不相关

一:官方支持的数据格式?

1.官方文档

1.1 PaddleOCR 支持两种数据格式:

  • lmdb 用于训练以lmdb格式存储的数据集(LMDBDataSet);
  • 通用数据 用于训练以文本文件存储的数据集(SimpleDataSet);

1.2 训练数据的默认存储路径

PaddleOCR/train_data/

1.3 自定义数据集的准备

1.3.1 通用数据集

(见官网文档)

1.3.2 lmdb数据集

(引用——by程序员阿德)

**什么是lmdb数据集?**
1.英文全名:Lightning Memory-Mapped Database (LMDB);
2.对应中文名:轻量级内存映射数据库。
3.因为最开始 Caffe 就是使用的这个数据库,所以网上的大多数关于 LMDB 的教程都通过 Caffe 实现的
4.LMDB属于key-value数据库,而不是关系型数据库( 比如 MySQL ),LMDB提供 key-value 存储,其中每个键值对都是我们数据集中的一个样本。LMDB的主要作用是提供数据管理,可以将各种各样的原始数据转换为统一的key-value存储。
5.LMDB的文件结构很简单,一个文件夹,里面是一个数据文件和一个锁文件。数据随意复制,随意传输。它的访问简单,不需要单独的数据管理进程。只要在访问代码里引用LMDB库,访问时给文件路径即可。
1.3.2.1 lmdb基本函数:
  1. env = lmdb.open():创建 lmdb 环境
  2. txn = env.begin():建立事务
  3. txn.put(key, value):进行插入和修改
  4. txn.delete(key):进行删除
  5. txn.get(key):进行查询
  6. txn.cursor():进行遍历
  7. txn.commit():提交更改
1.3.2.2 创建一个 lmdb 环境:
# 安装:pip install lmdb
import lmdbenv = lmdb.open(lmdb_path, map_size=1099511627776)
# lmdb_path:指定存放生成的lmdb数据库的文件夹路径,如果没有该文件夹则自动创建。
# map_size: 指定创建的新数据库所需磁盘空间的最小值,1099511627776B=1T。# 会在指定路径下创建 data.mdb 和 lock.mdb 两个文件,一是个数据文件,一个是锁文件。
1.3.2.3 修改数据库内容:
# 创建一个事务(transaction) 对象 txn,所有的操作都必须经过这个事务对象。
# 因为我们要对数据库进行写入操作,所以将 write 参数置为 True,默认其为 False。
txn = env.begin(write=True)# 使用 .put(key, value) 对数据库进行插入和修改操作,传入的参数为键值对。
# 需要在键值字符串后加 .encode() 改变其编码格式,
# 将 str 转换为 bytes 格式,否则会报该错误:# TypeError: Won't implicitly convert Unicode to bytes; use .encode()。
# 在后面使用 .decode() 对其进行解码得到原数据。
# insert/modify
txn.put(str(1).encode(), "Alice".encode())
txn.put(str(2).encode(), "Bob".encode())# 使用 .delete(key) 删除指定键值对。
# delete
txn.delete(str(1).encode())# 对LMDB的读写操作在事务中执行,需要使用 commit 方法提交待处理的事务。
txn.commit()
1.3.2.4 查询数据库内容:
# 每次 commit() 之后都要用 env.begin() 更新 txn(得到最新的lmdb数据库)。
txn = env.begin()# 使用 .get(key) 查询数据库中的单条记录。
print(txn.get(str(2).encode()))# 使用 .cursor() 遍历数据库中的所有记录,
# 其返回一个可迭代对象,相当于关系数据库中的游标,每读取一次,游标下移一位。
for key, value in txn.cursor():print(key, value)env.close()
1.3.2.5 完整的demo如下:
import lmdb
import os, sysdef initialize():env = lmdb.open("lmdb_dir")return envdef insert(env, sid, name):txn = env.begin(write=True)txn.put(str(sid).encode(), name.encode())txn.commit()def delete(env, sid):txn = env.begin(write=True)txn.delete(str(sid).encode())txn.commit()def update(env, sid, name):txn = env.begin(write=True)txn.put(str(sid).encode(), name.encode())txn.commit()def search(env, sid):txn = env.begin()name = txn.get(str(sid).encode())return namedef display(env):txn = env.begin()cur = txn.cursor()for key, value in cur:print(key, value)env = initialize()print("Insert 3 records.")
insert(env, 1, "Alice")
insert(env, 2, "Bob")
insert(env, 3, "Peter")
display(env)print("Delete the record where sid = 1.")
delete(env, 1)
display(env)print("Update the record where sid = 3.")
update(env, 3, "Mark")
display(env)print("Get the name of student whose sid = 3.")
name = search(env, 3)
print(name)# 最后需要关闭关闭lmdb数据库
env.close()# 执行系统命令
os.system("rm -r lmdb_dir")
1.3.2.6 将图片和对应的文本标签存放到lmdb数据库:
在这里插入代码片
1.3.2.7 从lmdb数据库中读取图片数据:
在这里插入代码片

做OCR,在搜索中常常碰到一个优质博主:冠军的试炼(【OCR技术系列之八】端到端不定长文本识别CRNN代码实现)
这篇文章对理解CRNN训练的数据输入有帮助

1.3.3文字标签数字化(涉及到解码部分,训练输入的数据不用编码,按一般格式输入即可):

在数据准备部分还有一个操作需要强调的,那就是文字标签数字化,即我们用数字来表示每一个文字(汉字,英文字母,标点符号)。

比如“我”字对应的id是1,
“l”对应的id是1000,
“?”对应的id是90,
如此类推,这种编解码工作使用字典数据结构存储即可,训练时先把标签编码(encode),预测时就将网络输出结果解码(decode)成文字输出
参考代码:

# 定义str to label 类
class strLabelConverter(object):"""Convert between str and label.转换str和labelNOTE:Insert `blank` to the alphabet for CTC.Args:alphabet (str): set of the possible characters.ignore_case (bool, default=True): whether or not to ignore all of the case."""def __init__(self, alphabet, ignore_case=False):self._ignore_case = ignore_caseif self._ignore_case:alphabet = alphabet.lower()self.alphabet = alphabet + '-'  # for `-1` indexself.dict = {}for i, char in enumerate(alphabet):# NOTE: 0 is reserved for 'blank' required by wrap_ctcself.dict[char] = i + 1def encode(self, text):"""Support batch or single str.Args:text (str or list of str): texts to convert.Returns:torch.IntTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts.torch.IntTensor [n]: length of each text."""length = []result = []for item in text:item = item.decode('utf-8', 'strict')length.append(len(item))for char in item:index = self.dict[char]result.append(index)text = result# print(text,length)return (torch.IntTensor(text), torch.IntTensor(length))def decode(self, t, length, raw=False):"""Decode encoded texts back into strs.Args:torch.IntTensor [length_0 + length_1 + ... length_{n - 1}]: encoded texts.torch.IntTensor [n]: length of each text.Raises:AssertionError: when the texts and its length does not match.Returns:text (str or list of str): texts to convert."""if length.numel() == 1:length = length[0]assert t.numel() == length, "text with length: {} does not match declared length: {}".format(t.numel(),length)if raw:return ''.join([self.alphabet[i - 1] for i in t])else:char_list = []for i in range(length):if t[i] != 0 and (not (i > 0 and t[i - 1] == t[i])):char_list.append(self.alphabet[t[i] - 1])return ''.join(char_list)else:# batch modeassert t.numel() == length.sum(), "texts with length: {} does not match declared length: {}".format(t.numel(), length.sum())texts = []index = 0for i in range(length.numel()):l = length[i]texts.append(self.decode(t[index:index + l], torch.IntTensor([l]), raw=raw))index += lreturn texts
  • 所以要看PaddleOCR这一部分设置的对应关系

2.FAQ中的相关问题

2.1 Q:对于图片中的密集文字,有什么好的处理方法?

A:可以先试用预训练模型测试一下,例如DB+CRNN,判断下密集文字图片中是检测还是识别的问题,然后针对性的改善。还有一种是如果图象中密集文字较小,可以尝试增大图像分辨率,对图像进行一定范围内的拉伸,将文字稀疏化,提高识别效果。

2.2 Q:文本行较紧密的情况下如何准确检测?

A:使用基于分割的方法,如DB,检测密集文本行时,最好收集一批数据进行训练,并且在训练时,并将生成二值图像的shrink_ratio参数调小一些。

2.3 Q:文档场景中,使用DB模型会出现整行漏检的情况应该怎么解决?

A:可以在预测时调小 det_db_box_thresh 阈值,默认为0.5, 可调小至0.3观察效果。

2.4 Q: 弯曲文本(如略微形变的文档图像)漏检问题

A: db后处理中计算文本框平均得分时,是求rectangle区域的平均分数,容易造成弯曲文本漏检,已新增求polygon区域的平均分数,会更准确,但速度有所降低,可按需选择,在相关pr中可查看可视化对比效果。该功能通过参数 det_db_score_mode进行选择,参数值可选[fast(默认)、slow],fast对应原始的rectangle方式,slow对应polygon方式。感谢用户buptlihang提pr帮助解决该问题

PaddleOCR手写体训练摸索相关推荐

  1. CNN卷积神经网络—LeNet原理以及tensorflow实现mnist手写体训练

    CNN卷积神经网络-LeNet原理以及tensorflow实现minst手写体训练 1. LeNet原理 2.tensorflow实现Mnist手写体识别 1.安装tensorflow 2.代码实现手 ...

  2. 【计算机视觉】Mnist手写体训练

    一.原理 1. Mnist数据集简介 MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分: Training set images: ...

  3. python+tensorflow LeNet---深度学习MINST手写体训练识别

    数据样本 1.首先我们要有手写体的数据集文件 下载地址MINST手写体数据 2.训练集:共60000个,其中55000个用于训练,另外5000个用于验证   测试集:共10000个  训练集:和机器学 ...

  4. win10caffe-GPU环境配置+mnist手写体训练以及python接口导入详细教程(一步成功)

    什么是caffe Caffe是一个深度学习框架,具有表达力强.速度快和模块化的思想,由伯克利视觉学习中心(BVLC)和社区贡献者开发.Yangqing Jia在加州大学伯克利分校攻读博士期间创建了这个 ...

  5. paddleocr模型训练

    1:下载paddleocr develop和release分支都可以,这里以release为例 下载地址:https://github.com/PaddlePaddle/PaddleOCR paddl ...

  6. 百度paddleocr检测训练

    一.源码准备 下载地址:paddleocr 注意:如果需要使用tensorrt加速,需要下载2.2以上版本的 运行环境 1.准备一个新的虚拟环境,安装下载的源码当中对应的requirements.tx ...

  7. OCR/STR生僻字数据训练 | PaddleOCR的Fine-tune常见问题汇总(3)

    1.印章如何识别? 使用带tps的识别网络或abcnet,2.使用极坐标变换将图片拉平之后使用crnn 2.多语言的字典里是混合了不同的语种,这个是有什么讲究吗?统一到一个字典里会对精度造成多大的损失 ...

  8. paddleocr训练自己的数据最简单方式软件一键训练

    paddleocr训练一般需要训练自己的文本检测模型或者文本识别模型,对于刚入门编程小白或者对paddleocr还不太熟悉的同学们很难短时间上手,也不知道怎么去配置让自己的数据集训练起来.为了解决pa ...

  9. PaddleOCR使用笔记之模型训练

    目录 简介 模型训练 步骤一:文本检测模型(`detection`) 1.准备训练数据集 2.下载预训练模型 模型介绍 下载预训练模型 3. 开始训练 断点训练 4.模型评估 5.模型测试 6.训练模 ...

  10. opencv#4 手写体识别:自建训练集完美

    一直在研究手写体识别,最终的目标是识别自己写的数字,目前能正确识别我自己写的字,识别率达到98.62%,可以识别自己的大小不一字体.学习例程如下: 1.学习opencv的自带手写体识别例程,发现无法识 ...

最新文章

  1. 0320互联网新闻 | 网易《明日之后》全球营收突破1.25亿美元;阿里AI labs宣布投入1亿元进行方言保护...
  2. Spring Boot中使用多数据库
  3. 状态模式和策略模式的区别
  4. weex 在 iOS 上如何实现常见的网络缓存
  5. 在线生成艺术字_生成艺术:如何修改绘画
  6. 微信小程序|开发实战篇之一
  7. 爬虫_淘宝(selenium)
  8. Webservice更新时出错。下载”。。。”时出错。请求失败,错误信息为:
  9. 0-9 倒计时 8x8 点阵 实现
  10. ubuntu16.04安装翻译软件stardict
  11. EFI Driver Model(中)-PCI 驱动设计
  12. 用docx把文字写入word并且插入图片、表格
  13. 7、对数组中下标为奇(偶)数的元素进行操作
  14. latex转word_最有效率的论文排版利器来了,word排版再见吧~
  15. MT7628 wifi模块,MTK路由器芯片介绍
  16. 事务原子性、一致性、持久性的实现原理
  17. 十问旷视印奇、唐文斌:AI企业都在经历「死亡之谷」
  18. Xcode 下载真机包调试
  19. PeckShield宣布与IOST达成全球战略合作
  20. sparksql中大小表jion

热门文章

  1. 基于C语言设计的仓库管理系统(小超市)
  2. 大学生竞赛管理系统项目
  3. MySQL彻底卸载干净
  4. STM32F407控制舵机
  5. 数据库设计--企业人事管理系统(有关数据库的课程设计)
  6. Arduino学习(一)蓝牙模板之JDY-16 BLE(1)
  7. PEST、波特五力、波士顿矩阵、SWOT、价值链等战略分析方法整理学习笔记
  8. 一起学英语 | 用JavaScript实现数字阶乘的三种方法
  9. 知识付费系统源码基于PHP开源的网站内容付费源码|知识付费小程序源码
  10. echarts 实现世界地图地域流向炫酷效果