AutoML Visionで某スマートフォンゲームのキャラクターイラストから色々予測してみた

FGOではないです。

# はじめに
1. アドベントカレンダーにとりあえず登録したものの、元々書こうと思っていた内容を[別のアドベントカレンダーに書いてしまった](https://qiita.com/natsuume/items/b7f704aeb0e692cea8e5)のでネタが思いつかない。
2. 最近社内で[AutoMLの話](https://qiita.com/technicakidz/items/76b9d00c08c1688d6a00)がちらほら聞こえてくる。
3. AutoML触ったこと無かったのでAutoML Vision試してみることにする。
4. 自分で手軽に試せる内容ということで、自分がプレイしているスマートフォンゲームのキャラクターイラストからゲームのクラス等を予測するモデルを学習させてみた。

なお、AutoMLの手順等については~~書き忘れたので~~先人たちの記録がたくさん転がっているのでこちらでは省略したいと思います。

# データセット
今回はデータとして[きららファンタジア](https://kirarafantasia.com/)というゲームから、私がプレイしているアカウントで所持している☆4, ☆5のキャラクターの進化前後のスクリーンショットを利用します。
実装されていても私が持っていないキャラクターの画像は含まれません。

## ラベル

各キャラクターは`レアリティ`, `クラス`, `属性`, `進化`のそれぞれについて下記のいずれか一つのラベルが付与されます

* レアリティ: `☆4`, `☆5`
* クラス: `戦士`, `ナイト`, `僧侶`, `魔法使い`, `アルケミスト`
* 属性: `火`, `水`, `土`, `風`, `陽`, `月`
* 進化: `進化前`, `進化後`

## データの内訳
||進化前|進化後|合計|
|---|---|---|---|
|☆4|152|152|304|
|☆5|55|51|106|

||戦士|ナイト|僧侶|魔法使い|アルケミスト|
|---|---|---|---|---|---|
|☆4|60|58|62|62|62|
|☆5|18|14|32|30|12|

||火|水|土|風|陽|月|
|---|---|---|---|---|---|---|
|☆4|50|58|60|48|44|44|
|☆5|18|26|20|13|16|13|

## データの特徴/実例

全体の画像例としては下記のようになります。  
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/013af384-d4ce-c5f3-6161-f4613866a710.png">

また、下記のように☆5キャラクター(右)は背景も含めた一枚絵のイラスト、☆4(左)はキャラクターのみのイラスト(背景はゲーム画面で共通)といった違いがあります。
(その関連で余白のスペースも☆4, ☆5で異なります)
この辺の前処理をサボっているのでレアリティの判定自体は100%に近い性能が出るのではと思っています。
キャラクターのイラストからのレアリティ予測を真面目にやるなら、背景切り取ってランダムに適当な背景くっつけるとか余白のトリミングとかデータセットの作成を工夫する必要がありそうです。
<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/7d28c351-1b24-f462-3a73-4a082e67e13d.png"><img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/359b5261-fad8-412e-e5b9-210e00711f44.png">

加えて、同一キャラクターの☆4/☆5間ではクラスは共通ですが属性が異なるという特徴があります。
属性については上記の画像(左は水属性、右は土属性)のように人手でも分類不可能なものが多数なので、基本的には非常に低い結果になることが予想できます。

# 訓練

## マルチラベル分類
まずはマルチラベル分類として学習させてみました。

### 結果
結論から言ってしまうと、ほぼ全てのラベルで散々な結果になりました。
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/d99bcb24-8e15-07a4-d563-c007f7854e23.png">
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/ac6e8f72-5d22-1ae6-ec6d-7a1fcef83362.png">
<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/0539b997-d6d6-d658-c183-fc28f4d93663.png">
パフォーマンスを見て分かる通り、ごく一部のラベルを除いてひどい結果でした。
レアリティについては前述したとおりなので、予想通り非常に高いパフォーマンスが出ました。
属性についても予想通りですが火属性が極端に低く、月属性は比較的マシなど結構属性ラベル内でも差があるのは気になる点です。
クラスのラベルについてはもう少し高いパフォーマンスが出ることを期待していたのですが、予想に反して属性ラベルと似たような結果になってしまいました。

進化前後についてのラベルがそこそこ高いのは以外でした。

マルチラベル分類として解くにはデータ数が足りていないのは明らかなので、次に`レアリティ`, `クラス`, `属性`, `進化`の4つの単一ラベル分類に分けてそれぞれ学習させたときに結果が変化するか実験してみます。

## 単一ラベル分類

### レアリティ分類
予想通り100%の結果が出てしまいました。
これは完全に前処理サボったせいなので、特に言及することはないです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/d91a39ea-024f-4007-c9f5-b17404e481e1.png)

### クラス分類
`僧侶`については比較的マシな結果ですが、全体としては閾値0.5でprecision, recallともに0.55と微妙な結果でした。
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/0c5e5f8c-7fa0-1ecd-55ec-765a773d9b56.png">
<img  src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/3fc3da6a-1a91-cf18-11e4-9b1c91b942dd.png">


とはいえ前述した属性の件と同様に、例えば下の`魔法使い`の偽陰性の結果のように人手でも正しく分類するのが困難な画像が少なからず含まれているので妥当といえば妥当な結果ではあります。
<img width="%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/c49f5790-226d-c71c-ffa8-4febd87cebc8.png">
左から2番目は魔法使い的な帽子を被っているため人手なら魔法使いと判別付く可能性もありますが、それ以外の3枚は人手でもどのクラスか判別できません。

また、☆5キャラクターの誤りが`魔法使い`, `僧侶`の2つに固まっていますが、前述のデータ数の通り☆5のクラスの割合で魔法使いと僧侶の数が他クラスの約2倍存在することが影響しているのではないかと思います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/5afd289a-c15e-001b-344b-c90208f3e915.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/789bca86-30ed-cf7b-a990-1cde6bb85c5a.png)

結果を見ていてい興味深かったものとして、下記左は約0.99のスコアで`ナイト`と正しく予測されたのに対して、右は約0.98のスコアで`アルケミスト`と予測されていたりしました。
<img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/abd565cb-3eeb-95d1-ad0d-785806012c78.png"><img width="25%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/1ef6080b-1e40-b7d6-520f-876f9bfce9f3.png">

人間的にはいずれも右手に武器っぽいなにかを持っていて左手に盾っぽいなにかを持っているのでどちらも`ナイト`だと高い確率で判断できるように思います。

そこで元のデータになにか特徴がないか`アルケミスト`ラベルのデータを確認したところ、他のクラスのラベルと比較して紫系の色を含むキャラクターが多い印象でした。

仮にキャラクターの色を特徴量として重視しているのであれば、モノクロにしたデータや輪郭のみを抽出したデータで学習させた結果と比較すると面白いかもしれません。
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/6b2dbde3-3dc6-3b1a-6150-dc54a6990606.png">

### 属性分類
属性の分類についてはマルチラベル分類の際と比べてパフォーマンスが低かったラベルが多少上昇していますが、全体としては特筆するほど変化が有りませんでした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/7508e8fa-7e75-9ef2-a9ff-bf6c4b037936.png)

