ZMonster's Blog 巧者劳而智者忧,无能者无所求,饱食而遨游,泛若不系之舟

Tesseract: 训练(续)

续上篇: 《Tesseract:训练》。本篇主要解释一下 DAWG 文件的生成方法,并提供一个更易用的训练工具。

更易配置和使用的训练工具

Tesseract 自身提供的训练工具分为了多个不同的程序,用起来比较灵活,但说实话,要记住每个程序的使用方法还真是一件费力的事情。此外,为了得到较好的训练结果,往往会需要用多种字体进行训练,而不同的字体除了一两个参数(一般为字体名称、位置)不一样外,其他的过程、参数都是相似的,这里有大量的重复性操作。

为此我写了一个更好的训练工具,只要开始时在配置文件中设置好字体、文本等信息,然后就可以敲击几个简单的命令进行训练。当然了,与此同时,训练过程中的灵活性会受到一定的影响。

获取工具

工具放在我的 Github 项目中,项目地址为:

https://github.com/Linusp/zutil

项目 python 目录下的 tess_train.py 就是了

配置

见项目 python/configs/ 目录下的 tess.json,其内容为:

{
    "name": "chi_eng",
    "font": {
        "wqy": {
            "font-dir": "/usr/share/fonts/truetype",
            "sub-font": {
                "fixed": "WenQuanYi Micro Hei"
            }
        },
        "sun": {
            "font-dir": "/home/linusp/datas/fonts/",
            "sub-font": {
                "serif": "SimSun"
            }
        },
        "nsun": {
            "font-dir": "/home/linusp/datas/fonts/",
            "sub-font": {
                "serif": "NSimSun"
            }
        },
        "times": {
            "font-dir": "/home/linusp/data/fonts/TimesNewRoman",
            "sub-font": {
                "italic": "Times New Roman, Italic",
                "bold": "Times New Roman, Bold",
                "serif": "Times New Roman,"
            }
        }
    },
    "data": {
        "chi": {
            "file-name": "chi.txt",
            "font-list": ["wqy", "sun", "nsun"]
        },
        "eng": {
            "file-name": "eng.txt",
            "font-list": ["wqy", "times"]
        }
    }
}

可以看到,配置文件内容分为三大块:

  • name: 即最后生成的 traineddata 文件名称
  • font: 要使用到的字体
  • data: 要用于训练的文本,以及它们各自要使用的字体

name 和 data 这两块都比较易懂,这里只对 font 这一块多做一点说明。

以其中的 times 为例:

"times": {
    "font-dir": "/home/linusp/data/fonts/TimesNewRoman",
    "sub-font": {
        "italic": "Times New Roman, Italic",
        "bold": "Times New Roman, Bold",
        "serif": "Times New Roman,"
    }
}

"times" 是这个字体的名称,用于区别其他字体,在训练过程中生成中间结果时也会用到。需要注意的是,一个名称不一定是只对应 一个字体文件 ,因为种字体除了它的普通形式外,还有斜体、粗体等不同样式,这些不同的样式可能是通过不同的字体文件来表现的。

"font-dir" 就是字体文件所在的目录了,如上,如果要使用同一种字体的多种样式且它们在不同的字体文件中,请将它们放置到相同的目录下。

"sub-font" 指定需要使用的字体样式,可用的有五种,分别是:

  • italic: 斜体
  • bold: 粗体
  • serif: 衬线体
  • fixed: 无衬线体
  • fraktur: 哥特体

serif 和 fixed 都是字体的普通样式,但是这两者是只能有其一的,这是字体自身设计决定的。

每种字体样式对应的 真实字体名称 ,可以用 text2image 来的到:

text2image --fonts_dir=/home/linusp/data/fonts/TimesNewRoman --list_available_fonts

训练

在设置好配置文件后,就可以方便地使用 tess_train.py 进行训练了, tess_train.py 的使用方法是:

./tess_train.py -c <conf file> [-a <action>]

不使用 -a 选项时,会认为是一个全新的训练过程,并将处理整个训练过程,通过 -a 选项可以指定进行训练过程中的某个子步骤,以便更灵活地控制训练过程。可以使用的 <action> 有:

  • tifbox: 用配置文件中 "data" 部分指定的文本生成图像和 BOX 文件
  • charset: 提取字符集信息并生成字符集文件
  • fontprop: 生成字体信息文件
  • feature: 用之前生成的图像和 BOX 文件提取每个字符的特征
  • cluster: 从特征文件产生每个字符的 原型
  • combine: 将中间文件打包成 traineddata

字符识别歧义校正

针对单个字符的识别,所谓歧义,包含以下三种情况(以下A, B皆为代指):

  1. 将字符 A 识别作字符 B
  2. 将一个字符 A 识别多个字符
  3. 将多个字符识别作一个字符 A

