E試験 2024#2 シラバスメモ④-3 深層学習の応用 生成モデル

E試験のシラバスとその概要をメモしたものです。
書籍、各サイトや生成AIに聞いたものを自分なりに解釈したツギハギです。

シラバスは2024#2に準拠しています

https://www.jdla.org/certificate/engineer/

本記事は4．深層学習の応用 のうち
- 生成モデル

についてとなります。
試験範囲外部分は割愛しています。

# 生成モデル
画像認識や物体検出などの識別モデル(Discriminative Model)に対し、画像を新たに生成する生成モデル(Generative Model)がある。

- 生成モデル
VAE、GANに代表される生成
- **フローベース生成モデル Flowbased generative model**
データを逆算して画像の生成過程を理解
- **拡散モデル Diffusion Model**
「ノイズを追加する関数」と「画像を復元するネットワーク」の2種類のモデルを使用し
データにランダムなノイズをゆっくりと追加し、Diffusionプロセスを逆にしてノイズから元のデータや類似画像(●●風画像など元の特徴を有した別の画像)を生成

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/64490751-cfc5-a397-bcf0-403a17b166d9.png)
https://lilianweng.github.io/posts/2021-07-11-diffusion-models/
識別モデル、生成モデル、拡散モデル、フローベース生成モデル
## オートエンコーダ
### オートエンコーダー
入力と同じデータを出力に設定して学習させるモデル。一見何の役にも立たないように見えるが、
次元の小さい中間層を設置した多層ニューラルネットワークを、入力と同じデータを出力するように学習することで、中間層部分の出力からより特徴的な表現を少ない次元で得ることができる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/9df80cea-d5a8-dcc6-4d71-764f23095a26.png)
https://hazm.at/mox/machine-learning/computer-vision/generative-model/keras-variational-autoencoder/index.html

### ノイズ除去オートエンコーダ(DAE:Denoising autoencoder)
AutoEncoderの亜種で学習データにノイズを与えたものを入力にし、元の画像を出力にする
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/ac966b2c-4c70-1051-86c2-3d329d0a71c3.png)

### 変分オートエンコーダ(VAE:Variational Autoencoder)
オートエンコーダのデコーダに変数を混ぜて、入力とは異なる出力を行うものです。 
平均と分散を出力するし
AEでは入力画像に対する特徴の「実数表現」、入力画像に対する「確率分布」に代わっている。
確率的ゆらぎによって様々なデータの生成ができるようにした。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/d15a10cd-9f9c-94b8-613f-f72f942a867d.png)
出所：https://www.scaleway.com/en/blog/vae-getting-more-out-of-your-autoencoder/ より一部編集

#### Reparameterization Trick
z部分が$z \sim N(\mu, \sigma)$確率分布となってしまい逆伝播ができない。
ランダムサンプリングしている部分$\epsilon \sim N(0, I)$(平均0,分散1の正規分布によるランダムサンプリング)という形で別に分け、
$z=\mu+\sigma\bigodot\epsilon$という形でつなげることで逆伝播可能としている。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/19094bc8-9afe-c11c-4cdd-c81701090e65.png)


#### 変分下限（ELBO:Evidence Lower Bound）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/206aa908-d1a2-f58e-af9b-ba27bd04cb19.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/d9e26435-8ed1-70f0-3ece-fde0ed2b4e92.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/6be85db8-b47c-1d39-315a-4b3296e82246.png)
出所：https://www.slideshare.net/slideshow/variational-autoencoder-64515581/64515581
## GAN
### 基本的なGAN
「生成器:Generator」と「識別器:Discriminator」二つのモデルで競争させあう。教師なし学習
1. 識別器Discriminatorの訓練
   1.1. 実際の画像をDiscriminatorに与えLossをとる。(生成された画像と判断したら間違い)
   1.2  ランダムノイズからGeneratorで生成した画像をDiscriminatorに判断させLossをとる。(実際の画像と判断したら間違い)
   1.2. 逆伝播でDiscriminatorの重みを更新する。
