ふたくちおとこ

クチート大好きな私が、主にポケモンやボドゲに関して書くブログ

SSD + Keras でクチート認識するぞ。モデル作成編

みなさまこんにちは。さっちんです。

最近PokemonGOを再開しました。リリース後1ヶ月位しか遊んでいなかったのでクチートを捕まえていませんでしたが、最近はレイドバトルばかりを探してクチートをお出迎えしています。

さて、今回は画像認識のお話です。前回の記事で、ポケモンの選出画面を画像認識することでパーティーを簡単に登録できるようにする試みがあることをご紹介しました。 これを実現するためには、画像のどの箇所にどのポケモンが写っているかを判定する必要があります。

私もパーティー記録ツールを作りたいなと思っていましたので、勉強のため、まずクチートを認識するモデルを作ってみようと決心しました。以下で、モデル構築までの手順を記載していこうと思います。

下記に今回の記事で説明するコードを置いていますので、適宜参照してください。 github.com

利用する手法

リアルタイムに物体検出したかったので、SSD(Single Shot Multibox Detector)を利用しました。 以下のgithubレポジトリが広く使われていたので、私も下記を利用しました。

github.com

手順

手順は以下になります。

データの準備

まずは画像を用意します。「ワシのクチート画像は百八式まであるぞ」ということで、 秘蔵のクチート画像フォルダから108枚の画像を選出してきました。

まずは、画像のどこにクチートが写っているのかという教師データを作成する必要があります。 今回、以下のサイトを参考にさせて頂き、AnnotationTool.exeを利用しました。 このツールを利用して、108枚すべての画像に手作業で丁寧にアノテーションしていきます。 すると、108個のxmlファイルが生成されます。

arkouji.cocolog-nifty.com

次に、画像のData Augmentationで画像を増やしていきます。 image_augmentation.ipynb が、Data Augmentationを実施しているコードになります。 ガウシアンノイズやソルトペッパーノイズを付与したり、画像を白黒化したりして、 1つの画像から6枚の画像を生成しています。これにより、108枚の画像が756枚になりました。

最後に、xmlファイルをonehot表現に変換して、pickle形式で出力します。 create_mawile_pkl.py の中にある _to_one_hot(self, name) で判定したいクラスを定義しているので、ここを編集します。 (今回は、44行目に書かれていたaeroplaneという文字列を、アノテーションで付与したラベルと同じ文字列 kucheat に変更しました。)

以上で、データの準備は完了です。

コーディング

詳しい説明は上記の参考資料を参照してください。下記のソースコード群が学習に利用しているソースコードになります。

training.ipynb
ssd.py
ssd_layers.py
ssd_training.py
ssd_utils.py
kucheat_training.py

training.ipynb を実行すると、学習が始まります。 特にカスタマイズしていないPCだと、かなり時間がかかりますので、下記にAWSを利用する方法を記載します。

クラウドで学習環境を構築する

お安くするため、スポットインスタンスを活用した構築方法を記載します。 (最近、Amazon SageMakerという便利なサービスが登場したので、そちらを利用しても良いかもしれません。)

インスタンスの作成

まず、EC2インスタンスを作成して、SSHで接続します。

  • ステップ1
    • AMI:AmazonLinux2を選択
  • ステップ2
    • GPU コンピューティング: p2.xlargeを選択
  • ステップ3: インスタンスの詳細の設定
    • スポットインスタンスのリクエストにチェックを入れる
    • 最大価格の設定
      • 現在の価格という欄が現れて、ap-northeast-1a:$0.4626といった情報が表形式で表示される
      • この表示価格より高い金額を設定する
        • 上記の場合、0.5だとエラーとなり、0.6でうまく作成できたので、ギリギリを攻めすぎるとダメかも
  • セキュリティグループの8000を許可
  • 作成されたインスタンスのグローバルアドレスにSSHする

環境の構築

下記のコマンドを実行していきます。

[ec2-user@ip-x-x-x-X ~]$ sudo yum -y upgrade
[ec2-user@ip-x-x-x-X ~]$ sudo yum -y install git tmux emacs gcc gcc-c++ python-setuptools python-devel 
[ec2-user@ip-x-x-x-X ~]$ sudo git clone https://github.com/yyuu/pyenv.git /usr/bin/.pyenv
[ec2-user@ip-x-x-x-X ~]$ cd /usr/bin/.pyenv
[ec2-user@ip-x-x-x-X ~]$ sudo mkdir shims
[ec2-user@ip-x-x-x-X ~]$ sudo mkdir versions
[ec2-user@ip-x-x-x-X ~]$ sudo chown -R ec2-user:ec2-user /usr/bin/.pyenv
[ec2-user@ip-x-x-x-X ~]$ vi ~/.bashrc

