跳至内容。

如何训练 Tesseract 4.00

**使用 tesstrain.sh 进行训练现在已不再支持/废弃。请使用来自 https://github.com/tesseract-ocr/tesstrain 的 python 脚本进行训练。**

**对训练过程有疑问?** 如果您在训练过程中遇到了一些问题,并且需要帮助,请使用 tesseract-ocr 邮件列表来提出您的问题(s)。 **请勿** 将您的问题和关于训练的问题报告为 问题

Ray Smith 的指南和教程内容

初步说明

以下指南和教程已针对 Tesseract 5 过时。使用 tesstrain.sh 进行训练不再支持/废弃。请使用来自 https://github.com/tesseract-ocr/tesstrain 的脚本进行训练。

介绍

Tesseract 4.00 包含一个新的基于神经网络的识别引擎,与以前的版本相比,该引擎在文档图像上的准确性显着提高(对于文档图像),但需要显着提高计算能力。然而,对于复杂的语言,它实际上可能比基本 Tesseract **更快**。

神经网络需要比基本 Tesseract 多得多的训练数据,并且训练速度**慢得多**。对于基于拉丁语系的语言,提供的现有模型数据已在约 400000 条文本线(跨越约 4500 个字体) 上进行过训练。对于其他脚本,可用的字体并不多,但它们仍然在类似数量的文本线上进行了训练。Tesseract 4.00 的训练时间不是几分钟到几个小时,而是需要**几天**到几个**星期**。即使有了所有这些新的训练数据,您仍然可能会发现它不足以解决您的特定问题,因此您来这里是为了重新训练它。

有多种训练选择

虽然上述选项听起来不同,但训练步骤实际上几乎相同,除了命令行之外,所以如果您有时间或硬件并行运行它们,尝试所有方法相对容易。

对于 4.00,至少,旧的识别引擎仍然存在,也可以进行训练,但已弃用,并且,除非有充分的理由保留它,否则可能会在将来的版本中删除。

开始之前

您不需要任何神经网络方面的背景知识来训练 Tesseract 4.00,但这可能有助于理解训练选项之间的差异。在深入研究训练过程之前,请阅读 实现介绍,并且与训练 Tesseract 3.04 相同的说明适用

**重要说明:** 在您投入时间和精力训练 Tesseract 之前,强烈建议您阅读 ImproveQuality 页面。

需要额外的库

从 3.03 开始,需要额外的库来构建训练工具。

sudo apt-get install libicu-dev libpango1.0-dev libcairo2-dev

构建训练工具

从 3.03 开始,如果您从源代码编译 Tesseract,则需要使用单独的 make 命令来制作和安装训练工具。安装完上述额外库后,从 Tesseract 源代码目录运行以下命令

./configure

或者,如果您计划在 docker 中运行(或不需要图形)

./configure --disable-graphics

默认情况下,如果缺少仅用于训练所需的依赖项,Tesseract 配置将继续进行,但对于训练,您必须确保所有这些可选依赖项都已安装,并且 Tesseract 的构建环境可以找到它们。在 ./configure 的输出中查找以下行

checking for pkg-config... [some valid path]
checking for lept >= 1.74... yes
checking for libarchive... yes
checking for icu-uc >= 52.1... yes
checking for icu-i18n >= 52.1... yes
checking for pango >= 1.22.0... yes
checking for cairo... yes
[...]
Training tools can be built and installed with:

(版本号可能会随着时间的推移而改变,当然。我们寻找的是“是”,所有可选依赖项都可用。)

如果 configure 没有说明可以构建训练工具,您仍然需要添加库或确保 pkg-config 可以找到它们。

配置后,您可以尝试构建训练工具

make
make training
sudo make training-install

构建 ScrollView.jar 也很有用,但不是必需的

make ScrollView.jar
export SCROLLVIEW_PATH=$PWD/java

在使用 Homebrew 的 macOS Mojave 上

Homebrew 有一个不寻常的方式来设置 pkgconfig,因此您必须选择加入某些文件。一般来说,运行 brew info package,并确保将提到的 PKG_CONFIG_PATH 附加到此环境变量。

brew install cairo pango icu4c autoconf libffi libarchive
export PKG_CONFIG_PATH=\
$(brew --prefix)/lib/pkgconfig:\
$(brew --prefix)/opt/libarchive/lib/pkgconfig:\
$(brew --prefix)/opt/icu4c/lib/pkgconfig:\
$(brew --prefix)/opt/libffi/lib/pkgconfig
./configure

硬件-软件要求

在撰写本文时,训练仅在 Linux 上有效。(macOS 几乎可以使用;它需要对 shell 脚本进行一些小的调整,以说明它提供的较旧版本的 bash 以及 mktemp 中的差异。)Windows 未知,但需要 msys 或 Cygwin。

至于运行 Tesseract 4.0.0,拥有多核(4 核很好)机器,并支持 OpenMP 和 Intel Intrinsics 的 SSE/AVX 扩展,这很有用,但并非必要。基本上,它仍然可以在任何具有足够内存的机器上运行,但您的处理器越高档,运行速度就越快。不需要 GPU。(不支持。)可以使用 –max_image_MB 命令行选项来控制内存使用量,但您可能需要至少 1GB 的内存,超过操作系统所需的内存。

训练文本要求

对于基于拉丁语系的语言,提供的现有模型数据已在约 400000 条文本线(跨越约 4500 个字体) 上进行过训练。对于其他脚本,可用的字体并不多,但它们仍然在类似数量的文本线上进行了训练。

请注意,拥有更多训练文本并制作更多页面是有益的,因为神经网络不能很好地泛化,需要在与它们将要运行的类似内容上进行训练。如果目标域非常有限,那么所有关于需要大量训练数据的可怕警告可能不适用,但可能需要更改网络规范。

训练过程概述

总体训练过程与 训练 3.04 相似。

从概念上来说相同

  1. 准备训练文本。
  2. 将文本渲染到图像 + 框文件中。(或者为现有的图像数据创建手工制作的框文件。)
  3. 制作 unicharset 文件。(可以部分指定,即手动创建)。
  4. 从 unicharset 和可选的词典数据中制作启动训练数据。
  5. 运行 tesseract 来处理图像 + 框文件以制作训练数据集。
  6. 在训练数据集上运行训练。
  7. 组合数据文件。

