tutoriales.com

Introducción al Reconocimiento de Imágenes con Redes Neuronales Convolucionales (CNN) en Keras

Este tutorial te guiará paso a paso a través de los fundamentos del reconocimiento de imágenes utilizando Redes Neuronales Convolucionales (CNNs). Aprenderás a construir un modelo simple con Keras y TensorFlow, entrenarlo con un dataset de imágenes y evaluar su rendimiento. Es ideal para aquellos que se inician en el Deep Learning aplicado a la visión por computadora.

Principiante20 min de lectura16 views17 de marzo de 2026Reportar error

¡Hola, entusiastas del Machine Learning! 👋 Hoy nos sumergimos en el fascinante mundo del reconocimiento de imágenes, una de las aplicaciones más impactantes del Deep Learning. En particular, exploraremos las Redes Neuronales Convolucionales (CNNs), la columna vertebral de casi todos los avances modernos en visión por computadora.

🚀 ¿Qué es el Reconocimiento de Imágenes y por qué CNNs?

El reconocimiento de imágenes es la tarea de identificar y clasificar objetos o patrones dentro de una imagen. Desde detectar cáncer en radiografías hasta el desbloqueo facial en tu teléfono, esta tecnología está por todas partes. Pero, ¿cómo 'ven' las computadoras?

Las imágenes son, para una computadora, matrices de números (píxeles). Una imagen en escala de grises es una matriz 2D, mientras que una imagen a color (RGB) es una matriz 3D. Entrenar redes neuronales tradicionales (MLPs) con estos datos es un desafío inmenso debido a la gran cantidad de parámetros y la dificultad para capturar relaciones espaciales locales. Aquí es donde brillan las CNNs.

💡 Consejo: Piensa en las CNNs como si tuvieran 'ojos' especializados que pueden identificar características locales (bordes, texturas) y luego combinarlas para reconocer patrones más complejos (formas, objetos).

Las CNNs están diseñadas para procesar datos con una topología conocida, como imágenes. Utilizan tres ideas principales:

  1. Capas Convolucionales: Detectan características locales aplicando filtros pequeños a través de la imagen.
  2. Pooling (Submuestreo): Reduce la dimensionalidad de las características, haciendo el modelo más robusto a pequeñas variaciones.
  3. Peso Compartido: Un mismo filtro se aplica en toda la imagen, lo que reduce drásticamente el número de parámetros y permite que el modelo aprenda jerarquías de características.

🛠️ Entorno de Desarrollo y Librerías Necesarias

Antes de empezar a programar, necesitamos configurar nuestro entorno. Usaremos Python, Keras (una API de alto nivel para construir y entrenar modelos de Deep Learning) y TensorFlow (su backend).

🐍 Instalación de Python y Librerías

Si no tienes Python, puedes descargarlo de python.org. Se recomienda usar un entorno virtual para tus proyectos.

# Crear un entorno virtual (opcional pero recomendado)
python -m venv cnn_env
source cnn_env/bin/activate  # En Linux/macOS
cnn_env\Scripts\activate   # En Windows

# Instalar librerías
pip install tensorflow keras matplotlib numpy scikit-learn

Verifica las versiones:

import tensorflow as tf
import keras
print(f"TensorFlow Version: {tf.__version__}")
print(f"Keras Version: {keras.__version__}")

📊 El Dataset: Fashion MNIST

Para este tutorial, utilizaremos el dataset Fashion MNIST. Es un excelente reemplazo para el clásico MNIST (dígitos escritos a mano) porque es un poco más desafiante y más representativo de problemas del mundo real. Contiene 70,000 imágenes en escala de grises de artículos de moda (ropa, bolsos, zapatos) en 10 categorías, de 28x28 píxeles cada una.

ClaseDescripción
0Camiseta/top
1Pantalón
2Suéter
3Vestido
4Abrigo
5Sandalia
6Camisa
7Zapatilla
8Bolso
9Bota de tobillo
🔥 Importante: La elección de un dataset adecuado es crucial para cualquier proyecto de Machine Learning. Fashion MNIST es ideal para empezar por su tamaño manejable y su naturaleza de clasificación.

