AC-GANでアニメの顔画像を生成してみた

クラスを条件とした画像生成モデルであるAC-GANを使って、アニメ顔の画像生成してみました。

## AC-GANとは
理論的な解説は[こちらの記事](https://qiita.com/koshian2/items/1a1c8d59b81fb121e012)で書いたので省略。一言でいうと、Dに真偽判定だけではなく、多クラス分類の機能をもたせたものです。

![acgan_anime_01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/aa293c8a-6bee-3a34-03fd-cf7e503aeec0.png)

画像は[https://github.com/gitlimlab/ACGAN-PyTorch](https://github.com/gitlimlab/ACGAN-PyTorch)より

## CIFAR-10でやってみる
手始めとして[論文の通り](https://arxiv.org/abs/1610.09585)の設定でCIFAR-10を生成してみました。CIFAR-10の訓練データ5万枚を使っているため、**1クラスあたりのデータ数は5000枚**となります。

### サンプリング
![sampling_cifar_acgan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/5971834b-d7d0-d008-df53-c0c9a5e1e101.png)
クラスラベルも潜在空間の変数も乱数から出力したものです。そこそこ綺麗に出ているのがわかります。

### 潜在空間の補間
AC-GANの論文によると、GANが上手くいっているかどうかを確認する一つの方法として、「潜在空間の補間を行うこと」とありました。これを実行してみます。
![inter_cifar_acgan.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/8ad366a3-bf79-a9b9-2efd-426bc5687fe6.png)
行方向でクラスラベルを固定し（0、1、2……）て任意の2つの画像を乱数で生成し、その2つの画像に対応する潜在空間を線形に補間し、対応する画像を生成します（列方向）。

出力画像がきれいかどうかはさておいて、このように**クラス単位で滑らかな補間ができれば上手くいっている**ということになります。

### コード
https://gist.github.com/koshian2/d044981c732df855ed25ee4a7372a53e

## AnimeFace Character Dataset（全種＋論文と同じ）
こちらの[AnimeFace Character Dataset](http://www.nurs.or.jp/~nagadomi/animeface-character-dataset/README.html)を使い、論文と同じ設定で生成してみます。ただし、AnimeFace Character Datasetは176クラスで14490枚の画像があるため、**1クラス平均82.3枚**とCIFAR-10よりはかなり少ないデータセットになります。

### サンプリング
![sampling_anime_acgan_original.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/3309028d-0526-3a59-a9c3-bb2691802f3d.png)
ちょっと出力画像が粗い？ ただしこれはネットワーク構造を見直すことで改善します（後述）。

### 潜在空間の補間
![inter_anime_acgan_original.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/074a2a05-3741-7893-6791-27953f4dfbf4.png)
潜在空間の補間は上手く言っているように見えますが、実は**クラス単位で同一の画像しか生成していないのではないか**ということに気づきます。

これは論文にかかれていたことなのですが、論文のImageNetによる実験では、大量のクラスを同一のネットワーク（AC-GAN）で訓練すると、出力画像の多様性が落ちてしまうという現象が確認されたそうです。ImageNetは1000個のクラスからなりますが、論文では10個のクラスを1つのネットワークとして訓練していました。これも後で試してみます。

### コード
https://gist.github.com/koshian2/c067149d97de37a9917237e7c469da51

## AnimeFace Character Dataset（全種＋ResNetベース）
先程の全種のケースを、ネットワーク構造を変更して実験してみます。

### 変更点
* GのネットワークをResNetベースに変更する（詳細はコード参照）
* アップサンプリングのレイヤーをConvTransposeから[PixelShufflerに変更](http://musyoku.github.io/2017/03/18/Deconvolution%E3%81%AE%E4%BB%A3%E3%82%8F%E3%82%8A%E3%81%ABPixel-Shuffler%E3%82%92%E4%BD%BF%E3%81%86/)する
* 損失関数を[Hinge関数に変更](https://qiita.com/koshian2/items/9add09dabb44cab2b4c0)（[GauGANの実装](https://github.com/NVlabs/SPADE)を参考にしました）

### サンプリング
![sampling_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/8870951c-eb0a-e642-afe1-48e9bb466a9b.png)

ネットワークをResNetベースにしたら**明らかに綺麗**になりました。ただし、多様性の面からは疑問があります（同じ画像を出力しているだけではないか）。

### 潜在空間の補間
![inter_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/db83b014-b3d6-818e-32c6-358c210a8880.png)

このケースでは、潜在空間の補間がうまくいきませんでした。**クラスのラベル（行方向）が効いていなく、それ以外のノイズ（横方向）で説明できてしまい**ます。データが少なすぎたのか、もしかしたら実装のどこかが良くなかったのかもしれません。

### コード
https://gist.github.com/koshian2/9be6d617ba26452a51a9fc2e34477e14

## AnimeFace Character Dataset（10種＋論文と同じ）
オリジナルの設定に戻し、訓練するクラス数を10に減らします。具体的にはデータの多いクラス上位10個[^1]を採用しました。

[^1]: 木之本桜（カードキャプターさくら）、ララ・サタリン・デビルーク（ToLOVEる）、月村真由（ご愁傷さま二ノ宮くん）、向坂環（ToHeart2）、西連寺春菜（ToLOVEる）、天海春香（アイドルマスター）、宮村みやこ（ef）、めろんちゃん（メロンブックス）、スバル・ナカジマ（魔法少女リリカルなのはStrikerS）、日奈森あむ（しゅごキャラ！）

### サンプリング
![sampling_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/4364aa05-efbd-6d43-1999-d035ab808156.png)
全種のクラスと比べて画質が若干良くなりました。論文に書いてあるとおり、**AC-GANでは一度に訓練するクラス数が多すぎるのはよくない**です。

### 潜在空間の補間
![inter_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/1d427388-a4c2-716c-86c2-84568dcbad3d.png)
潜在空間の補間は少なくともクラス別の変数はうまく効いているというのがわかります。そこそこ形になっているのが5行目で、潜在空間の乱数によって背景のスタイルをコントロールできているのがわかります。

### コード
https://gist.github.com/koshian2/7c75e449bf86ba0262a933fed42c7dca

## AnimeFace Character Dataset（10種＋ResNetベース）
最後にResNetベースで、クラス数10の場合を試してみました。

### サンプリング
![sampling_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/16d42aa8-842a-5c12-a7fd-74bd9ba2214f.png)
一部目の位置が怖い感じになっていますが、ぱっと見綺麗に言っているように見えます。ただ多様性の面が厳しそうですね。

### 潜在空間の補間
![inter_models.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232088/24744070-8cec-b92b-18d6-72c90e9cdb86.png)
10種の場合よりかは、クラスの変数が効いているように見えます。しかし、キャラごとの違いが潜在空間の乱数で決まってしまい、class coditionalな生成は上手く行かなかったです。やはり1クラスあたりのデータ数が問題なのかもしれません。

### コード
https://gist.github.com/koshian2/024e2c247a94c050165942e96a886d27


## 感想/まとめ
* CIFAR-10（1クラス5000）やImageNet（1クラス1300）のように、1クラスあたりのデータ数が多ければ、AC-GANでもかなりいい感じに生成できそう。AC-GAN自体は若干古い（2016年）モデルなので、最新形を使えばまだ伸びしろはある。
* AnimeFace Character Datasetでは1クラスあたりのデータ数が平均82.3枚で、画像そのものを綺麗に生成することはできたが、生成画像の多様性が課題。データ数が多いほど有利になるのはGANでも変わらない。
* そもそもクラス別にアノテーションされたアニメ絵の画像で、クラス数あたりそこそこの枚数があるデータセットというのを聞いたことがない（存在しない？）
* ResNetが生成画像の高画質化に非常に効いているので、WGANのようにGANの安定性を損失関数でカバーし、ネットワークやデータによる成功可否の依存性を打ち消せれば、GANはかなり有望だと思われる