損失関数は以下で本物xを本物と判定$D(x)$したとき1が出力され。偽物$G(z)$を偽物と判定$\log(1-D(G(z)))$と判定したとき0が出力されるようになっている。
$L_D=\cfrac{1}{m}\sum[\log{D(x)}+\log(1-D(G(z)))]$
2. 生成器Generatorの訓練
  2.1. 訓練されたDiscriminatorに対してGeneratorが生成した画像を判断させる。
  2.2. 生成された画像と見破られなかったか見破られたかでLossをとり学習をする。
損失関数は偽物を本物と判定されるようにするためDiscriminatorの損失関数の右側部分を最小にする(Discriminatorをより騙せたら良いとする)。D(G(z))を最大にする。
$L_G=\cfrac{1}{m}\sum{\log(1-D(G(z)))}$

1.と2.を繰り返しGeneratorとDiscriminatorを交互に学習させる。
G(z): 𝑧 → x(画像データ)
D(x): 𝑥 → (0, 1)
GeneratorとDiscriminatorを合わせて考えた損失関数は
```math
\underset{G}{min}\underset{D}{max}V(D,G)=\mathbb{E}_{x \sim P(x)}[\log D(x)]+\mathbb{E}_{z\sim P(z)}[log(1-D(G(z)))]
```
![004c16f6-b2ea-4edf-ba4c-a5eea2fd5a33_960x540.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/cc6b2cc4-1e87-b12c-4497-fb3499aacc0c.gif)
出所：https://newsletter.theaiedge.io/p/how-generative-adversarial-networks

### Wasserstein GAN
GANには **mode collapse（モード崩壊）** という訓練データの最頻値に分布を寄せてしまい同じようなデータばかり生成してしまう問題がある。
そこでWasserstein距離を用いて
```math
\underset{G}{min}\underset{D\in \mathbb{D}}{max}\mathbb{E}_{x \sim P(x)}[D(x)]-\mathbb{E}_{z\sim P(z)}[D(G(z))]
```
通常のGAN
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/aa3dfda2-1b6b-8fcd-e649-54e6f7267958.png)
対してWGANは
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/2d9d941d-c84e-5b4e-7050-091f39c5d519.png)
WGAN-gpでは、本物データと生成データを同時に学習させる必要があるので、Generatorは切り離さず、入力データとして、noizeとr-imgを用いる構造とします。ただし、Discriminatorに対する実質的な入力はnoizeによって生成されたデータf-img（fはfakeの意）と、r-img（rはrealの意）に加え、二つのサンプル間の任意の点であるa-img（aはaverageの意）を用います。二つの入力値から、各入力を直線で繋いだ任意の点を用います。そのための関数としてRandomWeightedAverageを実装します。

　Discriminatorからの出力も、これに対応して3つです。f-outとr-outを用いてOriginal critic lossを、a-outを用いてgradient penaltyを記述して、損失関数を定義します。最終的にOptimizerを定義することによってDiscriminatorの学習を進めます。
出所：https://qiita.com/triwave33/items/5c95db572b0e4d0df4f0

### DCGAN:Deep Convolutional GAN

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/19394af5-1f98-8b3a-cba3-7d060d497fec.png)
出所：https://arxiv.org/pdf/1701.07875
- プーリングを使用せず
discriminatorでstrided convolutions(ストライドが大きいConv)、
generatorでfractional-strided convolutions(アップサンプリングのための逆畳み込み。deconvolutionと所作は同じだと思うが論文内で誤用だと指摘されている。)に置き換える。
- 全結合層を使用せず、Global average poolingに置き換え。
- discriminator、generator両方でBatch normalizationを適用する。
- discriminatorの全ての層で活性化関数にLeaky ReLUを使用する。
- generatorの中間層の活性化関数にReLU活性化を使用。出力はtanh
### 条件付きGAN
Generator,Discriminatorの両方にラベルyが与えられる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/aa8a18d9-a60b-857a-05c3-03ab31aa80ba.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/f88436ce-cb9d-5c6e-4784-3568d87f5730.png)
https://arxiv.org/pdf/1411.1784
Discriminatorは学習の際に、画像がfakeかrealかを判断した後、ラベルと画像が一致しているかどうかも見る。(当然ラベルが一致していてもfakeと判断した画像は拒否する。)
GeneratorはDiscriminatorが画像とラベルが一致していないと拒否されるので、画像とラベルが一致していくように学習するようになる。

これにより、ラベルを入力することで画像を生成できるようになる。
### pix2pix
二つの画像セットのペア(オリジナル画像とその線画の画像など)を用意し、2画像間の関係を特徴として学習する。
それにより線画等を入力すると、それに相当する画像が生成できるようになる。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/320eba78-eb62-2802-89dc-3a8b965da510.png)
https://toukei-lab.com/cyclegan

以下のサイトでおためしができる
https://affinelayer.com/pixsrv/

学習データとして画像のペアを用意する必要があるので教師あり学習となる。

### CycleGAN
pix2pixと同じように入力データに任意の特徴を付加したものを出力できるモデルとなるが、
pix2pixとは異なり、2つのデータソースの画像が1対1に対応していなくても学習が行える。教師なし学習
pix2pixは左のように画像がペアになっている必要があったが、CycleGANはペアである必要はない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/b9e58734-550c-5c6c-0ab2-a66f487bf979.png)
出所：https://arxiv.org/pdf/1703.10593
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/ec6f46d7-0d86-a95b-52ed-c5376c3cde8a.png)
出所：https://arxiv.org/pdf/1703.10593

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/757c18cf-4a20-8ffe-2db0-0ca916d95525.png)
Xというデータセット（例：色付きの絵画）とYというデータセット（例：色なしの絵画）のそれぞれをGeneratorで相互変換しDiscriminatorで真贋を判別するアプローチ。

Xを一旦Yに変換し、その状態でYの偽物データが本物かどうかをDiscriminatorが判断します。
変換後のYをXに再変換し、再変換後のXが元の画像なのか変換後の画像なのかを別のDiscriminatorが判断します。
すなわちここでは通常のGANで使われる敵対的損失（Adversarial Loss）に加えてサイクルで元に戻した時の損失であるサイクル一貫性の損失（Cycle Consistency Loss）という2つの損失を最小化するような学習が行われる
出所：https://toukei-lab.com/cyclegan

## 拡散モデル:Diffusion Model
「ある画像に対してランダムノイズを徐々に当てていき完全にノイズになったものを逆向きに推定した際にノイズ除去後の画像と元の画像の差分を少なくするように学習した技術」です。
X0 の人間の顔画像に対してランダムノイズを当てていき、最終的に完全なノイズになっているのがXTですね。

このランダムノイズを与える過程を逆に遡った時に元の画像と近い画像が得られるようにパラメータを最適化するのが拡散モデルの考え方です。

もう少し単純化して図で見てみましょう
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/8fa79fee-8236-706b-8444-52dce36d5170.png)

図のように犬の画像に対してノイズを乗せて、そのノイズを逆に取り除く際にノイズを取り除く部分は複数のパラメータを用いて定式化することが可能です。
ちなみに一般的にノイズには正規分布（ガウス分布）に従うノイズが当てられます。
この「ノイズ取り除く過程を定式化した部分のパラメータを調整して元の画像との差分を小さくする試み」が拡散モデルなのです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/31b11aa0-94e3-897f-3e35-d48ad47218d6.png)
出所：https://toukei-lab.com/diffusion-model

## フローベース生成モデル
フローベースの生成モデルは、可逆変換のシーケンスによって構築される。
他の2つのモデルとは異なり、このモデルはデータ分布p(x)を明示的に学習するため、損失関数は単純に負の対数尤度となる。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/bb489824-9e57-02fe-e1d8-0249581f0ee5.png)
このように, 生成時に潜在変数からデータに向かって
が順番に適用されていく流れをFlowと呼びます. また, 逆（推論）方向に見ると複雑な分布を単純な分布に少しずつ変換していることからNormalizing Flowと呼ばれることもあります（元の変分推論におけるNormalizing Flowとは意味が異なって広まっているようです）.

動画で見るとより分かりやすいです. Densityが2次元の正規分布からGitHubの公式キャラクター「Octcat」のシルエットに移っていく様子がFlowらしいですよね.
Vector Fieldは, サンプリングされた各点の動きをベクトルで示したものです.
![github_flow.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/666388/7e8d0286-ab0e-6f70-bd5c-d127c6c578a0.gif)
出所：https://qiita.com/shionhonda/items/0fb7f91a150dff604cc5