tensorflowを用いてAuto Encoderの特徴抽出の実装(MNIST)

tensorflowを用いて特徴抽出器として用いられるAuto Encoder(AE)の実装を行います。

手書き数字データセットのMNISTをAEで特徴抽出を行います。

![ダウンロード - 2023-06-01T145819.762.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/ea54ac7e-c6a6-06a7-84ef-14f7a2658455.png)



まず、適当にimportします。

```python 
import matplotlib.pyplot as plt
import numpy as np
import tensorflow as tf

import tensorflow.keras.layers as layers
import tensorflow.keras.utils
from tensorflow.keras.models import Model
from tensorflow.keras.layers import Input, Dense, Flatten, Reshape, Conv2D, Conv2DTranspose, Lambda,UpSampling2D,AveragePooling2D
```
次にデータセットをダウンロードします。
MNISTのデータとラベル情報が得られます。

```python 
(X, y) , (test_images, test_labels) = tensorflow.keras.datasets.mnist.load_data()
#(60000, 28, 28) (60000,)
```
Xのデータの形状は(x)なので畳み込みニューラルネットワーク(CNN)で学習ができるように形を整えます。
また、MNISTの値は0~255のint8の値になっているため0~1の値に正規化して学習を行います。
```python 
print(np.min(X),np.max(X))
X=X/255
print(np.min(X),np.max(X))
#0 255
#0.0 1.0

X_reshape=X.reshape(-1,28,28,1)
```
## 学習
次にAEの学習モデルの作成に入ります。
まずは入力から次元を圧縮するEncoderを作成します。
```python 
encoder_inputs = Input(shape=(28,28,1),name='encoder_inputs')
x = Conv2D( 32,3, padding="same",use_bias=True, strides=(2,2))( encoder_inputs)
x=layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = Conv2D( 64,3, padding="valid",use_bias=True , strides=(2,2))( x )
x=layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = Conv2D( 128,3, padding="same",use_bias=True, strides=(2,2))( x )
x=layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = Conv2D( 64,3, padding="valid",use_bias=True)( x )
x=layers.BatchNormalization()(x)
x = layers.ReLU()(x)
x = layers.GlobalAveragePooling2D()(x)
encoder_output =Dense(2,use_bias=True)(x)
encoder = Model( encoder_inputs, encoder_output, name='encoder' )

```
![encoder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/021d5d32-ec10-b014-fdd5-d351c76d9c99.png)


次に圧縮されたデータから再構成をするDecoderを作成します。
```python
decoder_input = Input( shape=(2), name='decoder_input')
x=Dense(1024)(decoder_input) 
x=Reshape((1,1,1024))(x)
x = Conv2DTranspose( 512,3,padding="valid",use_bias=True , strides=(2,2))( x )
x = layers.ReLU()(x)
x = Conv2DTranspose(256 ,3,padding="valid",use_bias=True, strides=(2,2) )( x )
x = layers.ReLU()(x)
x = Conv2DTranspose(128 ,3,padding="same",use_bias=True, strides=(2,2) )( x )
x = layers.ReLU()(x)
x = Conv2DTranspose(64,3,padding="same",use_bias=True, strides=(2,2) )( x )
decoder_output=Conv2D( 1,3, padding="same",use_bias=True)( x )
decoder = Model( decoder_input, decoder_output,name='decoder' )
```
![decoder.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/c0e34639-976e-715f-d990-05a557dfd957.png)

EncoderとDecoderを組み合わせて、AEのモデルを作成します。

```python
model_input = encoder_inputs
model_output = decoder( encoder_output )
AE = Model( model_input, model_output )
```

コンパイルをして実際に学習を行います。
epoch 30,batch_size=128,varbose=0(詳細を表示したい場合は1に)
```python
AE.compile( optimizer='adam',loss='mean_squared_error')
history = AE.fit( X_reshape[:10000], X_reshape[:10000], epochs=30,batch_size=128,verbose=0)
```

## 特徴抽出
AEのEncoderのみを用いて、特徴の抽出を行います。
```python
latent=encoder.predict(X_reshape)
plt.scatter(latent[:,0],latent[:,1],c=y,cmap="tab10")
plt.colorbar()

```

圧縮された空間にて、MNISTのラベルごとに分かれていることが分かります。

![ダウンロード jhjhvu.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/bd43518d-0479-d02f-e32c-f58bce857fe7.png)


入力した画像を、実際の圧縮された空間にプロットしたものがこちらです。
各数字ごとに特徴が抽出されていることが分かります。

![ダウンロード - 2023-06-01T123655.822.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/623871/75e6c8a2-f966-4516-4351-29cf4e9330b1.png)