主要区别在于

训练不能像 3.04 的训练那样自动化,原因如下

了解训练过程中使用的各种文件

与基本 Tesseract 一样,完成的 LSTM 模型及其所需的所有其他内容都收集在 traineddata 文件中。与基本 Tesseract 不同,在训练期间会提供一个 starter traineddata 文件,并且必须提前设置。它可以包含

粗体元素**必须**提供。其他是可选的,但如果提供了任何 dawgs,则必须提供标点符号 dawg。提供了一个新工具:combine_lang_model,用于从 unicharset 和可选的词表中制作 starter traineddata

在训练过程中,训练器会写入检查点文件,这是神经网络训练器的标准行为。这允许在需要时停止训练并继续进行。可以使用 --stop_training 命令行标志将任何检查点转换为完整的识别模型 traineddata

训练器还会定期在训练期间达到新的最佳状态时写入检查点文件。

可以通过告诉训练器 --continue_from 现有检查点文件或从使用 combine_tessdata 从现有 traineddata 文件中提取的裸 LSTM 模型文件中来修改网络并重新训练其一部分,或针对特定训练数据进行微调(即使使用修改后的 unicharset!),**前提是它尚未转换为整数**。

如果 --traineddata 标志中的 unicharset 与通过 --continue_from 提供的模型中使用的 unicharset 相比发生了变化,则必须使用 --old_traineddata 标志提供相应的 traineddata 文件,该文件包含 unicharsetrecoder。这使训练器能够计算字符集之间的映射。

训练数据通过 .lstmf 文件提供,这些文件是序列化的 DocumentData,它们包含图像及其相应的 UTF8 文本转录,并且可以使用 Tesseract 从 tif/box 文件对中生成,类似于为旧引擎创建 .tr 文件的方式。

LSTMTraining 命令行

lstmtraining 程序是用于训练神经网络的多功能工具。下表描述了它的命令行选项

标志 类型 默认值 解释
traineddata 字符串 指向包含 unicharset、recoder 和可选语言模型的启动训练数据文件的路径。
net_spec 字符串 指定网络的拓扑结构。
model_output 字符串 输出模型文件/检查点的基本路径。
max_image_MB int 6000 用于缓存图像的最大内存量。
learning_rate double 10e-4 SGD 算法的初始学习率。
sequential_training bool false 设置为 true 以进行顺序训练。默认情况下是循环处理所有训练数据。
net_mode int 192 来自 NetworkFlags in network.h 的标志。可能的值:128 用于 Adam 优化而不是动量;64 允许不同的层具有自己的学习率,自动发现。
perfect_sample_delay int 0 当网络变好时,仅在看到此数量的不完美样本后才对完美样本进行反向传播,自上次允许完美样本通过以来。
debug_interval int 0 如果非零,则每隔此数量的迭代显示一次可视化调试。
weight_range double 0.1 初始化权重的随机值的范围。
momentum double 0.5 用于 alpha 平滑梯度的动量。
adam_beta double 0.999 在 ADAM 算法中平滑平方梯度的因子。
max_iterations int 0 在此数量的迭代后停止训练。
target_error_rate double 0.01 如果平均百分比误差率低于此值,则停止训练。
continue_from 字符串 指向要从中继续训练或微调的先前检查点的路径。
stop_training bool false --continue_from 中的训练检查点转换为识别模型。
convert_to_int bool false 使用 stop_training 时,转换为 8 位整数,以获得更高的速度,但精度略有下降。
append_index int -1 在给定的索引处将网络的头部切断,并将 --net_spec 网络附加到切断的部分。
train_listfile 字符串 列出训练数据文件的列表文件的名称。
eval_listfile 字符串 列出用于独立于训练数据评估模型的评估数据文件的列表文件的名称。

大多数标志都使用默认值,其中一些标志仅在下面列出的特定操作中需要,但首先要对更复杂的标志进行一些详细的评论

Unicharset 压缩-重新编码

LSTM 非常擅长学习序列,但当状态数量过大时,速度会大幅下降。有实验证据表明,让 LSTM 学习一个长序列比学习一个包含许多类别的小序列更好,因此对于复杂脚本(汉语、韩语和印度语脚本),最好将每个符号重新编码为来自少量类别的小序列代码,而不是使用一大套类别。 combine_lang_model 命令默认情况下启用了此功能。它将每个汉字编码为 1-5 个代码的可变长度序列,韩语使用 Jamo 编码作为 3 个代码的序列,其他脚本作为其 Unicode 组件的序列。对于使用音节符号字符生成合体辅音的脚本(所有印度语脚本加上缅甸语和高棉语),函数 NormalizeCleanAndSegmentUTF8 将音节符号与适当的邻居配对,以在 unicharset 中生成更面向字形的编码。为了充分利用此改进,应为这些脚本的 combine_lang_model 设置 --pass_through_recoder 标志。

随机训练数据和 sequential_training

为了使随机梯度下降正常工作,训练数据应该在所有样本文件中随机打乱,以便训练器可以依次读取每个文件,并在到达文件末尾时返回第一个文件。

如果使用渲染代码(通过 tesstrain.sh),它将在每个文件内打乱样本文本行,但您将获得一组文件,每个文件包含来自单个字体的训练样本。为了增加更均匀的混合,默认做法是依次处理每个文件的样本,即“循环”方式。如果您以其他方式生成了训练数据,或者它们都来自相同风格(例如手写稿本),那么您可以对 lstmtraining 使用 --sequential_training 标志。这更节省内存,因为它一次只加载两个文件的数据,并按顺序处理它们。(第二个文件是预读的,因此在需要时可以准备好。)

模型输出

训练器会定期使用 --model_output 作为基本名称保存检查点。因此,您可以随时停止训练,并使用相同的命令行重新启动训练,它将继续进行。要强制重新启动,请使用不同的 --model_output 或删除所有文件。

网络模式和优化

128 标志开启 Adam 优化,它似乎比普通动量效果要好得多。

64 标志启用自动分层特定学习率。当进度停滞时,训练器会调查哪些层应该独立降低学习率,并且可能会降低一个或多个学习率以继续学习。

