---
# System prepended metadata

title: Tesseract-OCR LSTM模型訓練指南
tags: [日月光]

---

# Tesseract-OCR LSTM模型訓練指南

## 前言
### 技術歷史
Tesseract-OCR在第3版以前用的是傳統的辨識引擎(legacy engine)，從第4版開始，Tesseract-OCR引入LSTM這種以深度學習為基礎的辨識引擎(LSTM engine)，使得辨識的準確度能進一步獲得提升，因此本指南將針對LSTM訓練相關的知識與技巧進行說明。

### 模型訓練成本、辨識速度與準確度間的權衡
中文屬於表意文字，因此中文系統中有著數以萬計的中文字用以表意，從模型訓練的角度來看這意味著一件事，若要建構「全中文字通用的OCR辨識模型」，將會有數萬個類別(label值)，從手寫數字數據集－MNIST類別與訓練資料的比例為10:60000來看，這表示訓練通用模型至少需要上千萬筆的訓練資料，因此不可能也不需要訓練這樣一個全中文字通用的模型，即便有這樣一個模型，辨識速度也可能因為模型過於龐大而變慢。

### 實務操作
從實務上來講，官方已有提供相對較通用且準確的辨識模型，只要以該辨識模型做為基礎，接著對模型進行微調(Fine tune)的動作，就能針對特定辨識錯誤的字詞加強訓練，切記，只需對關鍵字進行訓練，訓練過多的冗餘字，只會造成模型肥大效能下降，官方目前已經針對不同應用情境訓練對應的模型，如下表所示：
| 模型名稱      | 類型                       | 應用情境                 | 準確度 | 速度 |                        專案連結                        |
| ------------- | -------------------------- | -------------------- | ------ |:----:|:------------------------------------------------------:|
| tessdata      | Both legacy &  LSTM engine | 訴求辨識準確率<sup>註1</sup> | 較佳   |  慢  |   [點此](https://github.com/tesseract-ocr/tessdata)    |
| tessdata_best | Only LSTM engine           | 用於模型的微調  | 佳     |  中  | [點此](https://github.com/tesseract-ocr/tessdata_best) |
| tessdata_fast | Only LSTM engine           | 訴求辨識速度快         | 中     |  快  | [點此](https://github.com/tesseract-ocr/tessdata_fast) |
###### 註1. 以雙引擎模式(legacy+LSTM engine)進行辨識最準，缺點是最耗時。
## OCR辨識實務
### 說明
官方其實已經提供了很好的辨識模型，所以如果辨識關鍵字的辨識效果還堪用，那就就直接用就好，因為訓練的成本偏高，但如果關鍵字的辨識能力不足，那麼再繼續往下參閱說明。
### 辨識模型
我們選用的是上表所呈現的[tessdata](https://github.com/tesseract-ocr/tessdata)專案，該專案能啟動雙引擎辨識模式，較耗時但較準確。
### 模型位置
下載完後將模型傳到下列路徑的目錄中。
```
C:\Program Files\Tesseract-OCR\tessdata
```
### 指令格式：
```bash
tesseract [pic to be tested] [output file name] -l [lang] --psm [num] --oem [num]
```
### 指令說明
* 圖片辨識支援格式：包含bmp、pnm、png、jfif、jpeg、tiff，建議png或tif。
* `--psm [num]` 表示Page segmentation modes(分頁模式)<sup>註2</sup>，實務上設6為佳。
* `--oem [num]` 表示OCR Engine modes(OCR 引擎)模式<sup>註3</sup>。

### 指令範例
```
tesseract test.png result -l chi_tra --psm 6 --oem 2
```

###### 註2 psm的代碼意義 
| 代碼 | 意義                                                                                          |
|:----:|:--------------------------------------------------------------------------------------------- |
|  0   | Orientation and script detection (OSD) only.                                                  |
|  1   | Automatic page segmentation with OSD.                                                         |
|  2   | Automatic page segmentation, but no OSD, or OCR. (not implemented)                            |
|  3   | Fully automatic page segmentation, but no OSD. (Default)                                      |
|  4   | Assume a single column of text of variable sizes.                                             |
|  5   | Assume a single uniform block of vertically aligned text.                                     |
|  6   | Assume a single uniform block of text.                                                        |
|  7   | Treat the image as a single text line.                                                        |
|  8   | Treat the image as a single word.                                                             |
|  9   | Treat the image as a single word in a circle.                                                 |
|  10  | Treat the image as a single character.                                                        |
|  11  | Sparse text. Find as much text as possible in no particular order.                            |
|  12  | Sparse text with OSD.                                                                         |
|  13  | Raw line. Treat the image as a single text line, bypassing hacks that are Tesseract-specific. |

###### 註3 oem的代碼意義
| 代碼 | 意義                                   |
|:---- |:-------------------------------------- |
| 0    | Legacy engine only.                    |
| 1    | Neural nets LSTM engine only.          |
| 2    | Legacy + LSTM engines.(雙引擎辨識模式) |
| 3    | Default, based on what is available.   |
## 先備條件
### 運行環境
* Windows 10
* Tesseract OCR v 5.0 alpha([下載](https://github.com/UB-Mannheim/tesseract/wiki))
### 預備檔案
- 訓練文本
- 已訓練模型(tessedata_best－[下載](https://github.com/tesseract-ocr/tessdata_best/blob/master/chi_tra.traineddata))
- 字型檔<sup>註4</sup>
###### 註4. 字型檔若系統有內建就不用特別準備

## 訓練步驟
### Step1. 文字轉圖像
**目的：** 將字型套用在給定的字集生成圖檔
**產出：**
 * `[lang].[fontname].exp[num].tif` 文件
 * `[lang].[fontname].exp[num].box` 文件

**指令格式：**
```bash
text2image --text="[text file path]" --outputbase="[lang].[fontname].exp[num]" --fontconfig_tmpdir="[temp directory]" --font="[fontname]" --fonts_dir="[fontname directory]"
```
**指令說明：**
以下針對`text2image`的常用參數選項功能進行說明：
* `--text="all_chi_new.txt"` 是要進行訓練的樣本文件路徑。
* `--outputbase="chi_tra.MicrosoftJhengHei.exp0"` 欲生成`.tif`和`.box`文件的路徑與名稱。
* `--fontconfig_tmpdir="%temp%"` 字型組態檔的暫存位置(填環境變數即可)，不填會報錯。
* `--font="Microsoft JhengHei"` 字型名稱(不見得是檔名，通常要特別去查)<sup>註5註6</sup>。
* `--fonts_dir="C:\Windows\Fonts"` 原則上是填系統字型文件的路徑，也可以自訂路徑。

若想進一步瞭解各種參數選項的功能與用法，可直接在terminal輸入`text2image`參閱。

**指令範例：**
```bash
text2image --text="all_chi_new.txt" --outputbase="chi_tra.MicrosoftJhengHei.exp0" --fontconfig_tmpdir="%temp%" --font="Microsoft JhengHei" --fonts_dir="C:\Windows\Fonts"
```

###### 註5. 常見字型對應名稱

| 中文名稱   | 樣式       | 對應英文名稱           |
| ---------- | ---------- | ---------------------- |
| 微軟正黑體 | Regular    | Microsoft JhengHei      |
| 微軟正黑體 | Bold       | Microsoft JhengHei Bold  |
| 微軟正黑體 | Light      | Microsoft JhengHei weight=290 |
| 新細明體   | Regular    | mingliub               |
| 標楷體     | Regular    | DFKai-SB               |
| 蘋方體     | Ultralight | PingFang TC Ultralight   |
| 蘋方體     | Light      | PingFang TC Light        |
| 蘋方體     | Thin       | PingFang TC Thin         |
| 蘋方體     | Regular    | PingFang TC Regular      |
| 蘋方體     | Medium     | PingFang TC Medium       |
| 蘋方體     | Semibold   | PingFang TC Semibold     |
###### 註6. 命名注意事項
填入字型名稱時，`--font`須填入正確的fontname，該空格就要空格，但是`--outputbase`出現空格則會報錯，正確範例如下：
* `--font="Microsoft JhengHei weight=290"`
* `--outputbase="chi_tra.MicrosoftJhengHeiLight.exp0"`
### Step2. `.box`文件重建
**目的：** 由於LSTM訓練一次只接受一整排框，而不是一格格的文字框，而在行末還需要一行`\t`表示該行結束，因此需透過`tesseract`指令中的`wordstrbox`參數重建`.box`文件，在訓練的資料量較大時，此步驟相當耗時，若不做可能會報錯，但即便沒報錯，訓練時的錯誤率(loss)也會極高。

**格式：** 
```
# .box file with wordstrbox format
1 148 127 268 151 0
2 148 127 268 151 0
3 148 127 268 151 0
4 148 127 268 151 0
5 148 127 268 151 0
6 148 127 268 151 0
7 148 127 268 151 0
8 148 127 268 151 0
     148 127 268 151 0
```
**產出：**
 * `[lang].[fontname].exp[num].box` 文件

**指令格式：**
```bash
tesseract [lang].[fontname].exp[num].tif [lang].[fontname].exp[num] -l [lang] --psm [num] wordstrbox
```
**指令說明：**
以下針對`tesseract`用於「構建wordstrbox格式的.box文件」的參數選項功能進行說明：
* `-l [lang]` 指定欲使用的辨識語言e.g. chi_tra。
* `wordstrbox` 表示欲構建wordstrbox格式的.box文件。

若想進一步瞭解各參數選項的功能與用法，可在terminal輸入`tesseract --help-extra`參閱。

**指令範例：**
```bash
tesseract chi_tra.MicrosoftJhengHei.exp0.tif chi_tra.MicrosoftJhengHei.exp0 -l chi_tra --psm 6 wordstrbox
```

### Step3. 模型訓練檔構建
**目的：** 透過`.box`與`.tif`檔產生`.lstmf`檔，用於模型訓練。
**產出：**
  * `[lang].[fontname].exp[num].lstmf` 文件

**指令格式：**
```bash
tesseract [lang].[fontname].exp[num].tif  -l [lang] --psm [lang] lstm.train
```
**指令說明：**
以下針對`tesseract`用於「構建.lstmf文件」的參數選項功能進行說明：
* `lstm.train` 表示欲構建.lstmf文件。

**指令範例：**
```bash
tesseract chi_tra.MicrosoftJhengHei.exp0.tif chi_tra.MicrosoftJhengHei.exp0 -l chi_tra --psm 6 lstm.train
```

### Step4. 已訓練的LSTM模型擷取
**目的：** 將`tessedata_best`所下載的`chi_tra.traineddata`中擷取`chi_tra.lstm`文件<sup>註7</sup>。
**產出：**
  * `[lang].lstm` 文件

**指令格式：**
```bash
combine_tessdata -e [target .traineddata file] [target file to extract]
```
**指令說明：**
以下針對`combine_tessdata`的常用參數選項功能進行說明：
* `-e` 可從`.traineddata`中擷取出特定的文件
* `-u` 可從`.traineddata`中擷取出所有文件至特定資料夾。
* `-o` 可將某文件覆寫進`.traineddata`的文件。

**指令範例：**
```bash
combine_tessdata -e chi_tra.traineddata chi_tra.lstm
```
若想進一步瞭解各參數選項的功能與用法，可直接在terminal輸入`combine_tessdata`參閱。
###### 註7. 模型的微調並非一定要以`tessedata_best`的`.lstm`文件為基礎，而是要確定`.traineddata`需為基於LSTM模型所訓練，但由於`tessedata_best`是官方所提供訓練較全面且準確的模型，因此通常以`tessedata_best`為基礎。

### Step5. 訓練資料清單建立
**目的：** 建立一個文件檔，提供訓練檔的路徑。
**產出：**
  * `[lang].training_files.txt` 文件

**文件內容<sup>註8</sup>：**
```
chi_tra.MicrosoftJhengHei.exp0.lstmf
```
###### 註8. 文件中只能有一個`.lstmf`檔的路徑，超過會報錯，請務必留意。

### Step6. 模型訓練
**目的：** 將所有前置作業所準備好的文件用來進行訓練。
**產出：**
  * `[name]_checkpoint` 文件
  * `[name]_[error_rate]_[iterations].checkpoint` 文件

**指令格式：**
```bash
lstmtraining --model_output="[directory of output]" --continue_from="[path to lstm]" --traineddata="[path to .traineddata file]" --train_listfile="[path to train_listfile]" --target_error_rate=[float]
```
**指令說明：**
以下針對`lstmtraining`用以「訓練模型」的參數選項功能進行說明：
* `--model_output` 指定模型訓練完所輸出的路徑。
* `--continue_from` 指定LSTM模型的路徑，以該模型繼續訓練。
* `--train_listfile` 指定存放欲被訓練之`.lstmf`檔的文件路徑。
* `--traineddata` 指定`.traineddata`文件路徑。
* `--target_error_rate` 指定模型準確度收斂的標準(停止標準)。
* `--debug_interval` (optional)預設為0，每100個迭代輸出進度報告，若為-1則改為每次迭代輸出進度。

若想進一步瞭解各參數選項的功能與用法，可直接在terminal輸入`lstmtraining`參閱。

**指令範例：**
```bash
lstmtraining --model_output="dist" --continue_from="chi_tra.lstm" --traineddata="chi_tra.traineddata" --train_listfile="chi_tra.training_files.txt" --target_error_rate=0.01
```

### Step7. 模型輸出
**目的：** 模型訓練完產生的`[name]_checkpoint`文件表示模型參數，將其寫入模型。
**產出：**
  * `[lang].traineddata` 文件

**指令格式：**
```bash
lstmtraining --stop_training --continue_from="[path to [name]_checkpoint file]" --traineddata="[path to .traineddata file]" --model_output="[directory of output]"
```
**指令說明：**
以下針對`lstmtraining`用以「模型輸出」的參數選項功能進行說明：
* `--stop_training` 表示將training model轉換為runtime model。
* `--continue_from` 指定`[name]_checkpoint`文件的路徑，以轉換為runtime model。
* `--traineddata` 指定將被更新model的`.traineddata`文件路徑。
* `--model_output` 指定模型訓練完所輸出的路徑。

若想進一步瞭解各參數選項的功能與用法，可直接在terminal輸入`lstmtraining`參閱。
**指令範例：**
```bash
lstmtraining --stop_training --continue_from="dist_checkpoint" --traineddata="chi_tra.traineddata" --model_output="dist"
```
### Step8. 模型測試
將`[lang].traineddata`放入系統的`~\Tesseract-OCR\tessdata`後，接著將terminal的目錄切換到要測試的圖片目錄底下，即可開始進行測試。

**指令範例：**
```bash
tesseract test.png result -l chi_tra --psm 6
```

## Trobule shooting


### Case1：Compute CTC targets failed!
#### 原因：
Tesseract OCR發現`.box`文件格式錯誤，通常發生在訓練LSTM模型時，因為LSTM訓練一次只接受一整排框，而不是一格格的文字框，而在行末需要一行\t表示該行結束。
#### 相關討論：[討論1](https://github.com/tesseract-ocr/tesseract/issues/591) 、 [討論2](https://github.com/tesseract-ocr/tesseract/issues/2357#issuecomment-477239316)
#### 解決方式：
確保有Step2與Step3有確實完成，並直接跳到Step.6。

### Case2：Encoding of string failed!
#### 原因：
在`[lang].traineddata`文件中有包含許多模型相關的文件，其中一個是`unicharset`文件，裡面記錄著該辨識模型所能辨識的字，相當於LSTM模型能夠分類圖像的類別數量，因此當訓練資料中出現`unicharset`文件沒紀錄的字元時，就相當於模型輸入未知的類別(label)，所以就會報出這個錯誤。

#### 相關討論：[討論1](https://github.com/tesseract-ocr/tesseract/issues/2695) 、 [討論2](https://github.com/tesseract-ocr/tesseract/issues/1012)

#### 解決方式：
針對`unicharset`文件中「沒有被紀錄的字」新建一個`unicharset`文件，並包裝成一個新的`[lang].traineddata`文件對於舊的(欲訓練的)`[lang].traineddata`文件進行訓練，使得原有LSTM模型能夠「支援新類別」也能夠「正確辨識新類別」，因此，也需要針對「欲新增的類別(字)」準備一份訓練文本讓模型訓練。

#### 注意事項：
此步驟相當費工，要擴充的新字除非很關鍵，否則千萬不要貪心的認為反正都要做了，那就連同一些罕用字或特殊符號都一起擴充，這可能會造成樣本蒐集不足，導致模型無法收斂，也可能造成模型訓練成本(時間、精力)過高，甚至使模型過於龐大而造成效能不足。

#### 步驟流程：
**Step1. `unicharset`文件中「沒有被紀錄的字」獲取**
* **想法流程：** 展開`[lang].traineddata`文件，並從中找到`unicharset`文件，接著可以透過自行撰寫程式，進而過濾訓練文本中有哪些未被`unicharset`文件所記錄到的文字而保留下來。
* **目標產出：** 未被`unicharset`文件所記錄到的文字。
* **指令格式：**
```bash
combine_tessdata -u [path of target file]
```
* **指令範例：**
```bash
combine_tessdata -u dist/chi_tra.traineddata
```
**Step.2 `.box`文件獲取**
* **想法流程：** 透過`text2image`指令能將文字轉為`.tif`與`.box`。
* **目標產出：** `.box`文件。
* **指令格式：**
```bash
text2image --text="[path to text file]" --outputbase="[lang].[fontname].exp[num]" --fontconfig_tmpdir="[directory of temp]" --font="[fontname]" --fonts_dir="[directory of fontname]"
```
* **指令範例：**
```bash
text2image --text="all_chi_new.txt" --outputbase="chi_tra.MicrosoftJhengHei.exp0" --fontconfig_tmpdir="%temp%" --font="Microsoft JhengHei" --fonts_dir="C:\Windows\Fonts"
```
**Step.3 `unicharset`文件構建**
* **想法流程：** 透過`unicharset_extractor`指令能將`.box`文件轉為`unicharset`文件。
* **目標產出：** `unicharset`文件。
* **指令格式：**
```bash
unicharset_extractor --output_unicharset [path to unicharset] --norm_mode 1 [path to .box file]
```
* **指令範例：**
```bash
unicharset_extractor --output_unicharset  chi_tra.unicharset --norm_mode 1 chi_tra.MicrosoftJhengHei.exp0.box
```
**Step.4 `unicharset`文件的字元屬性設定**
* **想法流程：** 透過`set_unicharset_properties`指令，將讀取官方所提供langdata<sup>註9</sup>內的資訊，寫入`unicharset`文件的字元屬性中。
* **目標產出：** 已修改字元屬性的`unicharset`文件。
* **指令格式：**
```bash
set_unicharset_properties -U [path to unicharset] -O chi_tra.unicharset --script_dir [directory of langdata]
```
* **指令範例：**
```bash
set_unicharset_properties -U chi_tra.unicharset -O chi_tra.unicharset --script_dir dist\langdata-master
```
###### 註9：請將官方提供的[langdata](https://github.com/tesseract-ocr/langdata)整個專案都clone下來。
**Step.5 新建`.traineddata`文件打包**
* **想法流程：** 將新產生的`unicharset`文件重新打包成`.traineddata`文件，以備後續訓練進行使用。
* **目標產出：** `.traineddata`文件
* **指令格式：**
```bash
combine_lang_model --input_unicharset [path to unicharset] --lang [lang] --script_dir [directory of langdata] --output_dir [directory of output]
```
* **指令範例：**
```bash
combine_lang_model --input_unicharset chi_tra.unicharset --lang chi_tra --script_dir dist\langdata-master --output_dir dist
```
**Step.6 訓練資料準備**
* **想法流程：** 將第一步所保留未被`unicharset`文件所記錄的文字用於建構訓練的語料，可用不同的字型、角度、雜訊等等方式產出圖片，並接續產出所有訓練所需的檔案。
* **目標產出：** 
	* `[lang].[fontname].exp[num].box` 文件
	* `[lang].[fontname].exp[num].tif` 文件
	* `[lang].[fontname].exp[num].lstmf` 文件
	* `[lang].training_files.txt` 文件 
* **指令範例：**
```bash
# 文字轉圖像
text2image --text="training_text.txt" --outputbase="chi_tra.MicrosoftJhengHei.exp0" --fontconfig_tmpdir="%temp%" --font="Microsoft JhengHei" --fonts_dir="C:\Windows\Fonts" --xsize=2000 --ysize=3000

# .box文件重建
tesseract chi_tra.MicrosoftJhengHei.exp0.tif chi_tra.MicrosoftJhengHei.exp0 -l chi_tra --psm 6 wordstrbox

# 模型訓練檔構建
tesseract chi_tra.MicrosoftJhengHei.exp0.tif chi_tra.MicrosoftJhengHei.exp0 -l chi_tra --psm 6 lstm.train
```
**Step.7 寫入新`unicharset`文件並訓練模型**
* **想法流程：** 準備好下列文件，並進行模型訓練。
    - [ ] 由新`unicharset`文件打包成的新`traineddata`文件
    - [ ] 由原`traineddata`文件擷取出來的`lstm`模型
    - [ ] 原`traineddata`文件
    - [ ] 存放欲被訓練之`.lstmf`檔的`training_files`文件。
* **目標產出：** `.traineddata`文件
* **指令範例：**
```bash
lstmtraining --model_output="dist" --continue_from="chi_tra.lstm" --traineddata="dist\chi_tra\chi_tra.traineddata" --old_traineddata="chi_tra.traineddata" --train_listfile="chi_tra.training_files.txt" --target_error_rate=0.05
```
* **指令說明**
    * `--traineddata` 指定新`traineddata`文件的路徑
    * `--old_traineddata` 指定原`traineddata`文件的路徑

**Step.8 將訓練結果寫入新模型**
* **想法流程：** 選定錯誤率最低的`[name]_[error_rate]_[iterations].checkpoint` 文件寫入模型，更新版的模型就會支援新字元並且具備辨識能力，後續就能以該模型為基礎，針對其它辨識效果不佳的字元加強訓練。
* **目標產出：** `.traineddata`文件
* **指令範例：**
```bash
lstmtraining --stop_training --continue_from="dist_0.012_360000_360000.checkpoint" --traineddata="dist\chi_tra\chi_tra.traineddata" --old_traineddata="chi_tra.traineddata" --model_output="dist\chi_tra.traineddata"
```
#### 應變邏輯
![](https://i.imgur.com/0bBNhGa.png)


### More detail
#### 官方說明：[連結](https://tesseract-ocr.github.io/tessdoc/TrainingTesseract-4.00.html#error-messages-from-training)
#### 官方論壇：[連結](https://groups.google.com/g/tesseract-ocr)


## 參考資料
* [官方文件](https:/https://tesseract-ocr.github.io/tessdoc/TrainingTesseract-4.00.html)
* [中譯版-官方文件](https://ivanzz1001.github.io/records/post/ocr/2017/09/18/tesseract-training)
* [Tesseract-OCR 4.0LSTM訓練流程 (Windows環境下)](https://www.twblogs.net/a/5d744adbbd9eee541c3423a2)
* [Tesseract 4.0 LSTM训练超详细教程](https://zhuanlan.zhihu.com/p/58366201)
* [Tesseract OCR tips — custom dictionary to improve OCR](https://vovaprivalov.medium.com/tesseract-ocr-tips-custom-dictionary-to-improve-ocr-d2b9cd17850b)
* [WORDLIST2DAWG(1) Manual Page](https://github.com/tesseract-ocr/tesseract/blob/master/doc/wordlist2dawg.1.asc)
###### tags: `日月光`





