2.5 - Autoencoders
Contents
2.5 - Autoencoders¶
!wget -nc --no-cache -O init.py -q https://raw.githubusercontent.com/rramosp/2021.deeplearning/main/content/init.py
import init; init.init(force_download=False);
import numpy as np
import matplotlib.pyplot as plt
import pandas as pd
%matplotlib inline
1. Introduction¶
An autoencoder is an unsupervised lerarning method in which we seek to obtain a LATENT REPRESENTATION of our data, usually with reduced dimensionality.
We will be using
Tensorflow. Since TF can use GPUs or TPUs if available, it is usually better to force all data types to be
np.float32
orint
.The MNIST digits classification dataset. Observe how we normalize the MNIST images.
mnist = pd.read_csv("local/data/mnist1.5k.csv.gz", compression="gzip", header=None).values
X=(mnist[:,1:785]/255.).astype(np.float32)
y=(mnist[:,0]).astype(int)
print("dimension de las imagenes y las clases", X.shape, y.shape)
dimension de las imagenes y las clases (1500, 784) (1500,)
perm = np.random.permutation(list(range(X.shape[0])))[0:50]
random_imgs = X[perm]
random_labels = y[perm]
fig = plt.figure(figsize=(10,6))
for i in range(random_imgs.shape[0]):
ax=fig.add_subplot(5,10,i+1)
plt.imshow(random_imgs[i].reshape(28,28), interpolation="nearest", cmap = plt.cm.Greys_r)
ax.set_title(int(random_labels[i]))
ax.set_xticklabels([])
ax.set_yticklabels([])
and we do the regular train/test split
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=.2)
2. Assembling and training an autoencoder¶
Observe how an autoencoder is just a concatenation of two regular Dense
layers. Why are we using a sigmoid as decoder output activation?
from tensorflow.keras import Model
from tensorflow.keras.layers import Dense, Dropout, Flatten, Input
import tensorflow as tf
def get_model(input_dim, code_size):
inputs = Input(shape=input_dim, name="input")
encoder = Dense(code_size, activation='relu', dtype=np.float32, name="encoder")(inputs)
outputs = Dense(input_dim, activation='sigmoid', dtype=np.float32, name="decoder")(encoder)
model = Model([inputs], [outputs])
model.compile(optimizer='adam', loss='mse')
return model
model = get_model(input_dim=X.shape[1], code_size=50)
model.summary()
Model: "model_27"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input (InputLayer) [(None, 784)] 0
_________________________________________________________________
encoder (Dense) (None, 50) 39250
_________________________________________________________________
decoder (Dense) (None, 784) 39984
=================================================================
Total params: 79,234
Trainable params: 79,234
Non-trainable params: 0
_________________________________________________________________
and we simply train the autoencoder. Observe how we use the same data as input and output
model.fit(X_train, X_train, epochs=100, batch_size=16)
Train on 1200 samples
Epoch 1/100
1200/1200 [==============================] - 0s 219us/sample - loss: 0.1047
Epoch 2/100
1200/1200 [==============================] - 0s 80us/sample - loss: 0.0597
Epoch 3/100
1200/1200 [==============================] - 0s 84us/sample - loss: 0.0493
Epoch 4/100
1200/1200 [==============================] - 0s 86us/sample - loss: 0.0427
Epoch 5/100
1200/1200 [==============================] - 0s 83us/sample - loss: 0.0380
Epoch 6/100
1200/1200 [==============================] - 0s 82us/sample - loss: 0.0344
Epoch 7/100
1200/1200 [==============================] - 0s 81us/sample - loss: 0.0314
Epoch 8/100
1200/1200 [==============================] - 0s 81us/sample - loss: 0.0290
Epoch 9/100
1200/1200 [==============================] - 0s 81us/sample - loss: 0.0269
Epoch 10/100
1200/1200 [==============================] - 0s 82us/sample - loss: 0.0251
Epoch 11/100
1200/1200 [==============================] - 0s 93us/sample - loss: 0.0234
Epoch 12/100
1200/1200 [==============================] - 0s 91us/sample - loss: 0.0220
Epoch 13/100
1200/1200 [==============================] - 0s 84us/sample - loss: 0.0207
Epoch 14/100
1200/1200 [==============================] - 0s 80us/sample - loss: 0.0195
Epoch 15/100
1200/1200 [==============================] - 0s 76us/sample - loss: 0.0185
Epoch 16/100
1200/1200 [==============================] - 0s 78us/sample - loss: 0.0176
Epoch 17/100
1200/1200 [==============================] - 0s 76us/sample - loss: 0.0168
Epoch 18/100
1200/1200 [==============================] - 0s 82us/sample - loss: 0.0160
Epoch 19/100
1200/1200 [==============================] - 0s 85us/sample - loss: 0.0152
Epoch 20/100
1200/1200 [==============================] - 0s 93us/sample - loss: 0.0145
Epoch 21/100
1200/1200 [==============================] - 0s 86us/sample - loss: 0.0139
Epoch 22/100
1200/1200 [==============================] - 0s 93us/sample - loss: 0.0134
Epoch 23/100
1200/1200 [==============================] - 0s 92us/sample - loss: 0.0128
Epoch 24/100
1200/1200 [==============================] - 0s 97us/sample - loss: 0.0123
Epoch 25/100
1200/1200 [==============================] - 0s 101us/sample - loss: 0.0119
Epoch 26/100
1200/1200 [==============================] - 0s 88us/sample - loss: 0.0114
Epoch 27/100
1200/1200 [==============================] - 0s 88us/sample - loss: 0.0110
Epoch 28/100
1200/1200 [==============================] - 0s 80us/sample - loss: 0.0107
Epoch 29/100
1200/1200 [==============================] - 0s 94us/sample - loss: 0.0103
Epoch 30/100
1200/1200 [==============================] - 0s 92us/sample - loss: 0.0100
Epoch 31/100
1200/1200 [==============================] - 0s 98us/sample - loss: 0.0097
Epoch 32/100
1200/1200 [==============================] - 0s 102us/sample - loss: 0.0094
Epoch 33/100
1200/1200 [==============================] - 0s 96us/sample - loss: 0.0091
Epoch 34/100
1200/1200 [==============================] - 0s 81us/sample - loss: 0.0089
Epoch 35/100
1200/1200 [==============================] - 0s 77us/sample - loss: 0.0086
Epoch 36/100
1200/1200 [==============================] - 0s 77us/sample - loss: 0.0084
Epoch 37/100
1200/1200 [==============================] - 0s 77us/sample - loss: 0.0082
Epoch 38/100
1200/1200 [==============================] - 0s 85us/sample - loss: 0.0080
Epoch 39/100
1200/1200 [==============================] - 0s 80us/sample - loss: 0.0078
Epoch 40/100
1200/1200 [==============================] - 0s 92us/sample - loss: 0.0077
Epoch 41/100
1200/1200 [==============================] - 0s 82us/sample - loss: 0.0075
Epoch 42/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0073
Epoch 43/100
1200/1200 [==============================] - 0s 60us/sample - loss: 0.0072
Epoch 44/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0070
Epoch 45/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0069
Epoch 46/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0068
Epoch 47/100
1200/1200 [==============================] - 0s 61us/sample - loss: 0.0067
Epoch 48/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0066
Epoch 49/100
1200/1200 [==============================] - 0s 63us/sample - loss: 0.0065
Epoch 50/100
1200/1200 [==============================] - 0s 61us/sample - loss: 0.0064
Epoch 51/100
1200/1200 [==============================] - 0s 74us/sample - loss: 0.0063
Epoch 52/100
1200/1200 [==============================] - 0s 71us/sample - loss: 0.0062
Epoch 53/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0061
Epoch 54/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0060
Epoch 55/100
1200/1200 [==============================] - 0s 63us/sample - loss: 0.0059
Epoch 56/100
1200/1200 [==============================] - 0s 67us/sample - loss: 0.0059
Epoch 57/100
1200/1200 [==============================] - 0s 64us/sample - loss: 0.0058
Epoch 58/100
1200/1200 [==============================] - 0s 69us/sample - loss: 0.0057
Epoch 59/100
1200/1200 [==============================] - 0s 78us/sample - loss: 0.0057
Epoch 60/100
1200/1200 [==============================] - 0s 66us/sample - loss: 0.0056
Epoch 61/100
1200/1200 [==============================] - 0s 69us/sample - loss: 0.0055
Epoch 62/100
1200/1200 [==============================] - 0s 66us/sample - loss: 0.0055
Epoch 63/100
1200/1200 [==============================] - 0s 63us/sample - loss: 0.0054
Epoch 64/100
1200/1200 [==============================] - 0s 68us/sample - loss: 0.0054
Epoch 65/100
1200/1200 [==============================] - 0s 88us/sample - loss: 0.0053
Epoch 66/100
1200/1200 [==============================] - 0s 70us/sample - loss: 0.0053
Epoch 67/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0052
Epoch 68/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0051
Epoch 69/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0051
Epoch 70/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0051
Epoch 71/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0051
Epoch 72/100
1200/1200 [==============================] - 0s 67us/sample - loss: 0.0050
Epoch 73/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0050
Epoch 74/100
1200/1200 [==============================] - 0s 59us/sample - loss: 0.0049
Epoch 75/100
1200/1200 [==============================] - 0s 59us/sample - loss: 0.0049
Epoch 76/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0049
Epoch 77/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0048
Epoch 78/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0048
Epoch 79/100
1200/1200 [==============================] - 0s 59us/sample - loss: 0.0048
Epoch 80/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0047
Epoch 81/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0047
Epoch 82/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0047
Epoch 83/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0046
Epoch 84/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0046
Epoch 85/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0046
Epoch 86/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0046
Epoch 87/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0045
Epoch 88/100
1200/1200 [==============================] - 0s 63us/sample - loss: 0.0045
Epoch 89/100
1200/1200 [==============================] - 0s 61us/sample - loss: 0.0045
Epoch 90/100
1200/1200 [==============================] - 0s 59us/sample - loss: 0.0045
Epoch 91/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0044
Epoch 92/100
1200/1200 [==============================] - 0s 61us/sample - loss: 0.0044
Epoch 93/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0044
Epoch 94/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0044
Epoch 95/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0044
Epoch 96/100
1200/1200 [==============================] - 0s 65us/sample - loss: 0.0043
Epoch 97/100
1200/1200 [==============================] - 0s 63us/sample - loss: 0.0043
Epoch 98/100
1200/1200 [==============================] - 0s 60us/sample - loss: 0.0043
Epoch 99/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0043
Epoch 100/100
1200/1200 [==============================] - 0s 59us/sample - loss: 0.0043
<tensorflow.python.keras.callbacks.History at 0x7fdef872e710>
The training seems to have gone well (the loss was reduced)
Question: How can we measure how good was the result?
You can try with larger layers, with more layers, etc.
Making predictions¶
We can feed the model any input and get the output. Observe we get eager tensors, which are like a symbolic wrapper to numpy matrices. We will see more about this later in this course.
o = model(X_train)
o
<tf.Tensor: shape=(1200, 784), dtype=float32, numpy=
array([[3.6984453e-08, 1.9736575e-10, 2.5541331e-09, ..., 3.9784051e-10,
2.2014549e-10, 1.1092759e-09],
[2.4385532e-08, 5.4472249e-08, 1.0746028e-07, ..., 3.1418881e-07,
3.5111746e-08, 4.8708703e-08],
[6.5164496e-09, 9.6711994e-10, 2.4460364e-10, ..., 3.5345697e-09,
1.6141123e-10, 6.1249552e-09],
...,
[7.9344659e-07, 8.7452588e-07, 8.2074229e-07, ..., 2.4234178e-06,
9.3258961e-07, 5.6553978e-07],
[9.9626490e-08, 6.0966705e-08, 8.2821021e-09, ..., 1.4567654e-08,
1.0074373e-08, 6.9440011e-07],
[5.3350539e-07, 3.4182764e-07, 1.0137308e-06, ..., 3.1523388e-07,
5.7831215e-08, 2.0375307e-07]], dtype=float32)>
in eager tensors we can access the underlying numpy
matrix.
o.numpy()
array([[3.6984453e-08, 1.9736575e-10, 2.5541331e-09, ..., 3.9784051e-10,
2.2014549e-10, 1.1092759e-09],
[2.4385532e-08, 5.4472249e-08, 1.0746028e-07, ..., 3.1418881e-07,
3.5111746e-08, 4.8708703e-08],
[6.5164496e-09, 9.6711994e-10, 2.4460364e-10, ..., 3.5345697e-09,
1.6141123e-10, 6.1249552e-09],
...,
[7.9344659e-07, 8.7452588e-07, 8.2074229e-07, ..., 2.4234178e-06,
9.3258961e-07, 5.6553978e-07],
[9.9626490e-08, 6.0966705e-08, 8.2821021e-09, ..., 1.4567654e-08,
1.0074373e-08, 6.9440011e-07],
[5.3350539e-07, 3.4182764e-07, 1.0137308e-06, ..., 3.1523388e-07,
5.7831215e-08, 2.0375307e-07]], dtype=float32)
which is equivalent to using the predict
method
model.predict(X_train)
array([[8.51090044e-06, 9.57351585e-06, 1.13940905e-05, ...,
3.42914391e-05, 3.14637837e-05, 2.88015835e-05],
[1.86773832e-07, 1.27578161e-07, 1.07958464e-07, ...,
1.01204898e-06, 2.39109053e-08, 8.60198028e-08],
[3.13102419e-07, 1.51896174e-07, 9.71393774e-07, ...,
2.90563321e-07, 1.50165334e-07, 1.02712795e-06],
...,
[5.47624950e-06, 1.08655540e-05, 3.28201281e-06, ...,
1.65009769e-05, 3.28613760e-06, 6.86891599e-06],
[1.78545015e-05, 3.65451124e-05, 1.01834385e-05, ...,
3.14925092e-05, 9.99619442e-06, 3.84393861e-05],
[1.01194764e-05, 1.31769011e-05, 3.37959609e-05, ...,
2.97471677e-04, 3.17740560e-05, 5.00498973e-05]], dtype=float32)
X_sample = np.random.permutation(X_test)[:10]
X_pred = model.predict(X_sample)
plt.figure(figsize=(20,5))
for i in range(len(X_sample)):
plt.subplot(2,len(X_sample),i+1)
plt.imshow(X_sample[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
plt.subplot(2,len(X_sample),len(X_sample)+i+1)
plt.imshow(X_pred[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
Accessing model layers¶
We can also get the output of any layer, including the final layer
layer_input = model.get_layer("input")
layer_encoder = model.get_layer("encoder")
layer_decoder = model.get_layer("decoder")
m = Model([layer_input.input], [layer_decoder.output])
m(X_train)
<tf.Tensor: shape=(1200, 784), dtype=float32, numpy=
array([[8.51090044e-06, 9.57351585e-06, 1.13941014e-05, ...,
3.42914718e-05, 3.14638128e-05, 2.88015835e-05],
[1.86773661e-07, 1.27578161e-07, 1.07958464e-07, ...,
1.01204989e-06, 2.39109053e-08, 8.60198028e-08],
[3.13102760e-07, 1.51896316e-07, 9.71393774e-07, ...,
2.90563577e-07, 1.50165334e-07, 1.02712988e-06],
...,
[5.47624950e-06, 1.08655540e-05, 3.28200645e-06, ...,
1.65009933e-05, 3.28613760e-06, 6.86891599e-06],
[1.78545015e-05, 3.65451488e-05, 1.01834385e-05, ...,
3.14925092e-05, 9.99619442e-06, 3.84393861e-05],
[1.01194764e-05, 1.31769148e-05, 3.37959900e-05, ...,
2.97471968e-04, 3.17740851e-05, 5.00498973e-05]], dtype=float32)>
of the encoder, shapes must match
me = Model([layer_input.input], [layer_encoder.output])
me(X_train)
<tf.Tensor: shape=(1200, 50), dtype=float32, numpy=
array([[ 1.4733481 , 5.6071835 , 0.4546271 , ..., 6.584404 ,
0. , 3.4143682 ],
[ 5.7947493 , 6.376433 , 0. , ..., 1.1779828 ,
1.8339571 , 2.2694755 ],
[ 1.7550068 , 4.7390604 , 0.64162546, ..., 8.171952 ,
4.2970653 , 1.2317356 ],
...,
[ 5.9646645 , 6.6686645 , 3.091914 , ..., 1.5258911 ,
2.0375972 , 8.356914 ],
[ 3.3050153 , 4.8892 , 4.8872223 , ..., 2.1351342 ,
4.004214 , 7.943392 ],
[ 5.2594194 , 3.1832466 , 1.4421158 , ..., 4.5179844 ,
12.360394 , 3.8473024 ]], dtype=float32)>
Accessing model weights¶
recall that these are the weights adjusted during training
w = model.get_weights()
for i, wi in enumerate(w):
print (f"weights {i}: {str(wi.shape):10s} sum {np.sum(wi):+6.2f}")
weights 0: (784, 50) sum +1014.07
weights 1: (50,) sum +24.43
weights 2: (50, 784) sum -1458.86
weights 3: (784,) sum -181.90
the same weights can also we accessed via the layers
for i, li in enumerate(model.layers):
print ("layer", i, ", ".join([(str(wi.shape)+" sum %+6.2f"%(np.sum(wi.numpy()))) for wi in li.weights]))
layer 0
layer 1 (784, 50) sum +1014.07, (50,) sum +24.43
layer 2 (50, 784) sum -1458.86, (784,) sum -181.90
In this case, we can also get a visual representation of the weights in the same image space as MNIST.
Can you tell if the autoencoder “learnt” something?
TRY: inspect the weights, BEFORE and AFTER training.
def show_img_grid(w):
plt.figure(figsize=(6,6))
for k,wi in enumerate(w):
plt.subplot(10,10,k+1)
plt.imshow(wi.reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
show_img_grid(model.get_layer("encoder").weights[0].numpy().T)
show_img_grid(model.get_layer("decoder").weights[0].numpy())
Custom feeding data and extracting intermediate activations¶
TF offers different ways to feed in and out of specific layers. The tensorflow.keras.backend
offers somewhat more flexiblity.
Observe how we can feed data to our autoencoder and get the activations on the encoder.
layer_input = model.get_layer("input")
layer_encoder = model.get_layer("encoder")
me = Model([layer_input.input], [layer_encoder.output])
me(X_train)
<tf.Tensor: shape=(1200, 50), dtype=float32, numpy=
array([[ 1.4733481 , 5.6071835 , 0.4546271 , ..., 6.584404 ,
0. , 3.4143682 ],
[ 5.7947493 , 6.376433 , 0. , ..., 1.1779828 ,
1.8339571 , 2.2694755 ],
[ 1.7550068 , 4.7390604 , 0.64162546, ..., 8.171952 ,
4.2970653 , 1.2317356 ],
...,
[ 5.9646645 , 6.6686645 , 3.091914 , ..., 1.5258911 ,
2.0375972 , 8.356914 ],
[ 3.3050153 , 4.8892 , 4.8872223 , ..., 2.1351342 ,
4.004214 , 7.943392 ],
[ 5.2594194 , 3.1832466 , 1.4421158 , ..., 4.5179844 ,
12.360394 , 3.8473024 ]], dtype=float32)>
from tensorflow.keras import backend as K
ke = K.function(layer_encoder.input, layer_encoder.output)
ke(X_train)
array([[ 1.4733481 , 5.6071835 , 0.4546271 , ..., 6.584404 ,
0. , 3.4143682 ],
[ 5.7947493 , 6.376433 , 0. , ..., 1.1779828 ,
1.8339571 , 2.2694755 ],
[ 1.7550068 , 4.7390604 , 0.64162546, ..., 8.171952 ,
4.2970653 , 1.2317356 ],
...,
[ 5.9646645 , 6.6686645 , 3.091914 , ..., 1.5258911 ,
2.0375972 , 8.356914 ],
[ 3.3050153 , 4.8892 , 4.8872223 , ..., 2.1351342 ,
4.004214 , 7.943392 ],
[ 5.2594194 , 3.1832466 , 1.4421158 , ..., 4.5179844 ,
12.360394 , 3.8473024 ]], dtype=float32)
2. inspecting data in latent space (the encoder)¶
for one randomly chosen image
img = np.random.permutation(X_test)[:1]
e = me(img).numpy()
e
array([[ 7.409996 , 2.951494 , 6.331457 , 8.699426 , 0. ,
3.6293492, 14.668295 , 2.578187 , 3.3282623, 1.3088968,
5.8035784, 7.909799 , 1.5063348, 5.7516637, 10.001439 ,
2.7947378, 9.866833 , 4.3022175, 3.6016984, 8.251985 ,
5.2355657, 3.9983935, 0. , 5.183774 , 7.8268447,
2.6671238, 6.396924 , 0. , 2.674741 , 7.8847423,
4.667186 , 7.176488 , 1.8782392, 3.4621015, 6.589601 ,
0. , 9.805147 , 9.412526 , 4.40743 , 2.5635386,
7.575318 , 9.788577 , 11.278124 , 7.1031804, 3.389275 ,
3.0128388, 8.713953 , 4.1965656, 13.539381 , 3.0892658]],
dtype=float32)
plt.imshow(img.reshape(28,28), cmap=plt.cm.Greys_r);
plt.plot(e[0])
plt.xlabel("hidden neuron number")
plt.ylabel("activation (ReLU)")
Text(0, 0.5, 'activation (ReLU)')
encoder activations¶
or more comprehensively for a set of images. Observe we sort the images grouping all images of each class together.
Can you see some activation patterns for different classes?
Is there a most active neuron per class
idxs = np.random.permutation(len(X_test))[:200]
idxs = idxs[np.argsort(y_test[idxs])]
y_sample = y_test[idxs]
X_sample = X_test[idxs]
X_sample_encoded = me([X_sample]).numpy()
print("encoded data size", X_sample_encoded.shape)
plt.figure(figsize=(20,4))
plt.imshow(X_sample_encoded.T, cmap=plt.cm.Greys_r, origin="bottom")
plt.colorbar()
plt.ylabel("component")
plt.xlabel("sample class number")
plt.xticks(range(len(y_sample))[::5], y_sample[::5]);
print ("mean activation at encoder %.3f"%np.mean(X_sample_encoded))
encoded data size (200, 50)
mean activation at encoder 6.036
let’s get the average activation of the neurons in the latent space for each class.
Remember however that we trained the network WITHOUT the class information (unsupervised)
e = me(X_test).numpy()
plt.figure(figsize=(20,4))
for i in range(10):
plt.subplot(2,5,i+1)
plt.plot(e[y_test==i].mean(axis=1))
plt.title(f"class {i}")
plt.tight_layout()
observe distribution of activations at the encoder¶
plt.hist(e.flatten(), bins=30);
From this we can inspect the neuron activations in our dataset.
for instance, we can get the average activation of the encoder neurons across all inputs
me(X_train).numpy().mean(axis=0)
array([6.54092 , 6.890245 , 5.0332685, 4.638923 , 4.586272 , 4.872563 ,
4.452017 , 6.6687894, 5.845137 , 9.670084 , 5.5277524, 3.8713033,
6.623263 , 6.4029975, 5.745097 , 6.755461 , 6.059909 , 5.918733 ,
4.8369656, 3.787856 , 5.030886 , 4.2290273, 7.1920123, 6.9971023,
5.206792 , 4.4348135, 4.7578964, 7.8614182, 6.2570157, 8.095148 ,
5.5375223, 5.2380457, 5.7093854, 5.4041505, 3.3272092, 4.686344 ,
6.4694433, 4.4688597, 6.687395 , 7.0459824, 6.1812396, 9.49828 ,
8.421416 , 6.230216 , 4.630983 , 4.014663 , 6.3445034, 5.1579123,
7.8651147, 5.29035 ], dtype=float32)
3. Custom loss, unsupervised .fit(X)
call \(\rightarrow\) MSE¶
given:
\(\mathbf{x}^{(i)} \in \mathbb{R}^{784}\)
\(e(\mathbf{x}^{(i)}) \in \mathbb{R}^{50}\), the encoder
\(d(e(\mathbf{x}^{(i)})) \in \mathbb{R}^{784}\), the decoder
we define the loss function as (MSE):
and implement it by hand, instead of using the prebuilt implementation
from tensorflow.keras import backend as K
from tensorflow.keras.losses import mse
import tensorflow as tf
def get_model_U(input_dim, code_size):
inputs = Input(shape=input_dim, name="input")
encoder = Dense(code_size, activation='relu', name="encoder")(inputs)
outputs = Dense(input_dim, activation='sigmoid', name="output")(encoder)
loss = tf.reduce_mean( (inputs-outputs)**2)
model = Model([inputs], [outputs])
model.add_loss(loss)
model.compile(optimizer='adam')
return model
model = get_model_U(input_dim=X.shape[1], code_size=40)
model.summary()
W1221 08:07:36.892163 4737162752 training_utils.py:1444] Output output missing from loss dictionary. We assume this was done on purpose. The fit and evaluate APIs will not be expecting any data to be passed to output.
Model: "model_32"
__________________________________________________________________________________________________
Layer (type) Output Shape Param # Connected to
==================================================================================================
input (InputLayer) [(None, 784)] 0
__________________________________________________________________________________________________
encoder (Dense) (None, 40) 31400 input[0][0]
__________________________________________________________________________________________________
output (Dense) (None, 784) 32144 encoder[0][0]
__________________________________________________________________________________________________
tf_op_layer_sub_2 (TensorFlowOp [(None, 784)] 0 input[0][0]
output[0][0]
__________________________________________________________________________________________________
tf_op_layer_pow_2 (TensorFlowOp [(None, 784)] 0 tf_op_layer_sub_2[0][0]
__________________________________________________________________________________________________
tf_op_layer_Mean_12 (TensorFlow [()] 0 tf_op_layer_pow_2[0][0]
__________________________________________________________________________________________________
add_loss_2 (AddLoss) () 0 tf_op_layer_Mean_12[0][0]
==================================================================================================
Total params: 63,544
Trainable params: 63,544
Non-trainable params: 0
__________________________________________________________________________________________________
observe .fit
call is now unsupervised (hence, the warning above)
model.fit(X_train, epochs=100, batch_size=32)
Train on 1200 samples
Epoch 1/100
1200/1200 [==============================] - 0s 190us/sample - loss: 0.1415
Epoch 2/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0702
Epoch 3/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0635
Epoch 4/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0572
Epoch 5/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0519
Epoch 6/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0475
Epoch 7/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0442
Epoch 8/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0418
Epoch 9/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0398
Epoch 10/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0381
Epoch 11/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0364
Epoch 12/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0348
Epoch 13/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0334
Epoch 14/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0321
Epoch 15/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0309
Epoch 16/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0297
Epoch 17/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0285
Epoch 18/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0275
Epoch 19/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0267
Epoch 20/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0257
Epoch 21/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0250
Epoch 22/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0242
Epoch 23/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0234
Epoch 24/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0227
Epoch 25/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0221
Epoch 26/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0214
Epoch 27/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0207
Epoch 28/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0202
Epoch 29/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0196
Epoch 30/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0191
Epoch 31/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0186
Epoch 32/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0180
Epoch 33/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0176
Epoch 34/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0172
Epoch 35/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0168
Epoch 36/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0163
Epoch 37/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0160
Epoch 38/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0156
Epoch 39/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0153
Epoch 40/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0150
Epoch 41/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0146
Epoch 42/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0144
Epoch 43/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0140
Epoch 44/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0138
Epoch 45/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0135
Epoch 46/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0133
Epoch 47/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0130
Epoch 48/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0128
Epoch 49/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0126
Epoch 50/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0124
Epoch 51/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0122
Epoch 52/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0120
Epoch 53/100
1200/1200 [==============================] - 0s 58us/sample - loss: 0.0118
Epoch 54/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0116
Epoch 55/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0114
Epoch 56/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0113
Epoch 57/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0111
Epoch 58/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0110
Epoch 59/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0108
Epoch 60/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0107
Epoch 61/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0105
Epoch 62/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0104
Epoch 63/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0103
Epoch 64/100
1200/1200 [==============================] - 0s 46us/sample - loss: 0.0102
Epoch 65/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0100
Epoch 66/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0099
Epoch 67/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0098
Epoch 68/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0097
Epoch 69/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0096
Epoch 70/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0095
Epoch 71/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0094
Epoch 72/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0093
Epoch 73/100
1200/1200 [==============================] - 0s 45us/sample - loss: 0.0093
Epoch 74/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0092
Epoch 75/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0091
Epoch 76/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0090
Epoch 77/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0089
Epoch 78/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0089
Epoch 79/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0088
Epoch 80/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0087
Epoch 81/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0086
Epoch 82/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0086
Epoch 83/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0085
Epoch 84/100
1200/1200 [==============================] - 0s 45us/sample - loss: 0.0085
Epoch 85/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0084
Epoch 86/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0084
Epoch 87/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0083
Epoch 88/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0082
Epoch 89/100
1200/1200 [==============================] - 0s 47us/sample - loss: 0.0082
Epoch 90/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0082
Epoch 91/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0081
Epoch 92/100
1200/1200 [==============================] - 0s 47us/sample - loss: 0.0080
Epoch 93/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0080
Epoch 94/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0079
Epoch 95/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0079
Epoch 96/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0079
Epoch 97/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0078
Epoch 98/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0078
Epoch 99/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0078
Epoch 100/100
1200/1200 [==============================] - 0s 36us/sample - loss: 0.0077
<tensorflow.python.keras.callbacks.History at 0x7fdefadc1ba8>
X_sample = np.random.permutation(X_test)[:10]
X_pred = model.predict(X_sample)
plt.figure(figsize=(20,5))
for i in range(len(X_sample)):
plt.subplot(2,len(X_sample),i+1)
plt.imshow(X_sample[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
plt.subplot(2,len(X_sample),len(X_sample)+i+1)
plt.imshow(X_pred[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
4. Autoencoder for image denoising¶
observe reconstruction when fed with noisy data
def add_noise(x, noise_level=.2):
return x + np.random.normal(size=x.shape)*noise_level
X_sample = np.random.permutation(X_test)[:10]
X_pred = model.predict(X_sample)
X_sample_noisy = add_noise(X_sample)
X_pred_noisy = model.predict(X_sample_noisy)
plt.figure(figsize=(20,5))
for i in range(len(X_sample_noisy)):
plt.subplot(2,len(X_sample_noisy),i+1)
plt.imshow(X_sample_noisy[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
plt.subplot(2,len(X_sample_noisy),len(X_sample_noisy)+i+1)
plt.imshow(X_pred_noisy[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
in a more real scenario we only have noisy data to train the model¶
n_model = get_model(input_dim=X.shape[1], code_size=40)
X_train_noisy = add_noise(X_train)
n_model.fit(X_train_noisy, X_train_noisy, epochs=100, batch_size=32)
Train on 1200 samples
Epoch 1/100
1200/1200 [==============================] - 0s 199us/sample - loss: 0.1847
Epoch 2/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.1102
Epoch 3/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.1042
Epoch 4/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0972
Epoch 5/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0917
Epoch 6/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0872
Epoch 7/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0836
Epoch 8/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0808
Epoch 9/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0786
Epoch 10/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0766
Epoch 11/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0747
Epoch 12/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0730
Epoch 13/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0714
Epoch 14/100
1200/1200 [==============================] - 0s 46us/sample - loss: 0.0698
Epoch 15/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0684
Epoch 16/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0671
Epoch 17/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0659
Epoch 18/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0648
Epoch 19/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0637
Epoch 20/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0627
Epoch 21/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0618
Epoch 22/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0610
Epoch 23/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0602
Epoch 24/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0595
Epoch 25/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0589
Epoch 26/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0582
Epoch 27/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0576
Epoch 28/100
1200/1200 [==============================] - 0s 54us/sample - loss: 0.0570
Epoch 29/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0565
Epoch 30/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0560
Epoch 31/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0555
Epoch 32/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0550
Epoch 33/100
1200/1200 [==============================] - 0s 55us/sample - loss: 0.0546
Epoch 34/100
1200/1200 [==============================] - 0s 52us/sample - loss: 0.0542
Epoch 35/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0538
Epoch 36/100
1200/1200 [==============================] - 0s 57us/sample - loss: 0.0533
Epoch 37/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0530
Epoch 38/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0527
Epoch 39/100
1200/1200 [==============================] - 0s 36us/sample - loss: 0.0523
Epoch 40/100
1200/1200 [==============================] - 0s 35us/sample - loss: 0.0520
Epoch 41/100
1200/1200 [==============================] - 0s 35us/sample - loss: 0.0517
Epoch 42/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0514
Epoch 43/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0512
Epoch 44/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0509
Epoch 45/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0506
Epoch 46/100
1200/1200 [==============================] - 0s 50us/sample - loss: 0.0504
Epoch 47/100
1200/1200 [==============================] - 0s 62us/sample - loss: 0.0502
Epoch 48/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0499
Epoch 49/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0497
Epoch 50/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0495
Epoch 51/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0493
Epoch 52/100
1200/1200 [==============================] - 0s 46us/sample - loss: 0.0492
Epoch 53/100
1200/1200 [==============================] - 0s 45us/sample - loss: 0.0490
Epoch 54/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0488
Epoch 55/100
1200/1200 [==============================] - 0s 51us/sample - loss: 0.0487
Epoch 56/100
1200/1200 [==============================] - 0s 56us/sample - loss: 0.0485
Epoch 57/100
1200/1200 [==============================] - 0s 48us/sample - loss: 0.0483
Epoch 58/100
1200/1200 [==============================] - 0s 47us/sample - loss: 0.0482
Epoch 59/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0480
Epoch 60/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0478
Epoch 61/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0477
Epoch 62/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0476
Epoch 63/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0475
Epoch 64/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0473
Epoch 65/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0472
Epoch 66/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0471
Epoch 67/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0470
Epoch 68/100
1200/1200 [==============================] - 0s 46us/sample - loss: 0.0469
Epoch 69/100
1200/1200 [==============================] - 0s 45us/sample - loss: 0.0468
Epoch 70/100
1200/1200 [==============================] - 0s 40us/sample - loss: 0.0467
Epoch 71/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0466
Epoch 72/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0465
Epoch 73/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0464
Epoch 74/100
1200/1200 [==============================] - 0s 45us/sample - loss: 0.0463
Epoch 75/100
1200/1200 [==============================] - 0s 49us/sample - loss: 0.0462
Epoch 76/100
1200/1200 [==============================] - 0s 53us/sample - loss: 0.0462
Epoch 77/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0461
Epoch 78/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0460
Epoch 79/100
1200/1200 [==============================] - 0s 42us/sample - loss: 0.0459
Epoch 80/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0458
Epoch 81/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0458
Epoch 82/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0457
Epoch 83/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0456
Epoch 84/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0456
Epoch 85/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0455
Epoch 86/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0454
Epoch 87/100
1200/1200 [==============================] - 0s 44us/sample - loss: 0.0454
Epoch 88/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0453
Epoch 89/100
1200/1200 [==============================] - 0s 43us/sample - loss: 0.0452
Epoch 90/100
1200/1200 [==============================] - 0s 46us/sample - loss: 0.0452
Epoch 91/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0451
Epoch 92/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0450
Epoch 93/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0450
Epoch 94/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0450
Epoch 95/100
1200/1200 [==============================] - 0s 37us/sample - loss: 0.0449
Epoch 96/100
1200/1200 [==============================] - 0s 39us/sample - loss: 0.0448
Epoch 97/100
1200/1200 [==============================] - 0s 41us/sample - loss: 0.0448
Epoch 98/100
1200/1200 [==============================] - 0s 38us/sample - loss: 0.0447
Epoch 99/100
1200/1200 [==============================] - 0s 36us/sample - loss: 0.0447
Epoch 100/100
1200/1200 [==============================] - 0s 36us/sample - loss: 0.0447
<tensorflow.python.keras.callbacks.History at 0x7fdefb0fbb00>
X_sample_noisy = add_noise(X_sample)
X_pred_noisy = n_model.predict(X_sample_noisy)
plt.figure(figsize=(20,5))
for i in range(len(X_sample_noisy)):
plt.subplot(2,len(X_sample_noisy),i+1)
plt.imshow(X_sample_noisy[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")
plt.subplot(2,len(X_sample_noisy),len(X_sample_noisy)+i+1)
plt.imshow(X_pred_noisy[i].reshape(28,28), cmap=plt.cm.Greys_r)
plt.axis("off")