从头开始训练自己的 Tesseract 5 LSTM 识别库(超详细)
从头开始训练自己的 Tesseract 5 LSTM 识别库(超详细)
最新工作中涉及到OCR的内容,用了百度的OCR精度不错,但是速度有点慢,看网上有提到Tesseract这一开源的项目,下载试了一试发现速度是比百度快不少,但是精度差很多,所以研究了下怎么可以提高识别的精度,发现可以通过训练识别库的方式,所以才有了这篇文章,按Tesseract官方的说法,训练有三种方式:一从头开始训练(官方不推荐使用此方法);二对现有模型进行微调训练;三对现有模型的部分神经元网络进行训练,本文是使用的方式一,从头始开始训练完全符合自己需要的字库,废话少说下面开始一步步进行说明。
一、准备工作
1、相关程序和资源
tesseract-ocr:tesseract-ocr-w64-setup-v5.0.1.20220118.exe
tessdata_best:https://github.com/tesseract-ocr/tessdata_best
langdata_lstm:https://github.com/tesseract-ocr/langdata_lstm
文本编辑器:我使用的是notepad++(这个按个人使用的习惯,没有要求),还要用到cmd或者Power Shell,另外jTessBoxEditor这个工具也可下载(需要Java环境),虽然本例子中并不需要jTessBoxEditor,但是可用它打开图片+box文件看看。
2、安装Tesseract-OCR
Tesseract-OCR安装过程中需要选择中文的支持,安装完成后在环境变量中增加路径设置,方便cmd中的使用,这一过程网上有详细的说明,不会的百度一下即可。
3、建立目录结构
在e:盘新建文件夹t,把下载的tessdata_best和langdata_lstm放入,新建output和tmp文件夹,注意下面的所有步骤都是按e:\t这个根路径进行的,都是用的绝对路径,用其它路径当做根目录的请自行修改路径,当然也可以使用相对路径,但是我不喜欢相对路径(需要考虑相对的位置,容易出错),最始的目录结构如下:
E:\T
├─langdata_lstm
├─output
├─tessdata_best
└─tmp
4、处理tessdata_best简体中文库chi_sim.traineddata
1)解包简体中文库chi_sim.traineddata
combine_tessdata -u e:\t\tessdata_best\chi_sim.traineddata e:\t\tessdata_best\chi_sim,执行完成上面这条命令后,就会把chi_sim.traineddata解为几个文件,具体文件内容可以自己去e:\t\tessdata_best文件夹中去看一看。
2)转化dawg字典文件为文本文件(Directed Acyclic Word Graph)
文字字典:
dawg2wordlist e:\t\tessdata_best\chi_sim.lstm-unicharset e:\t\tessdata_best\chi_sim.lstm-word-dawg e:\t\tessdata_best\word.txt
数字字典:
dawg2wordlist e:\t\tessdata_best\chi_sim.lstm-unicharset e:\t\tessdata_best\chi_sim.lstm-number-dawg e:\t\tessdata_best\number.txt
标点符号字典:
dawg2wordlist e:\t\tessdata_best\chi_sim.lstm-unicharset e:\t\tessdata_best\chi_sim.lstm-punc-dawg e:\t\tessdata_best\punc.txt
5、研究tessdata_best的字符集文件
用文本编辑器打开字符集文件,就是e:\t\tessdata_best\chi_sim.lstm-unicharset,可以看到4022这个数字(这是一个重要的数字),第5行是字母“S”,第4023行是汉字“掺”,从“S”到“掺”这4019行就是tessdata_best中文的全部编码,同理也可以自己查看一下tessdata_fast中文编码也是4019个,tessdata多一些有5071个(tessdata的文件名为chi_sim.unicharset),编码文件内容看来没有什么规律,为了方便看少了什么字,本人进行了变换处理(只保留编码字符并按GB2312顺序排序),结果如下:字符数字标点符号共有120个(其中多了一个GB2312中没有的〇),汉字有3899个,可GB2312有汉字6763个(一级汉字3755,二级汉字3008个),这个差距有点大呀,所以tessdata汉字识别精度不高在所难免(字符集中都没有还怎么识别呀)。
下面开始关键的步骤
二、生成字符集lstm-unicharset文件
1、生成字符集txt文件
把字符集所要包含的数字、字母、标点符号和汉字,保存在e:\t\chi_sim.txt,要求无重复内容,并且中间无空格、回车换行或类似tab等无法显示的特殊符号,本例子中编辑了一些数字、字符、标点符号和汉字一共167个,请记住这个数字,下面还要用到这个数字。
2、生成字符集box文件
下面的命令生成box文件的同时还会生成相关的图片文件,字体无要求只要支持你准备的字符集文字能输出box文件就行,这一步也可以不执行,直接进行下一步,另外生成的图片+box文件可以用jTessBoxEditor打开看一看(具体方法自己百度)。
text2image --text e:\t\chi_sim.txt --outputbase e:\t\chi_sim --fonts_dir C:\Windows\Fonts --font="simhei" --fontconfig_tmpdir e:\t\tmp
参数说明:
--text:需要转换的文件,就是你准备的字符集的内容
--outputbase:输出图片和box文件名前缀
--fonts_dir:使用字体的文件路径C:\Windows\Fonts
--font:使用字体的文件名(默认Arial),不要扩展名,“简黑”字体在在win10下的文件名是simhei.ttf,不支持ttc字体,你要使用什么字体就去系统字体文件夹下查字体文件的名称(不要扩展名)。
--fontconfig_tmpdir:字体配置(临时)文件夹
3、生成字符集lstm-unicharset文件
用box文件和txt文件都能生成lstm-unicharset文件,用txt生成的过程中可能还要临时生成box所以慢一些,两种方式都可试一试,执行后生成文件chi_sim.lstm-unicharset,文件第1行是个数字,本例是170,就是字符集字数+3(167+3)。
1)用box文件生成
unicharset_extractor --norm_mode 3 --output_unicharset e:\t\chi_sim.lstm-unicharset e:\t\chi_sim.box
2)用txt文件生成
unicharset_extractor --norm_mode 3 --output_unicharset e:\t\chi_sim.lstm-unicharset e:\t\chi_sim.txt
参数说明:
--norm_mode:模式(默认1)
1:组合字母(用于拉丁语和其他简单的语言)
2:分裂字母(用于印度语/高棉/缅甸)
3:unicode(用于阿拉伯语/希伯来语/泰国语/西藏语)
--output_unicharset:输出字符集文件名称
三、生成starter traineddata文件
starter traineddata翻译成初始traineddata比较好,它应该是一个最初始的一个状态,模型包含字符集、语言信息和字典(不是必须的)。
1、生成字典文本文件
参考e:\t\tessdata_best文件夹中的3个字典文件(word文字,number数字,punc标点符号),编辑自己的3个字典文件,分别为e:\t\word.txt,e:\t\number.txt和e:\t\punc.txt,punc.txt和number.txt用的是tessdata_best中的字典文件转化来的,word.txt按实际需要生成,3个字典都是每条内容占1行,注意number.txt和punc.txt的第1行都是空格可能有特别用处最好也保留空格,特别是number.txt的内容没弄懂直接用的tessdata_best的文件,这3个文件官方的说明不是必需的,但是如果前期不增加后期只有更新的方法没有插入的方法,所以最好还是加上吧(哪怕是随便写几行内容也行)。
2、生成starter traineddata文件
combine_lang_model --input_unicharset e:\t\chi_sim.lstm-unicharset --lang chi_sim --script_dir e:\t\langdata_lstm --output_dir e:\t --version_str "CSDN:watt:2022.04[1,48,0,1C3,3Ft16Mp3,3TxyLfys64Lfx96RxLrx96Lfx512O1c170]" --words e:\t\word.txt --numbers e:\t\number.txt --puncs e:\t\punc.txt --pass_through_recoder
参数说明:
--input_unicharset:字符集文件
--script_dir:脚本路径(要求指向langdata路径)
--output_dir:输出路径(生成文件输出到output_dir\lang,其中lang是你指定使用的的语言)
--lang:使用的语言chi_sim,程序会读取script_dir\lang\lang.config中的设置,如果没有这个语言会用默认设置
--version_str:版本字符串,注意170(字符数+3),这个字符串也可不设置,不设置以后就不知道用了什么神经元网络和网络参数了,这个也是下面要使用的神经元网络和网络参数,所以最好还是设置一下。
--words:文字字典
--numbers:数字字典
--puncs:标点符号字典
--pass_through_recoder: 直通记录器(默认否),是:简单的直通unicharset记录器,否:韩语用Jamos编码压缩,将multi-unicode字符分解为unicode序列,
汉语用radical_table_data中的数据进行编码,编码数据来自文件langdata/radical-stroke.txt文件中的内容,Virama字符的语言(所有的印度语、缅甸和高棉)需要使用此设置。(不使用出错:Invalid format in radical table at line 0: 19886 3 23 6 3 Creation of encoded unicharset failed!!)
3、查看新生成的starter traineddata信息
combine_tessdata -d e:\t\chi_sim\chi_sim.traineddata
结果大概就是下面的这个样子(设置不同内容不同):
Version:v5.0.1.20220118:CSDN:watt:2022.04[1,48,0,1C3,3Ft16Mp3,3TxyLfys64Lfx96RxLrx96Lfx512O1c170]
0:config:size=2107, offset=192
18:lstm-punc-dawg:size=570, offset=2299
19:lstm-word-dawg:size=74, offset=2869
20:lstm-number-dawg:size=82, offset=2943
21:lstm-unicharset:size=11678, offset=3025
23:version:size=88, offset=14703
四、生成训练文件
1、生成训练文本文件train.txt
训练文本如何准备,官方的文档没有给出明确的说明,不知道应该怎么做,感觉应该用字符集中的所有字符,按实际使用的频率编辑成1个训练用的文本。文本应该有一定的复杂度。本例子中的中文比较少所以把中文多复制了几次把这个当基础,再进行随机排序处理,一共生成20组,最后生成训练文本共7740个字符。训练文本可以参考tessdata_best的中文训练文本,文件位置:langdata_lstm\chi_sim\chi_sim.training_text。
2、生成图片+box文件
text2image命令默认使用ptsize=12,300 DPI进行处理,换算成72 DPI就是ptsize=50,但是有一些字显示的不清楚所以设置ptsize=18进行渲染,这也可能是我使用黑体字笔画比较粗有关,这个要根据实际的选择的字体进行设置。
text2image --text e:\t\train.txt --outputbase e:\t\train --fonts_dir C:\Windows\Fonts --font="simhei" --ptsize 18 --fontconfig_tmpdir e:\t\tmp
3、生成训练文件:
tesseract e:\t\train.tif e:\t\train -l chi_sim --psm 6 lstm.train
参数说明:
d:/t/train.tif:训练用的图片(也会用到train.box文件)
d:/t/train:生成的文件名.lstmf
-l:语言,chi_sim
--psm 6:0~13可选择,感觉6比较适合当前的情况
lstm.train:生成lstmf文件,注意lstm.train这个参数是一个文件名,tesseract会在C:\Program Files\Tesseract-OCR\tessdata\configs文件夹下查找此文件,
在这个参数走了半天的弯路,看官方的手册以为“lstm.train”就行了或者自己编辑个文本文件(内容写上lstm.train),可执行就是报错,说什么lstm.train参数值不对,期间试了“lstm.train true”,“lstm.train=true”,“lstm.train 1”,“lstm.train=1”都报错,打开源代码看了看也不弄明白,最后去官网发现tessdata\configs下有lstm.train文件,其它几个可选参数也是configs下的文件,回过头再看官方的资料才发现是英文不过关理解错误,原文写着是文件(Interesting config files include)。注意,正常安装后是带有lstm.train这个文件的,我是从别处复制过来的tessdata所以不带。
4、新建训练列表文件
新建e:\t\train_listfile.txt文件,内容是e:\t\train.lstmf,如果有多个训练文件就分多行,但是要注意不要使用回车换行,只能是换行,就是不要用\r\n,只使用\n,即16进制方式不能是0d 0a只能是0a不然会报错,不明白什么回车换行和换行的区别的只能自己弄明白了。
五、训练
1、cmd或Power Shell转为UTF8编码,否则中文显示乱码
chcp 65001
2、开始训练:
lstmtraining --traineddata e:\t\chi_sim\chi_sim.traineddata --net_spec "[1,48,0,1Ct3,3,16 Mp3,3 Lfys64 Lfx96 Lrx96 Lfx512 O1c170]" --model_output e:\t\output\output --train_listfile e:\t\train_listfile.txt --max_iterations 0 --target_error_rate 0.01 --debug_interval -1
参数说明:
--traineddata:使用的starter traineddata模型
--net_spec:神经元网络设置,和输入、输出和网络参数有关(这个参数是根据tessdata_best得来的),O1c170中的170上面已经说过了(字符集字数+3),具体网络的功能是什么没研究不清楚,官网查询了也没有找到具体的说明,暂时用和tessdata_best中文一样的神经元网络参数,注意170这个数字要替换成你自己的字符数+3,这个数字不正确也能执行,我最初用的是O1c1也可以进行训练(多个警告),开始训练时程序会计算相关参数然后会报告新的网络参数,--net_spec参数应该是最重要的参数了,它指定了你的模型使用了何种神经元算法和参数,如果自己可以更进一优化神经元网络可以试着改动参数。
--model_output:输出文件名前缀
--train_listfile:训练文件列表
--max_iterations:最大迭代次数,达到次数停止,0=无限制
--target_error_rate:目标错误率,达到停止
--debug_interval:debug信息显示设置,0=每百条显示;-1=每条显示
3、停止与继续训练
运行的程序可以关闭,停止后可以用“开始训练”同样的命令继续训练。
4、训练说明
字符集字数:167(数字,字母,标点符号,汉字)
训练字数:7740:用字符集中的字符编辑了387字符,程序随机排序,共随机处理20次,组成了20行的内容
电脑:i5-4590 CPU 3.3GHz 16G内存(旧电脑有点慢)
迭代次数:13414次,13413 train=0.011%(0.6%)-->13414 train=0.009%(0.5%)
达到目标:0.009% < 0.01%
总用时:201分种
5、重要训练日志
1)开始日志:
Num outputs,weights in Series:
1,48,0,1:1, 0
Num outputs,weights in Series:
C3,3:9, 0
Ft16:16, 160
Total weights = 160
[C3,3Ft16]:16, 160
Mp3,3:16, 0
TxyLfys64:64, 20736
Lfx96:96, 61824
RxLrx96:96, 74112
Lfx512:512, 1247232
Fc170:170, 87210
Total weights = 1491274
Built network:[1,48,0,1[C3,3Ft16]Mp3,3TxyLfys64Lfx96RxLrx96Lfx512Fc170] from request [1,48,0,1Ct3,3,16 Mp3,3 Lfys64 Lfx96 Lrx96 Lfx512 O1c170]
Training parameters:
Debug interval = -1, weights = 0.1, learning rate = 0.001, momentum=0.5
null char=2
Loaded 160/160 lines (1-160) of document e:\t\train.lstmf
2)达到目标日志:
Iteration 13413: GROUND TRUTH : 字~始练#】'ó的↓{Q字_ě从&bh4库库〖ǖ始己l始自从K库训J头=头练库的]O〈ùC《U库u练自练→训
File e:\t\train.lstmf line 47 (Perfect):
Mean rms=0.057%, delta=0.001%, train=0.011%(0.6%), skip ratio=0%
Iteration 13414: GROUND TRUTH : Q自:练ìKǒ己头的ó库i」4练》开E库"始
File e:\t\train.lstmf line 2 (Perfect):
Mean rms=0.057%, delta=0%, train=0.009%(0.5%), skip ratio=0%
3)结束日志:
Iteration 13499: GROUND TRUTH : @ü'库3从]练A练训己从4字从字"练D〉库开→自始的自:的a~字的ǘV自己[ī=自头]开库从始从
File e:\t\train.lstmf line 136 (Perfect):
Mean rms=0.054%, delta=0%, train=0.006%(0.3%), skip ratio=0%
2 Percent improvement time=1673, best error was 2.32 @ 4134
At iteration 5807/13500/13500, Mean rms=0.054000%, delta=0.000000%, BCER train=0.006000%, BWER train=0.300000%, skip ratio=0.000000%, New best BCER = 0.006000 wrote best model:e:\t\output\output_0.006000_5807_13500.checkpoint wrote checkpoint.
Finished! Selected model with minimal training error rate (BCER) = 0.006
六、评估生成的checkpoint文件
1、生成评估文本eval.txt
编辑一些评估用文本保存到e:\t\eval.txt,尽可能的能全面覆盖,并有一定的复杂度。
2、生成图片+box文件
text2image --text e:\t\eval.txt --outputbase e:\t\eval --fonts_dir C:\Windows\Fonts --font="simhei" --ptsize 18 --fontconfig_tmpdir e:\t\tmp
3、生成评估lstmf文件
tesseract e:\t\eval.tif e:\t\eval -l chi_sim --psm 6 lstm.train
4、生成评估列表文件
新建e:\t\eval_listfile.txt文件,内容是e:\t\eval.lstmf
5、开始评估
编码设置:
chcp 65001
开始评估:
lstmeval --model e:\t\output\output_checkpoint --traineddata e:\t\chi_sim\chi_sim.traineddata --eval_listfile e:\t\eval_listfile.txt
七、生成标准的traineddata
经过评估,达到使用要求后就可以生成标准的traineddata文件了,如果对结果不满意还可以调整指标(比如错误率调整为0.001)继续训练或者重新编制训练文本训练。
1、生成浮点(小数)型的traineddata文件(类似tessdata_best)
lstmtraining --stop_training --continue_from e:\t\output\output_checkpoint --traineddata e:\t\chi_sim\chi_sim.traineddata --model_output e:\t\output\chi_sim.traineddata
2、生成整数型的traineddata文件(类似tessdata_fast)
lstmtraining --stop_training --convert_to_int --continue_from e:\t\output\output_checkpoint --traineddata e:\t\chi_sim\chi_sim.traineddata --model_output e:\t\output\chi_sim.traineddata
参数说明:
--stop_training:从训练模型转化为运行模型
--convert_to_int:转化识别模型为一个整数模型,小数模型还可以继续训练,整数模型不可继续训练
--continue_from:文件来自,除了用output_checkpoint这个最后checkpoint的文件,也可以用output_1.352000_2168_2900.checkpoint这样的中间chechpoint文件生成标准traineddata文件
--traineddata:starter traineddata模型
--model_output:输出文件名
3、查看生成的traineddata信息
combine_tessdata -d e:\t\output\chi_sim.traineddata
最后,把e:\t\output\chi_sim.traineddata复制Tesseract-OCR中就可以使用了,本例子是只用了的黑体进行的训练,实际可以考虑用多种中文字体训练,如果只训练了1种字体显然把它命名为chi_simhei.traineddata可能更准确。
最后再一次强调一下,所有的文本文件不要使用“回车换行”,必须是换行不然会报错误,如果训练过程中出现了不明的错误可以查看一下文本文件中是否多了“回车”,回车换行是windows支持的。