Implementación de Redes Q Profundas para el Control Autónomo en Flappy Bird

Arquitectura del Sistema y Preprocesamiento

El aprendizaje por refuerzo profundo permite que los agentes artificiales aprendan políticas de control óptimas mediante la interacción directa con el entorno. En este contexto, el juego Flappy Bird representa un problema clásico de control continuo con un espacio de estados visual y recompensas dispersas. A continuación, se detalla la arquitectura y el flujo de trabajo para entrenar una Red Q Profunda (DQN) que resuelva este entorno.

El entorno del juego devuelve marcos de imagen en formato RGB de alta resolución, los cuales contienen información redundante. Para optimizar el cómputo y extraer las características espaciales relevantes (como la posición de los tubos y el pájaro), se aplica una tubería de preprocesamiento de visión por computadora.


import cv2
import numpy as np

def transformar_frame_visual(frame_rgb):
    # Convertir a escala de grises para eliminar redundancia de color
    frame_gris = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2GRAY)
    
    # Recortar la región de interés (ROI) eliminando el marcador de puntuación
    roi = frame_gris[20:380, 0:288]
    
    # Redimensionar a una matriz cuadrada para la entrada de la red convolucional
    frame_escalado = cv2.resize(roi, (84, 84), interpolation=cv2.INTER_AREA)
    
    # Aplicar umbralización adaptativa para resaltar bordes y objetos
    _, mascara_binaria = cv2.threshold(frame_escalado, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)
    
    # Normalizar los valores de píxeles entre 0 y 1
    return mascara_binaria / 255.0

Diseño de la Red Neuronal Convolucional

El aproximador de la función Q utiliza una arquitectura de red neuronal convolucional (CNN). La entrada consiste en un apilamiento de 4 frames consecutivos para capturar la dinámica temporal (velocidad de caída y posición relativa). Se utiliza la API de Keras en TensorFlow 2.x para definir el modelo de manera más limpia y moderna.


import tensorflow as tf
from tensorflow.keras import layers, models

def construir_modelo_dqn(filas=84, columnas=84, canales=4, num_acciones=2):
    entradas = layers.Input(shape=(filas, columnas, canales))
    
    # Capas convolucionales para extracción de características espaciales
    x = layers.Conv2D(32, kernel_size=(8, 8), strides=(4, 4), activation='relu')(entradas)
    x = layers.Conv2D(64, kernel_size=(4, 4), strides=(2, 2), activation='relu')(x)
    x = layers.Conv2D(64, kernel_size=(3, 3), strides=(1, 1), activation='relu')(x)
    
    # Aplanamiento y capas densas para la toma de decisiones
    x = layers.Flatten()(x)
    x = layers.Dense(512, activation='relu')(x)
    
    # Capa de salida con valores Q para cada acción discreta
    salidas_q = layers.Dense(num_acciones, activation='linear')(x)
    
    modelo = models.Model(inputs=entradas, outputs=salidas_q)
    
    # Compilación con optimizador Adam y error cuadrático medio
    modelo.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.00025), loss='mse')
    return modelo

Bucle de Entrenamiento y Estrategia de Exploración

El entrenamiento requiere un balance entre exploración y explotación. Se implementa una política épsilon-greedy con decaimiento exponencial para reducir la exploración aleatoria a medida que el agente converge hacia una política óptima. Además, se utiliza un búfer de repetición de experiencia (Experience Replay) para romper la correlación entre muestras consecutivas.


import random

class ControladorExploracion:
    def __init__(self, epsilon_inicial=1.0, epsilon_minimo=0.05, decaimiento=0.995):
        self.epsilon = epsilon_inicial
        self.epsilon_minimo = epsilon_minimo
        self.decaimiento = decaimiento

    def seleccionar_accion(self, valores_q):
        if np.random.rand() <= self.epsilon:
            return np.random.randint(0, 2)  # Exploración aleatoria
        
        # Explotación: elegir la acción con el mayor valor Q predicho
        return np.argmax(valores_q[0])

    def actualizar_epsilon(self):
        if self.epsilon > self.epsilon_minimo:
            self.epsilon *= self.decaimiento

Optimización del Proceso de Aprendizaje

Para garantizar la estabilidad del algoritmo DQN, se deben considerar varias técnicas de optimización durante el entrenamiento:

  • Red Objetivo (Target Network): Se mantiene una copia de la red principal cuyos pesos se actualizan periódicamente (por ejemplo, cada 10,000 pasos) para calcular los valores Q objetivo, evitando la oscilación o divergencia del entrenamiento.
  • Factor de Descuento (Gamma): Un valor de 0.99 permite que el agente priorice recompensas a largo plazo (sobrevivir más tiempo) en lugar de recompensas inmediatas.
  • Muestreo por Prioridad (Prioritized Experience Replay): En lugar de un muestreo uniforme, las transiciones con un error de diferencia temporal (TD-error) más alto se muestrean con mayor frecuencia, enfocando el aprendizaje en las experiencias más informativas.

Diagnóstico de Problemas Comunes

Durante la implementación, pueden surgir diversos problemas de convergencia y rendimiento:

  • Falta de convergencia: Si la pérdida (loss) no disminuye o el agente no mejora, verifique la normalización de las entradas. Asegúrese de que los píxeles estén escalados correctamente y considere reducir la tasa de aprendizaje inicial.
  • Sobreajuste (Overfitting): Aunque el sobreajuste es menos común en entornos deterministas, puede ocurrir si el búfer de experiencia es demasiado pequeño. Aumente la capacidad del búfer (por ejemplo, a 100,000 transiciones) para mantener la diversidad de los datos.
  • Cuellos de botella de hardware: El procesamiento de imágenes y el entrenamiento de la CNN son intensivos. Utilice aceleración por GPU y aumente el tamaño del lote (batch size) a 64 o 128 si la memoria VRAM lo permite, para maximizar el rendimiento del entrenamiento.

Etiquetas: Deep Q-Network Reinforcement Learning TensorFlow keras opencv

Publicado el 10-3 10:24