net_mode 的默认值为 192,同时启用 Adam 和分层特定学习率。

以下是一些在学习率降低时发生分歧的情况下看到的示例消息。


Iteration 8999: GROUND  TRUTH : . هريغ )9(فرعي ال ؛ ميملا رسكب » رخنم « و » رخنم « اولاق
Iteration 8999: BEST OCR TEXT : . هريغ )6(فرعي ال ؛ ميملا رسكب » رخنم « و » رخنم « اولاق
File /home/ubuntu/OCR_GS_Data/ara/AWN/book_IbnQutayba.Adab_7_final_200_000742.lstmf line 0 :
Mean rms=1.696%, delta=3.16%, train=113.332%(18.851%), skip ratio=0.1%
Warning: LSTMTrainer deserialized an LSTMRecognizer!
At iteration 7794/9000/9011, Mean rms=1.696%, delta=3.16%, char train=113.332%, word train=18.851%, skip ratio=0.1%,  New worst char error = 113.332At iteration 7507, stage 0, Eval Char error rate=5.4443537, Word error rate=16.233627
Divergence! Reverted to iteration 5870/6400/6408
Reduced learning rate to :0.00025000001
 wrote checkpoint.

Iteration 6400: GROUND  TRUTH : بيرق ناك اذإ »)1(ددعقو ددعق لجر « و ، هتصاخ : يأ » هللخدو نالف للخد«
File /home/ubuntu/OCR_GS_Data/ara/AWN/book_IbnQutayba.Adab_7_final_b_200_000438.lstmf line 0 (Perfect):
Mean rms=1.759%, delta=2.898%, train=62.442%(21.232%), skip ratio=0.2%
Iteration 6401: GROUND  TRUTH : . )1(هجيه ام ردق ىلع
Iteration 6401: ALIGNED TRUTH : . )1(هجيه ام ردق ىىلع
Iteration 6401: BEST OCR TEXT : . )1(هجيمه ام ردق مع

完美样本延迟

在“简单”样本上进行训练不一定是好事,因为它浪费时间,但网络不应该忘记如何处理这些样本,因此如果简单的样本出现得太频繁,可以丢弃一些。 --perfect_sample_delay 参数会丢弃完美的样本,如果自上次看到完美的样本以来还没有看到那么多不完美的样本。当前默认值为零,使用所有样本。在实践中,该值似乎没有太大影响,如果允许训练运行足够长的时间,零会产生最佳结果。

调试间隔和可视化调试

使用零(默认值) --debug_interval,训练器每 100 次迭代输出一个进度报告,类似于以下示例。

At iteration 61239/65000/65015, Mean rms=1.62%, delta=8.587%, char train=16.786%, word train=36.633%, skip ratio=0.1%,  wrote checkpoint.

At iteration 61332/65100/65115, Mean rms=1.601%, delta=8.347%, char train=16.497%, word train=36.24%, skip ratio=0.1%,  wrote checkpoint.

2 Percent improvement time=44606, best error was 17.77 @ 16817
Warning: LSTMTrainer deserialized an LSTMRecognizer!
At iteration 61423/65200/65215, Mean rms=1.559%, delta=7.841%, char train=15.7%, word train=35.68%, skip ratio=0.1%,  New best char error = 15.7At iteration 45481, stage 0, Eval Char error rate=6.9447893, Word error rate=27.039255 wrote best model:./SANLAYER/LAYER15.7_61423.checkpoint wrote checkpoint.

使用 --debug_interval -1,训练器会为每次训练迭代输出详细的调试文本。文本调试信息包括真实文本、识别文本、迭代次数、训练样本 ID(lstmf 文件和行)以及几个错误指标的平均值。所有情况下都会显示行的 GROUND TRUTHALIGNED TRUTHBEST OCR TEXT 仅在与 GROUND TRUTH 不同时显示。

Iteration 455038: GROUND  TRUTH : उप॑ त्वाग्ने दि॒वेदि॑वे॒ दोषा॑वस्तर्धि॒या व॒यम् ।
File /tmp/san-2019-03-28.jsY/san.Mangal.exp0.lstmf line 451 (Perfect):
Mean rms=1.267%, delta=4.155%, train=11.308%(32.421%), skip ratio=0%
Iteration 455039: GROUND  TRUTH : मे अपराध और बैठे दुकानों नाम सकते अधिवक्ता, दोबारा साधन विषैले लगाने पर प्रयोगकर्ताओं भागे
File /tmp/san-2019-04-04.H4m/san.FreeSerif.exp0.lstmf line 28 (Perfect):
Mean rms=1.267%, delta=4.153%, train=11.3%(32.396%), skip ratio=0%
Iteration 1526: GROUND  TRUTH : 𒃻 𒀸 𒆳𒆳 𒅘𒊏𒀀𒋾
Iteration 1526: ALIGNED TRUTH : 𒃻 𒀸 𒆳𒆳 𒅘𒊏𒊏𒀀𒋾
Iteration 1526: BEST OCR TEXT :    𒀀𒋾
File /tmp/eng-2019-04-06.Ieb/eng.CuneiformComposite.exp0.lstmf line 19587 :
Mean rms=0.941%, delta=12.319%, train=56.134%(99.965%), skip ratio=0.6%
Iteration 1527: GROUND  TRUTH : 𒀭𒌋𒐊
Iteration 1527: BEST OCR TEXT : 𒀭𒌋
File /tmp/eng-2019-04-06.Ieb/eng.CuneiformOB.exp0.lstmf line 7771 :
Mean rms=0.941%, delta=12.329%, train=56.116%(99.965%), skip ratio=0.6%

使用 --debug_interval > 0,训练器会在网络层上显示多个调试信息窗口。在 --debug_interval 1 的特殊情况下,它会在继续到下一个迭代之前等待 LSTMForward 窗口中的单击,但对于所有其他情况,它只是继续并按要求的频率绘制信息。

注意,要使用 –debug_interval > 0,您必须构建 ScrollView.jar 以及其他训练工具。 请参阅 构建训练工具

视觉调试信息包括

每个网络层的正向和反向窗口。大多数只是随机噪声,但 Output/Output-backConvNL 窗口值得查看。 Output 显示最终 Softmax 的输出,它最初是空字符的黄色线,并逐渐在它认为有字符的每个点开发出黄色标记。(x 轴是图像 x 坐标,y 轴是字符类。) Output-back 窗口显示实际输出与目标之间的差异,使用相同的布局,但黄色表示“给我更多”,蓝色表示“给我更少”。随着网络学习, ConvNL 窗口开发出您期望从底层获得的典型边缘检测结果。

LSTMForward 显示网络在训练图像上的整体输出。 LSTMTraining 显示训练图像上的训练目标。在这两者中,都绘制了绿线以显示每个字符的峰值输出,并在线的右侧绘制了字符本身。

其他两个值得查看的窗口是 CTC OutputsCTC Targets。这些将网络的当前输出和目标显示为输出强度相对于图像 x 坐标的线图。与 Output 窗口不同,它不是热图,而是为每个字符类绘制了不同颜色的线,y 轴是输出强度。

迭代和检查点

在训练期间,我们看到了这种信息

At iteration 100/100/100, Mean rms=4.514%, delta=19.089%, char train=96.314%, word train=100%, skip ratio=0%,  New best char error = 96.314 wrote checkpoint.
...
At iteration 14615/695400/698614, Mean rms=0.158%, delta=0.295%, char train=1.882%, word train=2.285%, skip ratio=0.4%,  wrote checkpoint.

在上面的示例中,

14615 : learning_iteration
695400 : training_iteration
698614 : sample_iteration

sample_iteration : “训练样本集中的索引。(sample_iteration >= training_iteration)。” 它表示训练文件被传递到学习过程中的次数。

training_iteration : “使用的实际反向训练步骤数量。” 它表示训练文件被成功传递到学习过程中的次数。因此,每次出现错误时:“图像太大而无法学习!” - “字符串编码失败!” - “反序列化标头失败”,sample_iteration 会递增,但 training_iteration 不会递增。实际上,您有 1 - (695400 / 698614) = 0.4%,即跳过比率:由于错误而跳过的文件的比例

learning_iteration : “产生非零增量误差并因此提供显著学习的迭代次数。(learning_iteration <= training_iteration)。learning_iteration 用于衡量学习进度的速度。” 因此,它使用增量值来评估迭代是否有效。

需要注意的是,当您向训练过程指定最大迭代次数时,它使用中间迭代次数(training_iteration)来知道何时停止。但是,当它写入检查点时,检查点名称还使用最佳迭代次数(learning_iteration)以及字符训练率。因此,检查点名称是model_name & char_train & learning_iteration & training_iteration 的串联,例如 sanLayer_1.754_347705_659600.checkpoint。

lstmtraining 程序输出两种检查点文件

这两种检查点文件都可以使用 lstmtraining 的 stop_trainingconvert_to_int 标志转换为标准(最佳/浮点)训练数据文件或略微不太准确(快速/整数)训练数据文件。

TessTutorial

创建训练数据 的过程记录在下面,接着是 LSTM 训练教程,它介绍了主要的训练过程,并包含了经过实际测试的命令行。至少在 Linux 上,您应该能够直接将命令行复制粘贴到终端中。

为了使 tesstrain.sh 脚本正常工作,您需要将 PATH 设置为包含本地 trainingapi 目录,或者使用 make install

TessTutorial 的一次性设置

为了成功运行 TessTutorial,您需要拥有一个正常工作的 Tesseract 和训练工具安装,并且在特定目录中拥有训练脚本和所需的训练数据文件。这些说明仅涵盖从字体进行渲染的情况,因此必须首先安装 所需的字体。请注意,字体的存放位置可能会有所不同。

sudo apt update
sudo apt install ttf-mscorefonts-installer
sudo apt install fonts-dejavu
fc-cache -vf

按照以下说明完成 TessTutorial 的首次设置。

mkdir ~/tesstutorial
cd ~/tesstutorial

mkdir langdata
cd langdata
wget https://raw.githubusercontent.com/tesseract-ocr/langdata_lstm/main/radical-stroke.txt
wget https://raw.githubusercontent.com/tesseract-ocr/langdata_lstm/main/common.punc
wget https://raw.githubusercontent.com/tesseract-ocr/langdata_lstm/main/font_properties
wget https://raw.githubusercontent.com/tesseract-ocr/langdata_lstm/main/Latin.unicharset
wget https://raw.githubusercontent.com/tesseract-ocr/langdata_lstm/main/Latin.xheights
mkdir eng
cd eng
wget https://raw.githubusercontent.com/tesseract-ocr/langdata/main/eng/eng.training_text
wget https://raw.githubusercontent.com/tesseract-ocr/langdata/main/eng/eng.punc
wget https://raw.githubusercontent.com/tesseract-ocr/langdata/main/eng/eng.numbers
wget https://raw.githubusercontent.com/tesseract-ocr/langdata/main/eng/eng.wordlist

cd ~/tesstutorial
git clone --depth 1 https://github.com/tesseract-ocr/tesseract.git
cd tesseract/tessdata
wget https://github.com/tesseract-ocr/tessdata/raw/main/eng.traineddata
wget https://github.com/tesseract-ocr/tessdata/raw/main/osd.traineddata
mkdir best
cd best
wget https://github.com/tesseract-ocr/tessdata_best/raw/main/eng.traineddata
wget https://github.com/tesseract-ocr/tessdata_best/raw/main/heb.traineddata
wget https://github.com/tesseract-ocr/tessdata_best/raw/main/chi_sim.traineddata

创建训练数据

与基本 Tesseract 一样,您可以在从字体渲染合成训练数据或标记一些预先存在的图像(例如古代手稿)之间进行选择。

无论哪种情况,所需格式仍然是 tiff/box 文件对,只是框只需要覆盖文本行,而不是单个字符。

如果您使用 tesstrain.sh,则所需的 synthetic 训练数据(box/tiff 文件对和 lstmf 文件)将从训练文本和给定的字体列表中创建。

制作框文件

Tesseract 4 为 LSTM 训练接受多种格式的框文件,尽管它们与 Tesseract 3 使用的格式不同(详情)。

框文件中的每一行对应于 tiff 图像中的一个“字符”(字形)。

<symbol> <left> <bottom> <right> <top> <page> 其中 <left> <bottom> <right> <top> <page> 可以是单个字形或整个文本行的边界框坐标(参见示例)。

要标记文本行的结尾,必须在多行之后插入一个特殊行。

<tab> <left> <bottom> <right> <top> <page>

可以使用 Tesseract 4.0 使用 lstmbox 配置从图像数据生成框文件,方法是使用 tesseract <image name including extension> <box file name> lstmbox。例如, tesseract image.png image lstmbox 将为当前目录中的图像生成一个名为 image.box 的框文件。

请注意,在所有情况下,即使对于阿拉伯语等从右到左的语言,文本行的转录也应该从左到右排序。 换句话说,网络将从左到右学习,无论语言如何,从右到左/双向处理在 Tesseract 内部更高层面上进行。

使用 tesstrain.sh

运行 tesstrain.sh 的设置与基本 Tesseract 相同。对于 LSTM 训练,请使用 --linedata_only 选项。请注意,拥有更多训练文本并创建更多页面是有益的,因为神经网络的泛化能力不强,需要在与运行环境类似的东西上进行训练。如果目标领域非常有限,那么关于需要大量训练数据的严重警告可能不适用,但可能需要更改网络规范。

使用 tesstrain.sh 创建训练数据,如下所示

src/training/tesstrain.sh --fonts_dir /usr/share/fonts --lang eng --linedata_only \
  --noextract_font_properties --langdata_dir ../langdata \
  --tessdata_dir ./tessdata --output_dir ~/tesstutorial/engtrain

成功运行后,将打印出以下内容

Created starter traineddata for LSTM training of language 'eng'
Run 'lstmtraining' command to continue LSTM training for language 'eng'

上面的命令创建了等同于用于训练英语基本 Tesseract 的数据的 LSTM 训练数据。对于创建通用的基于 LSTM 的 OCR 引擎,它远远不够,但可以作为很好的教程演示。

现在尝试以下操作,为“Impact”字体创建评估数据

src/training/tesstrain.sh --fonts_dir /usr/share/fonts --lang eng --linedata_only \
  --noextract_font_properties --langdata_dir ../langdata \
  --tessdata_dir ./tessdata \
  --fontlist "Impact Condensed" --output_dir ~/tesstutorial/engeval

我们将在后面使用这些数据来演示调整。

lstmtraining 的教程指南

创建启动训练数据

lstmtraining 在其命令行上接受一个 traineddata 文件,以获取有关要学习的语言的所有必要信息。 traineddata 必须至少包含 lstm-unicharsetlstm-recoder 组件,并且还可以包含三个 dawg 文件: lstm-punc-dawg lstm-word-dawg lstm-number-dawg 一个 config 文件也是可选的。如果存在其他组件,将被忽略和未使用。

没有工具可以直接创建 lstm-recoder。相反,有一个工具 combine_lang_model,它接受 input_unicharsetscript_dir (script_dir 指向 langdata 目录) 以及 lang (lang 是正在使用的语言) 以及可选的单词列表文件作为输入。它从 input_unicharset 创建 lstm-recoder,并在提供单词列表的情况下创建所有 dawg,并将所有内容组合成一个 traineddata 文件。

如果您使用 tesstrain.sh,那么启动训练数据也会与 synthetic 训练数据(box/tiff 文件对和 lstmf 文件)一起创建,这些数据来自训练文本和给定的字体列表。

从头开始训练

以下示例显示了从头开始训练的命令行。尝试使用上面命令行创建的默认训练数据来执行此操作。

mkdir -p ~/tesstutorial/engoutput
training/lstmtraining --debug_interval 100 \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --net_spec '[1,36,0,1 Ct3,3,16 Mp3,3 Lfys48 Lfx96 Lrx96 Lfx256 O1c111]' \
  --model_output ~/tesstutorial/engoutput/base --learning_rate 20e-4 \
  --train_listfile ~/tesstutorial/engtrain/eng.training_files.txt \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt \
  --max_iterations 5000 &>~/tesstutorial/engoutput/basetrain.log

(请注意,网络规范中的“O1c111”表示 111 个输出类别;这应该与 unicharset 文件中的条目数量相匹配。)

在一个单独的窗口中监控日志文件

tail -f ~/tesstutorial/engoutput/basetrain.log

您应该观察到,在 600 次迭代后,空格(白色)开始出现在 CTC Outputs 窗口中,并且在 1300 次迭代后,绿色线条出现在 LSTMForward 窗口中,图像中有空格的地方。

在 1300 次迭代后,CTC Outputs 中出现了明显的非空格凸起。请注意,CTC Targets 最初的高度都相同,但现在高度各不相同,因为空格和一些字符的输出是确定的,而其他字符的输出则是暂时的。同时,LSTMTraining 窗口中绿色线条的字符和位置不如最初准确,因为网络的局部输出使 CTC 算法感到困惑。(CTC 假设不同 x 坐标之间统计独立,但它们显然并非独立。)

在 2000 次迭代后,在 Output 窗口中应该可以清楚地看到,一些淡黄色的标记正在出现,以指示非空且非空格字符的输出正在增长,并且字符开始出现在 LSTMForward 窗口中。

字符错误率在 3700 次迭代后降至 50% 以下,并在 5000 次迭代后降至约 13%,然后停止。(在具有 AVX 的当前高端机器上大约需要 20 分钟。)

请注意,此引擎使用与传统 Tesseract 引擎相同的训练数据量进行训练,但在其他字体上的准确率可能非常低。对“Impact”字体进行独立测试

training/lstmeval --model ~/tesstutorial/engoutput/base_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

字符错误率 85%?不太好!

现在,基础 Tesseract 在“Impact”上表现不佳,但它包含在用于训练新的 LSTM 版本的约 4500 种字体中,因此,如果您可以在上面运行以进行比较

training/lstmeval --model tessdata/best/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

字符错误率 2.45%?好多了!

为了在下节中参考,还要对我们一直在使用的训练集运行完整模型的测试

training/lstmeval --model tessdata/best/eng.traineddata \
  --eval_listfile ~/tesstutorial/engtrain/eng.training_files.txt

字符错误率=0.25047642,词错误率=0.63389585

您可以再训练 5000 次迭代,并将训练集上的错误率降得更低,但这对“Impact”字体没有多大帮助

mkdir -p ~/tesstutorial/engoutput
training/lstmtraining \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --net_spec '[1,36,0,1 Ct3,3,16 Mp3,3 Lfys48 Lfx96 Lrx96 Lfx256 O1c111]' \
  --model_output ~/tesstutorial/engoutput/base --learning_rate 20e-4 \
  --train_listfile ~/tesstutorial/engtrain/eng.training_files.txt \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt \
  --max_iterations 10000 &>>~/tesstutorial/engoutput/basetrain.log

现在,“Impact”上的字符错误率 > 100%,即使训练集上的错误率已降至字符 2.68% / 词 10.01%

training/lstmeval --model ~/tesstutorial/engoutput/base_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

这表明该模型已完全过拟合提供的训练集!这是一个很好的例子,说明当训练集没有涵盖目标数据中所需的变异时会发生什么。

总之,从头开始训练需要非常受限的问题、大量训练数据,或者您需要通过减小上面 --net_spec 中某些层的尺寸来缩小网络。或者,您可以尝试微调……

微调以产生影响

请注意,只有使用 float 模型作为基础才能继续进行 Impact 的微调,即使用 tessdata_best 存储库中的训练数据文件,而不是使用 tessdatatessdata_fast

微调是在不改变网络的任何部分的情况下,使用新数据训练现有模型的过程,尽管您现在可以将字符添加到字符集中。(参见 ± 几个字符的微调)。

training/lstmtraining --model_output /path/to/output [--max_image_MB 6000] \
  --continue_from /path/to/existing/model \
  --traineddata /path/to/original/traineddata \
  [--perfect_sample_delay 0] [--debug_interval 0] \
  [--max_iterations 0] [--target_error_rate 0.01] \
  --train_listfile /path/to/list/of/filenames.txt

注意--continue_from 参数可以指向训练检查点识别模型,即使文件格式不同。训练检查点是使用 --model_output 开头并以 checkpoint 结尾的文件。可以使用 combine_tessdata 从现有的 traineddata 文件中提取识别模型。请注意,还需要提供原始 traineddata 文件,因为它包含 unicharset 和 recoder。让我们从微调之前构建的模型开始,看看我们是否可以使其适用于“Impact”

mkdir -p ~/tesstutorial/impact_from_small
training/lstmtraining --model_output ~/tesstutorial/impact_from_small/impact \
  --continue_from ~/tesstutorial/engoutput/base_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --train_listfile ~/tesstutorial/engeval/eng.training_files.txt \
  --max_iterations 1200

在 100 次迭代后,字符/词错误率分别为 22.36%/50.0%,在 1200 次迭代后降至 0.3%/1.2%。现在进行独立测试

training/lstmeval --model ~/tesstutorial/impact_from_small/impact_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

这显示了 0.0086%/0.057% 的更好结果,因为训练器正在对 1000 次迭代进行平均,并且一直在改进。但这并不是“Impact”字体的代表性结果,因为我们正在对训练数据进行测试!

这是一个有点玩具的例子。微调的真正思想是将其应用于完全训练过的现有模型之一

mkdir -p ~/tesstutorial/impact_from_full
training/combine_tessdata -e tessdata/best/eng.traineddata \
  ~/tesstutorial/impact_from_full/eng.lstm
training/lstmtraining --model_output ~/tesstutorial/impact_from_full/impact \
  --continue_from ~/tesstutorial/impact_from_full/eng.lstm \
  --traineddata tessdata/best/eng.traineddata \
  --train_listfile ~/tesstutorial/engeval/eng.training_files.txt \
  --max_iterations 400

在 100 次迭代后,字符/词错误率分别为 1.35%/4.56%,在 400 次迭代后降至 0.533%/1.633%。同样,独立测试给出了更好的结果

training/lstmeval --model ~/tesstutorial/impact_from_full/impact_checkpoint \
  --traineddata tessdata/best/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

字符错误率 0.017%,词错误率 0.120%。更有趣的是,它对其他字体的影响,因此对我们一直在使用的基础训练集进行测试

training/lstmeval --model ~/tesstutorial/impact_from_full/impact_checkpoint \
  --traineddata tessdata/best/eng.traineddata \
  --eval_listfile ~/tesstutorial/engtrain/eng.training_files.txt

字符错误率=0.25548592,词错误率=0.82523491

尽管在训练集上已接近零错误,并且仅在 400 次迭代中就实现了,但它只略微变差。请注意,超过 400 次迭代的进一步训练会导致基础集上的错误率更高。

总之,可以对预训练模型进行微调或调整,使其适用于小型数据集,不会对其整体准确性造成很大损害。然而,避免过度拟合仍然非常重要。

微调以调整 +/- 几个字符

请注意,只有使用 float 模型作为基础才能继续进行 ± 几个字符的微调,即使用 tessdata_best 存储库中的训练数据文件,而不是使用 tessdatatessdata_fast

新功能 可以通过微调将一些新字符添加到字符集中并为它们进行训练,而无需大量训练数据。

训练需要新的 unicharset/recoder、可选语言模型以及包含旧 unicharset/recoder 的旧 traineddata 文件。

training/lstmtraining --model_output /path/to/output [--max_image_MB 6000] \
  --continue_from /path/to/existing/model \
  --traineddata /path/to/traineddata/with/new/unicharset \
  --old_traineddata /path/to/existing/traineddata \
  [--perfect_sample_delay 0] [--debug_interval 0] \
  [--max_iterations 0] [--target_error_rate 0.01] \
  --train_listfile /path/to/list/of/filenames.txt

让我们尝试将加减号 (±) 添加到现有的英文模型中。修改 langdata/eng/eng.training_text 以包含 ± 的一些样本。我在下面插入了 14 个,如下所示

grep ± ../langdata/eng/eng.training_text
alkoxy of LEAVES ±1.84% by Buying curved RESISTANCE MARKED Your (Vol. SPANIEL
TRAVELED ±85¢ , reliable Events THOUSANDS TRADITIONS. ANTI-US Bedroom Leadership
Inc. with DESIGNS self; ball changed. MANHATTAN Harvey's ±1.31 POPSET Os—C(11)
VOLVO abdomen, ±65°C, AEROMEXICO SUMMONER = (1961) About WASHING Missouri
PATENTSCOPE® # © HOME SECOND HAI Business most COLETTI, ±14¢ Flujo Gilbert
Dresdner Yesterday's Dilated SYSTEMS Your FOUR ±90° Gogol PARTIALLY BOARDS firm
Email ACTUAL QUEENSLAND Carl's Unruly ±8.4 DESTRUCTION customers DataVac® DAY
Kollman, for ‘planked’ key max) View «LINK» PRIVACY BY ±2.96% Ask! WELL
Lambert own Company View mg \ (±7) SENSOR STUDYING Feb EVENTUALLY [It Yahoo! Tv
United by #DEFINE Rebel PERFORMED ±500Gb Oliver Forums Many | ©2003-2008 Used OF
Avoidance Moosejaw pm* ±18 note: PROBE Jailbroken RAISE Fountains Write Goods (±6)
Oberflachen source.” CULTURED CUTTING Home 06-13-2008, § ±44.01189673355 €
netting Bookmark of WE MORE) STRENGTH IDENTICAL ±2? activity PROPERTY MAINTAINED

现在生成新的训练和评估数据

src/training/tesstrain.sh --fonts_dir /usr/share/fonts --lang eng --linedata_only \
  --noextract_font_properties --langdata_dir ../langdata \
  --tessdata_dir ./tessdata --output_dir ~/tesstutorial/trainplusminus
src/training/tesstrain.sh --fonts_dir /usr/share/fonts --lang eng --linedata_only \
  --noextract_font_properties --langdata_dir ../langdata \
  --tessdata_dir ./tessdata \
  --fontlist "Impact Condensed" --output_dir ~/tesstutorial/evalplusminus

对新的训练数据运行微调。这需要更多迭代,因为它只有少量新目标字符的样本可以参考

training/combine_tessdata -e tessdata/best/eng.traineddata \
  ~/tesstutorial/trainplusminus/eng.lstm
training/lstmtraining --model_output ~/tesstutorial/trainplusminus/plusminus \
  --continue_from ~/tesstutorial/trainplusminus/eng.lstm \
  --traineddata ~/tesstutorial/trainplusminus/eng/eng.traineddata \
  --old_traineddata tessdata/best/eng.traineddata \
  --train_listfile ~/tesstutorial/trainplusminus/eng.training_files.txt \
  --max_iterations 3600

在 100 次迭代后,字符/词错误率分别为 1.26%/3.98%,在 3600 次迭代后降至 0.041%/0.185%。同样,独立测试给出了更好的结果

training/lstmeval --model ~/tesstutorial/trainplusminus/plusminus_checkpoint \
  --traineddata ~/tesstutorial/trainplusminus/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/trainplusminus/eng.training_files.txt

字符错误率 0.0326%,词错误率 0.128%。更有趣的是,新字符是否可以在“Impact”字体中识别,因此对 impact 评估集进行测试

training/lstmeval --model ~/tesstutorial/trainplusminus/plusminus_checkpoint \
  --traineddata ~/tesstutorial/trainplusminus/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/evalplusminus/eng.training_files.txt

字符错误率=2.3767074,词错误率=8.3829474

这与原始模型在 impact 数据集上的原始测试相比非常出色。此外,如果您检查错误

training/lstmeval --model ~/tesstutorial/trainplusminus/plusminus_checkpoint \
  --traineddata ~/tesstutorial/trainplusminus/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/evalplusminus/eng.training_files.txt 2>&1 |
  grep ±

…您应该看到它将所有 ± 符号都识别正确!(每个包含 ± 的真值行也包含对应 OCR 行上的 ±,并且没有真值行没有在 grep 输出中匹配的 OCR 行。)

这是一个好消息!这意味着可以添加一个或多个新字符,而不会影响现有准确率,并且识别新字符的能力将在某种程度上推广到其他字体!

注意:在微调时,重要的是要试验迭代次数,因为对小型数据集过度训练会导致过度拟合。ADAM 非常适合找到识别该稀有类别所需的特征组合,但它似乎比更简单的优化器更容易过度拟合。

仅训练几层

请注意,只有使用 float 模型作为基础才能继续进行仅训练几层的操作,即使用 tessdata_best 存储库中的训练数据文件,而不是使用 tessdatatessdata_fast

如果您只想添加新的字体样式或需要几个新字符,那么微调就可以了,但如果您想为克林贡语进行训练呢?您不太可能拥有很多训练数据,并且它与任何其他东西都不一样,那么您该怎么办?您可以尝试删除现有网络模型的某些顶层,用新的随机层替换其中一些层,并使用您的数据进行训练。命令行与 从头开始训练 几乎相同,但此外您还必须向 --continue_from--append_index 提供模型。

--append_index 参数告诉它删除高于具有给定索引的层的所有层(从最外层系列的零开始),然后将给定的 --net_spec 参数附加到剩余部分。虽然这种索引系统不是一个完美的网络层引用方式,但这是由于网络规范语言大大简化了。构建器将输出与它生成的网络相对应的字符串,使其能够方便地检查索引是否引用了预期的层。

4.00 alpha 的一项新功能是 combine_tessdata 可以列出 traineddata 文件的内容及其版本字符串。在大多数情况下,版本字符串包含用于训练的 net_spec

training/combine_tessdata -d tessdata/best/heb.traineddata
Version string:4.00.00alpha:heb:synth20170629:[1,36,0,1Ct3,3,16Mp3,3Lfys48Lfx96Lrx96Lfx192O1c1]
17:lstm:size=3022651, offset=192
18:lstm-punc-dawg:size=3022651, offset=3022843
19:lstm-word-dawg:size=673826, offset=3024221
20:lstm-number-dawg:size=625, offset=3698047
21:lstm-unicharset:size=1673826, offset=3703368
22:lstm-recoder:size=4023, offset=3703368
23:version:size=80, offset=3703993

以及 chi_sim

training/combine_tessdata -d tessdata/best/chi_sim.traineddata
Version string:4.00.00alpha:chi_sim:synth20170629:[1,48,0,1Ct3,3,16Mp3,3Lfys64Lfx96Lrx96Lfx512O1c1]
0:config:size=1966, offset=192
17:lstm:size=12152851, offset=2158
18:lstm-punc-dawg:size=282, offset=12155009
19:lstm-word-dawg:size=590634, offset=12155291
20:lstm-number-dawg:size=82, offset=12745925
21:lstm-unicharset:size=258834, offset=12746007
22:lstm-recoder:size=72494, offset=13004841
23:version:size=84, offset=13077335

请注意,层数相同,但只有大小不同。因此,在这些模型中,--append_index 的以下值将保留关联的最后一层,并在其上面附加

索引
0 输入
1 Ct3,3,16
2 Mp3,3
3 Lfys48/64
4 Lfx96
5 Lrx96
6 Lfx192/512

现有模型剩余部分的权重最初保持不变,但允许由新的训练数据修改。

例如,让我们尝试将现有的 chi_sim 模型转换为 eng。我们将截断最后一层 LSTM(它比用于训练 eng 模型的 LSTM 更大)和 softmax,并用更小的 LSTM 层和新的 softmax 替换。

mkdir -p ~/tesstutorial/eng_from_chi
training/combine_tessdata -e tessdata/best/chi_sim.traineddata \
  ~/tesstutorial/eng_from_chi/eng.lstm
training/lstmtraining --debug_interval 100 \
  --continue_from ~/tesstutorial/eng_from_chi/eng.lstm \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --append_index 5 --net_spec '[Lfx256 O1c111]' \
  --model_output ~/tesstutorial/eng_from_chi/base \
  --train_listfile ~/tesstutorial/engtrain/eng.training_files.txt \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt \
  --max_iterations 3000 &>~/tesstutorial/eng_from_chi/basetrain.log

由于较低的层已经过训练,因此学习速度比从头开始训练要快一些。在 600 次迭代后,它突然开始产生输出,并在 800 次迭代后,它已经开始识别大多数字符。到它在 3000 次迭代后停止时,它应该达到 6.00% 的字符错误率/22.42% 的词错误率。

尝试对完整训练集进行通常的测试

training/lstmeval --model ~/tesstutorial/eng_from_chi/base_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/engtrain/eng.training_files.txt

以及对 Impact 字体的独立测试

training/lstmeval --model ~/tesstutorial/eng_from_chi/base_checkpoint \
  --traineddata ~/tesstutorial/engtrain/eng/eng.traineddata \
  --eval_listfile ~/tesstutorial/engeval/eng.training_files.txt

在完整训练集上,我们得到了 5.557%/20.43%,在 Impact 上得到了 36.67%/83.23%,这比从头开始训练要好得多,但仍然严重过拟合。

总之,可以截断现有网络的顶层并进行训练,就像从头开始训练一样,但仍然需要相当大量的训练数据来避免过度拟合。

训练中的错误消息

运行训练时可能会出现各种错误消息,其中一些消息很重要,而另一些消息则不太重要

Encoding of string failed! 当训练图像的文本字符串无法使用给定的 unicharset 编码时,就会出现此错误。可能的原因是

  1. 文本中存在未表示的字符,例如您的 unicharset 中没有的英镑符号。
  2. 文本中存在一个不打印的字符(如制表符或控制字符)。
  3. 文本中存在未表示的印度语音素/文字。

在任何情况下,都会导致训练器忽略该训练图像。如果错误很少见,则无害,但这可能表明您的 unicharset 不足以表示您正在训练的语言。

Unichar xxx is too long to encode!!(很可能仅限印度语)。recoder 中可以使用的 Unicode 字符长度存在上限,这简化了 LSTM 引擎的 unicharset。它会继续并使该 Aksara 无法识别,但如果有很多 Aksara 无法识别,那么您就麻烦了。

Bad box coordinates in boxfile string! LSTM 训练器只需要完整文本行的边界框信息,而不是字符级别的边界框信息,但如果您在框字符串中添加空格,例如

<text for line including spaces> <left> <bottom> <right> <top> <page>

解析器将会感到困惑,并向您显示该错误消息。

Deserialize header failed 发生在训练输入不是 LSTM 格式或文件不可读时。检查您的文件列表文件以查看它是否包含有效的文件名。

No block overlapping textline: 发生在布局分析未能正确分割作为训练数据给出的图像时。文本行被丢弃。如果不多,则问题不大,但如果很多,则可能是训练文本或渲染过程存在问题。

<Undecodable> 可能会在训练初期出现在 ALIGNED_TRUTH 或 OCR TEXT 输出中。这是 unicharset 压缩和 CTC 训练的结果。(参见上面的 Unicharset 压缩和 train_mode)。这应该是无害的,可以安全地忽略。其频率应该随着训练的进行而下降。

组合输出文件

lstmtraining 程序输出两种检查点文件

可以使用以下方法将这两个文件中的任何一个转换为标准的 traineddata 文件

training/lstmtraining --stop_training \
  --continue_from ~/tesstutorial/eng_from_chi/base_checkpoint \
  --traineddata /path/to/traineddata/used/in/lstmtraining/eng.traineddata \
  --model_output ~/tesstutorial/eng_from_chi/eng.traineddata

这将从训练转储中提取识别模型,并将它插入 –traineddata 参数中,以及训练期间提供的 unicharset、recoder 和任何 dawgs。

注意 Tesseract 4.00 现在将与仅包含 lang.lstmlang.lstm-unicharsetlang.lstm-recoder 的 traineddata 文件一起顺利运行。 lstm-*-dawgs 是可选的,当 OCR 引擎模式为 OEM_LSTM_ONLY 时,其他任何组件都不需要或使用。双字母组合、unichar ambigs 或任何其他组件都不需要,即使存在也不起作用。唯一起作用的其他组件是 lang.config,它可以影响布局分析和子语言。

如果添加到现有的 Tesseract traineddata 文件中,lstm-unicharset 不需要与 Tesseract unicharset 相匹配,但必须使用相同的 unicharset 来训练 LSTM 并构建 lstm-*-dawgs 文件。

幻觉效应

如果您注意到您的模型行为异常,例如

那么请阅读幻觉主题。