### 進化前後分類
今回試してみた中で個人的に一番いい感じの結果になってくれました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/c56863c8-45bc-3c66-b453-f928ff084b08.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/89d7e2b2-1dec-ab40-91b7-604daefc590d.png)
precision, recall共にいい感じのバランスかつそこそこ高い数値が出ました。
この分類については事前の予想ではクラスや属性ほどではないにせよ人手で分類が困難なものが結構あるのであまり高い性能は出ないと思っていたのですが、存外マシな性能が出て驚いています。

* 進化前  
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/33cd83cd-2950-581d-0966-b8f8353dc0e5.png">

* 進化後  
<img width="75%" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/5a267185-28f4-48f8-7abf-142478871c48.png">

進化前後のイラストを比較すると進化前は武器や装飾が少なくポーズも普通に立っているものが多い印象ですが、進化後は武器のようなものを持っていたり動きのあるポーズのイラストが多いように見えます。
こういった特徴をうまく学習しているのかもしれません。

実際、偽陰性/偽陽性の内容を見ても比較的そのような傾向がある気が……しないでもないですね？

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/34789/e45fe308-0b4d-a1a8-190f-b74ceca73570.png)


# まとめ
今回はきららファンタジアのキャラクター画像をデータセットにAutoML Visionで`レアリティ`, `クラス`, `属性`, `進化前/後`についてマルチラベル分類と単一ラベル分類でそれぞれ学習を行ってみました。

全体としてはラベルごとに十分なデータが存在するものについてはマルチラベル分類/単一ラベル分類のいずれでもそこそこ高く、かつ同程度の性能となることが見て取れます。
一方で、データ数が十分でないラベルの分類に関してはマルチラベル分類よりも単一ラベルの分類タスクとして学習させたほうが、比較的マシな性能になりました。

今回はデータ数が全体的に少ないのでデータ数を増やすことでより高い精度で予測できるようになる可能性は大いにありますが、各ラベルに対するモデルの性能としては「機械学習は前処理と問題設定が命」、という当たり前の話を再確認する形となりました。

また、今回の内容でtrainingは1回2時間前後、料金は1回あたり4000～5000円前後でした。
思いついてからデータ集めてラベルつけて訓練させて結果を確認してこの記事を書くまで1日前後で終わったので、ちゃんと問題設定をすればこれくらいの手軽さでそこそこの精度が出るのは知識として知っていても非常に面白いです。

私自身は画像処理系の経験が全く無かったので雰囲気を体験する意味でも試してみてよかったと感じます。
普段はNLP関連のことをやっているので、そのうちAutoML NLも試してみたいですね。

~~ただし人手でのラベル付けはやはり苦行なのでうまく正解ラベル付きデータを収集する方法は別途考える必要がありますね。~~

# おまけ

本当は[DeepLearning4J](https://deeplearning4j.org/)を使って今回のような内容をやろうと思っていたのですが、そこまで手が回らなかったのでこちらについては宿題としたいと思います。