# 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: `日月光`