Help us understand the problem. What is going on with this article?

ocrd-train(Tesseract)の学習で辞書が見つからない(Failed to load any lstm-specific dictionaries for lang XXX!!)

経緯

タイトルの通りなのですが、先日kmnistを使ってTesseractにLSTMの再学習をさせたのですが(ここ)、最後の認識で警告が出ているんですよね。

$ tesseract -l kuzusiPlus kuzusi.0.tif stdout
Failed to load any lstm-specific dictionaries for lang kuzusiPlus!!
Page 1
Warning: Invalid resolution 0 dpi. Using 70 instead.
Estimating resolution as 272
お れ お ま お は れ は は お を や き す す き す き つ や れ き な つ れ つ や き れ は き ま れ を き お お つ つ ま

コマンドを打った次の行!

Failed to load any lstm-specific dictionaries for lang kuzusiPlus!!

もちろん、学習前のjpn_bestではこんなの出てません。。。
今回はこの警告について調べたのであとで忘れてもいいように記事にまとめておきます。

注意)私がTesseractについて詳しくないので、現在(2019年12月22日時点)で間違った認識もあるかもしれないです。あくまでヒント程度で見て下さい。それと、間違いがあったら気軽にご指摘してくださるとありがたいです!

解決だけしたい方はここ

原因調査(警告を消したいだけなら読む必要はないです)

今回はTesseractの学習データであるXXX.traineddataについて調べてみて、警告が言っている事について調べてみました。

XXX.traineddataの構成についての調査

まず、(MODEL_NAME)Plus.traineddata(というか.traineddata全部)は、いくつかのファイルが統合されたものなんですね。
Tesseractのwikiを見てみると、、、

Understanding the Various Files Used During Trainingより

As with base Tesseract, the completed LSTM model and everything else it needs is collected in the traineddata file. Unlike base Tesseract, a starter traineddata file is given during training, and has to be setup in advance. It can contain:

 ・Config file providing control parameters.
 ・Unicharset defining the character set.
 ・Unicharcompress, aka the recoder, which maps the unicharset further to the codes actually used by the neural network recognizer.
 ・Punctuation pattern dawg, with patterns of punctuation allowed around words.
 ・Word dawg. The system word-list language model.
 ・Number dawg, with patterns of numbers that are allowed.

Bold elements must be provided. Others are optional, but if any of the dawgs are provided, the punctuation dawg must also be provided. A new tool: combine_lang_model is provided to make a starter traineddata from a unicharset and optional wordlists.

ふーんって感じですね。要するにtraineddataにはUnicharsetとUnicharcompressが必ず必要で、それ以外はオプションらしいですね。
具体的にどれ??ってことなんですが、次の3つのwikiの記事を見ると分かってきます。

まず、話は少し逸れますが、バージョン3.0.0or3.0.2での学習方法の記事を見ます。
Tesseractのwiki : Data file required

To train for another language, you have to create some data files in the tessdata subdirectory, and then crunch these together into a single file, using combine_tessdata. The naming convention is languagecode.file_name Language codes for released files follow the ISO 639-3 standard, but any string can be used. The files used for English (3.00) are:

 ・tessdata/eng.config
 ・tessdata/eng.unicharset
 ・tessdata/eng.unicharambigs
 ・tessdata/eng.inttemp
 ・tessdata/eng.pffmtable
 ・tessdata/eng.normproto
 ・tessdata/eng.punc-dawg
 ・tessdata/eng.word-dawg
 ・tessdata/eng.number-dawg
 ・tessdata/eng.freq-dawg

... and the final crunched file is:

 ・tessdata/eng.traineddata

なるほど、中間にリストアップされているeng.***を作ってcombine_tessdataを使うと、eng.treineddataの完成って事ですね。
これは4.0.0以降も大体同じことが言えるんです。

