酢ろぐ!

カレーが嫌いなスマートフォンアプリプログラマのブログ。

ポケモンカードゲームのカードをTensorFlowで学習させて写真からどのポケモンかを判定させる

2年くらい前に「機械学習」や「ディープラーニング」といった感じにキーワードだけが先行して飛び交っていた時期がありました。猫も杓子もAIとニュースになっていました。ここ最近では、そういった流行り技術から実用技術へシフトしたのか、以前のように「ディープラーニングで○○やってみた!」系の記事もあまり見かけなくなってきました。

話は変わりますが、僕は2ヶ月前にポケモンカードゲーム(以下ポケカ)を始めたばかりなのですが、お店で売っているのカードをみながら、このポケモンは他のポケモンとコンボを決めることができるんだろう?と気になることが多々あります。写真からなんのカードなのかを特定することができれば作業が捗りそうです!

僕も遅ればせながらTensorFlowを使って画像識別をやっていきたいと思います。

本記事では、ポケカのカードをTensorFlowで学習させて写真からどのポケモンかを判定させるまでを紹介したいと思います。TensorFlowもPythonもよくわからない状態でしたが、プログラミング要素なしでどのカードかを判定する識別器を作ることができました。

全体を通してPythonを使っているので、その部分の説明に関しては省かせていただきます。自分のOSやバージョン等の環境に合ったインストール方法を採用してください。

また、この記事で扱うのは「ラランテスGX」と「かんこうきゃく」のみですが、画像を集めることができれば他のカードにも応用が効くと思います。

もしこの記事を読んでポケカに興味を持たれた方がいれば「GXスタートデッキ」がオススメです。一時期人気が殺到して店舗から消えていましたが、先週末くらいから再販されて再び店頭に並ぶようになってきました。個人的には草ラランテスデッキが好きです。

ポケモンカードゲーム サン&ムーン「GXスタートデッキ リザードン」

ポケモンカードゲーム サン&ムーン「GXスタートデッキ リザードン」

ポケモンカードゲーム サン&ムーン「GXスタートデッキ ライチュウ」

ポケモンカードゲーム サン&ムーン「GXスタートデッキ ライチュウ」

画像を集める

まずは識別器を作るために対象物の写真を複数枚用意する必要があります。トラブルシューティングには書きませんでしたが最低20画像ないとエラーになってしまったような気がします。

pipを使ってgoogle-images-downloadをインストールします。

pip install google_images_download

google-images-downloadはGoogle画像検索の画像を一気にダウンロードしてこれるので、大量に画像を集める必要がある時にとても重宝します。-kはkeywordを指定するオプションで、その他のオプションについてはこちらをご覧ください。

cd ~/Desktop/works/
googleimagesdownload -k "LurantisGX"
googleimagesdownload -k "ラランテスGX"

ラランテスGXの画像がたくさん集まりました。GXスタートバトルの動画のアイキャッチ画像などもひっかりましたがその辺りは手作業で削除しました。

f:id:ch3cooh393:20180929165758j:plain

枚数はあればあるほど精度があがりますが学習に時間がかかります。何枚くらいが適切なんでしょうね?OpenCVを使った画像認識の時はポジティブ画像8000枚・ネガティブ画像4000枚といった規模でしたが……

複数のカードが写っている写真に関しては、対象物だけを切り抜いたりした方が精度があがります。

TensorFlowをダウンロードする

次にTensorFlowをpipを使ってインストールします。TensorFlow Hubは機械学習をモジュールを再利用することができるライブラリです。よくわかっていないのでここでは言及を避けます。

pip install tensorflow
pip install tensorflow-hub

画像を元に学習させるretrain.pyと、識別器を使って該当の画像が何なのかを判別するlabel_image.pyが最低限必要になります。

retrain.pyは、https://github.com/tensorflow/hub/blob/master/examples/image_retraining/retrain.py を、label_image.pyは、 https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/label_image/label_image.py をそれぞれダウンロードして、任意のフォルダに格納しておきます。

事前準備は以上です。

Tensorflowを使って学習させる

Tensorflowを使って学習させる準備が整いました!学習前のフォルダとファイル構造は以下の通りとなりました。