Cargaremos el dataset directamente desde Keras:

import tensorflow as tf
from tensorflow import keras
import numpy as np
import matplotlib.pyplot as plt

# Cargar el dataset Fashion MNIST
(train_images, train_labels), (test_images, test_labels) = keras.datasets.fashion_mnist.load_data()

# Nombres de las clases para visualización
class_names = ['T-shirt/top', 'Trouser', 'Pullover', 'Dress', 'Coat',
               'Sandal', 'Shirt', 'Sneaker', 'Bag', 'Ankle boot']

print(f"Dimensiones de las imágenes de entrenamiento: {train_images.shape}") # (60000, 28, 28)
print(f"Dimensiones de las etiquetas de entrenamiento: {train_labels.shape}") # (60000,)
print(f"Número de imágenes de test: {len(test_images)}") # 10000

✨ Preprocesamiento de Datos

Las imágenes están en escala de grises, con valores de píxel entre 0 y 255. Es una buena práctica escalar estos valores a un rango de 0 a 1 para ayudar a la red neuronal a aprender de manera más eficiente.

Además, las CNNs esperan un formato de entrada con un canal (para imágenes en escala de grises) o tres canales (para RGB). Actualmente, nuestras imágenes tienen la forma (num_imagenes, alto, ancho). Necesitamos agregar una dimensión para el canal, convirtiéndolas a (num_imagenes, alto, ancho, 1).

# Escalar los valores de los píxeles al rango [0, 1]
train_images = train_images / 255.0
test_images = test_images / 255.0

# Remodelar las imágenes para que tengan un canal (CNNs lo esperan)
train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))

print(f"Dimensiones de las imágenes de entrenamiento después de preprocesar: {train_images.shape}")
print(f"Dimensiones de las imágenes de test después de preprocesar: {test_images.shape}")
Visualizando el Dataset Es una buena práctica visualizar algunas imágenes para asegurarnos de que todo está correcto.
plt.figure(figsize=(10,10))
for i in range(25):
    plt.subplot(5,5,i+1)
    plt.xticks([])
    plt.yticks([])
    plt.grid(False)
    plt.imshow(train_images[i].reshape(28,28), cmap=plt.cm.binary)
    plt.xlabel(class_names[train_labels[i]])
plt.show()

🏗️ Construyendo Nuestra Primera CNN con Keras

Ahora viene la parte emocionante: ¡diseñar la arquitectura de nuestra CNN! Una CNN típica para clasificación de imágenes consiste en una secuencia de capas convolucionales y de pooling, seguidas de capas densas (fully connected) para la clasificación final.

🧠 Arquitectura del Modelo

Usaremos una arquitectura sencilla para empezar:

  1. Capa Convolucional (Conv2D): Aprende 32 filtros de 3x3. activation='relu' es una función de activación común. input_shape solo se necesita en la primera capa para especificar las dimensiones de entrada (28x28 píxeles, 1 canal).
  2. Capa de Pooling (MaxPooling2D): Reduce las dimensiones espaciales en 2x2. Esto ayuda a reducir la cantidad de parámetros y a extraer las características más importantes.
  3. Capa Convolucional (Conv2D): Otra capa convolucional, esta vez con 64 filtros.
  4. Capa de Pooling (MaxPooling2D): Otro pooling.
  5. Capa Flatten: Convierte la salida 3D de las capas convolucionales/pooling en un vector 1D, preparándolo para las capas densas.
  6. Capa Densa (Dense): Una capa de red neuronal tradicional con 128 neuronas y activación ReLU.
  7. Capa de Salida (Dense): Capa final con 10 neuronas (una por cada clase) y activación softmax. softmax asegura que las salidas sumen 1, interpretándose como probabilidades para cada clase.
Input Layer (28x28x1) Conv2D (32 filtros, 3x3) MaxPooling2D (2x2) Conv2D (64 filtros, 3x3) MaxPooling2D (2x2) Flatten Layer Dense (128 neuronas, ReLU) Output (10 neuronas, Softmax)
model = keras.Sequential([
    keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Flatten(),
    keras.layers.Dense(128, activation='relu'),
    keras.layers.Dense(10, activation='softmax') # 10 clases de Fashion MNIST
])

