物体の形状変化を伴う画像変換

[CycleGAN](https://junyanz.github.io/CycleGAN/)は画像の文脈を保ったまま画像変換を行うことができる手法です（[以前に書いたCycleGANの解説記事](https://qiita.com/hrs1985/items/050acb15ce33675f07ec)）。しかし、形状の変化を伴うような画像変換は苦手としていました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/5e9ed141-ebec-c1da-78b7-63c09fcae661.png)


これに対処するため、物体のマスク情報を明示的に使って画像だけでなくマスクも変換しようというInstaGANが提案されています。画像に対してインスタンスごとにマスクが与えられた状態のデータを必要としてますが、面白い手法なので解説したいと思います。

#InstaGAN
[InstaGAN: Instance-aware Image-to-Image Translation](https://openreview.net/forum?id=ryxwJhC9YX)
[著者の実装](https://github.com/sangwoomo/instagan)

また、著者の実装はかなり煩雑なので[こちらに再現実装を置いておきました](https://github.com/kiyohiro8/InstaGAN)。

下の画像は再現実装でのシマウマ→キリンの変換例です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/629acf76-6bf3-acfe-deb9-3880b6f3a8d2.png)

記号は以下の意味で用います。

$D\_{X/Y}$: ドメイン$X/Y$についてのDiscriminator
$G\_{XY/YX}$: ドメイン$X→Y/Y→X$の変換を行うGenerator
$(x, a)$: ドメイン$X$の画像とマスクの組
$(y, b)$: ドメイン$Y$の画像とマスクの組
$(x', a')$: $G_{YX}$により生成されたドメイン$X$の画像とマスクの組
$(y', b')$: $G_{XY}$により生成されたドメイン$Y$の画像とマスクの組


通常のCycleGANでは2つのGenerator $G_{XY/YX}$はそれぞれドメイン$X/Y$の画像を入力としてドメイン$Y/X$へと変換します。InstaGANでは画像だけでなく画像とマスクの組に対して変換を試みます。
2つのgenerator $G_{XY}/G_{YX}$はそれぞれドメイン$X/Y$の画像とマスクの組をそれぞれ$Y/X$ドメインに変換します。一方で、Discriminator $D_{X}/D_{Y}$はそれぞれ与えられた画像が元からドメイン$X/Y$に属しているものかGeneratorによって変換されたものかを判別します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/74f6442a-706a-aeb6-623c-411974dc99b0.png)

## Generator
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/dea4574d-a0b8-ef0b-fc63-8e2010c1f9c6.png)
Generatorは4つのモジュール(括弧内は画像中での表記)からなります。

1. Image Encoder ($f_{GX}$)
2. Mask Encoder ($f_{GA}$)
3. Image Decoder ($g_{GX}$)
4. Mask Decoder ($g_{GA}$)

Image EncoderとMask Encoderはそれぞれ画像とインスタンスごとのマスクから特徴を抽出します。
各インスタンスのマスク特徴の総和を取ったもの（総和マスク特徴、斜線）を取っておきます。

Image Decoderは画像特徴と総和マスク特徴を使って変換後の画像を生成します。
Mask Decoderはそれらに加えて各インスタンスのマスク特徴を使ってそれぞれ対応する変換後のマスクを生成します。


## Discriminator
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/798d25be-591b-a221-a055-bda5babd1a3d.png)

Discriminatorは

1. Image Encoder ($f_{GX}$)
2. Mask Encoder ($f_{GA}$)
3. Head ($g_{GX}$)

からなります。
2つのEncoderはGeneratorのものと同様に画像と各インスタンスのマスクから特徴を抽出します。
Head部分はDiscriminatorの最終的な出力を行うモジュールです。

## 損失関数
InstaGANのGeneratorの損失はAdversarial Loss ($\mathcal{L}\_{LSGAN}$)、Cycle Consistency Loss ($\mathcal{L}\_{cyc}$)、Identity Loss ($\mathcal{L}\_{idt}$)、Context Preserving Loss ($\mathcal{L}\_{ctx}$) の4つの項からなります。

