PaddleOCR手写体训练摸索
手写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基本函数:
env = lmdb.open()
:创建 lmdb 环境txn = env.begin()
:建立事务txn.put(key, value)
:进行插入和修改txn.delete(key)
:进行删除txn.get(key)
:进行查询txn.cursor()
:进行遍历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手写体训练摸索相关推荐
- CNN卷积神经网络—LeNet原理以及tensorflow实现mnist手写体训练
CNN卷积神经网络-LeNet原理以及tensorflow实现minst手写体训练 1. LeNet原理 2.tensorflow实现Mnist手写体识别 1.安装tensorflow 2.代码实现手 ...
- 【计算机视觉】Mnist手写体训练
一.原理 1. Mnist数据集简介 MNIST 数据集可在 http://yann.lecun.com/exdb/mnist/ 获取, 它包含了四个部分: Training set images: ...
- python+tensorflow LeNet---深度学习MINST手写体训练识别
数据样本 1.首先我们要有手写体的数据集文件 下载地址MINST手写体数据 2.训练集:共60000个,其中55000个用于训练,另外5000个用于验证 测试集:共10000个 训练集:和机器学 ...
- win10caffe-GPU环境配置+mnist手写体训练以及python接口导入详细教程(一步成功)
什么是caffe Caffe是一个深度学习框架,具有表达力强.速度快和模块化的思想,由伯克利视觉学习中心(BVLC)和社区贡献者开发.Yangqing Jia在加州大学伯克利分校攻读博士期间创建了这个 ...
- paddleocr模型训练
1:下载paddleocr develop和release分支都可以,这里以release为例 下载地址:https://github.com/PaddlePaddle/PaddleOCR paddl ...
- 百度paddleocr检测训练
一.源码准备 下载地址:paddleocr 注意:如果需要使用tensorrt加速,需要下载2.2以上版本的 运行环境 1.准备一个新的虚拟环境,安装下载的源码当中对应的requirements.tx ...
- OCR/STR生僻字数据训练 | PaddleOCR的Fine-tune常见问题汇总(3)
1.印章如何识别? 使用带tps的识别网络或abcnet,2.使用极坐标变换将图片拉平之后使用crnn 2.多语言的字典里是混合了不同的语种,这个是有什么讲究吗?统一到一个字典里会对精度造成多大的损失 ...
- paddleocr训练自己的数据最简单方式软件一键训练
paddleocr训练一般需要训练自己的文本检测模型或者文本识别模型,对于刚入门编程小白或者对paddleocr还不太熟悉的同学们很难短时间上手,也不知道怎么去配置让自己的数据集训练起来.为了解决pa ...
- PaddleOCR使用笔记之模型训练
目录 简介 模型训练 步骤一:文本检测模型(`detection`) 1.准备训练数据集 2.下载预训练模型 模型介绍 下载预训练模型 3. 开始训练 断点训练 4.模型评估 5.模型测试 6.训练模 ...
- opencv#4 手写体识别:自建训练集完美
一直在研究手写体识别,最终的目标是识别自己写的数字,目前能正确识别我自己写的字,识别率达到98.62%,可以识别自己的大小不一字体.学习例程如下: 1.学习opencv的自带手写体识别例程,发现无法识 ...
最新文章
- 0320互联网新闻 | 网易《明日之后》全球营收突破1.25亿美元;阿里AI labs宣布投入1亿元进行方言保护...
- Spring Boot中使用多数据库
- 状态模式和策略模式的区别
- weex 在 iOS 上如何实现常见的网络缓存
- 在线生成艺术字_生成艺术:如何修改绘画
- 微信小程序|开发实战篇之一
- 爬虫_淘宝(selenium)
- Webservice更新时出错。下载”。。。”时出错。请求失败,错误信息为:
- 0-9 倒计时 8x8 点阵 实现
- ubuntu16.04安装翻译软件stardict
- EFI Driver Model(中)-PCI 驱动设计
- 用docx把文字写入word并且插入图片、表格
- 7、对数组中下标为奇(偶)数的元素进行操作
- latex转word_最有效率的论文排版利器来了,word排版再见吧~
- MT7628 wifi模块,MTK路由器芯片介绍
- 事务原子性、一致性、持久性的实现原理
- 十问旷视印奇、唐文斌:AI企业都在经历「死亡之谷」
- Xcode 下载真机包调试
- PeckShield宣布与IOST达成全球战略合作
- sparksql中大小表jion