ちょっと将棋関連の画像認識をやってみたいな、と思って。
理想的には、将棋の盤面の写真や盤面図の画像から認識を行い 盤面の状態をデータとして取得できるようにしたい。
となると、
- 入力画像から盤面の部分を検出し、切り出す
- 切り出した盤面をさらに、9x9の各マスに分割する
- 分割した各マスに対し どの駒が置かれているか(もしくは何も置かれていないか)を分類する
- さらに持駒の部分も画像内から検出し、同様に分類
といった処理が必要になりそう。 1, 2, や 4, の処理はともかくとして、3, の分類はアイドル顔認識と同じようなimage classifierで出来るはずなので、まずはこれを作ってみることに。
目標
将棋盤における駒の状態として有り得るのは「歩兵」「桂馬」「香車」「銀将」「金将」「角行」「飛車」「王将」の8種類、それに成駒である「と金」「成香」「成桂」「成銀」「竜馬」「竜王」を加えた14種類、それぞれ先手側と後手側があるので倍の28種類。そして何も駒が置かれていないマス、も分類対象に加える必要があるので合計で29 classの分類taskとなる。
また さらに、「将棋盤のマスでも何でもない、まったく関係ない画像である」というclassも含めても良さそう。このへんは用途によるかもしれない。
とにかく、この 29 or 30 classの分類を高精度・高速度でできるImage classifierを簡単に作りたい。
データセットを「生成」する
普通の画像分類には大量の「画像」と「正解ラベル」のセットが学習データとして必要になるが、それを用意するのがとにかく大変。 将棋駒のラベル付きデータセットがどこかに公開されていれば良いけど、少し探してみた限りではやはり存在してないようだ。
アイドル顔画像のときのようにやろうとすると、様々な将棋盤の画像を収集して 盤面を切り抜いて 各マスに分割して ラベル付けて… を繰り返すことになる。 極力それは避けたい。
ということで、画像データを自動的に「生成」して用意することを考えてみる。
有り難いことに、将棋盤画像を生成するのに使える良い素材を無料で公開してくださっている方々がいる。
こちらの記事で紹介されている素材データは、それぞれ盤の画像と 透過pngの駒画像が個別に用意してあり(「しんえれ外部駒」は背景色固定の駒画像のみ)、これらを貼り合わせることで任意の盤面画像を作ることができる。
例えば以前の記事で載せている
のような画像は、すべて「CC Resources for Shogi Applications」に含まれている盤・枠・駒それぞれの素材画像を使って貼り合わせることで生成している。
任意の盤面を自由に生成できるということは、当然どの位置にどの駒が置かれているかを分かっているということなので、生成した盤面画像から対象の駒の置いてあるマスの位置を切り抜いて、それと正解ラベルを関連づけることができる。
例えば上記の画像を生成した上で 2三
の位置のマスの部分を切り抜けば、それを「歩兵」としてラベル付けしたデータとして扱うことができる。
必要な画像処理は
- 画像の任意の位置に別の透過画像を貼り付ける
- 任意の位置を切り抜く
- 任意の大きさにリサイズする
くらい。これらは Pillow でもあれば簡単に実現できる。
また、素材画像の組み合わせではなくすべて自分で描画して生成することも出来る。 よく書籍などで使われる局面図は、漢字一文字(もしくは二文字)で表現される。
(上図はShogipicより)
こういうものも、枠線を引いて任意のマス位置に文字を描画(後手側の場合は180°回転をする)することで生成することができる。
OSに入っているヒラギノ*.ttc
などのフォントを使って複数の種類のものを生成できる。
これらの方法で画像を生成し、自動でラベル付けする というより「ラベルに合う画像を生成する」という手法でデータセットを作ってみた。 素材の組み合わせを変えたり 画像の質を変えたりして少しずつ違う画像が生成されるよう調整し、各駒300〜400点が全自動で生成できた。
TensorFlow Hubのモデルを使って学習
データセットがある程度用意できたら、いよいよこれらを識別する分類器を作る…ところだけど、これも既存のものを再利用できるならそれがラクで良い。
3月末に行われたTensorFlow Dev Summit 2018で、「TensorFlow Hub」が発表された。 ここで様々な学習済みモデルが公開され、独自データセットでの利用のための再学習の仕組みも整備されているようだ。
この中にある examples/image_retraining/retrain.py
を使うことで、TensorFlow Hub のモジュールを使用して独自データに対する学習ができる。
今回は mobilenet_v2_100_96/classification/1
というMobileNet V2のものを使ってみた。
python retrain.py \ --image_dir ${IMAGEDIR} \ --tfhub_module https://tfhub.dev/google/imagenet/mobilenet_v2_100_96/classification/1 \ --how_many_training_steps 10000
これで、指定したモジュールをダウンロードし そのモデルを使って指定ディレクトリ以下の画像データに対する分類のための再学習を行ってくれる。 distortionを行わない場合は最初に全データに対するbottleneckを計算してそれを使っていくだけのようなので、手元のMacBookProのCPUでも10,000 stepsくらいなら十数分程度で学習が完了する。
順調にcross entropyが減少し、train dataset に対してはほぼ100%、validation datasetに対しても97〜98%くらいの正答率になっている。
結果と考察
学習が終わると output_graph.pb
ファイルが書き出されるので、これを使って実際に幾つかの画像を入力して試してみる。
入力データは (?, 96, 96, 3)
のshapeを持つTensorで、値は[0, 1]
の範囲にscalingされたものとして学習されているので、それに合わせてやる必要がある。
盤面の部分だけを切り抜いた画像を用意し、縦横それぞれ9分割して81マスすべてに対して学習済みの分類器にかけて 最も高スコアになったラベルを表示してみる。
1. 学習データに使った素材で作ったもの
-KI * +TO * -OU * +TO+TO+NY * -FU * * * +FU * * * +RY-TO * * -FU-FU * -FU-KY * +KE+KE-GI-KI-TO * * +RY -UM-NK+KY+TO * -TO * * * * +FU * * * -GI-GI+FU * * * +FU * +TO-GI * * +KE * * * * +TO * +FU * +KY +UM * * * * * +KI * -KI
学習データそのままなのだから、当然と言えば当然なんだけど、すべて正解。
そのままとはいえ少し縦長のものを96 x 96
にリサイズしているので縦横比など少しずれているとは思うのだけど、そのへんは上手く吸収してくれているようだ。
2. Shogipicで生成された局面図
漢字のみで表現するタイプのもの。 これは…何というフォントを使って生成されているんだろう? ヒラギノ丸ゴ?であれば学習データにも含まれている。
-KI * +TO * -OU * +TO+TO+NY * -UM * * * +FU * * * +RY-TO+UM+UM-UM-FU ? -UM-KY * +KE+KE-KA-KI-TO ? * +RY -UM-KA+KY+TO * -TO * * * * +FU ? ? * -KE-KE+FU * * * +FU ? +TO-KE ? * +KE * * * * +TO * +FU * +KY +UM * * * * * +KI * -KI
不思議なことに 2三
、5三
や 8二
などの後手側の「歩兵」が「竜馬」として認識されてしまっている。 4三
の位置のものは正しく「歩兵」になっているのに…。
それぞれ切り抜いて認識結果の上位3つとscoreを出してみる。
・4三
W_FU: 0.6095971 W_UM: 0.25771713 W_TO: 0.095992066
・5三
W_UM: 0.69194067 W_FU: 0.10603738 W_TO: 0.07219603
・8二
W_UM: 0.62901 W_TO: 0.24588391 W_NY: 0.05405906
うーん、真ん中部分は大きく違わないはずなのに結果は随分バラバラになる…。枠線部分の影響を強く受けてしまっているのだろうか…
その他にも、「銀将」が「桂馬」になってしまっていたり、「成桂」が「角行」になってしまっていたり、誤判定が目立つ。
3. 激指 14の局面スクリーンショット
こちらは学習データの素材とはまったく関連がない画像、のはず。同じ駒でも微妙に模様が違っていたりする。とはいえ最もメジャーな菱湖書体、のものなのかな?
-KI * +TO * -OU * +TO+TO+NY * -FU * * * +FU * * * +RY-TO * * -FU-FU * -FU-KY * +HI+HI-GI-KI-TO * * +RY -UM-NG+KY+TO * -TO * * * * +FU * * * -GI-GI+FU * * * +OU * +TO-GI * * +HI * * * * +TO * +FU * +KY +RY * * * * * +KI * -KI
2.
のものよりは正答率が高いようだ。
8五
の「成桂」が「成銀」になってしまっているのは似ているから仕方無いかな、という感じはするけど、 7七
の「歩兵」が「王将」になってしまっているのはヒドい。その他にも 1七
の「桂馬」が「飛車」になってしまっていたり、やっぱりちょっと理解できない誤答がある…。
4. Shogi.ioの局面スクリーンショット
-NG * +TO * -FU * +TO+TO+UM * -FU * * * +NK * * * -UM-TO ? * -FU-FU * -FU-NG * +KE+OU-GI-NG-TO * * +KE -NG-UM+NG+TO * -TO * * * * +NK ? * * -GI-GI-UM * * * +NK * +TO-GI * * +KE * * * * +TO * -UM * +NG -UM * * * * * +NG * -NG
なんと、ビックリするくらい当たらない。めちゃくちゃだ。正解しているのは「と金」と後手の「歩兵」くらいか…? 駒の向きさえ正しくない場合がある。
そういえば今回作成したデータセットにはこのような形の「一字駒」を使用していなかった。 まったく学習していないタイプの駒画像なので正解しないのは当然と言えるかもしれない。「と金」だけは普通の書体の駒でも一字のものになるから似ていて正答できているのかもしれない。
この一字駒系はあまりフリー素材としては公開されていないのかな? しかしこうした局面図も正しく認識できるようにするためにはこうした一字駒も学習データに加える必要がありそうだ。
まとめ
一応それっぽく簡単に学習データを作って学習させて分類モデルを作ることは出来た。 が、使えるかどうかというと全然まだまだダメそう。
枠線の影響を受けずにもっとロバストに駒部分を正しく分類できるように、また一字駒などに対しても正しく分類できるよう より良い学習データを作る必要がありそうだ。
分類モデルの再利用については MobileNet V2のもので問題ないか、他のモデルを使った方が良いかどうか? もう少し良質な学習データが揃ってから検証したいところ。