### Adversarial Loss
Adversarial LossはGeneratorの生成した画像がDiscriminatorを騙せた度合いに関する損失です。論文中ではLSGANを使用しています。

$ \mathcal{L}\_{LSGAN} = (D\_{X}(x, a) - 1)^2 + (D\_{X}(G\_{YX}(y, b))^2 + (D\_{Y}(y, b) - 1)^2 + (D\_{Y}(G\_{XY}(x, a))^2$

### Cycle Consistency Loss
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/4cef122b-e9a1-2372-25be-aaaac67dcb10.png)
Cycle Consistency Lossは変換後の画像が元の画像の文脈を残せているかに関する損失で、CycleGANの論文中で提案されています。Cycle Consistency Lossは図のように$X→Y→X$のような変換を行うと元の画像に戻ってくるようGeneratorに制約を課しており、これにより元の画像の文脈を維持した変換方法を学習することが期待できます。

$\mathcal{L}\_{cyc} = || G\_{XY}(G\_{YX}(x, a)) - (x, a) ||\_{1} + || G\_{YX}(G\_{XY}(y, b)) - (y, b) ||\_{1}$

### Identity Loss
2つのGenerator $G_{XY/YX}$ はそれぞれ$X→Y, Y→X$の変換だけをしてほしい、言い換えれば画像の対象ドメイン以外の領域には変化を加えないことが望ましいです。そこで、$G_{XY/YX}$に変換対象ではないドメイン$Y/X$の画像を与えても何も変化させないよう制約を与えるための損失です。これもCycleGANで使用されていたものです。

$\mathcal{L}\_{idt} = || G\_{XY}(y, b) - (y, b) ||\_{1} + || G\_{YX}(x, a) - (x, a) ||\_{1} $

### Context Preserving Loss
インスタンスマスク以外の領域に極力変化させないような制約を与える損失です。
$\mathcal{L}\_{ctx} = || w(a,b') \bigodot (x - y') ||\_1 + || w(b,a') \bigodot (y - x') ||\_1$
$w(a,b')$および$w(b,a')$はそれぞれ変換前後でのマスクの合併を除いた領域、つまり変換前でも変換後でも背景となっている領域を示しています。$x - y', y - x'$は変換前後の画像の差分。 $\bigodot$は要素積を表しており、全体として変換対象となっているマスク領域以外を極力変化させないような制約を与えています。

### Total Loss
$\mathcal{L}\_{InstaGAN} = \mathcal{L}\_{LSGAN} + \lambda\_{cyc}\mathcal{L}\_{cyc} + \lambda\_{idt}\mathcal{L}\_{idt} + \lambda\_{ctx}\mathcal{L}\_{ctx}$
$\lambda\_{cyc}, \lambda\_{idt}, \lambda\_{ctx}$はそれぞれの項の重みを調整する係数です。


## Sequential Mini-batch Translation
InstaGANではMask EncoderとMask Decoderは個々のインスタンスごとにマスクの変換を行います。これはその画像中に変換対象となるインスタンスが少数しかない場合は上手くいきますが、数が増えるとメモリの使用量が増えていってしまいます。それを解決するための手法としてSequential Mini-batch Translationを提案しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/c714808b-7a43-ec5b-2dd2-3ab02be20139.png)
Sequential Mini-batch Translationを使う場合、Generatorは与えられたインスタンスを一度に全て変換するのではなく、数個ごとに変換を行います。学習時の誤差逆伝播は実線の部分だけで行います。iterationをまたぐ点線部分はdetachされており誤差情報が伝わりません。

## Result
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/134222/f5155075-971c-48db-fa29-53826b2a1f85.png)
InstaGANではヒツジとキリンやカップとボトルのような形状変化を伴う変換が上手くできています。また、スカートとパンツの変換などもできており仮想試着のようなことができています。