model.summary()

La función model.summary() es increíblemente útil para entender la arquitectura de tu red, el número de parámetros en cada capa y el tamaño de salida.

⚙️ Compilando el Modelo

Antes de entrenar, necesitamos configurar el proceso de aprendizaje del modelo. Esto se hace en el paso de compilación:

  • Optimizador (optimizer='adam'): Algoritmo que ajusta los pesos de la red para minimizar la función de pérdida. Adam es una elección popular y robusta.
  • Función de pérdida (loss='sparse_categorical_crossentropy'): Mide qué tan bien el modelo está funcionando. Para problemas de clasificación multiclase donde las etiquetas son enteros (0, 1, 2, ...), sparse_categorical_crossentropy es la adecuada.
  • Métricas (metrics=['accuracy']): Se utilizan para monitorear el rendimiento del modelo durante el entrenamiento y la evaluación. La accuracy (precisión) es una métrica común para clasificación.
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

🏋️ Entrenando el Modelo

Con el modelo compilado, ¡estamos listos para entrenarlo! El proceso de entrenamiento implica iterar sobre el dataset de entrenamiento, ajustando los pesos del modelo para minimizar la función de pérdida.

history = model.fit(train_images, train_labels, epochs=10, validation_split=0.1)
  • epochs=10: El número de veces que el algoritmo recorrerá todo el conjunto de datos de entrenamiento. Más epochs pueden llevar a una mayor precisión, pero también a overfitting.
  • validation_split=0.1: Durante el entrenamiento, el 10% de los datos de entrenamiento se utilizarán como conjunto de validación. Esto nos permite monitorear el rendimiento del modelo en datos no vistos durante el entrenamiento y detectar overfitting temprano.

Durante el entrenamiento, Keras mostrará la pérdida y la precisión tanto para el conjunto de entrenamiento como para el de validación en cada epoch.


📊 Evaluando el Modelo

Una vez que el modelo ha sido entrenado, necesitamos evaluar su rendimiento en el conjunto de datos de prueba (test_images, test_labels) que nunca ha visto antes. Esto nos dará una estimación de cómo se comportará el modelo en datos nuevos y del mundo real.

test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
print(f'\nPrecisión en el conjunto de prueba: {test_acc:.4f}')

Una buena precisión en el conjunto de prueba indica que nuestro modelo ha aprendido a generalizar bien. Si la precisión de entrenamiento es mucho más alta que la de prueba, es una señal de overfitting.

📈 Visualizando el Historial de Entrenamiento

Es útil visualizar cómo la precisión y la pérdida cambiaron durante el entrenamiento. Esto puede ayudar a identificar problemas como overfitting o underfitting.

plt.figure(figsize=(12, 4))

plt.subplot(1, 2, 1)
plt.plot(history.history['accuracy'], label='Precisión de Entrenamiento')
plt.plot(history.history['val_accuracy'], label='Precisión de Validación')
plt.xlabel('Epoch')
plt.ylabel('Precisión')
plt.legend()
plt.title('Precisión de Entrenamiento vs. Validación')

plt.subplot(1, 2, 2)
plt.plot(history.history['loss'], label='Pérdida de Entrenamiento')
plt.plot(history.history['val_loss'], label='Pérdida de Validación')
plt.xlabel('Epoch')
plt.ylabel('Pérdida')
plt.legend()
plt.title('Pérdida de Entrenamiento vs. Validación')

plt.show()

🔮 Realizando Predicciones

Finalmente, usemos nuestro modelo entrenado para hacer predicciones en nuevas imágenes.

predictions = model.predict(test_images)

# La primera predicción
print(f"Predicciones para la primera imagen de prueba: {predictions[0]}")

# La clase predicha con mayor probabilidad
predicted_class = np.argmax(predictions[0])
print(f"Clase predicha para la primera imagen: {class_names[predicted_class]}")
print(f"Clase real para la primera imagen: {class_names[test_labels[0]]}")

Las predictions son un array de arrays, donde cada subarray contiene las probabilidades de que la imagen pertenezca a cada una de las 10 clases. np.argmax() nos da el índice (clase) con la probabilidad más alta.

📌 Nota: Para ver cómo el modelo predice en una imagen individual, asegúrate de que la imagen tenga la forma correcta (añadir una dimensión para el batch). Por ejemplo, si tienes `imagen_simple` de forma `(28, 28, 1)`, deberías usar `model.predict(np.expand_dims(imagen_simple, axis=0))`.

🖼️ Visualizando Predicciones

Podemos crear una función para visualizar la imagen, su etiqueta real y la predicción del modelo, junto con las probabilidades para cada clase.

def plot_image_prediction(i, predictions_array, true_label, img):
    true_label, img = true_label[i], img[i]
    plt.grid(False)
    plt.xticks([])
    plt.yticks([])

    plt.imshow(img.reshape(28,28), cmap=plt.cm.binary)

    predicted_label = np.argmax(predictions_array)
    if predicted_label == true_label:
        color = 'blue'
    else:
        color = 'red'

    plt.xlabel(f"{class_names[predicted_label]} {100*np.max(predictions_array):.2f}% (Real: {class_names[true_label]})",
               color=color)

def plot_value_array(i, predictions_array, true_label):
    true_label = true_label[i]
    plt.grid(False)
    plt.xticks(range(10), class_names, rotation=90)
    plt.yticks([])
    thisplot = plt.bar(range(10), predictions_array, color="#777777")
    plt.ylim([0, 1])
    predicted_label = np.argmax(predictions_array)

    thisplot[predicted_label].set_color('red')
    thisplot[true_label].set_color('blue')

# Elige una imagen para visualizar
i = 0 # Primera imagen de test
plt.figure(figsize=(6,3))
plt.subplot(1,2,1)
plot_image_prediction(i, predictions[i], test_labels, test_images)
plt.subplot(1,2,2)
plot_value_array(i, predictions[i],  test_labels)
plt.show()

# Visualizar varias predicciones
num_rows = 5
num_cols = 3
num_images = num_rows*num_cols
plt.figure(figsize=(2*2*num_cols, 2*num_rows))
for i in range(num_images):
  plt.subplot(num_rows, 2*num_cols, 2*i+1)
  plot_image_prediction(i, predictions[i], test_labels, test_images)
  plt.subplot(num_rows, 2*num_cols, 2*i+2)
  plot_value_array(i, predictions[i], test_labels)
plt.tight_layout()
plt.show()

⏭️ Próximos Pasos y Mejoras Potenciales

¡Felicidades! Has construido y entrenado tu primera CNN para reconocimiento de imágenes. Este es solo el comienzo. Aquí hay algunas ideas para llevar tus conocimientos al siguiente nivel:

  • Aumentación de Datos (Data Augmentation): Técnicas como rotación, zoom, volteo de imágenes pueden ayudar a generar más datos de entrenamiento sintéticos y hacer que tu modelo sea más robusto al overfitting.
  • Transfer Learning: Utilizar modelos preentrenados en datasets masivos (como ImageNet) y adaptarlos a tu problema específico. Es una técnica muy potente para cuando tienes datasets pequeños.
  • Arquitecturas Más Complejas: Explorar modelos como ResNet, VGG, Inception, que han ganado concursos de reconocimiento de imágenes.
  • Regularización: Técnicas como Dropout o L2 regularization para reducir el overfitting.
  • Ajuste de Hiperparámetros: Experimentar con diferentes tamaños de kernel, número de filtros, optimizadores, tasas de aprendizaje y epochs.
  • Otros Datasets: Prueba tu modelo con otros datasets de clasificación de imágenes como CIFAR-10 o MNIST.
🔥 Importante: La experimentación es clave en Deep Learning. No tengas miedo de probar diferentes arquitecturas y parámetros.

📖 Recursos Adicionales

  • Documentación oficial de Keras: keras.io
  • Tutoriales de TensorFlow: tensorflow.org/tutorials
  • Curso de Deep Learning de Andrew Ng (Coursera): Excelente para entender los fundamentos teóricos.
Tutorial Completo

Tutoriales relacionados

Comentarios (0)

Aún no hay comentarios. ¡Sé el primero!