第一种情况就是典型的误分类情况,其后两种情况则和字符分割不正确有关系。

对于这三种情况,Tesseract 提供了途径,以便在后处理时对识别结果进行校正。方法是在 traineddata 中添加 unicharambigs 这个 歧义校正文件

该文件有两种格式,旧版本格式在文件首行用 v1 标识,对应的新版本的则用 v2 标识。

注意: 歧义校正文件应编码为 UTF-8

旧版本格式

不管是哪个版本,unicharambigs 文件都是以文本文件的形式存在,并且每行一条校正规则。

在旧版本格式中,每条校正规则是这样的:

<字符数量> <字符串> <校正后的字符数量> <校正后的字符串> <是否强制替换>

最后一个字段如果为 0,则表示匹配到该规则时,不会进行强制替换,只是提供 "建议" ;为 0 时则进行强制替换。

比如说如果 unicharambigs 文件中内容为:

v1
2 ' ' 1 " 1
1 m 2 r n 0
3 i i i 1 m 0

从前到后三条规则的含义分别为:

  1. 识别结果中两个连续的单引号(')应当被强制替换为双引号(")
  2. 识别结果中的字符 m 有可能是 rn
  3. 识别结果中的连续字符串 iii 可能是字符 m

新版本格式

新版本格式更为友好一点,每条校正规则为:

<字符串> <字符串> <是否强制替换>

上面那个例子可以写作:

v2
'' " 1
m rn 0
iii m 0

需要注意的是,新版本格式里的两个字符串 内部不能有空格

词典: DAWG 文件

上篇中提到有 DAWG 文件可以增强、调整识别结果,这些 DAWG 文件被称为词典(dictionary),使用来对识别结果进行后处理的。

所谓后处理是这样的: 对没一个字符,都会有多个候选结果,如果每次都挑选候选结果中最好的结果,不一定是正确的,这是因为实际的数据中会有各种各样的干扰信息,所谓的 "最好结果" 并不一定是正确的结果。在 假设 待识别的文本都是由正常的、 拼写正确的 词组成的时,通过预定义的词典,就可以 以词为单位 对识别结果进行校正。

在 Tesseract 中,DAWG 文件就是作为词典用在后处理中的,自然也应该是从训练用的文本中进行统计得到的。

Tesseract 中支持的 DAWG 文件有五种类型,分别是:

  1. word-dawg

    这个词典文件记录可用的词,每个词占一行。

  2. freq-dawg

    这个词典文件记录最常用的一些词,建议数量在 这个量级。

  3. bigram-dawg

    这个词典记录二元词,同样每个二元词一行。

    所谓的二元词是由前后连续的两个词组成的一个单元,比如说

    生存 还是 死亡 这 是 一个 问题
    

    这句话里的二元词就有:

    生存 还是
    还是 死亡
    死亡 这
    这 是
    是 一个
    一个 问题
    

    其实这已经近似一个二元语言模型(2-Gram Language Model)了,只不过这里不记录词频等信息。

    另外一点要注意的是,在 bigram-dawg 中,二元词之中的数字统一用英文的问号(?)替代

  4. number-dawg

    这个词典用来记录包含数字的词,同样每个词一行,但和 word-dawg 不一样的是,这里记录的词里面的数字,都要用空格替代。

  5. punc-dawg

    这个文件用来记录标点的 模式 ,所谓模式就是说标点在训练用的文本(或语言)中是如何使用的。描述不太直观,下面是从 Tesseract 的英文 traineddata 中 punc-dawg 提取出来的的一段,可以参考一下:

    [
    [ ]
    [ ],
    [ ];
    [ ]:
    [ ]!
    [ ]!!!
    [ ]?
    [ ]?!
    [ ]???
    [ ].
    [ ]...
    {
    { }
    { },
    { };
    { }:
    { }!
    { }!!!
    { }?
    { }?!
    { }???
    { }.
    { }...
    

这五个文件的名称必须是 word-dawg, freq-dawg, bigram-dawg, number-dawg 和 punc-dawg,然后和其他所有用于打包 traineddata 的中间结果一样,应当加上前缀,如要生成名为 eng.traineddata 的最终结果,这五个文件必须是 eng.word-dawg, eng.freq-dawg, eng.bigram-dawg, eng.number-dawg 和 eng.punc-dawg

另外,这五个文件必须是 DAWG 格式,而不是文本文件。一般是先从训练文本中生成对应的文本文件,然后用 Tesseract 提供的 wordlist2dawg 来进行转换,如将 word-list-last 转换为 eng.word-dawg

wordlist2dawg word-list-last eng.word-dawg eng.unicharset

注意: 以上文件都应编码为 UTF-8 再转换为 DAWG 文件