それじゃ逆に完成されているeng.traineddataを分解した例を見てみましょう。
Tesseractのwiki : Pre 4.0.0 format from Nov 2016 (with both LSTM and Legacy models)

combine_tessdata -u eng.traineddata eng.
Extracting tessdata components from eng.traineddata
Wrote eng.unicharset
Wrote eng.unicharambigs
Wrote eng.inttemp
Wrote eng.pffmtable
Wrote eng.normproto
Wrote eng.punc-dawg
Wrote eng.word-dawg
Wrote eng.number-dawg
Wrote eng.freq-dawg
Wrote eng.cube-unicharset
Wrote eng.cube-word-dawg
Wrote eng.shapetable
Wrote eng.bigram-dawg
Wrote eng.lstm
Wrote eng.lstm-punc-dawg
Wrote eng.lstm-word-dawg
Wrote eng.lstm-number-dawg
Wrote eng.version
Version string:Pre-4.0.0

これは3.0.0のOCRエンジン(LSTMの前)とLSTMの2つのモードができる.traineddataを分解した例なのですが、緑色がさっき引用したバージョン3.0.0or3.0.2で必要なデータに対応していますね。そして青色の部分にlstmと入っています。なるほど、こんな感じなファイルの塊が.traineddataになるわけですね。(この色については次説明します)
ちなみにこれは最新のやつじゃなくて、最新のLSTM onlyは
Tesseractのwiki : 4.00.00alpha LSTM only format

combine_tessdata -u eng.traineddata eng.
Extracting tessdata components from eng.traineddata
Wrote eng.lstm
Wrote eng.lstm-punc-dawg
Wrote eng.lstm-word-dawg
Wrote eng.lstm-number-dawg
Wrote eng.lstm-unicharset
Wrote eng.lstm-recoder
Wrote eng.version
Version string:4.00.00alpha:eng:synth20170629:[1,36,0,1Ct3,3,16Mp3,3Lfys64Lfx96Lrx96Lfx512O1c1]

ほほう。最新のやつでは全部にlstmが付いてますね。単純に考えると、この色のlstm-unicharsetとlstm-recoderが上記の引用の同じ色のやつに対応してる訳ですね。

やっと話を戻そうかと思います(あくまで私のメモなので必要ない事も書きました。くどい説明で申し訳ないですm(_ _)m)。
さっき「要するにtraineddataにはUnicharsetとUnicharcompressが必ず必要」と言いましたが、それはどれかというと、

Wrote eng.lstm
Wrote eng.lstm-unicharset
Wrote eng.lstm-recoder

の3つです。Unicharsetはeng.lstm-unicharsetの事です。
Unicharcompressは、引用の説明を読んでみると「Unicharcompress(別名recoder)は、unicharsetをニューラルネットワーク認識エンジンが実際に使用するコードにさらにマッピングします。」とあります。つまり、Neural Networkがある前提(まあlstm使うから当たり前)でrecorderが必要って事ですね。
結論、
eng.lstmがlstm本体で、eng.lstm-recoderがそのrecoderらしいです。

警告についての調査

それじゃ!必要なその3つだけにしちゃえ!!って事でcombine_tessdataを使ってやってみますね。
(combine_tessdataの使い方も後でまとめようかと思います)

・追記、combine_tessdataのまとめにまとめました。(12月25日時点)

実験するだけなので、今まで作った.traineddataに影響が出ないように適当な場所(今回はデスクトップ)にeng.traineddataを置きます。
ここからeng.traineddataをダウンロードしてデスクトップに置いて下さい。(DownLoadを押すだけで取得できます)

そして端末を開いてデスクトップに行って作業しましょう!(ここではcombine_tessdataの説明は省きます)

# デスクトップにさっきのeng.traineddataを置いて下さい
$ cd デスクトップ

# eng.traineddataを分解する
$ combine_tessdata -u eng.traineddata eng_unpack.

