ディープラーニングで落書きを消す

# ディープラーニングで落書きを消す
先日[畳み込みオートエンコーダでノイズ除去](https://qiita.com/cvusk/items/019c254db883957b3050)を行いましたが、そのときの課題は再現された画像が滲んでしまっていたことです。

今回はもう少し改良して、オートエンコーダやCNNで落書きを消してみようと思います。
ライブラリにはKerasを使います。

データセットはCifar10を使います。
Cifar10にランダムに棒線で落書きします。
棒線の色は黒バージョンとランダム色バージョンを作りました。

黒バージョン

![4.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/caaa0c4e-59fc-4be6-9be7-44a63c194158.png)


ランダム色バージョン

![5.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/2dd7ed87-1483-c434-2b98-69e8124b21f2.png)


この棒線を消して元画像を再現するよう、ディープラーニングで学習します。
トレーニングデータ50,000点の落書き除去を学習し、テストデータ10,000点の落書き除去＆元画像再現性を評価します。
再現性の評価関数はmean squared errorを使います。

落書きを消す手法として、オートエンコーダとCNNを試しました。
試した手法：
1. 畳み込みオートエンコーダ
2. 畳み込みオートエンコーダ改良版
3. DNCNN
4. Win5-RB

コードは以下にあります。
https://github.com/shibuiwilliam/DeepLearningDenoise


## 畳み込みオートエンコーダ
前回同様の畳み込みオートエンコーダです。

![0.png](https://qiita-image-store.s3.amazonaws.com/0/55384/3e7cb6ad-3415-cd33-52d3-15fab87b6803.png)


レイヤー定義

```python
# encoder
input_img = Input(shape=(32, 32, 3))
x = Conv2D(32, (3, 3), padding='same')(input_img)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = MaxPooling2D((2, 2), padding='same')(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
encoded = MaxPooling2D((2, 2), padding='same')(x)

# decoder
x = Conv2D(32, (3, 3), padding='same')(encoded)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('relu')(x)
x = UpSampling2D((2, 2))(x)
x = Conv2D(3, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
decoded = Activation('sigmoid')(x)

# compile
model = Model(input_img, decoded)
model.compile(optimizer='adam', loss='mean_squared_error')

# options
es_cb = EarlyStopping(monitor='val_loss', patience=2, verbose=1, mode='auto')
chkpt = saveDir + 'AutoEncoder_Cifar10_deline_weights.{epoch:02d}-{loss:.2f}-{val_loss:.2f}.hdf5'
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1, save_best_only=True, mode='auto')

# train
history = model.fit(x_train_line, x_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test_line, x_test),
                    callbacks=[es_cb, cp_cb],
                    shuffle=True)
```

黒バージョンもランダム色バージョンも、やはり滲んでしまいます。
[結果（黒バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_DeLine_AutoEncoder.ipynb)
mean squred error: 0.00251344182827

![ae1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/716e6cd6-2395-e73d-24a6-6bc13d8c40b5.png)
![ae2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/aa8804fe-75e7-bf34-653b-7666f54a6ec5.png)

[結果（ランダム色バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_DeLineColor_AutoEncoder.ipynb)
mean squred error: 0.00406358846352

![aeColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/a7f47926-8686-db88-f73a-8427feff5788.png)
![aeColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/11e6c076-cc2b-872d-acab-f32bfa9b4edf.png)


## 畳み込みオートエンコーダ改良版
畳み込みオートエンコーダを改良しました。こちらはエンコーダ・デコーダの間を全結合に変換して接続します。

![1.png](https://qiita-image-store.s3.amazonaws.com/0/55384/53affd49-c02d-74d1-4cc5-6c678381259b.png)


レイヤー定義

```python

# encoder
input_img = Input(shape=(32, 32, 3))
x = Conv2D(32, (3, 3), padding='same')(input_img)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Flatten()(x)
x = Dense(3072)(x)
x = BatchNormalization()(x)
encoded = Activation('sigmoid')(x)

# decoder
x = Dense(3072)(encoded)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Reshape((32,32,3))(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Conv2D(32, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
x = Activation('elu')(x)
x = Conv2D(3, (3, 3), padding='same')(x)
x = BatchNormalization()(x)
decoded = Activation('sigmoid')(x)

# compile
model = Model(input_img, decoded)
model.compile(optimizer='adam', loss='mean_squared_error')

# options
es_cb = EarlyStopping(monitor='val_loss', patience=3, verbose=1, mode='auto')
chkpt = saveDir + 'AutoEncoder_Cifar10_delineBlack_CAE_weights.{epoch:02d}-{loss:.2f}-{val_loss:.2f}.hdf5'
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1, save_best_only=True, mode='auto')

# train
history = model.fit(x_train_line, x_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test_line, x_test),
                    callbacks=[es_cb, cp_cb],
                    shuffle=True)
```

こうするだけでも意外と再現性が向上するようです。
[結果（黒バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_Denoise_CAE.ipynb)
mean squred error: 0.00139122980386

![cae2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/1970bc0b-8119-3d41-d072-e02fb53a81a9.png)
![cae1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/403fa3b7-54c8-7d33-c31e-5daee93f28d6.png)

[結果（ランダム色バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_DenoiseColor_CAE.ipynb)
mean squred error: 0.00257390149683

![caeColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/0257eb95-70b9-868f-5b6a-9db526d1bcbe.png)
![caeColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/7c7c08ae-4c42-beda-93c0-75e5be5cb0b9.png)

多少滲んでしますが、前の畳み込みオートエンコーダよりはきれいに再現できています。


## DNCNN
DNCNNはDenoising Convolutional Neural Network（ノイズ除去畳み込みニューラルネットワーク）という、その名のとおりのノイズ除去を目的としたCNNです。
https://arxiv.org/pdf/1608.03981v1.pdf
構造は以下のようなものです。

![2.png](https://qiita-image-store.s3.amazonaws.com/0/55384/15d376db-a6d9-6619-7799-44b45837579b.png)


畳み込みとBatchNormalization、活性化関数Reluを重ねていき、最後の層だけ活性化関数Tanhを使います。
中間層が16層と厚い構成です。

レイヤー定義

```python
# DNCNN
input_img = Input(shape=(32, 32, 3))
x = Conv2D(64, (3, 3), padding='same')(input_img)
x = Activation('relu')(x)

for i in range(15):
    x = Conv2D(64, (3, 3), padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)

x = Conv2D(3, (3, 3), padding='same')(x)
output_img = Activation('tanh')(x)

# compile
model = Model(input_img, output_img)
model.compile(optimizer='adam', loss='mean_squared_error')

# options
es_cb = EarlyStopping(monitor='val_loss', patience=2, verbose=1, mode='auto')
chkpt = saveDir + 'AutoEncoder_Cifar10_dncnn_weights.{epoch:02d}-{loss:.2f}-{val_loss:.2f}.hdf5'
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1, save_best_only=True, mode='auto')

# train
history = model.fit(x_train_line, x_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test_line, x_test),
                    callbacks=[es_cb, cp_cb],
                    shuffle=True)
```

結果は以下のとおりで、大分きれいに落書きが消えて、画像も再現できています。
[結果（黒バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_Denoise_DNCNN.ipynb)
mean squred error: 0.000638661881443

![dncnn1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/fcccfa7f-e2ac-e590-7200-956b375438ac.png)
![dncnn2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/c6afdf89-1c62-ccb4-eeb3-413bced65fcd.png)

[結果（ランダム色バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_DenoiseColor_DNCNN.ipynb)
mean squared error: 0.000755158919282

![dncnnColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/3331c9d7-2775-7245-42ea-948736b39ad3.png)
![dncnnColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/58d4712e-09c6-ff4f-9a9a-704c733e3924.png)


ところどころ別のノイズが入ってしまっているのが難点です。


## Win5-RB
Win5-RBはDNCNNをResnetにしたものです。
Win5-RBはWide Inference Network（Win）が5層構成で、Resnet（R）とBatchNormalization（B）を使っているという意味です。
https://arxiv.org/pdf/1707.05414.pdf

![3.png](https://qiita-image-store.s3.amazonaws.com/0/55384/931277ec-aac1-7ce3-e5c5-fcc6dbd10ce1.png)


レイヤー定義

```python
# Win5-RB
input_img = Input(shape=(32, 32, 3))
x = Conv2D(64, (7, 7), padding='same')(input_img)
x = BatchNormalization()(x)
x = Activation('relu')(x)

for i in range(3):
    x = Conv2D(64, (7, 7), padding='same')(x)
    x = BatchNormalization()(x)
    x = Activation('relu')(x)

x = Conv2D(3, (7, 7), padding='same')(x)
x = BatchNormalization()(x)
output_img = layers.add([x, input_img])

# compile
model = Model(input_img, output_img)
model.compile(optimizer='adam', loss='mean_squared_error')

# options
es_cb = EarlyStopping(monitor='val_loss', patience=2, verbose=1, mode='auto')
chkpt = saveDir + 'AutoEncoder_Cifar10_win5rb_weights.{epoch:02d}-{loss:.2f}-{val_loss:.2f}.hdf5'
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1, save_best_only=True, mode='auto')

# train
history = model.fit(x_train_line, x_train,
                    batch_size=batch_size,
                    epochs=epochs,
                    verbose=1,
                    validation_data=(x_test_line, x_test),
                    callbacks=[es_cb, cp_cb],
                    shuffle=True)
```

評価関数的にはもっとも良い値を出しています。
[結果（黒バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_Denoise_Win5RB.ipynb)
mean squred error: 0.000271678016009

![win1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/6a45d5bd-c806-4019-5916-180adeb68021.png)
![win2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/1dad7231-2025-7017-9aeb-f959689484ca.png)

[結果（ランダム色バージョン）](https://github.com/shibuiwilliam/DeepLearningDenoise/blob/master/Cifar_DenoiseColor_Win5RB.ipynb)
mean squred error: 0.000558209863212

![winColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/7a329e7e-6421-4d1a-398e-df367d6dbc63.png)
![winColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/812acffc-e1e6-4fc6-5958-e493daf4b3fe.png)


きれいに再現できていますが、DNCNN同様に違うノイズが入ってしまっています。

どうやらDNCNNもWin5RBも、真っ白い部分や真っ黒い部分にノイズが残ってしまうようです。


## 最後に
比較のため、それぞれの結果を並べて表示します。

#### 評価関数

|  | 黒バージョン  | ランダム色バージョン　|
|:--|---|--:|
| 畳み込みオートエンコーダ  |  0.00251344182827 |  0.00406358846352 |
| 畳み込みオートエンコーダ改良版  |  0.00139122980386 |  0.00257390149683 |
| DNCNN  | 0.000638661881443  |  0.000755158919282 |
| Win5-RB  | 0.000271678016009  |  0.000558209863212 | 


#### 畳み込みオートエンコーダ
##### 黒バージョン
![ae1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/716e6cd6-2395-e73d-24a6-6bc13d8c40b5.png)
![ae2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/aa8804fe-75e7-bf34-653b-7666f54a6ec5.png)
##### ランダム色バージョン
![aeColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/a7f47926-8686-db88-f73a-8427feff5788.png)
![aeColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/11e6c076-cc2b-872d-acab-f32bfa9b4edf.png)


#### 畳み込みオートエンコーダ改良版
##### 黒バージョン
![cae2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/1970bc0b-8119-3d41-d072-e02fb53a81a9.png)
![cae1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/403fa3b7-54c8-7d33-c31e-5daee93f28d6.png)
##### ランダム色バージョン
![caeColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/0257eb95-70b9-868f-5b6a-9db526d1bcbe.png)
![caeColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/7c7c08ae-4c42-beda-93c0-75e5be5cb0b9.png)


#### DNCNN
##### 黒バージョン
![dncnn1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/fcccfa7f-e2ac-e590-7200-956b375438ac.png)
![dncnn2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/c6afdf89-1c62-ccb4-eeb3-413bced65fcd.png)
##### ランダム色バージョン
![dncnnColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/3331c9d7-2775-7245-42ea-948736b39ad3.png)
![dncnnColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/58d4712e-09c6-ff4f-9a9a-704c733e3924.png)

#### Win5-RB
##### 黒バージョン
![win1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/6a45d5bd-c806-4019-5916-180adeb68021.png)
![win2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/1dad7231-2025-7017-9aeb-f959689484ca.png)
##### ランダム色バージョン
![winColor1.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/7a329e7e-6421-4d1a-398e-df367d6dbc63.png)
![winColor2.PNG](https://qiita-image-store.s3.amazonaws.com/0/55384/812acffc-e1e6-4fc6-5958-e493daf4b3fe.png)