Semana 7 – Aplicación de Autoencoder para la Reconstrucción de Imágenes¶
Autor: Alexander Oviedo Fadul
Programa: Especialización en Inteligencia Artificial y Deep Learning – UNIMINUTO
Asignatura: NRC-198 Deep Learning
Profesor: Juan Carlos Valencia
Fecha: 27 de abril de 2026
Objetivo¶
Implementar un autoencoder para reconstrucción de imágenes utilizando Keras y TensorFlow, respondiendo a las preguntas orientadoras:
- ¿Cómo trabaja un autoencoder?
- ¿Cómo se utiliza un autoencoder para la reconstrucción de imágenes con Keras y TensorFlow?
Pregunta 1: ¿Cómo trabaja un autoencoder?¶
Un autoencoder es una red neuronal de aprendizaje no supervisado compuesta por tres bloques:
| Componente | Función | Activación típica |
|---|---|---|
| Encoder (Codificador) | Comprime la entrada a una representación de menor dimensión | ReLU |
| Bottleneck (Espacio latente) | Representación comprimida que captura la esencia de los datos | — |
| Decoder (Decodificador) | Reconstruye la salida a partir de la representación comprimida | Sigmoid |
Principio de funcionamiento¶
- La red se entrena para que la salida sea lo más parecida posible a la entrada.
- La función de pérdida mide la discrepancia entre entrada (x) y reconstrucción (x̂).
- Al comprimir y descomprimir, la red aprende a retener solo la información más relevante.
- Es un método no supervisado: no requiere etiquetas, los propios datos son el objetivo.
Aplicaciones¶
- Reducción de dimensionalidad
- Eliminación de ruido (denoising)
- Detección de anomalías
- Generación de datos sintéticos
- Compresión de datos
Referencia: Bonaccorso, G. (2018). Mastering Machine Learning Algorithms. Packt Publishing.
Pregunta 2: ¿Cómo se utiliza un autoencoder para la reconstrucción de imágenes con Keras y TensorFlow?¶
A continuación se implementa paso a paso un autoencoder con el dataset MNIST.
In [1]:
# 0. Instalación / Imports
import numpy as np
import matplotlib.pyplot as plt
import keras
from keras.datasets import mnist
from tensorflow.keras import layers, models
print('Entorno listo ✅')
Entorno listo ✅
In [2]:
# 1. Cargar y preparar datos para autoencoder denso
(x_train, _), (x_test, _) = mnist.load_data()
# Normalizar [0, 1] y aplanar a vectores de 784
x_train = x_train.astype('float32') / 255.
x_test = x_test.astype('float32') / 255.
x_train = x_train.reshape((len(x_train), np.prod(x_train.shape[1:])))
x_test = x_test.reshape((len(x_test), np.prod(x_test.shape[1:])))
print(f'Train shape: {x_train.shape}')
print(f'Test shape: {x_test.shape}')
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/mnist.npz 11490434/11490434 ━━━━━━━━━━━━━━━━━━━━ 0s 0us/step Train shape: (60000, 784) Test shape: (10000, 784)
In [3]:
# 2. Construir el autoencoder denso
entrada = keras.Input(shape=(784,))
codificacion = layers.Dense(32, activation='relu')(entrada)
salida = layers.Dense(784, activation='sigmoid')(codificacion)
autoencoder = keras.Model(entrada, salida)
codificador = keras.Model(entrada, codificacion)
entrada_codifi = keras.Input(shape=(32,))
capa_descod = autoencoder.layers[-1]
descodificador = keras.Model(entrada_codifi, capa_descod(entrada_codifi))
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
autoencoder.summary()
Model: "functional"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ input_layer (InputLayer) │ (None, 784) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense (Dense) │ (None, 32) │ 25,120 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_1 (Dense) │ (None, 784) │ 25,872 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 50,992 (199.19 KB)
Trainable params: 50,992 (199.19 KB)
Non-trainable params: 0 (0.00 B)
In [4]:
# 3. Entrenar el autoencoder denso (base)
history_dense = autoencoder.fit(
x_train, x_train,
epochs=10,
batch_size=256,
shuffle=True,
validation_data=(x_test, x_test)
)
Epoch 1/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 4s 9ms/step - loss: 0.2787 - val_loss: 0.1896 Epoch 2/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1698 - val_loss: 0.1528 Epoch 3/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1439 - val_loss: 0.1342 Epoch 4/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1294 - val_loss: 0.1228 Epoch 5/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1199 - val_loss: 0.1149 Epoch 6/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1131 - val_loss: 0.1090 Epoch 7/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1077 - val_loss: 0.1042 Epoch 8/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1033 - val_loss: 0.1003 Epoch 9/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.1001 - val_loss: 0.0978 Epoch 10/10 235/235 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.0979 - val_loss: 0.0958
In [5]:
# 4. Visualizar resultados del autoencoder denso
encoded_imgs = codificador.predict(x_test)
decoded_imgs = descodificador.predict(encoded_imgs)
n = 5 # Modificado según instrucciones (original: 4)
plt.figure(figsize=(20, 6))
for i in range(n):
# Originales
ax = plt.subplot(3, n, i + 1)
plt.imshow(x_test[i].reshape(28, 28), cmap='gray')
plt.title('Original')
ax.axis('off')
# Codificación
ax = plt.subplot(3, n, i + 1 + n)
plt.imshow(encoded_imgs[i].reshape(8, 4).T, cmap='gray')
plt.title('Codificado')
ax.axis('off')
# Reconstruidas
ax = plt.subplot(3, n, i + 1 + n * 2)
plt.imshow(decoded_imgs[i].reshape(28, 28), cmap='gray')
plt.title('Reconstruido')
ax.axis('off')
plt.suptitle('Autoencoder Denso – Original vs Codificado vs Reconstruido', fontsize=14)
plt.tight_layout()
plt.show()
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step 313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step
Modificaciones solicitadas en la actividad¶
A continuación se aplican todas las variaciones requeridas:
- Cambiar
na 5 ✅ (ya realizado arriba) - Modificar optimizador (SGD con lr=0.001)
- Modificar epochs y batch_size
- Agregar capa oculta con 256 neuronas
- Aplicar Dropout = 0.2
- Modificar loss (usar
mean_squared_error) - Imprimir
model.summary() - Guardar modelo y pesos
In [6]:
# 5. Autoencoder Denso MODIFICADO
from tensorflow.keras.optimizers import SGD
entrada_m = keras.Input(shape=(784,))
# Encoder con capa oculta adicional de 256 + Dropout
x = layers.Dense(256, activation='relu')(entrada_m)
x = layers.Dropout(0.2)(x) # Dropout 20%
codificacion_m = layers.Dense(32, activation='relu')(x)
# Decoder con capa oculta adicional de 256
x = layers.Dense(256, activation='relu')(codificacion_m)
x = layers.Dropout(0.2)(x)
salida_m = layers.Dense(784, activation='sigmoid')(x)
autoencoder_mod = keras.Model(entrada_m, salida_m)
# Optimizador SGD con lr=0.001
opt_sgd = SGD(learning_rate=0.001)
# Función de pérdida diferente: mean_squared_error
autoencoder_mod.compile(optimizer=opt_sgd, loss='mean_squared_error')
print('\n=== Modelo Modificado ===')
print(autoencoder_mod.summary())
=== Modelo Modificado ===
Model: "functional_3"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ input_layer_2 (InputLayer) │ (None, 784) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_2 (Dense) │ (None, 256) │ 200,960 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout (Dropout) │ (None, 256) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_3 (Dense) │ (None, 32) │ 8,224 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_4 (Dense) │ (None, 256) │ 8,448 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dropout_1 (Dropout) │ (None, 256) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ dense_5 (Dense) │ (None, 784) │ 201,488 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 419,120 (1.60 MB)
Trainable params: 419,120 (1.60 MB)
Non-trainable params: 0 (0.00 B)
None
In [7]:
# 6. Entrenar modelo modificado (epochs=10, batch_size=200)
history_mod = autoencoder_mod.fit(
x_train, x_train,
epochs=10,
batch_size=200,
shuffle=True,
validation_data=(x_test, x_test)
)
Epoch 1/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 3s 4ms/step - loss: 0.2316 - val_loss: 0.2316 Epoch 2/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2316 - val_loss: 0.2315 Epoch 3/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2315 - val_loss: 0.2314 Epoch 4/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2314 - val_loss: 0.2314 Epoch 5/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2314 - val_loss: 0.2313 Epoch 6/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2313 - val_loss: 0.2312 Epoch 7/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step - loss: 0.2312 - val_loss: 0.2312 Epoch 8/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - loss: 0.2312 - val_loss: 0.2311 Epoch 9/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 1s 4ms/step - loss: 0.2311 - val_loss: 0.2310 Epoch 10/10 300/300 ━━━━━━━━━━━━━━━━━━━━ 2s 3ms/step - loss: 0.2310 - val_loss: 0.2310
In [8]:
# 7. Guardar modelo y pesos
autoencoder_mod.save('modeloinicial.keras')
autoencoder_mod.save_weights('model_pesos.weights.h5')
print('Modelo y pesos guardados ✅')
Modelo y pesos guardados ✅
In [9]:
# 8. Visualizar resultados del modelo modificado
decoded_mod = autoencoder_mod.predict(x_test)
n = 5
plt.figure(figsize=(20, 4))
for i in range(n):
ax = plt.subplot(2, n, i + 1)
plt.imshow(x_test[i].reshape(28, 28), cmap='gray')
plt.title('Original')
ax.axis('off')
ax = plt.subplot(2, n, i + 1 + n)
plt.imshow(decoded_mod[i].reshape(28, 28), cmap='gray')
plt.title('Reconstruido')
ax.axis('off')
plt.suptitle('Autoencoder Modificado (SGD + Dropout + MSE) – n=5', fontsize=14)
plt.tight_layout()
plt.show()
313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step
Parte B – Autoencoder Convolucional para Eliminación de Ruido¶
Basado en el ejemplo de referencia de Keras (Valdarrama, 2021).
In [10]:
# 9. Preparar datos para autoencoder convolucional
from keras.datasets import mnist
from keras.models import Model
def preprocess(array):
"""Normaliza y redimensiona."""
array = array.astype('float32') / 255.0
array = np.reshape(array, (len(array), 28, 28, 1))
return array
def noise(array, noise_factor=0.4):
"""Añade ruido gaussiano."""
noisy = array + noise_factor * np.random.normal(loc=0.0, scale=1.0, size=array.shape)
return np.clip(noisy, 0.0, 1.0)
def display(array1, array2, title1='', title2='', n=10):
"""Muestra n imágenes aleatorias de dos arreglos."""
indices = np.random.randint(len(array1), size=n)
images1 = array1[indices, :]
images2 = array2[indices, :]
plt.figure(figsize=(20, 4))
for i, (img1, img2) in enumerate(zip(images1, images2)):
ax = plt.subplot(2, n, i + 1)
plt.imshow(img1.reshape(28, 28), cmap='gray')
if i == 0: plt.ylabel(title1)
ax.axis('off')
ax = plt.subplot(2, n, i + 1 + n)
plt.imshow(img2.reshape(28, 28), cmap='gray')
if i == 0: plt.ylabel(title2)
ax.axis('off')
plt.tight_layout()
plt.show()
(train_data, _), (test_data, _) = mnist.load_data()
train_data = preprocess(train_data)
test_data = preprocess(test_data)
noisy_train = noise(train_data)
noisy_test = noise(test_data)
display(train_data, noisy_train, title1='Original', title2='Ruidosa')
In [11]:
# 10. Construir autoencoder convolucional
inp = layers.Input(shape=(28, 28, 1))
# Encoder
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(inp)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
x = layers.Conv2D(32, (3, 3), activation='relu', padding='same')(x)
x = layers.MaxPooling2D((2, 2), padding='same')(x)
# Decoder
x = layers.Conv2DTranspose(32, (3, 3), strides=2, activation='relu', padding='same')(x)
x = layers.Conv2DTranspose(32, (3, 3), strides=2, activation='relu', padding='same')(x)
x = layers.Conv2D(1, (3, 3), activation='sigmoid', padding='same')(x)
conv_autoencoder = Model(inp, x)
conv_autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
conv_autoencoder.summary()
Model: "functional_4"
┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┓ ┃ Layer (type) ┃ Output Shape ┃ Param # ┃ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━┩ │ input_layer_3 (InputLayer) │ (None, 28, 28, 1) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d (Conv2D) │ (None, 28, 28, 32) │ 320 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d (MaxPooling2D) │ (None, 14, 14, 32) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_1 (Conv2D) │ (None, 14, 14, 32) │ 9,248 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ max_pooling2d_1 (MaxPooling2D) │ (None, 7, 7, 32) │ 0 │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_transpose │ (None, 14, 14, 32) │ 9,248 │ │ (Conv2DTranspose) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_transpose_1 │ (None, 28, 28, 32) │ 9,248 │ │ (Conv2DTranspose) │ │ │ ├─────────────────────────────────┼────────────────────────┼───────────────┤ │ conv2d_2 (Conv2D) │ (None, 28, 28, 1) │ 289 │ └─────────────────────────────────┴────────────────────────┴───────────────┘
Total params: 28,353 (110.75 KB)
Trainable params: 28,353 (110.75 KB)
Non-trainable params: 0 (0.00 B)
In [12]:
# 11. Entrenamiento fase 1: reconstrucción limpia (50 épocas)
conv_autoencoder.fit(
x=train_data, y=train_data,
epochs=50,
batch_size=128,
shuffle=True,
validation_data=(test_data, test_data)
)
predictions_clean = conv_autoencoder.predict(test_data)
display(test_data, predictions_clean, title1='Original', title2='Reconstruido')
Epoch 1/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 10s 13ms/step - loss: 0.1340 - val_loss: 0.0720 Epoch 2/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0706 - val_loss: 0.0687 Epoch 3/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0685 - val_loss: 0.0675 Epoch 4/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0675 - val_loss: 0.0666 Epoch 5/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0668 - val_loss: 0.0661 Epoch 6/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0662 - val_loss: 0.0655 Epoch 7/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - loss: 0.0658 - val_loss: 0.0652 Epoch 8/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0655 - val_loss: 0.0649 Epoch 9/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0652 - val_loss: 0.0646 Epoch 10/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0649 - val_loss: 0.0644 Epoch 11/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 8ms/step - loss: 0.0647 - val_loss: 0.0642 Epoch 12/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0645 - val_loss: 0.0640 Epoch 13/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0643 - val_loss: 0.0638 Epoch 14/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0641 - val_loss: 0.0636 Epoch 15/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0640 - val_loss: 0.0636 Epoch 16/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0638 - val_loss: 0.0634 Epoch 17/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0637 - val_loss: 0.0633 Epoch 18/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0636 - val_loss: 0.0632 Epoch 19/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0635 - val_loss: 0.0631 Epoch 20/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0634 - val_loss: 0.0630 Epoch 21/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0633 - val_loss: 0.0629 Epoch 22/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0632 - val_loss: 0.0629 Epoch 23/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0632 - val_loss: 0.0627 Epoch 24/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0631 - val_loss: 0.0628 Epoch 25/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0630 - val_loss: 0.0627 Epoch 26/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0630 - val_loss: 0.0626 Epoch 27/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0629 - val_loss: 0.0625 Epoch 28/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0629 - val_loss: 0.0625 Epoch 29/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0628 - val_loss: 0.0625 Epoch 30/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 8ms/step - loss: 0.0628 - val_loss: 0.0624 Epoch 31/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0627 - val_loss: 0.0624 Epoch 32/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0627 - val_loss: 0.0624 Epoch 33/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0627 - val_loss: 0.0624 Epoch 34/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0626 - val_loss: 0.0623 Epoch 35/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0626 - val_loss: 0.0623 Epoch 36/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0626 - val_loss: 0.0623 Epoch 37/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0625 - val_loss: 0.0622 Epoch 38/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0625 - val_loss: 0.0622 Epoch 39/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0625 - val_loss: 0.0622 Epoch 40/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0625 - val_loss: 0.0621 Epoch 41/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - loss: 0.0624 - val_loss: 0.0621 Epoch 42/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0624 - val_loss: 0.0621 Epoch 43/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0624 - val_loss: 0.0620 Epoch 44/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0624 - val_loss: 0.0620 Epoch 45/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0621 Epoch 46/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0621 Epoch 47/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0620 Epoch 48/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0619 Epoch 49/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0619 Epoch 50/50 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0623 - val_loss: 0.0619 313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 3ms/step
In [13]:
# 12. Entrenamiento fase 2: eliminación de ruido (100 épocas)
conv_autoencoder.fit(
x=noisy_train, y=train_data,
epochs=100,
batch_size=128,
shuffle=True,
validation_data=(noisy_test, test_data)
)
predictions_denoised = conv_autoencoder.predict(noisy_test)
display(noisy_test, predictions_denoised, title1='Con Ruido', title2='Limpiado por AE')
Epoch 1/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 8ms/step - loss: 0.1022 - val_loss: 0.0944 Epoch 2/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0938 - val_loss: 0.0920 Epoch 3/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0921 - val_loss: 0.0907 Epoch 4/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0911 - val_loss: 0.0899 Epoch 5/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0902 - val_loss: 0.0894 Epoch 6/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0897 - val_loss: 0.0888 Epoch 7/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0892 - val_loss: 0.0883 Epoch 8/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0887 - val_loss: 0.0883 Epoch 9/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - loss: 0.0883 - val_loss: 0.0876 Epoch 10/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0880 - val_loss: 0.0874 Epoch 11/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0877 - val_loss: 0.0876 Epoch 12/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0874 - val_loss: 0.0868 Epoch 13/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0872 - val_loss: 0.0866 Epoch 14/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0870 - val_loss: 0.0863 Epoch 15/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0869 - val_loss: 0.0862 Epoch 16/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0867 - val_loss: 0.0860 Epoch 17/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0866 - val_loss: 0.0862 Epoch 18/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0865 - val_loss: 0.0860 Epoch 19/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0864 - val_loss: 0.0858 Epoch 20/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 8ms/step - loss: 0.0863 - val_loss: 0.0857 Epoch 21/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0862 - val_loss: 0.0857 Epoch 22/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0861 - val_loss: 0.0855 Epoch 23/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0860 - val_loss: 0.0855 Epoch 24/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0859 - val_loss: 0.0855 Epoch 25/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0859 - val_loss: 0.0854 Epoch 26/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0858 - val_loss: 0.0853 Epoch 27/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0857 - val_loss: 0.0854 Epoch 28/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0857 - val_loss: 0.0855 Epoch 29/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0856 - val_loss: 0.0851 Epoch 30/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0856 - val_loss: 0.0854 Epoch 31/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 8ms/step - loss: 0.0855 - val_loss: 0.0850 Epoch 32/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0854 - val_loss: 0.0852 Epoch 33/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0854 - val_loss: 0.0850 Epoch 34/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0854 - val_loss: 0.0849 Epoch 35/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0853 - val_loss: 0.0849 Epoch 36/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0853 - val_loss: 0.0850 Epoch 37/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0852 - val_loss: 0.0850 Epoch 38/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0852 - val_loss: 0.0849 Epoch 39/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - loss: 0.0852 - val_loss: 0.0847 Epoch 40/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0852 - val_loss: 0.0848 Epoch 41/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0851 - val_loss: 0.0848 Epoch 42/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0851 - val_loss: 0.0847 Epoch 43/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0850 - val_loss: 0.0848 Epoch 44/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0850 - val_loss: 0.0846 Epoch 45/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0850 - val_loss: 0.0847 Epoch 46/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0850 - val_loss: 0.0846 Epoch 47/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0849 - val_loss: 0.0846 Epoch 48/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0849 - val_loss: 0.0848 Epoch 49/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0849 - val_loss: 0.0847 Epoch 50/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0849 - val_loss: 0.0846 Epoch 51/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0849 - val_loss: 0.0845 Epoch 52/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0848 - val_loss: 0.0845 Epoch 53/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0848 - val_loss: 0.0844 Epoch 54/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0848 - val_loss: 0.0844 Epoch 55/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0848 - val_loss: 0.0845 Epoch 56/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0848 - val_loss: 0.0845 Epoch 57/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0844 Epoch 58/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0844 Epoch 59/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0845 Epoch 60/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0844 Epoch 61/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0843 Epoch 62/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0844 Epoch 63/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0847 - val_loss: 0.0843 Epoch 64/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0844 Epoch 65/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 66/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 67/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 68/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 69/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 70/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0846 - val_loss: 0.0843 Epoch 71/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0845 Epoch 72/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0843 Epoch 73/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0843 Epoch 74/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0844 Epoch 75/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0842 Epoch 76/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0842 Epoch 77/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 78/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0842 Epoch 79/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0843 Epoch 80/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0845 - val_loss: 0.0842 Epoch 81/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 4s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 82/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 83/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 84/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 5s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 85/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 86/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0844 - val_loss: 0.0842 Epoch 87/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0841 Epoch 88/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0842 Epoch 89/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0842 Epoch 90/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0842 Epoch 91/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0842 Epoch 92/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0841 Epoch 93/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0841 Epoch 94/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0840 Epoch 95/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0841 Epoch 96/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0842 Epoch 97/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0843 - val_loss: 0.0841 Epoch 98/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0842 - val_loss: 0.0841 Epoch 99/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0842 - val_loss: 0.0841 Epoch 100/100 469/469 ━━━━━━━━━━━━━━━━━━━━ 3s 7ms/step - loss: 0.0842 - val_loss: 0.0841 313/313 ━━━━━━━━━━━━━━━━━━━━ 1s 2ms/step
Conclusiones¶
- Los autoencoders aprenden representaciones comprimidas de forma no supervisada, lo que los hace ideales cuando no se dispone de datos etiquetados.
- La combinación encoder-bottleneck-decoder con funciones de activación adecuadas (ReLU + Sigmoid) permite reconstruir imágenes con alta fidelidad.
- El autoencoder convolucional supera al denso en tareas de reconstrucción de imágenes, ya que preserva la estructura espacial bidimensional.
- La eliminación de ruido (denoising) demuestra que el autoencoder no memoriza los datos, sino que aprende la distribución subyacente.
- Desde la perspectiva profesional, estas técnicas tienen aplicación directa en la restauración de documentos escaneados deteriorados, la compresión eficiente de expedientes digitales y la detección de anomalías en flujos documentales del sector judicial.
Referencias¶
- Bonaccorso, G. (2018). Mastering Machine Learning Algorithms. Packt Publishing.
- Fandango, A. (2018). Mastering TensorFlow 1.x. Packt Publishing.
- Valdarrama, S. L. (2021). Convolutional autoencoder for image denoising. Keras. https://keras.io/examples/vision/autoencoder/
- Valencia, J. C. (2026). Semana 7. Aplicación de autoencoder para la reconstrucción de imágenes [Transcripción y Recursos del Curso]. UNIMINUTO.