さあ、デスクトップに大量にeng_unpack.***が発生しましたね。これらがeng.traineddataのパーツとなります。それじゃ、

・eng_unpack.lstm
・eng_unpack.lstm-unicharset
・eng_unpack.lstm-recoder

以外を消してcombine_tessdataで.traineddataを作ってみましょう。(手動でやってもいいですが一応コマンドを乗っけときます)

# 必須なパーツ以外全て消す
$ rm eng_unpack.unicharset
$ rm eng_unpack.unicharambigs
$ rm eng_unpack.inttemp
$ rm eng_unpack.pffmtable
$ rm eng_unpack.normproto
$ rm eng_unpack.punc-dawg
$ rm eng_unpack.word-dawg
$ rm eng_unpack.number-dawg
$ rm eng_unpack.freq-dawg
$ rm eng_unpack.shapetable
$ rm eng_unpack.bigram-dawg
$ rm eng_unpack.lstm-punc-dawg
$ rm eng_unpack.lstm-word-dawg
$ rm eng_unpack.lstm-number-dawg
$ rm eng_unpack.version

よーし、これで準備は整いましたね。combine_tessdataで残ったパーツを統合しましょう。

# パーツの結合
$ combine_tessdata eng_unpack.

すると、デスクトップ上にeng_unpack.traineddataができてますね!
最低限のパーツで構成されたデータは大丈夫なのか?試してみましょう。
このeng_unpack.traineddataを$TESSDATA_PREFIX(tesseractの学習データが置いてあるフォルダ、参考)にコピーさせましょう。

$ sudo cp eng_unpack.traineddata $TESSDATA_PREFIX/

そして、適当な英語の画像をデスクトップに置いて下さい。
(適当な英語)
sample.png
これを認識にかけてみると、

$ tesseract -l eng_unpack sample.png stdout
Failed to load any lstm-specific dictionaries for lang eng_unpack!!
| am a student of National College of Technology/

おお!出ました「Failed to load any lstm-specific dictionaries for lang eng_unpack!!」最低限しかないとこの警告が出るんですね。
それじゃ何が足りないんだ!とそろそろ説明が長すぎて罵倒されそうですが、まずdictionaryについて調べてみました。

ここにありました。
tesseractのwiki : Overview of Training Process
ここの4.Make a starter traineddata from the unicharset and optional dictionary data.をクリックすると以下の記事に飛ばされて、

lstmtraining takes a traineddata file on its command-line, to obtain all the information it needs on the language to be learned. The traineddata must contain at least an lstm-unicharset and lstm-recoder component, and may also contain the three dawg files: lstm-punc-dawg lstm-word-dawg lstm-number-dawg A config file is also optional. The other components, if present, will be ignored and unused.

なるほど、何やらdictionaryはlstm-punc-dawg、lstm-word-dawg、lstm-number-dawg、config fileのどれかっぽいですね。
それじゃ3.0.0 or 3.0.2ではdictionaryは何だったのか。

tesseractのwiki : Dictionary Data (Optional)

Seven of the files are coded as a Directed Acyclic Word Graph (DAWG), and the other is a plain UTF-8 text file:

DAWGが辞書って扱いになってますね。(DAWGとは文字列から単語を検索するためのデータ構造です、詳しくはここ
という事で、lstm-punc-dawg lstm-word-dawg lstm-number-dawg の3つが辞書ファイルに相当する訳です。

じゃあeng.traineddataからその3つのファイルを取り出してeng_unpack.traineddataに組み込もうじゃないか。

# lstm-punc-dawgを取り出し、組み込む
$ combine_tessdata -e eng.traineddata eng.lstm-punc-dawg
$ combine_tessdata -o eng_unpack.traineddata eng.lstm-punc-dawg

# lstm-number-dawgを取り出し、組み込む
$ combine_tessdata -e eng.traineddata eng.lstm-number-dawg
$ combine_tessdata -o eng_unpack.traineddata eng.lstm-number-dawg

# lstm-word-dawgを取り出し、組み込む
$ combine_tessdata -e eng.traineddata eng.lstm-word-dawg
$ combine_tessdata -o eng_unpack.traineddata eng.lstm-word-dawg

# 新しくできたeng_unpack.traineddataを$TESSDATA_PREFIXに移す
$ sudo cp eng_unpack.traineddata $TESSDATA_PREFIX/

できたファイルを移しました。これで辞書は組み込めたはず!それじゃあさっきやった実行をやってみます。

$ tesseract -l eng_unpack sample.png stdout
| am a student of National College of Technology/

やった!「Failed to load any lstm-specific dictionaries for lang eng_unpack!!」が出ません。
つまりこの警告は
・lstm-punc-dawg
・lstm-word-dawg
・lstm-number-dawg
がないために出てしまうんですね。

しかし、今回はおんなじデータを分解して、一部抜いて、組み直しただけです。
元データから一部取り出して、他のデータに組み込むのとは話が違います。
解決策(仮)はjpn_best.traineddataから辞書のみを取り出して、kuzusiPlus.traineddataに組み込んでいます。
なので精度にどのような影響が出るか正確に分かっている訳では無いのですが、自分なりに調べて結論が出たのでリンクを貼っておきます。
長いですが、良かったら読んで下さい。
Tesseractの辞書ファイルの有無の影響にてついて(Failed to load any specific lstm-dictionaries for lang XXX!)

解決策(仮)

とりあえず、こうすると警告が出なります。(仮)なのはこれが正しいかどうか分かっていないので仮です。
まず、前回作ったkuzusiPlus.traineddataとjpn_best.traineddataを適当な場所(今回はデスクトップ)に置きましょう。

$ cd デスクトップ
$ cp $TESSDATA_PREFIX/kuzusiPlus.traineddata .
$ cp $TESSDATA_PREFIX/jpn_best.traineddata .

そして、jpn_best.traineddataから辞書ファイルを取り出し、kuzusiPlus.traineddataに組み込みます。

# 辞書ファイルをjpn_best.traineddataから引き抜く
$ combine_tessdata -e jpn_best.traineddata jpn_best.lstm-punc-dawg
$ combine_tessdata -e jpn_best.traineddata jpn_best.lstm-number-dawg
$ combine_tessdata -e jpn_best.traineddata jpn_best.lstm-word-dawg

# 辞書ファイルをkuzusiPlus.traineddataに組み込む
$ combine_tessdata -o kuzusiPlus.traineddata jpn_best.lstm-punc-dawg
$ combine_tessdata -o kuzusiPlus.traineddata jpn_best.lstm-number-dawg
$ combine_tessdata -o kuzusiPlus.traineddata jpn_best.lstm-word-dawg

これで警告は出なくなるはずです。それではこれを$TESSDATA_PREFIXに移動させて、試しに以下の画像をデスクトップに置いて試してみましょう。
sample.jpeg

# 編集したkuzusiPlus.traineddataを TESSDATA_PREFIX に移す
$ sudo cp kuzusiPlus.traineddata $TESSDATA_PREFIX/

# sample.jpegをkuzusiPlusで認識してみる
$ tesseract -l kuzusiPlus sample.jpeg stdout
お れ お ま お は れ は は お を や きす すき すき つや れき な つれ つや きれ は きま れ を き お お つつ ま

警告が消えてますね^^ おめでとうございます!

注意)今回の方法は私が試して解決した方法であり、根本的な解決先ではない可能性が高いです。
   なので、これで精度に影響が出てしまっても責任は取れません。
   あくまで私の為のメモとして書きました。

mimuro_syunya
専攻科生です。拙い所はたくさんあると思いますが、温かい目で見てくださるとありがたいです。 現在研究でTesseractを扱っているのでそれに関する記事ばかりになると思います。
https://github.com/mimuro-lab
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした