选择在实际操作前先看一遍这个,是因为之前实验的时候有很多坑,提前看一遍预防一下,以便出了问题更好定位问题,不至于一模黑乱找。
建议还是去
github-Document-FAQ
上看,gitee上更新确实会慢一些,2021.4.8截的图,差了两次更新。(这个
FAQ每周一更新一次
,建议持续关注,👧我就是用一次关注一次,更新一次,哈哈哈)
因人而异,因项目而异。大家都在了解的基础上寻找对自己有用的即可。
整体看完一遍后,大概知道哪些问题是可以解决的,去哪里可以搜到就好,心里有底
0. 🎄StyleText相关的问题
A: Style-Text 如何不文字风格迁移,就像普通文本生成程序一样默认字体直接输出到分割的背景图?
使用image_synth模式会输出fake_bg.jpg,即为背景图。如果想要批量提取背景,可以稍微修改一下代码,将fake_bg保存下来即可。要修改的位置: github.com/PaddlePaddl…
B:你能否修改StyleText配置文件中的分辨率?
StyleText目前的训练数据主要是高度32的图片,建议不要改变高度。未来我们会支持更丰富的分辨率。
C:StyleText是否可以更换字体文件?
StyleText项目中的字体文件为标准字体,主要用作模型的输入部分,不能够修改。 StyleText的用途主要是:提取style_image中的字体、背景等style信息,根据语料生成同样style的图片。
D: style-text 融合模块的输入是生成的前景图像以及背景特征权重吗?
目前版本是直接输入两个图像进行融合的,没有用到feature_map,替换背景图片不会影响效果。
E:使用StyleText进行数据合成时,文本(TextInput)的长度远超StyleInput的长度,该怎么处理与合成呢?
在使用StyleText进行数据合成的时候,建议StyleInput(原图)的长度长于TextInput(目标图)的长度。有2种方法可以处理上述问题:
1. 将StyleInput按列的方向进行复制与扩充,直到其超过TextInput的长度。
2. 将TextInput进行裁剪,保证每段TextInput都稍短于StyleInput,分别合成之后,再拼接在一起。
实际使用中发现,使用第2种方法的效果在长文本合成的场景中的合成效果更好,StyleText中提供的也是第2种数据合成的逻辑。
1 🎃数据合成、标注/数据集构建
A:在使用PPOCRLabel的时候,如何标注倾斜的文字?
如果矩形框标注后空白冗余较多,可以尝试PPOCRLabel提供的四点标注,可以标注各种倾斜角度的文本。
B:简单的对于精度要求不高的OCR任务,数据集需要准备多少张呢?
(1)训练数据的数量和需要解决问题的复杂度有关系。难度越大,精度要求越高,则数据集需求越大,而且一般情况实际中的训练数据越多效果越好。
(2)对于精度要求不高的场景,检测任务和识别任务需要的数据量是不一样的。对于检测任务,500张图像可以保证基本的检测效果。对于识别任务,需要保证识别字典中每个字符出现在不同场景的行文本图像数目需要大于200张(举例,如果有字典中有5个字,每个字都需要出现在200张图片以上,那么最少要求的图像数量应该在200-1000张之间),这样可以保证基本的识别效果。
(X)对于工业识别场景,识别英文数字及符号等,基本都是50个字符左右,而且参考其他部分,对于这类场景,基本都是2w张图打底。
C:PubTabNet 数据集关注的是什么问题?
PubTabNet是IBM提出的基于图片格式的表格识别数据集,包含 56.8 万张表格数据的图像,以及图像对应的 html 格式的注释。该数据集的发布推动了表格结构化算法的研发和落地应用。
关于表格识别这一特定领域,可以看看论文:
三篇论文,纵览深度学习在表格识别中的最新应用
上面那个PubTabNet的github链接:
github.com/ibm-aur-nlp…
D:🧵训练文字识别模型,真实数据有30w,合成数据有500w,需要做样本均衡吗?
需要,一般需要保证一个batch中真实数据样本和合成数据样本的比例是1:1~1:3左右效果比较理想。如果合成数据过大,会过拟合到合成数据,预测效果往往不佳。还有一种启发性的尝试是可以先用大量合成数据训练一个base模型,然后再用真实数据微调,在一些简单场景效果也是会有提升的。
E:StyleText 合成数据效果不好?
StyleText模型生成的数据主要用于OCR识别模型的训练。PaddleOCR目前识别模型的输入为32 x N,因此当前版本模型主要适用高度为32的数据。 建议要合成的数据尺寸设置为32 x N。 尺寸相差不多的数据也可以生成,尺寸很大或很小的数据效果确实不佳 。
F:开源模型使用的训练数据是什么,能否开源?
目前开源的模型,数据集和量级如下:
英文数据集,ICDAR2015
中文数据集,LSVT街景数据集训练数据3w张图片
英文数据集,MJSynth和SynthText合成数据,数据量上千万。
中文数据集,LSVT街景数据集根据真值将图crop出来,并进行位置校准,总共30w张图像。此外基于LSVT的语料,合成数据500w。
其中,公开数据集都是开源的,用户可自行搜索下载,也可参考中文数据集,合成数据暂不开源,用户可使用开源合成工具自行合成,可参考的合成工具包括
text_renderer
、
SynthText
、
TextRecognitionDataGenerator
等。
G:文本检测和识别大概需要多少数据
检测需要的数据相对较少,在PaddleOCR模型的基础上进行Fine-tune,一般需要500张可达到不错的效果。 识别分英文和中文, 一般英文场景需要几十万数据可达到不错的效果 ,中文则需要几百万甚至更多。
2 🎨模型选择
A:CTC和Attention比较
CTC的局限性:
Attention:
Attention局限性:
B1:🎑CRNN特性介绍
CRNN是一种基于1D-CTC的算法,其原理决定无法识别2行或多行的文字,只能单行识别。
B2:🎋对于CRNN模型,backbone采用DenseNet和ResNet_vd,哪种网络结构更好?
Backbone的识别效果在CRNN模型上的效果,与Imagenet 1000 图像分类任务上识别效果和效率一致。在图像分类任务上ResnNet_vd(79%+)的识别精度明显优于DenseNet(77%+),此外对于GPU,Nvidia针对ResNet系列模型做了优化,预测效率更高,所以相对而言,resnet_vd是较好选择。如果是移动端,可以优先考虑MobileNetV3系列。
C:PaddleOCR提供的文本识别算法包括哪些?
PaddleOCR主要提供五种文本识别算法,包括 CRNN、StarNet、RARAE、Rosetta 和 SRN , 其中CRNN\StarNet和Rosetta是基于ctc的文字识别算法,RARE是基于attention的文字识别算法;SRN为百度自研的文本识别算法,引入了语义信息,显著提升了准确率。 详情可参照如下页面: 文本识别算法
3. 预处理(图像送入模型训练前)
A:弯曲形变的文字识别需要怎么处理?TPS应用场景是什么,是否好用?
(1)在大多数情况下,如果遇到的场景弯曲形变不是太严重,检测4个顶点,然后直接通过
仿射变换转正识别
就足够了。
(2)如果不能满足需求,可以尝试使用TPS(Thin Plate Spline),即薄板样条插值。TPS是一种插值算法,经常用于图像变形等,通过少量的控制点就可以驱动图像进行变化。一般用在有弯曲形变的文本识别中,当检测到不规则的/弯曲的(如,使用基于分割的方法检测算法)文本区域,往往先使用TPS算法对文本区域矫正成矩形再进行识别,如,STAR-Net、RARE等识别算法中引入了TPS模块。 Warning:TPS看起来美好,在实际应用时经常发现并不够鲁棒,并且会增加耗时,需要谨慎使用。
B:预处理部分,图片的长和宽为什么要处理成32的倍数?
以检测中的resnet骨干网络为例,图像输入网络之后,需要经过5次2倍降采样,共32倍,因此建议输入的图像尺寸为32的倍数。
4. 💎配置/命令行参数
A:PaddleOCR中文模型是否支持数字识别?
支持的,可以看下ppocr/utils/ppocr_keys_v1.txt 这个文件,是支持的识别字符列表,其中包含了数字识别。
查看这个 文件 ,可以发现,识别的字符主要是常见符号+中文(有繁体字)+英语+数字:
这些奇怪的符号
B:如何获取检测文本框的坐标?
def __call__(self, img):
ori_im = img.copy()
dt_boxes, elapse = self.text_detector(img)
logger.info("dt_boxes num : {}, elapse : {}".format(
len(dt_boxes), elapse))
if dt_boxes is None:
return None, None
img_crop_list = []
C:识别模型框出来的位置太紧凑,会丢失边缘的文字信息,导致识别错误
可以在命令中加入 --det_db_unclip_ratio ,参数定义位置,这个参数是检测后处理时控制文本框大小的,默认1.6,可以尝试改成2.5或者更大,反之,如果觉得文本框不够紧凑,也可以把该参数调小。
D:如何加入自己的检测算法?
在ppocr/modeling对应目录下分别选择backbone,head。如果没有可用的可以新建文件并添加
在ppocr/data下选择对应的数据处理处理方式,如果没有可用的可以新建文件并添加
在ppocr/losses下新建文件并编写loss
在ppocr/postprocess下新建文件并编写后处理算法
将上面四个步骤里新添加的类或函数参照yml文件写到配置中
E:如何可视化acc,loss曲线图,模型网络结构图等?
在配置文件里有use_visualdl的参数,设置为True即可,更多的使用命令可以参考:VisualDL使用指南。
F:数据里出现了预训练模型字符集中没有的字符,新的字符是在字符集前面添加还是在后面添加?
在后面添加,修改dict之后,就改变了模型最后一层fc的结构,之前训练到的参数没有用到,相当于从头训练,因此acc是0。
G:配置文件里面检测的阈值设置
检测相关的参数主要有以下几个: det_limit_side_len:预测时图像resize的长边尺寸 det_db_thresh: 用于二值化输出图的阈值 det_db_box_thresh:用于过滤文本框的阈值,低于此阈值的文本框不要 det_db_unclip_ratio: 文本框扩张的系数,关系到文本框的大小
这些参数的默认值见代码,可以通过从命令行传递参数进行修改。
H:PaddleOCR默认不是200个step保存一次模型吗?为啥文件夹下面都没有生成
因为默认保存的起始点不是0,而是4000,将eval_batch_step [4000, 5000]改为[0, 2000] 就是从第0次迭代开始,每2000迭代保存一次模型
5. 🎀模型训练
A:训练识别和检测时学习率要加上warmup,目的是什么?
Warmup机制先使学习率从一个较小的值逐步升到一个较大的值,而不是直接就使用较大的学习率,这样有助于模型的稳定收敛。在OCR检测和OCR识别中,一般会带来精度~0.5%的提升。
B:如何更换文本检测/识别的backbone?
无论是文字检测,还是文字识别,骨干网络的选择是预测效果和预测效率的权衡。一般,选择更大规模的骨干网络,例如ResNet101_vd,则检测或识别更准确,但预测耗时相应也会增加。而选择更小规模的骨干网络,例如MobileNetV3_small_x0_35,则预测更快,但检测或识别的准确率会大打折扣。幸运的是不同骨干网络的检测或识别效果与在ImageNet数据集图像1000分类任务效果正相关。飞桨图像分类套件PaddleClas汇总了ResNet_vd、Res2Net、HRNet、MobileNetV3、GhostNet等23种系列的分类网络结构,在上述图像分类任务的top1识别准确率,GPU(V100和T4)和CPU(骁龙855)的预测耗时以及相应的117个预训练模型下载地址。
(1)文字检测骨干网络的替换,主要是确定类似与ResNet的4个stages,以方便集成后续的类似FPN的检测头。此外,对于文字检测问题,使用ImageNet训练的分类预训练模型,可以加速收敛和效果提升。
(2)文字识别的骨干网络的替换,需要注意网络宽高stride的下降位置。由于文本识别一般宽高比例很大,因此高度下降频率少一些,宽度下降频率多一些。可以参考PaddleOCR中MobileNetV3骨干网络的改动。
C:训练识别时,如何选择合适的网络输入shape?
一般高度采用32,最长宽度的选择,有两种方法:
(1)统计训练样本图像的宽高比分布。最大宽高比的选取考虑满足80%的训练样本。
(2)统计训练样本文字数目。最长字符数目的选取考虑满足80%的训练样本。然后中文字符长宽比近似认为是1,英文认为3:1,预估一个最长宽度。
D:识别训练时,训练集精度已经到达90了,但验证集精度一直在70,涨不上去怎么办?
训练集精度90,测试集70多的话,应该是过拟合了,有两个可尝试的方法:
(1)加入更多的增广方式或者调大增广prob的概率,默认为0.4。
(2)调大系统的l2 dcay值
方式1实现:
# 这个位于23行文件附近
class RecAug(object):
def __init__(self, use_tia=True, aug_prob=0.4, **kwargs):
self.use_tia = use_tia
self.aug_prob = aug_prob
# 也有可能是下面这个
# 已经位于393行
def warp(img, ang, use_tia=True, prob=0.4):
h, w, _ = img.shape
config = Config(use_tia=use_tia)
config.make(w, h, ang)
new_img = img
调大增广prob的概率→链接指向的是341行,但是341行的内容和概率并不相关,文件应该更新过,查看该文件的历史版本。
在bc563c6
中看到,其实以前第341行是这个
到e84ea26
中,这个参数被放在了函数中,变成可以传递修改的了
所以可以判断这个prob指的是第二个的概率,结合下面这个新的,
class RecAug(object):
def __init__(self, use_tia=True, aug_prob=0.4, **kwargs):
self.use_tia = use_tia
self.aug_prob = aug_prob
def __call__(self, data):
img = data['image']
img = warp(img, 10, self.use_tia, self.aug_prob)
# 所以这里aug_prob调节的就是采样/采取增广操作的比率
data['image'] = img
return data
def warp(img, ang, use_tia=True, prob=0.4):
# warp函数中写了那些增广方式的调用
h, w, _ = img.shape
config = Config(use_tia=use_tia)
config.make(w, h, ang)
new_img = img
方式2实现:
Optimizer:
function: ppocr.optimizer,AdamDecay
base_lr: 0.0005
l2_decay: 0.00001 # 增大这个值
beta1: 0.9
beta2: 0.999
decay:
function: cosine_decay_warmup
step_each_epoch: 254
total_epoch: 500
warmup_minibatch: 1000
权重衰减(L2正则化项)为什么能够避免模型过拟合的问题?
奥卡姆剃刀法则;
过拟合模型的系数往往非常大,因为过拟合就是需要顾忌每一个点,最终形成的拟合函数波动很大,这就意味在某些小区间里的导数值非常大,也就是系数很大,而通过正则化约束参数的范数使其不要太大,可以在一定程度上减少过拟合情况。
E:参照文档做实际项目时,是重新训练还是在官方训练的基础上进行训练?具体如何操作?
基于官方提供的模型,进行finetune的话,收敛会更快一些。 具体操作上,以识别模型训练为例:如果修改了字符文件,可以设置pretraind_model为官方提供的预训练模型
F:PaddleOCR开源的超轻量模型和通用OCR模型的区别?
相同点:两者使用相同的算法和训练数据;
不同点:不同之处在于骨干网络和通道参数,超轻量模型使用MobileNetV3作为骨干网络,通用模型使用Resnet50_vd作为检测模型backbone,Resnet34_vd作为识别模型backbone,具体参数差异可对比两种模型训练的配置文件.
模型 骨干网络 检测训练配置 识别训练配置 8.6M超轻量中文OCR模型 MobileNetV3+MobileNetV3 det_mv3_db.yml rec_chinese_lite_train.yml 通用中文OCR模型 Resnet50_vd+Resnet34_vd det_r50_vd_db.yml rec_chinese_common_train.yml
G:文本长度超过25,怎么处理?
默认训练时的文本可识别的最大长度为25,超过25的文本会被忽略不参与训练。如果您训练样本中的长文本较多,可以修改配置文件中的 max_text_length 字段,设置为更大的最长文本长度
H:训练过程中,如何恰当的停止训练(直接kill,经常还有显存占用的问题)
可以通过下面的脚本终止所有包含train.py字段的进程,
ps -axu | grep train.py | awk '{print $2}' | xargs kill -9
I:如何对检测模型finetune,比如冻结前面的层或某些层使用小的学习率学习?
如果是冻结某些层,可以将变量的stop_gradient属性设置为True,这样计算这个变量之前的所有参数都不会更新了,参考:www.paddlepaddle.org.cn/documentati…
如果对某些层使用更小的学习率学习,静态图里还不是很方便,一个方法是在参数初始化的时候,给权重的属性设置固定的学习率,参考:www.paddlepaddle.org.cn/documentati…
实际上我们实验发现,直接加载模型去fine-tune,不设置某些层不同学习率,效果也都不错
J:识别模型训练时,loss能正常下降,但acc一直为0
识别模型训练初期acc为0是正常的,多训一段时间指标就上来了。
K:dygraph分支中,文本识别模型训练,要使用数据增强应该如何设置?
可以参考配置文件在Train[‘dataset’][‘transforms’]添加RecAug字段,使数据增强生效。可以通过添加对aug_prob设置,表示每种数据增强采用的概率。aug_prob默认是0.4.由于tia数据增强特殊性,默认不采用,可以通过添加use_tia设置,使tia数据增强生效。详细设置可以参考ISSUE 1744。
L:模型训练过程中如何得到 best_accuracy 模型?
配置文件里的eval_batch_step字段用来控制多少次iter进行一次eval,在eval完成后会自动生成 best_accuracy 模型,所以如果希望很快就能拿到best_accuracy模型,可以将eval_batch_step改小一点,如改为[10,10],这样表示第10次迭代后,以后没隔10个迭代就进行一次模型的评估。
6. 🥽 整体问题
A:背景干扰的文字(如印章盖到落款上,需要识别落款或者印章中的文字),如何识别?
(1)在人眼确认可识别的条件下,对于背景有干扰的文字,首先要保证检测框足够准确,如果检测框不准确,需要考虑是否可以通过过滤颜色等方式对图像预处理并且增加更多相关的训练数据;在识别的部分,注意在训练数据中加入背景干扰类的扩增图像。
(2)如果MobileNet模型不能满足需求,可以尝试ResNet系列大模型来获得更好的效果。
B:PaddleOCR项目中的中文超轻量和通用模型用了哪些数据集?训练多少样本,gpu什么配置,跑了多少个epoch,大概跑了多久?
(1)检测:LSVT街景数据集共3W张图像,超轻量模型,150epoch左右,2卡V100 跑了不到2天;通用模型:2卡V100 150epoch 不到4天。
(2)识别:520W左右的数据集(真实数据26W+合成数据500W)训练,超轻量模型:4卡V100,总共训练了5天左右。通用模型:4卡V100,共训练6天。
(3)超轻量模型训练分为2个阶段: ①全量数据训练50epoch,耗时3天 ;② 合成数据+真实数据按照1:1数据采样,进行finetune训练200epoch,耗时2天
(4)通用模型训练: 真实数据+合成数据,动态采样(1:1)训练,200epoch,耗时 6天左右。
C:PaddleOCR模型推理方式有几种?各自的优缺点是什么
目前推理方式支持基于训练引擎推理和基于预测引擎推理。
(1)基于训练引擎推理不需要转换模型,但是需要先组网再load参数,语言只支持python,不适合系统集成。
(2)基于预测引擎的推理需要先转换模型为inference格式,然后可以进行不需要组网的推理,语言支持c++和python,适合系统集成。
D: 目前OCR普遍是二阶段,端到端的方案在业界落地情况如何?
端到端在文字分布密集的业务场景,效率会比较有保证,精度的话看自己业务数据积累情况,如果行级别的识别数据积累比较多的话two-stage会比较好。百度的落地场景,比如工业仪表识别、车牌识别都用到端到端解决方案。
E: 对于一些在识别时稍微模糊的文本,有没有一些图像增强的方式?
在人类肉眼可以识别的前提下,可以考虑图像处理中的均值滤波、中值滤波或者高斯滤波等模糊算子尝试。也可以尝试从数据扩增扰动来强化模型鲁棒性,另外新的思路有对抗性训练和超分SR思路,可以尝试借鉴。但目前业界尚无普遍认可的最优方案,建议优先在数据采集阶段增加一些限制提升图片质量。
F:训练模型和测试模型的检测结果差距较大
检查两个模型使用的后处理参数是否是一样的,训练的后处理参数在配置文件中的PostProcess部分,测试模型的后处理参数在tools/infer/utility.py中,最新代码中两个后处理参数已保持一致。
G:使用合成数据精调小模型后,效果可以,为什么还没开源的小infer模型效果好?
(1)要保证使用的配置文件和pretrain weights是对应的;
(2)在微调时,一般都需要真实数据,如果使用合成数据,效果反而可能会有下降,PaddleOCR中放出的识别inference模型也是基于预训练模型在真实数据上微调得到的,效果提升比较明显;
(3)在训练的时候,文本长度超过25的训练图像都会被丢弃,因此需要看下真正参与训练的图像有多少,太少的话也容易过拟合。
7. 🎉运行过程的问题
都属于实战篇部分的内容,链接:【实战篇】PaddleOCR实战问题
A:PaddlePaddle怎么指定GPU运行 os.environ[“CUDA_VISIBLE_DEVICES”]这种不生效
通过设置export CUDA_VISIBLE_DEVICES='0'
环境变量
B:提供的inference model和预训练模型的区别
inference model为固化模型,文件中包含网络结构和网络参数,多用于预测部署。预训练模型是训练过程中保存好的模型,多用于fine-tune训练或者断点训练。
8. 🎁后处理
A:模型的解码部分有后处理?
有的检测的后处理在ppocr/postprocess路径下
B:怎样把OCR输出的结果组成有意义的语句呢?
OCR输出的结果包含坐标信息和文字内容两部分。如果您不关心文字的顺序,那么可以直接按box的序号连起来。 如果需要将文字按照一定的顺序排列,则需要您设定一些规则,对文字的坐标进行处理,例如按照坐标从上到下,从左到右连接识别结果。 对于一些有规律的垂类场景,可以设定模板,根据位置、内容进行匹配。 例如识别身份证照片,可以先匹配"姓名","性别"等关键字,根据这些关键字的坐标去推测其他信息的位置,再与识别的结果匹配。