# 下記を末尾に追記
# from
export PYENV_ROOT="/usr/bin/.pyenv"
if [ -d "${PYENV_ROOT}" ]; then
export PATH=${PYENV_ROOT}/bin:$PATH
eval "$(pyenv init -)"
fi
# to

[ec2-user@ip-x-x-x-X ~]$ source ~/.bashrc
[ec2-user@ip-x-x-x-X ~]$ pyenv install --list

ここまで実行して、ズラッと一覧が表示されればOKです。 上記の一覧からanacondaの最新バージョンを確認します。私の場合は3-5.2.0 が最新だったので、それをインストールします。

[ec2-user@ip-x-x-x-X ~]$ pyenv install anaconda3-5.2.0
[ec2-user@ip-x-x-x-X ~]$ pyenv global anaconda3-5.2.0
[ec2-user@ip-x-x-x-X ~]$ python --version

ここで、Python 3.6.5 :: Anaconda, Inc. と表示されていればOKです。 残りのライブラリをインストールしていきます。

[ec2-user@ip-x-x-x-X ~]$ conda install keras
[ec2-user@ip-x-x-x-X ~]$ conda install tensorflow
[ec2-user@ip-x-x-x-X ~]$ conda install -c conda-forge jupyterhub
[ec2-user@ip-x-x-x-X ~]$ cd /home/ec2-user/
[ec2-user@ip-x-x-x-X ~]$ mkdir jupyterhub
[ec2-user@ip-x-x-x-X ~]$ cd jupyterhub/
[ec2-user@ip-x-x-x-X ~]$ jupyterhub --generate-config
Writing default config to: jupyterhub_config.py
[ec2-user@ip-x-x-x-X ~]$  vi jupyterhub_config.py
# 下記を書き換える
#c.Spawner.notebook_dir = ''"
c.Spawner.notebook_dir = '~/notebook'

[ec2-user@ip-x-x-x-X ~]$ sudo passwd ec2-user
[ec2-user@ip-x-x-x-X ~]$ sudo reboot

再起動するまで待ち、再びSSHします。

[ec2-user@ip-x-x-x-X ~]$ jupyterhub -f /etc/jupyterhub/jupyterhub_config.py &

これでJupyteが動きます。インスタンスIPアドレス:8000にWebブラウザからアクセスするとjupyterhubのログイン画面が表示されます。 ec2-userでログイン(パスワードは上記で設定したもの)できたらOKです。

レーニングの実行

まずはソースコードをダウンロードします。

[ec2-user@ip-x-x-x-X ~]$ git clone https://github.com/sacchin/mawile_ssd_keras.git
[ec2-user@ip-x-x-x-X ~]$ cd mawile_ssd_keras/
[ec2-user@ip-x-x-x-X ~]$ git checkout add_training_code

用意した画像とxmlファイルをzipファイルにまとめて送信します。

[ec2-user@ip-x-x-x-X ~]$ mv /home/ec2-user/images.zip /home/ec2-user/mawile_ssd_keras/data
[ec2-user@ip-x-x-x-X ~]$ cd /home/ec2-user/mawile_ssd_keras/data
[ec2-user@ip-x-x-x-X ~]$ rm images/ -r
[ec2-user@ip-x-x-x-X ~]$ unzip images.zip

再びjupyterhubにログインして、kucheat_training.py を開きます。 下記を任意の値に編集します。

* 211行目: batch_size = 10
* 260行目: nb_epoch = 50
* 269行目: nb_worker = 1

その後、jupyterにある training.ipynb を開きます。 2行目までを実行すると学習が始まります。 最終結果が /home/ec2-user/mawile_ssd_keras/data/weights に、途中の結果が /home/ec2-user/mawile_ssd_keras/data/checkpoints に格納されたら成功です。

画像の判定

jupyterにある、 predictor.py を開きます。 こちらも9行目までを実行すると、画像を認識します。

f:id:sacchin13:20181101172724p:plain

学習の画像を増やしていくと、この判定の精度が向上していきます。

まとめ

今回は、SSD + Keras でクチートの画像認識するモデルを学習する流れを説明しました。 バッチサイズを10で実行すると、1つのEpochが30分くらいました。数百円くらいの出費でした。 この辺のノウハウが無くて、もっと早く安くする方法あるのか分かっていないので、誰か教えて頂けると嬉しいです!

p.s. Let's Go ピカチュウ予約しました。オリジナルコースターを貰うため、ノジマオンラインを選んでおります。