~/Desktop/works
├── images
│   ├── sm1m_006_LurantisGX
│   │   └── ラランテスGXの学習用画像
│   ├── sm1m_067_LurantisGX
│   │   └── ラランテスGX(SR)の学習用画像
│   └── sm7a_056_Sightseer
│       └── かんこうきゃくの学習用画像
├── label_image.py
├── retrain.py
└── test_images
    └── テスト用の画像

TensorFlowに必要な画像だけを与えて学習させます。いくつかパラメータの指定をミスしていて学習でエラーが発生しましたが、詳しくは「retrain.pyのトラブルシューティング」をご覧ください。

cd ~/Desktop/works/
python retrain.py \
  --bottleneck_dir=bottlenecks \
  --how_many_training_steps=500 \
  --model_dir=inception \
  --summaries_dir=training_summaries/basic \
  --output_graph=retrained_graph.pb \
  --output_labels=retrained_labels.txt \
  --image_dir=images

順調にいくとフォルダにretrained_graph.pbretrained_labels.txtが出力されていると思います。これで学習は完了しました。

学習したモデルを使って写真からどのポケモンかを判定させる

ここまでで学習したモデルを使って、与えられた写真からどのポケモンかを判定させます。

python label_image.py  \
  --graph=retrained_graph.pb  \
  --labels=retrained_labels.txt  \
  --output_layer=final_result  \
  --image=test_images/テスト画像.jpg  \
  --input_layer=Placeholder

実際にやってみました。

ラランテスGX

GXスタートデッキのパッケージを飾ったラランテスGXです。このカードはSMHの廉価版カードなのでキラ加工されていません。

f:id:ch3cooh393:20180929232546j:plain

キラキラしていないので光による反射もなく識別しやすいと思いましたが、判定結果はなぜか誤判定。SRの方のラランテスが一番スコアが高かったです。

sm1m 067 lurantisgx 0.6777606
sm1m 006 lurantisgx 0.2900931
sm7a 056 sightseer 0.0321463

ラランテスGX (SR)

「コレクションムーン(SM1M)」のラランテスGXのSRです。テキストは前述したラランテスGXと同じですが絵柄のみ異なっています。

f:id:ch3cooh393:20180929232549j:plain

判別結果は83.6%とそこまで高くないながらも正しくラランテスGX(SR)と判定できているようでした。

sm1m 067 lurantisgx 0.83667225
sm7a 056 sightseer 0.1379832
sm1m 006 lurantisgx 0.025344588

かんこうきゃく

最後に「かんこうきゃく」を判定させてみました。最終的な手札を6枚にするシロナやリーリエと比べるとドロー枚数は劣りますが、不要カードを好きなだけトラッシュすることができる強サポートです。あと絵柄がとても可愛い。

f:id:ch3cooh393:20180929232449j:plain

学習した3枚中一番絵柄が異なるので、判別結果は94.7%と上々な結果がでました。

sm7a 056 sightseer 0.9478891
sm1m 067 lurantisgx 0.041196633
sm1m 006 lurantisgx 0.010914299

まとめ

TensorFlowを使えば簡単に識別器を作ることができることがわかりました。ここまではプログラミング要素は全く必要ありませんでした。反面、ラランテスGXのRRとSRをうまく判別できなかったりと精度を上げるためにはここからやるべきことはたくさんありそうです。

トラブルシューティング

僕がこの記事を書くにあたって発生したエラーと対処方法などを備忘録として残しておきたいと思います。

Tensorflow Hubをインストールしてなかった

Traceback (most recent call last):
  File "retrain.py", line 133, in <module>
    import tensorflow_hub as hub
ImportError: No module named tensorflow_hub

Tensorflow Hubをインストールしていませんでした。

ディレクトリ構造がおかしい/教師画像ディレクトリがひとつしかない

ERROR:tensorflow:No valid folders of images found at downloads/LurantisGX
ERROR:tensorflow:Only one valid folder of images found at images - multiple classes are needed for classification.

ディレクトリ構造がおかしい/教師画像ディレクトリがひとつしかありませんでした。以下のように判定させる対象はふたつ以上必要のようです。

images
├── Lurantis
│   ├── images-1.jpg
│   ├── images-2.jpg
│   ├── images-3.jpg
│   ├── images-4.jpg
│   └── images-5.jpg
└── LurantisGX
    ├── images-1.jpg
    ├── images-2.jpg
    ├── images-3.jpg
    ├── images-4.jpg
    └──  images-5.jpg