Evaluación de la fidelidad del iris en imágenes GAN mediante segmentación e IoU

Introducción

Las Redes Generativas Adversarias (GANs, por sus siglas en inglés) son una técnica de inteligencia artificial para aprendizaje no supervisado. Enfrentan dos redes neuronales en competencia: un generador que crea datos sintéticos realistas y un discriminador que intenta distinguir entre datos reales y generados.

  • Generador (G): Transforma vectores aleatorios, tomados de una distribución gaussiana, en muestras que imitan datos reales.
  • Discriminador (D): Recibe imágenes reales y generadas, y estima la probabilidad de que una imagen sea auténtica.
  • Aprendizaje adversarial: Ambos modelos se entrenan de forma conjunta y adversaria en un juego de suma cero, donde el generador mejora al producir imágenes más realistas, y el discriminador mejora al detectar falsificaciones más sutiles. Este proceso se estabiliza mediante una actualización alterna de los pesos de G y D.

Este paradigma ha permitido avances notables en generación de imágenes realistas, particularmente en rostros humanos, arte, y entornos simulados, y ha sentado las bases para modelos más sofisticados.

Por otro lado, dentro de esta familia de modelos, StyleGAN2-ADA destaca por su capacidad para generar imágenes de alta fidelidad y por incorporar mecanismos que permiten su entrenamiento eficiente incluso con conjuntos de datos limitados. Esta arquitectura, desarrollada por NVIDIA, introduce mejoras tanto en el diseño interno del generador como en la estrategia de entrenamiento del discriminador [1].

Una de sus principales innovaciones es el uso de ADA (Adaptive Discriminator Augmentation), un módulo que regula dinámicamente la cantidad de aumentos geométricos y fotométricos aplicados a las imágenes. 

Se presenta el esquema general del entrenamiento en StyleGAN2-ADA [2]:

  1. Latent vector → Generador (G): A partir de un vector aleatorio z, el generador produce una imagen sintética  x̂  usando convoluciones moduladas y weight demodulation, generando rostros realistas.
  2. Aumentaciones dinámicas (ADA): Se aplican transformaciones (traslaciones, flips, blur, jitter, etc.) tanto a imágenes reales como sintéticas. La probabilidad de cada transformación se ajusta dinámicamente: aumenta si el discriminador memoriza y disminuye si se confunde con facilidad.
  3. Discriminador (D): Recibe imágenes ya transformadas y devuelve un escalar f(x) que representa su “confianza” en que una imagen sea real.
  4. Funciones de pérdida:
    • Para el generador: se busca maximizar f(x̂) (es decir, que el discriminador considere reales las imágenes generadas).
    • Para el discriminador: se maximiza la diferencia f(x) – f(x̂), penalizando imágenes falsas y recompensando las reales.
  5. Actualización alterna: Se actualiza únicamente uno de los dos modelos en cada iteración para preservar la estabilidad del entrenamiento.

La característica clave de StyleGAN2-ADA es que los aumentos afectan únicamente al discriminador y no al generador. Esto obliga al generador a generalizar mejor, produciendo imágenes realistas desde el punto de vista geométrico y textural, sin memorizar ejemplos concretos.

Estado del arte

Desde su aparición en 2014, las Redes Generativas Adversarias (GANs) han revolucionado la generación de contenido sintético, en especial de imágenes faciales. Su evolución ha dado lugar a modelos más precisos y controlables, destacando StyleGAN (NVIDIA, 2018) y sus sucesores StyleGAN2 y StyleGAN3, que introducen innovaciones como la manipulación jerárquica del espacio latente y una mayor estabilidad en el entrenamiento [3]. Estas mejoras han permitido crear rostros sintéticos de alta resolución, como demuestra el sitio This Person Does Not Exist [4].

Con estos avances, surgió la necesidad de métricas adecuadas para evaluar la calidad de las imágenes generadas. En entornos no supervisados, métricas como el Inception Score (IS) y la Fréchet Inception Distance (FID) se utilizan ampliamente para medir fidelidad y diversidad respecto a los datos reales.

Más recientemente, se han adoptado métricas como la Intersección sobre la Unión (IoU), originalmente usada en segmentación, para evaluar detalles internos como la forma del iris o la geometría facial. Estas herramientas permiten detectar anomalías sutiles que podrían pasar desapercibidas visualmente.

Fundamentos matemáticos de las GANs

Las Generative Adversarial Networks (GANs) operan mediante un juego de minimax entre dos redes neuronales: un generador, que crea datos sintéticos, y un discriminador, que los distingue de los reales [5]. La función de costo que guía este proceso es:

El discriminador maximiza la función de pérdida para mejorar su clasificación, mientras que el generador la minimiza para engañarlo. Este proceso iterativo busca un equilibrio de Nash, donde los datos sintéticos se vuelven casi indistinguibles de los reales, clave en tareas como generación de imágenes y mejora visual.

StyleGAN, una variante avanzada desarrollada por NVIDIA, introduce un mapeo del espacio latente y un control del estilo en distintos niveles. En lugar de pasar el ruido directamente al generador, se transforma en un espacio latente intermedio ww:

Para ajustar el estilo de las imágenes, StyleGAN emplea Adaptive Instance Normalization (AdaIN):

Donde ss y bb son parámetros generados por ww para controlar el estilo. Además, el discriminador utiliza un aprendizaje progresivo que mejora la resolución gradualmente. Este enfoque permite a StyleGAN generar imágenes hiperrealistas con un control detallado de su apariencia.[6]

Desarrollo: Pipeline de Detección y Segmentación del Iris en Imágenes Sintéticas

Aproximación Inicial: DC-GAN

Al iniciar el proyecto optamos por usar una GAN sencilla basada en la arquitectura DC-GAN tradicional del notebook de Kaggle/Colab «Generating Fake Faces Using GAN», enlace: https://colab.research.google.com/drive/1EoAaNGRp6O4ZGZZVIZWXJaXh2ndGzlUo). Se buscó generar retratos con recursos mínimos para el pipeline ocular, usando imágenes de 128 × 128 px, resolución baja pero suficiente para identificar el iris, y un vector latente de 100 dimensiones con distribución normal 𝒩(0, 1), estándar en estudios previos.

El generador se construyó como una secuencia de capas Dense hasta un tensor 128 × 128 × 3, seguido de varios bloques alternos de Conv2D / Conv2D-Transpose, normalización por lotes y activaciones LeakyReLU

Este patrón, heredado de la DC-GAN clásica, resulta fácil de depurar y de entrenar sin técnicas de estabilización costosas. 

En el discriminador se repitió la simetría inversa: convoluciones con stride 2 para reducir la resolución, normalización, Leaky ReLU y una capa densa sigmoide final.

Aunque la propuesta inicial parecía viable, los resultados tras 5 y 15 épocas fueron insatisfactorios: las imágenes eran solo ruido coloreado. Las pruebas revelaron tres problemas clave:

  • Resolución insuficiente: A 128 px, el iris apenas ocupaba unos pocos píxeles, dificultando su definición.
  • Falta de regularización: Sin técnicas como normalización espectral o gradient penalty, el discriminador aprendía demasiado rápido, causando mode collapse.
  • Limitaciones de tiempo: Se estimaba que se requerían al menos 50 épocas (~12 horas de GPU) para obtener resultados aceptables, algo inviable en el entorno disponible.

Imágenes generadas por DC-GAN  tras 5 épocas

Imágenes generadas por DC-GAN  tras 15 épocas

Con estos obstáculos concluimos que el modelo del notebook, aunque proporcionó una plataforma rápida de arranque, la falta de recursos computacionales y la resolución limitada, no era viable como fuente de datos y decidimos migrar a una solución preentrenada de alta fidelidad: StyleGAN2-ADA, descrita en la siguiente sección.

Migración a siguiente solución: StyleGAN2-ADA

La elección natural fue StyleGAN2-ADA, la variante de NVIDIA que combina la potencia de StyleGAN2 con el módulo Adaptive Discriminator Augmentation (ADA). Este sistema ya estaba disponible con pesos preentrenados sobre FFHQ a 1 024 px, de modo que podíamos generar imágenes realistas sin ningún entrenamiento adicional.

Ciclo de entrenamiento StyleGAN2-ADA

Para ello, hemos desarrollado el siguiente código:

Este bloque de comandos prepara el entorno y produce las imágenes sintéticas: instala dependencias ligeras que exige StyleGAN2-ADA (gestión de CLI, descargas, decodificador PNG, compilador ninja y soporte de vídeo), clona la implementación oficial en PyTorch desde GitHub, entra en ese directorio y ejecuta generate.py con el modelo FFHQ preentrenado. El script recorre las semillas 0-99, aplica una truncación de 0,7 (compromiso entre variedad y nitidez) y guarda los 100 retratos resultantes en la carpeta gan_faces/.

Imágenes generadas por StyleGAN2-ADA

Proceso de selección de imágenes generadas por StyleGAN2-ADA

Tras generar los rostros, se realiza una filtración manual en la carpeta gan_faces/ para conservar solo las imágenes de calidad, descartando aquellas que no sean frontales, tengan baja resolución o estén borrosas, presenten errores de renderizado o distorsiones, o contengan artefactos visuales producidos por la GAN.

A continuación, se muestran ejemplos de imágenes descartadas por no cumplir estos criterios:

Evaluación de fidelidad en iris

Para evaluar la fidelidad del iris en imágenes generadas por GAN, usamos un código de GitHub especializado en detección y segmentación del iris y reflejos (https://github.com/discovershu/gan_detect_iris) , útil en análisis forense. El proceso comienza con la detección automática de ojos, seguida de la segmentación de la córnea e iris, identificando también reflejos. Se calcula la métrica IoU para medir la precisión comparando con máscaras reales. La imagen final muestra la segmentación aplicada, y la función main automatiza todo el procedimiento usando las imágenes en la carpeta /data.

(Explicamos su funcionamiento más en detalle en el siguiente enlace: https://docs.google.com/document/d/19txjgz4XA9FPudsFvBX-HquBL2o_8WmhtIA_-UXGuCk/edit?tab=t.0.)

Resultados y conclusiones
Se procesaron seis retratos generados por StyleGAN2‑ADA. Todos se escalaron a 1 024 × 1 024 px y pasaron sin modificaciones por el pipeline del repositorio, obteniendo los siguientes resultados:

El análisis de los valores de IoU revela una variabilidad significativa en la calidad de segmentación del iris en imágenes generadas por StyleGAN2-ADA. Usuarios 1, 2 y 3 presentan puntuaciones bajas (alrededor de 0.30), lo que indica que las máscaras segmentadas no coinciden bien con la geometría ocular real. Esto sugiere errores en la generación, como contornos irregulares, artefactos visuales o reflejos mal colocados que dificultan la segmentación automática. En cambio, los usuarios 4 y 6 superan el umbral biométrico de 0.50, reflejando una segmentación más precisa y una estructura del iris más realista. El Usuario 5 se sitúa en un punto intermedio, lo que indica una calidad aceptable pero aún con margen de mejora.

Conclusiones finales

Las GANs, especialmente StyleGAN2-ADA, han supuesto un avance significativo en la generación de imágenes faciales realistas, integrando mecanismos que mejoran la estabilidad y calidad del entrenamiento con conjuntos de datos limitados. Sin embargo, persisten desafíos importantes en la reproducción fiel de detalles específicos, como la estructura del iris, lo que limita su aplicabilidad en ámbitos biométricos y forenses. Los resultados muestran que, aunque las imágenes sintéticas alcanzan un alto nivel visual, la precisión en elementos finos aún requiere optimización. Por tanto, es fundamental continuar mejorando las arquitecturas y desarrollar métricas especializadas que evalúen estos detalles para garantizar un uso confiable y seguro de estas tecnologías.

Consideraciones éticas de la tecnología deepfake

Las tecnologías deepfake presentan desafíos éticos relacionados con la privacidad, la manipulación y la regulación. Por un lado, permiten la suplantación de identidad, afectando la autonomía individual y exponiendo a las personas al robo de identidad digital mediante datos biométricos. También generan desinformación masiva, alterando debates públicos y dañando reputaciones, lo que debilita la confianza en instituciones y medios de comunicación [7] .Aunque tienen aplicaciones en cine y educación, la recreación de personas fallecidas sin consentimiento plantea dilemas éticos. Para mitigar riesgos, se necesitan leyes específicas que regulen su uso, distinguiendo entre aplicaciones legítimas y maliciosas, además de promover la alfabetización digital para que los ciudadanos puedan identificar contenido manipulado [7]. La creciente cantidad de leyes aprobadas sobre IA en distintos países demuestra la urgencia de una regulación que proteja derechos sin frenar la innovación.

BIBLIOGRAFÍA

[1] Karras, T., Aila, T., Laine, S., & Lehtinen, J. (2019). A Style-Based Generator Architecture for Generative Adversarial Networks. arXiv. https://arxiv.org/abs/1812.04948

[2] Karras, T., Laine, S., Aittala, M., Hellsten, J., Lehtinen, J., & Aila, T. (2020). Analyzing and improving the image quality of StyleGAN. In Proceedings of the IEEE/CVF Conference on Computer Vision and Pattern Recognition (CVPR) (pp. 8110–8119). https://doi.org/10.1109/CVPR42600.2020.00813

[3] Salimans, T., Goodfellow, I., Zaremba, W., Cheung, V., Radford, A., & Chen, X. (2016). Improved Techniques for Training GANs. arXiv. https://arxiv.org/abs/1606.03498

[4] This Person Does Not Exist. https://thispersondoesnotexist.com/

[5] Wikipedia. (2024). StyleGAN. https://en.wikipedia.org/wiki/StyleGAN

[6] Moralo García, J. (s. f.). Generative Adversarial Networks (GAN): Una introducción. LinkedIn. https://www.linkedin.com/pulse/generative-adversarial-networks-gan-una-introducci%C3%B3n-moralo-garc%C3%ADa/

[7] E. Gutiérrez Rojas, “Deepfakes y sus implicaciones éticas. Reflexiones desde la filosofía de la tecnología,” Rev. Iberoam. Cienc. Tecnol. Soc., vol. 19, no. 2, pp. 359–377, 2024. [En línea]. Disponible en: https://www.scielo.org.mx/scielo.php?script=sci_arttext&pid=S2448-51362024000200359

MATERIALES

Generación de caras falsas con GAN – 5 epochs [Notebook de Google Colab]. Disponible en: https://colab.research.google.com/drive/1yEOGNy69QNel4DK4IeMvE0a09cB0swt2

Generación de caras falsas con GAN – 15 epochs [Notebook de Google Colab]. Disponible en: https://colab.research.google.com/drive/1EoAaNGRp6O4ZGZZVIZWXJaXh2ndGzlUo

theblackmamba31. (s.f.). Generating Fake Faces Using GAN [Kaggle Notebook]. Disponible en: https://www.kaggle.com/code/theblackmamba31/generating-fake-faces-using-gan

PASD – BLOG: Generación de datos sintéticos con StyleGAN2-ADA [Notebook de Google Colab]. Disponible en: https://colab.research.google.com/drive/1tsblpAyWbwHpw6Yd7kVFpug0XuHzM9Ec

Shu, Y. (2021). gan_detect_iris [GitHub repository]. Disponible en: https://github.com/discovershu/gan_detect_iris

El mecanismo de atención y la transferencia de estilos en transfromers

Presentación

Desde la publicación del influyente artículo “Attention is All You Need” en 2017, el campo de la inteligencia artificial ha sido transformado por una nueva arquitectura: los Transformers. A diferencia de modelos tradicionales como las redes neuronales recurrentes (RNN), los Transformers son capaces de procesar secuencias completas en paralelo, lo que permite capturar relaciones complejas entre los elementos, sin importar su posición.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXcwV0oY3YJ1Boz48ZeJiBo5mP_gEDPXxASonw6HXYEmDNRsw6zpUFy5-wkAP9vGlTtzsVQvcXMLFUuW1X00gPbYZM25PX6iLKsa9t8jzVeb7PO1qn4UBNcj_AUjuez2zp7-JVhnsw.png

El corazón de esta arquitectura es el mecanismo de atención, una técnica que permite al modelo identificar y enfocarse en las partes más relevantes de la entrada. En vez de tratar toda la información por igual, el modelo aprende qué fragmentos son más importantes para la tarea. Esto ha sido clave en tareas como la traducción automática, el análisis de texto, y recientemente en visión por computadora y generación de imágenes. 

Por otro lado, un concepto emergente y creativo es el de la transferencia de estilo, que busca aplicar las características estéticas (como los colores o el trazo de una pintura, o el tono de un texto) a otro contenido, sin alterar su estructura. Aunque inicialmente se realizaba con redes convolucionales (CNN), el uso de Transformers ha llevado esta técnica a nuevos niveles de precisión y control.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXfhl0oHAqd5bKx6ZZijfgcmgoaRP0hg5nocH5cP3X9poZsYcUZjSra8AfijV3VuWovQRGrTLLWZ02PZmiqFr0GufAnK9Yf7iFLRc3_jHCJJtXQe6bxPSIKDWOxrQL-DIqqZNORjKA.png

En este blog explicaremos cómo los Transformers y el mecanismo de atención han dado lugar a modelos capaces de analizar, transformar y crear contenido. Nos enfocaremos especialmente en su aplicación a la transferencia de estilo en texto, abordando tanto su evolución técnica como sus retos actuales, siempre con un enfoque claro y visual. 


Estado del arte

Atención en visión por computadora

Aunque comenzaron en procesamiento de lenguaje natural, los Transformers se adaptaron a visión. El modelo Vision Transformer (ViT), por ejemplo, divide una imagen en parches y los procesa como si fueran palabras. Esto permitió superar algunas limitaciones de las redes convolucionales (CNN), sobre todo en tareas donde es importante captar relaciones globales dentro de una imagen.


La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXc7JnwgpMlZVi4kXy3MygrgiaVqdeWqLM7ozOVv25xyFaLukF9xlWU-rfiIw_pgZHTfeZLz4BAP08uSIkGNxTqTt6HggeopmqDgheaN5LXTAZkavp04G7qrtUUbPK9pVmypRFfQJg.png

También surgieron modelos como CLIP, que combinan texto e imagen usando atención cruzada. Esto permite, por ejemplo, que el modelo relaciona la frase “un perro con gafas de sol” con imágenes adecuadas. 

Transferencia de estilo: de CNN a Transformers 
La transferencia de estilo empezó con CNNs (Gatys et al. 2015), combinando el contenido de una imagen con el estilo de otra.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXeCsvlHkSg9nAMPQLhsF3EnYDwV-z-RY7114vfY2XwydPKzRL2VpuzxqrDoZ1890xv-b9XSyS4IXycHVFiD1ur0xCzWAjCjwfAMPGmCWcN3xLzjN1Lhe2omB3JFsJ0mrFnJsOwp.png

Pero los CNNs solo captaron patrones locales. Por eso, modelos como StyTr² han utilizado Transformers para aplicar atención global y mejorar la calidad del estilo transferido. Este modelo separa el contenido y el estilo en dos flujos distintos, y los une con atención cruzada. Aun así, sigue habiendo retos: estructuras deformadas, resultados no siempre controlables.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXc-wOne-x-XaKU_ByLmE3NkGnD-2-QS4Dtfa5tq3_9zycRKlAX615wUXOs2qe_HlpuPIh-L1hmnPJcGG5IinjZGgrY-RtkoGN-BU1WeoZ6N-L5sl-0cSeBKFl4jtub9e0vwddmaDw.png

 Modelos generativos actuales 
Hoy en día, modelos como DALL·E o Stable Diffusion generan desde texto con estilo incluido. Usan codificadores de texto, redes U-Net y atención para fusionar descripción y estilo.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXccgW4yNdiRY_iQmdsULYCsQdpOhcYwKFrp29aBGm0WFlr1YX1kROWDhxGl-vwnrMq5P5Lkj4vBd5cJSrdnrTsm_8lyIrJXaN1CnAbS1TqX78PAEnB8INFl19SEA8k6fY6o-U3g7w.png
La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXfyVb6_vCKyqdlxryLXQsRLyhm6b-LUsPIfjcpN4pC3h0XdhIRHF_jbkWp6Rt_P2ztqR3gqJGJnpRvhPY6K99_mJsp3hw54HvHDjbxRzge4eMPUj3livIhapWj8NJ_5Wsut_ZQR.png

Análisis matemático

Los mecanismos de atención permiten que un modelo se “enfoque” en partes específicas de la entrada al tomar decisiones. En lugar de procesar toda la información de manera uniforme, el modelo aprende a asignar pesos diferentes a distintas partes de la entrada según su relevancia para una tarea.

Matemáticas de la atención (Scaled Dot-Product Attention)

El tipo más usado de atención es el dot-product attention escalado. Dado un conjunto de consultas Q, claves K, y valores V, la atención se calcula como:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-10.png
La imagen tiene un atributo ALT vacío; su nombre de archivo es image-19.png

Este mecanismo es el núcleo del famoso Transformer, arquitectura base de modelos como BERT y GPT.

La transferencia de estilo en texto busca modificar el estilo lingüístico (por ejemplo, hacer que un texto suene más formal, sarcástico o poético) sin cambiar su contenido semántico. No existe una fórmula universal como en imágenes, pero la mayoría de los enfoques modernos usan modelos generativos (como Transformers) y una combinación de representaciones latentes, pérdidas de contenido y estilo, y a veces entrenamiento adversarial.

Matemáticas de la Transferencia de Estilo en Texto

1. Representaciones latentes del texto

El primer paso es codificar el texto en un espacio latente donde el contenido y el estilo puedan, en teoría, separarse.

Se supone que se tiene un codificador E y un decodificador D, como en un autoencoder o un modelo tipo Transformer. La idea es:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-12.png

donde x es el texto original, y z es su representación latente.

Se asume que esta representación z puede dividirse (explícita o implícitamente) en:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-13.png

2. Función de pérdida

La transferencia de estilo en texto se entrena minimizando una función de pérdida que mezcla varios objetivos:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-14.png

a) Pérdida de reconstrucción (Lrecon):

Esta pérdida asegura que al codificar y decodificar un texto sin cambiar el estilo, se obtiene el mismo texto:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-15.png

b) Pérdida de contenido:

Mide que el contenido del texto transformado sea similar al original. A menudo se hace usando representaciones semánticas (por ejemplo, activaciones de una red preentrenada)

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-16.png

donde ϕ(⋅) es una función que extrae representaciones de contenido (por ejemplo, de BERT), y x es el texto generado.

c) Pérdida de estilo:

Se entrena un clasificador de estilo C, y se penaliza si el texto generado no tiene el estilo deseado:

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-17.png

donde s es el estilo objetivo (por ejemplo, “formal”), y “x” es el texto generado.

3. Alternativas: Enfoques adversariales

Algunos métodos usan un discriminador adversarial para asegurarse de que el contenido y el estilo estén desacoplados. Es como en las GANs, pero aplicado al texto:

  • El codificador intenta ocultar el estilo en z,
  • Un discriminador intenta predecir el estilo desde z,
  • Se entrena al codificador para que engañe al discriminador.

Esto introduce una pérdida adversarial:       

La imagen tiene un atributo ALT vacío; su nombre de archivo es image-18.png

que se combina con las anteriores para reforzar la separación de contenido y estilo.

Descripción y análisis de resultados

Sistema de atención: Para este apartado se ha implementado un código en el que se ha usado el modelo BERT y se pretende mostrar cómo “presta atención” a diferentes partes del texto en distintas capas y cabezas. Es una forma útil de interpretar y visualizar el comportamiento interno del modelo.

En BERT, la atención mide qué tan relevante es un token para otro en un contexto. Cada token decide a qué otros tokens debe “mirar” para entender mejor su significado.

Las gráficas que se verán a continuación tienen las siguientes características:

  • Ejes:
    • Y (Query): Cada fila representa un token que está prestando atención (el que “mira”).
    • X (Key): Cada columna representa un token al que se le presta atención.
  • Colores (Viridis):
    • Amarillo brillante = alta atención.
    • Azul oscuro o violeta = poca o ninguna atención.

Resultados:

Esta es la atención generada en la primera capa (de las 12 de BERT) y en la primera cabeza (de las 12 cabezas por capa).

  • “[CLS]” presta mucha atención a [SEP].
  • “allows” es bastante observado por varios tokens como programming, it, to y problems.
La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXcVJo89BjrdBBQ1HaLPrHuGGrZrL8mg-4LasQ9CrOI5I16jyVXxCIo4iVxzZUrDwerowohBYXQf3ZWNrttwnBTqutKsYLw3ByPg_uQOyL_BquovtGOn0IbXgGw2xuzy-QQwJynHaw.png

Esta es la atención generada en la segunda capa (de las 12 de BERT) y en la cuarta cabeza (de las 12 cabezas por capa).

Se puede ver como la primera columna muestra que la atención se está centrando en algunas de las palabras más relevantes, como podría ser “i”, “solve” o “problems” y no presta tanta atención a otras que a nivel semántico no tienen tanta importancia, como podrian ser “it”, “me” o “to”.

El resto de la gráfica muestra cómo cada palabra presta atención justo a la que tiene delante, como “love” con “i”, “prgramming” con “love”, etc.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXfuikZdBY1MoReTX0vsoPtZTZNuaeiG6zUjxCWcV52fcFExl51SDWH8DTKDVBasoJSqkQyP9uUY3WGC5R4G_yLZKeEvzvUYVjOhwYwzYGOPCnlkyukeaxMtITjRr4J308QvRY6R7g.png


Esta es la atención generada en la capa once (de las 12 de BERT) y en la cuarta cabeza (de las 12 cabezas por capa).

  • La fila [CLS] muestra atención distribuida principalmente sobre “programming”, “love” y “because”. Esto es típico, porque [CLS] se usa para tareas como clasificación, y necesita una representación global del contenido.
  • Muchos tokens muestran una alta atención hacia [SEP]. Esto suele ser un comportamiento aprendido: [SEP] actúa como un marcador de final o de separación, y a veces las cabezas aprenden a usarlo como un apoyo.
La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXfuikZdBY1MoReTX0vsoPtZTZNuaeiG6zUjxCWcV52fcFExl51SDWH8DTKDVBasoJSqkQyP9uUY3WGC5R4G_yLZKeEvzvUYVjOhwYwzYGOPCnlkyukeaxMtITjRr4J308QvRY6R7g.png

Tras observar estas gráficas es importante señalar que en las capas inferiores (como la 0 la 1), BERT tiende a prestar atención local o a tokens vecinos como hemos podido observar. Mientras que en capas superiores, tiende a capturar dependencias de mayor nivel, como sujeto, verbo, etc.

Estas gráficas son útiles ya que se puede ver cómo BERT distribuye su “foco” al procesar una oración, además si una cabeza presta atención a tokens irrelevantes, podrías cuestionar su utilidad y algunas cabezas capturan dependencias gramaticales, otras relaciones semánticas.

Transferencia de estilo: Para esta parte se ha escogido un código el cual realiza la transferencia de estilos sobre texto, como por ejemplo pasando de texto escrito en formato coloquial a formal y viceversa.

A continuación se mostrarán y explicarán los resultados obtenidos:

Casual a formal

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXdSqoAWxpZlfnZVYmbocr_juQWPkXYcPmPyZc55vayPSVPs1ziziFIBqeGsEZMcA8dQLOtDn6Yop3XpXVKS13-ZzUnD2y6QoqLoJVSgnmEgks1vPfrlffutJs2xKDbwhRTb54U4Ww.png

Se puede observar como efectivamente se produce la transferencia de estilo. Cuando la frase casual es correcta y no hay nada que se pueda modificar se queda tal cual está y cuando se utiliza una expresión coloquial o inadecuada se sustituye por otra formal. 

Formal a casual

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXcGPMW614gcDQOPc8bq1sLgDCzsXvkwWhCg02cnPpdOebmDwEjazEjGiKCaIzp_87Njvm9UtOr_WORYc7aenk6ZbZTEun_31GrXFUWF1AGEjXKNWY7hbJcwc2-Jb4TVucXBYaMsQA.png

Sucede lo mismo en este caso.

Para entender mejor su funcionamiento se van a realizar más pruebas centradas en una misma frase con algunos cambios para ver su comportamiento.

La imagen tiene un atributo ALT vacío; su nombre de archivo es AD_4nXdUD8I0nh-mmkHNZOEac4DIrJY2fKw5hqMshuTeji5p5jkhDrvVrzM2ORIf3n9UMIi4euehWLSiHX2Vr6pF_coPrlg_FXYQ_7WIuERfF5aU7GgP01FXfCr1U1W28RyhbhG2usOG.png

Los Transformers, agrupan significados similares en el espacio de representación interna (embeddings). Si bien “enjoyyyyy” y “like” o “adore” y “be fond of” tienen diferencias de tono e intensidad, todas comparten una intención semántica básica: expresar disfrute por ir al cine. Por lo tanto el modelo interpreta que todas las expresiones significan lo mismo pero con diferente intensidad y por ello las pasa a su forma formal dependiendo de la intensidad.

Y entonces, al pasar a un estilo formal, tiene en cuenta matices emocionales, por lo tanto expresa el contenido nuclear en el estilo objetivo pero mantiene la intensidad.

Todo lo mostrado se ha realizado con el siguiente código.

Discusión

Los resultados obtenidos muestran el potencial de los transformers con atención multi-cabeza para manipular el estilo sin afectar significativamente el contenido semántico. La precisión lograda en la evaluación sugiere que el modelo ha aprendido a distinguir patrones estilísticos y adaptarlos durante la generación.

Sin embargo, también se observaron limitaciones, algunas frases se volvieron menos naturales al forzar un estilo opuesto, funcionaba mejor en frases cortas que en largas. 

Una de las observaciones más interesantes es cómo las cabezas de atención parecen especializarse en identificar diferentes aspectos lingüísticos: algunas se enfocan en entidades, otras en verbos, etc. Esta distribución sugiere que el mecanismo de atención permite una descomposición natural del estilo en componentes interpretables.

Otra línea de desarrollo relevante es la incorporación de feedback humano durante el entrenamiento, por ejemplo, usando aprendizaje por refuerzo con retroalimentación humana, lo cual permitiría entrenar modelos que generen resultados no solo correctos en estilo, sino también percibidos como naturales o adecuados por seres humanos. Asimismo, la integración de herramientas para el análisis de sesgos y diversidad de estilos puede contribuir a crear sistemas más justos y representativos.

También se podría investigar el uso de transformers multilingües para evaluar si el conocimiento estilístico aprendido en una lengua se transfiere a otra. Esto abriría la puerta a aplicaciones de transferencia de estilo multilingüe, lo cual resulta relevante en contextos interculturales, como traducción automática con preservación de tono.

Conclusiones

El mecanismo de atención ha permitido a los transformers convertirse en arquitecturas muy versátiles para tareas complejas como la transferencia de estilos. Ya hemos visto que es posible realizar modificaciones del estilo en el texto preservando su significado original. 

La atención multi-cabeza no solo mejora el rendimiento del modelo, sino que también sabemos que componentes del texto están siendo transformados. Esta capacidad resulta clave en aplicaciones específicas donde el tono del mensaje debe ajustarse automáticamente a su audiencia.

Aplicaciones:

  • En correos electrónicos automáticos, modificar el nivel de formalidad dependiendo de si el destinatario es un cliente, proveedor o compañero de equipo.
  • Respuestas personalizadas de atención al cliente: el modelo puede ajustar el estilo y el tono según la gravedad de la queja o el perfil del cliente que está atendiendo.
  • Herramientas de escritura asistida, por ejemplo, un corrector de estilo automático, para ayudar al usuario a reformular un texto informal a un texto más adecuado en contextos académicos o profesionales.

Cabe destacar, que la integración de feedback humano o aprendizaje por refuerzo podría permitir una transferencia de estilo más controlada, personalizada y contextual.

En resumen, la transferencia de estilo basada en transformers no solo ofrece una solución técnica potente, sino también una vía para mejorar la calidad de la comunicación en entornos digitales cada vez más personalizados. A medida que las organizaciones buscan adaptar sus mensajes a distintos perfiles de usuario, este tipo de modelos puede convertirse en una herramienta estratégica para automatizar la adaptación del lenguaje en tiempo real, manteniendo la coherencia del contenido, pero ajustando su presentación de manera inteligente y eficaz.

Referencias

  • Zhang, Y., Zhao, Y., Wang, Y., & Li, J. (2022). A Comparative Study of CNN-andTransformer-Based Visual Style Transfer. Journal of Computer Science and Technology, 37(3), 479–492. https://jcst.ict.ac.cn/fileup/1000-9000/PDF/2022-3-8-2140.pdf

  • Vaswani, A., Shazeer, N., Parmar, N., Uszkoreit, J., Jones, L., Gomez, A. N., Kaiser, L., & Polosukhin, I. (2017). Attention Is All You Need. arXiv preprint arXiv:1706.03762. https://arxiv.org/abs/1706.03762

  • Deng, Y., Tang, F., Pan, X., Dong, W., Ma, C., Wang, L., & Xu, C. (2021). StyTr2: ImageStyle Transfer with Transformers. arXiv preprint arXiv:2105.14576. https://arxiv.org/abs/2105.14576

  • CapCut. (2024). Transferencia de estilo neural: Una gu´ıa completa para estilizar tu imagen. CapCut Recursos. https://www.capcut.com/es-es/resource/neural-style-transfer

  • OpenAI. (2023, September 19). Anunciando GPT-4, un modelo multimodal de gran tama˜no… [Tweet]. X. https://x.com/OpenAI/status/1704545952533725572

  • Andrew. (2024, June 9). How does Stable Diffusion work?. Stable Diffusion Art. https://stable-diffusion-art.com/how-stable-diffusion-work/

Realizado por Iñigo Garcia-Vallaure, Luis Lopez y Nour Yasmine

Explorando espacios de representación: transferencia y aprendizaje en modelos de lenguaje

1. INTRODUCCIÓN Y ESTADO DEL ARTE

Para realizar tareas de procesamiento de lenguaje natural (NLP), los grandes modelos
de lenguaje (LLMs) deben convertir la información de entrada, texto, en vectores de alta
dimensión que capturan información sintáctica y semántica. El aprendizaje de estas representaciones o embeddings (representation learning) permite al modelo generalizar su conocimiento a nuevas tareas (transfer learning).

Cada palabra o secuencia de palabras es transformada, en distintas etapas del modelo,
en vectores que resumen su significado en contexto. Entender cómo se construyen estas representaciones y cómo pueden manipularse es clave para interpretar y mejorar el rendimiento de los modelos. [1]

En esta entrada exploraremos paso a paso cómo se procesan los textos en un modelo
preentrenado, desde la tokenización hasta las primeras capas del modelo. A partir de ahí, experimentaremos con transformaciones del espacio latente a otros de menor dimensionalidad mediante autoencoders —como PCA o VAEs— para obtener representaciones más compactas. Finalmente, mediremos si es posible adaptar el modelo a trabajar con esta nueva representación sin perder demasiada precisión. [2]

2. MATERIALES

El objetivo principal de esta experimentación es observar cómo se representan las secuencias de texto en un modelo preentrenado y cómo afectan distintas transformaciones de estas representaciones al rendimiento en tareas de clasificación.

DATASET Y TAREA

Para este estudio utilizamos el conjunto de datos TREC (Question Classification), una
colección clásica en procesamiento del lenguaje natural compuesta por preguntas cortas etiquetadas según su tipo. Las categorías incluyen seis clases generales: ABBR
(abreviaciones), DESC (descripciones), ENTY (entidades), HUM (personas), LOC
(localizaciones) y NUM (números). El objetivo del modelo es predecir correctamente la
categoría de una pregunta a partir de su texto. El conjunto incluye aproximadamente
5.000 ejemplos de entrenamiento y 500 de test [3]. Es una tarea sencilla, que nos facilita probar diversas aproximaciones, y que evaluaremos con la métrica F-score.

MODELO

Se ha empleado el modelo distilbert-base-uncased, una versión ligera de BERT que
mantiene su arquitectura principal pero con menos capas [4]. Esto facilita la inspección
de las representaciones internas y reduce el coste computacional.

3. DEL LENGUAJE NATURAL AL ESPACIO LATENTE: PROCESADO PASO A PASO EN UN MODELO DE CLASIFICACIÓN

El primer paso en el recorrido de una secuencia textual por un modelo como DistilBERT es la tokenización. Esto transforma el texto en fragmentos más pequeños (tokens), que luego son convertidos en números mediante un vocabulario entrenado.

from transformers import AutoTokenizer

tokenizer = AutoTokenizer.from_pretrained("distilbert-base-uncased")

texto = "Where is the Eiffel Tower?"
tokens = tokenizer.tokenize(texto)

print(tokens)
['where', 'is', 'the', 'e', '##iff', '##el', 'tower', '?']

Cada token es una subpalabra, generada según reglas específicas del vocabulario del modelo (WordPiece). Estos tokens se traducen a identificadores numéricos únicos que corresponden a posiciones concretas en el vocabulario de DistilBERT.

token_ids = tokenizer.convert_tokens_to_ids(tokens)
print(token_ids)
[2073, 2003, 1996, 1041, 13355, 2884, 3578, 1029]

En una aplicación real, el modelo espera una entrada que incluya tokens especiales como [CLS] (al inicio) y [SEP] (al final). También se aplica padding y truncamiento para ajustar las secuencias a una longitud fija.

encoded = tokenizer(
    texto,
    padding="max_length",
    truncation=True,
    max_length=12,
    return_tensors="pt"
)

print(encoded["input_ids"])
tensor([[  101,  2073,  2003,  1996,  1041, 13355,  2884,  3578,  1029,   102,
0, 0]])

Donde:

101 → [CLS]

102 → [SEP]

0 → padding

Una vez que los tokens están representados como IDs, se pasan por la capa de embeddings del modelo. Cada ID es convertido en un vector denso de dimensión fija (en DistilBERT, 768).

from transformers import AutoModel
import torch

model = AutoModel.from_pretrained("distilbert-base-uncased")
with torch.no_grad():
    embedding_output = model.embeddings(encoded["input_ids"])

print(embedding_output.shape)
torch.Size([1, 12, 768])

Esto indica que hay una secuencia de 12 tokens, cada uno representado como un vector de 768 dimensiones. Estos vectores combinan embeddings de tokens, embeddings de posición y embeddings de tipo de segmento (para tareas específicas, por ejemplo la tarea de clasificación a continuación).

Una vez hemos analizado el proceso de transformación del texto hasta su representación en el espacio latente, vamos a explorar este espacio y ver qué transformaciones podemos hacer sobre el mismo.

4. AJUSTE DEL MODELO A EMBEDDINGS REDUCIDOS

El objetivo es que el modelo pueda trabajar directamente con representaciones comprimidas [5]. Exploramos dos enfoques para lograrlo:

  • Reducción de dimensionalidad con PCA
  • Compresión mediante un autoencoder variacional (VAE)

Ambos se implementan de dos formas:

  • Dentro del modelo, añadiendo una capa de expansión al principio que reconstituye los embeddings comprimidos a su dimensión original (768).
  • Fuera del modelo, reconstruyendo los embeddings antes de pasarlos a DistilBERT.

ENFOQUE 1: REDUCCIÓN DE DIMENSIONALIDAD CON PCA

REDUCCIÓN DE DIMENSIONALIDAD

Como primer enfoque, utilizamos Análisis de Componentes Principales (PCA) para reducir los embeddings generados por la capa de entrada de DistilBERT. Estos embeddings tienen una dimensión original de 768. En nuestro experimento, los comprimimos a 512 dimensiones.

pca = PCA(n_components=512)
reduced = pca.fit_transform(flat.numpy())

Primero tokenizamos el texto y extraemos los embeddings de entrada del modelo, que tienen forma [batch_size, seq_len, 768]. Luego aplicamos PCA, reduciendo la dimensión de 768 a 512. Para ello, reordenamos los datos como una matriz de vectores [batch_size × seq_len, 768], aplicamos la transformación, y reconstruimos el tensor original con la nueva dimensión reducida: [batch_size, seq_len, 512].

ADAPTACIÓN DEL MODELO

El siguiente reto fue adaptar el modelo para que pudiera trabajar con estos nuevos embeddings reducidos. Para ello, implementamos una clase que incorpora:

  • Una capa lineal de proyección: transforma los vectores de 512 dimensiones de vuelta a los 768 requeridos por DistilBERT.
  • El encoder original de DistilBERT, reutilizado tal cual.
  • Una capa de clasificación final para predecir la categoría de cada pregunta del dataset TREC.
class FineTunedDistilBERT(nn.Module):
    def __init__(self, model, num_labels):
        super(FineTunedDistilBERT, self).__init__()
        self.num_labels = num_labels
        self.distilbert = model.distilbert  # Get the base model
        self.embedding_projector = nn.Linear(num_components, 768)  # Project custom embeddings
        self.classifier = nn.Linear(768, num_labels)    # Your classifier head
        self.loss_fn = nn.CrossEntropyLoss()

    def forward(self, inputs_embeds, labels=None, attention_mask=None):
        # Project the reduced embedding to 768
        projected = self.embedding_projector(inputs_embeds)

        # Pass through DistilBERT encoder
        outputs = self.distilbert(inputs_embeds=projected, attention_mask=attention_mask)
        hidden_state = outputs.last_hidden_state  # shape: (batch_size, seq_len, hidden_size)

        # Use the [CLS]-like token (first token) for classification
        cls_representation = hidden_state[:, 0, :]  # (batch_size, hidden_size)
        logits = self.classifier(cls_representation)

        loss = None
        if labels is not None:
            loss = self.loss_fn(logits, labels)

        return {"loss": loss, "logits": logits}
RESULTADOS

Aunque la implementación era funcional, el modelo no aprendía y los resultados fueron muy malos. Especulamos sobre algunas posibles razones:

  • El modelo original está optimizado para trabajar con una distribución específica de entradas; al modificar la entrada, rompemos esa alineación.
  • La capa de expansión al inicio del modelo no recupera adecuadamente la información textual.

ENFOQUE 2: RECONSTRUCCIÓN CON PCA

En base a estos resultados, decidimos cambiar el enfoque: aplicamos reducción de dimensionalidad con PCA, pero esta vez reconstruyendo los embeddings antes de ingresarlos al modelo. Es decir:

  • Obtenemos los embeddings de entrada (768 dim).
  • Los comprimimos a un espacio latente de menor dimensión (ej. 512).
  • Reconstruimos los embeddings originales con la transformación inversa del PCA.
  • Pasamos estos vectores reconstruidos al modelo, sin modificar su arquitectura.

Realmente, al experimentar con esta arquitectura lo que estamos evaluando es cuánta información se pierde al codificar y decodificar la información con un autoencoder, en este caso PCA.

recovered = compressor.decode(compressor.encode(embeddings), embeddings.shape)

A diferencia del enfoque anterior, este método sí ofrece buenos resultados (que presentaremos más adelante), especialmente cuando el espacio latente no es demasiado reducido.

ENFOQUE 3: VAE PARA CODIFICACIÓN Y DECODIFICACIÓN

VAE INTEGRADO CON EL MODELO

En esta aproximación, de nuevo partimos de la arquitectura de DistilBERT, a la que añadimos un módulo de compresión VAE entrenado de forma conjunta. La arquitectura utilizada es simple y simétrica: un codificador con una capa oculta de 512 unidades que proyecta a un espacio latente de dimensión configurable, y un decodificador con la misma estructura en orden inverso. Se usa ReLU como activación intermedia. La pérdida combina MSE (error de reconstrucción) y divergencia KL (forzar distribución normal en el espacio latente).

class VAECompressor(nn.Module):
    def __init__(self, input_dim, latent_dim):
        super(VAECompressor, self).__init__()
        self.input_dim = input_dim
        self.latent_dim = latent_dim
        
        # Encoder: input -> hidden -> latent
        self.fc1 = nn.Linear(input_dim, 512)
        self.fc2_mu = nn.Linear(512, latent_dim)
        self.fc2_logvar = nn.Linear(512, latent_dim)
        
        # Decoder: latent -> hidden -> output
        self.fc3 = nn.Linear(latent_dim, 512)
        self.fc4 = nn.Linear(512, input_dim)
        
    def encode(self, x):
        h1 = torch.relu(self.fc1(x))
        mu = self.fc2_mu(h1)
        logvar = self.fc2_logvar(h1)
        return mu, logvar

    def reparameterize(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def decode(self, z):
        h3 = torch.relu(self.fc3(z))
        return self.fc4(h3)

    def forward(self, x):
        mu, logvar = self.encode(x)
        z = self.reparameterize(mu, logvar)
        reconstructed = self.decode(z)
        return reconstructed, mu, logvar

    def loss_function(self, recon_x, x, mu, logvar):
        # Binary cross entropy loss for reconstruction
        BCE = nn.functional.mse_loss(recon_x, x, reduction='sum')
        
        # KL divergence loss
        KL = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
        
        # Total loss is reconstruction + KL
        return BCE + KL

El modelo optimiza simultáneamente la pérdida de clasificación y la pérdida del VAE, definiendo como función de pérdida la suma de ambos.

class FineTunedDistilBERTVAE(nn.Module):
    def __init__(self, model, vae_compressor, num_labels):
        super(FineTunedDistilBERTVAE, self).__init__()
        self.num_labels = num_labels
        self.distilbert = model.distilbert
        self.classifier = nn.Linear(768, num_labels)
        self.loss_fn = nn.CrossEntropyLoss()
        self.vae_compressor = vae_compressor

    def forward(self, inputs_embeds, labels=None, attention_mask=None):
        # Compresión y reconstrucción de embeddings
        reconstructed, mu, logvar = self.vae_compressor(inputs_embeds)
        
        # Paso por DistilBERT
        outputs = self.distilbert(inputs_embeds=reconstructed, attention_mask=attention_mask)
        cls_representation = outputs.last_hidden_state[:, 0, :]
        logits = self.classifier(cls_representation)

        # Cálculo de pérdidas
        loss = self.loss_fn(logits, labels) if labels is not None else None
        vae_loss = self.vae_compressor.loss_function(reconstructed, inputs_embeds, mu, logvar)
        total_loss = loss + vae_loss if loss is not None else vae_loss

        return {"loss": total_loss, "logits": logits}

Sin embargo, los resultados obtenidos fueron muy malos. Es posible que la combinación de ambos entrenamientos dificultara la optimización, ya que ambos objetivos (compresión y clasificación) competían por los recursos del modelo. También probamos a ajustar la función de pérdida mediante un parámetro beta, que ponderaba la pérdida de clasificación y del VAE, aunque de nuevo sin éxito.

total_loss = loss + beta * vae_loss
ENTRENAMIENTO SEPARADO

Finalmente decidimos separar los entrenamientos: primero entrenamos el VAE para realizar la compresión de los embeddings, y luego utilizamos los embeddings reconstruidos en el modelo de clasificación. El código completo está disponible en este enlace.

Este punto fue el más interesante, puesto que experimentamos con la arquitectura del VAE de diversas formas. Para medir su rendimiento (calidad de la reconstrucción) implementamos una función que devuelve el error MSE de reconstrucción sobre un subconjunto de datos, y de esta forma ir ajustando el VAE. Con ello finalmente implementamos los siguientes cambios que mejoraban el rendimiento, entre otros:

  • Nº y tamaño de capas: añadir una segunda capa y ajustar el tamaño por capa. La arquitectura definitiva fue (con dimensión de entrada 768): 2 capas de 640 y 512 neuronas cada una para codificación, y decodificación simétrica.
  • Función de pérdida: es mejor ponderar el componente KL al mínimo (beta = 0.001) para priorizar la reconstrucción.
  • Duración del entrenamiento: aumentar el nº de épocas hasta 30.
  • Función de activación: GELU (en vez de RELU).
  • Estabilidad del entrenamiento:
    • Acotar la magnitud del gradiente para evitar “explosiones del gradiente”.
    • Establecer una condición de parada en caso de empeoramiento (3 épocas de paciencia).
    • Acotar el rango del logaritmo de la varianza (logvar) al computar KL para evitar error.

Esto son sólo algunos de los detalles que tuvimos que considerar, y que darían para una entrada completa de blog 🙂

Con esta configuración, conseguimos un entrenamiento estable, cuya evolución podemos visualizar para las distintas dimensiones del espacio latente. El valor de la función de pérdida es muy alto, ya que utilizar la suma MSE, en vez de la media, mejoraba la estabilidad. Es probable que hubiera margen para mejorar el rendimiento aumentando el número de épocas, aunque con su consiguiente coste computacional.

A continuación, presentamos los resultados obtenidos en cuanto a la calidad de la reconstrucción. Como cabría esperar, a mayor dimensionalidad, menor pérdida de información.

Y, finalmente, podemos evaluar el rendimiento en la tarea de clasificación, comparando los resultados obtenidos con PCA frente a VAE. Previsiblemente, nuestro VAE proyecta de forma más eficiente la información, pudiendo alcanzar una reducción mayor de dimensionalidad con un mejor rendimiento.

5. CONCLUSIONES

A lo largo del trabajo, hemos explorado el espacio latente en los LLMs, desde el proceso
para obtener representaciones numéricas de información textual hasta la exploración y
transformaciones de dichos espacios.

Hemos intentado aplicar diversas estrategias para reducir la dimensionalidad de estas
representaciones textuales sin perder rendimiento. Probamos dos enfoques principales: el uso de PCA y VAEs, tanto integrados directamente en el modelo como aplicados de manera separada, obteniendo las siguientes conclusiones:

  • Modificar la arquitectura de una red neuronal sin perder rendimiento no es trivial, así como diseñar un VAE funcional: hay que tener en cuenta y elegir muchos detalles (tamaño y nº de capas, función de pérdida, etc.), y no está garantizado que funcione.
  • Para tareas específicas, es posible obtener buenos resultados tras reducir la representación a un espacio de menor dimensionalidad, lo que sugiere que se pueden desarrollar modelos de lenguaje mucho más pequeños y eficientes para aplicaciones concretas.
  • La reducción significativa de la dimensionalidad de las representaciones textuales es viable, siempre que no se altere la arquitectura original del modelo.

Realizado por Adrián Maldonado Robles, Paula Martín Fernández y Elena Moyano González

6. REFERENCIAS

Generación de rostros humanos con DCGANs

Introducción

Las Redes Generativas Adversarias (GANs) son una clase de modelos de aprendizaje profundo compuesto por dos redes neuronales, una red generativa y una discriminativa, que se entrenan en un proceso de competencia:

  • El generador es responsable de crear nuevos datos que se parezcan lo máximo posible al conjunto de datos original.
  • El discriminador, por su parte, tiene como objetivo distinguir entre los datos generados por el generador y los reales del conjunto original.

Esta competición entre el generador y el discriminador empuja a ambas redes a mejorar. Es decir, el generador aprenderá a producir datos más realistas y el discriminador mejorará en la distinción entre datos reales y falsos.

Las GANs han abierto un abanico de posibilidades en distintos campos, desde la generación de imágenes hasta la mejora de la resolución de fotografías o incluso el aumento del conjunto de datos de entrenamiento para un modelo de aprendizaje automático. En este blog nos centraremos en la generación de rostros humanos mediante el uso de una Deep Convolutional GAN (DCGAN). Estas, a diferencia de una GAN básica, utilizan redes neuronales convolucionales, lo que las hace especialmente aptas para trabajar con imágenes.

Estado del Arte

En el año 2014, Ian Goodfellow y sus colaboradores propusieron lo que hoy en día conocemos como Redes Generativas Adversarias: un enfoque innovador para entrenar modelos generativos mediante un proceso adversarial, en el que se entrenan simultáneamente dos redes neuronales: un generador (G) y un discriminador (D).

En este proceso, el generador toma ruido aleatorio y lo convierte en muestras sintéticas, que intentan imitar los datos reales. El discriminador, por su parte, recibe tanto muestras reales como generadas, calcula la probabilidad de que cada muestra provenga de los datos reales en lugar del generador.

Este entrenamiento está basado en un juego de minimax, donde el generador busca engañar al discriminador, y el discriminador intenta no ser engañado. Matemáticamente, esto se expresa como:

En 2015, se propuso una mejora significativa de las GANs originales conocida como Deep Convolutional GANs (DCGANs). La principal diferencia radica en la sustitución de las redes totalmente conectadas por redes neuronales convolucionales (CNNs) tanto en el generador (G) como en el discriminador (D). Esta modificación permite que las DCGANs sean más efectivas para trabajar con imágenes, ya que las CNNs son capaces de capturar las relaciones espaciales y estructurales dentro de los datos, lo que resulta en la generación de imágenes de mucho mayor calidad.

Desarrollo

Hemos decidido implementar una DCGAN para poder crear rostros humanos a partir del dataset CelebA que se puede encontrar en Kaggle.

Esta es la arquitectura de nuestro generador. Está compuesta por 5 capas convolucionales y 1 densa inicial que convierte el vector de ruido a una una representación de 4x4x128 usando la activación LeakyReLU. Después hay 4 capas de upsampling para poder producir imágenes de 64×64 con tres canales de color RGB. El Batch Normalization es una técnica que se utiliza para mejorar la estabilidad y el rendimiento durante el entrenamiento normalizando las activaciones de las capas de la red.

El discriminador se compone de 4 capas de convolución 2D con activaciones LeakyReLU para mejorar la propagación del gradiente e intercalando capas de Dropout para reducir el sobreajuste. Finalmente el discriminador aplana las características y a través de una capa densa con activación sigmoide saca una variable binaria para indicar si la entrada es real o falsa.

Después de establecer los optimizadores Adam para nuestra GAN el resultado de la misma sería este. Estos optimizadores permiten ajustar las tasas de aprendizaje de manera individual para cada parámetro, ayudando a mejorar la convergencia y permitiendo escapar al modelo de los mínimos locales.

Por último, esta es la función con la que hemos entrenado a nuestra GAN. Se define un ciclo de entrenamiento dividido en 2 fases. Durante la fase 1, el discriminador se actualiza usando un lote de imágenes mezcladas, mientras que en la fase 2 el generador se entrena para generar imágenes “reales” que engañen al discriminador.

Materiales

El dataset CelebA (CelebFaces Attributes Dataset) es un conjunto de 202.599 imágenes de rostros humanos extraídas de celebridades, que incluye aproximadamente 10.000 rostros diferentes. Estas imágenes están centradas y alineadas, lo que facilita su uso en tareas de visión por computador donde se requiere consistencia estructural en las entradas. Este es un ejemplo de rostros que aparecen en el dataset:

El uso de CelebA en el entrenamiento de redes generativas adversarias (GANs) ofrece diversas ventajas. Su gran volumen de datos, unido a la variedad de atributos y condiciones de iluminación, permite al modelo aprender representaciones ricas y generalizables del rostro humano.

Por otro lado, el código que hemos utilizado para nuestro estudio puede encontrarse en el siguiente enlace de GitHub:

En este caso, el autor utiliza el dataset CIFAR. Nosotros lo hemos adaptado a la generación de rostros humanos con el dataset CelebA.

Resultados

Para demostrar la evolución de las imágenes a lo largo de las épocas vamos a graficar las imágenes cada 10 épocas y veremos la evolución a la hora de generar rostros. Representamos los resultados a través de una imagen tipo GIF a lo largo de las épocas.

También vamos a estudiar los resultados de la época 300 y 400:

Discusión de resultados

Inicio del entrenamiento (Primeras 10 épocas)

En el GIF, al comienzo, las salidas del generador son todo ruido. Esto es esperado, ya que el generador aún no ha aprendido ninguna distribución del conjunto de datos real. Podríamos decir que el generador convierte ruido en ruido, el discriminador rechaza todo lo generado, y el generador apenas comienza a recibir señales útiles para aprender.

Fase temprana del aprendizaje (Épocas 10-30)

Se empiezan a vislumbrar formas vagas que podrían parecer estructuras faciales: distribuciones de color más organizadas, manchas que se transformarán en ojos, bocas, etc. El generador empieza a “engañar” parcialmente al discriminador en ciertas regiones de la imagen.

Fase intermedia (Épocas 30-60)

Las caras empiezan a ser más reconocibles, aunque distorsionadas. Vemos características como rasgos faciales mal colocados, algunas caras simétricas, otras claramente defectuosas y mejora de la distribución de color (colores de piel más realistas). Hay signos de colapso parcial ya que algunas imágenes parecen repetirse con poca variabilidad.

Fase avanzada (Épocas 60-100)

Las imágenes generadas se parecen a rostros humanos completos. Podemos ya decir que genera colores realistas, proporciones más consistentes, mejora en la  diversidad de rostros y rasgos faciales diferenciados. Aún así, la generación de imágenes sigue presentando errores más específicos que dejan la puerta abierta a una posterior mejora del modelo como: aumento de la diversidad de rostros, ojos o bocas desalineados, deformaciones en el fondo o cabello, y en algunas imágenes múltiples rostros superpuestos.

Fase mejorada (Épocas 300 y 400)

A pesar de la mejora de rostros, seguían existiendo los problemas mencionados. Por ello ejecutamos hasta las épocas 300 y 400. Vemos que a medida que el modelo avanza, se observa un refinamiento en las características faciales, mayor diversidad y detalles más precisos, aunque aún persisten pequeños defectos. Esto es una señal de que el generador está aprendiendo de manera efectiva las distribuciones de las caras humanas y está acercándose a un estado más realista en su capacidad para producir imágenes coherentes y variadas.

Referencias

AUTORES: Alejandro González, José María Martín, Pablo Mateo y Daniel Vigil.

Generative Adversarial Networks (GAN’s); ¿Qué son y qué problemas existen?

Introducción

Las redes generativas antagónicas (GANs) son un tipo de arquitectura de inteligencia artificial que ha revolucionado la generación de contenido sintético. Fueron propuestas en 2014 por el investigador Ian Goodfellow y, desde entonces, han sido ampliamente utilizadas para crear imágenes, sonidos y vídeos que imitan datos reales con sorprendente realismo.

El funcionamiento básico de una GAN se basa en dos redes: un generador, que intenta crear datos falsos realistas, y un discriminador, que intenta distinguir entre datos reales y generados. Este enfoque se inspira en una dinámica competitiva que permite a ambas redes mejorar a lo largo del entrenamiento. Tanto el generador como el discriminador utilizan redes convolucionales (CNN) para procesar la información de entrada [1], [2].

Diseño Red Neuronal Convolucional [3]

No obstante, a pesar de su enorme potencial, entrenar correctamente una GAN es una tarea compleja. En este blog se exploran de forma práctica algunos de los problemas más comunes que surgen durante el entrenamiento de estas redes. Para ello, se han realizado experimentos utilizando el conjunto de datos MNIST y se han inducido tres errores habituales: desbalance en las tasas de aprendizaje, colapso modal y desvanecimiento de gradientes provocado por funciones de activación inapropiadas. El objetivo es comprender cómo estos factores afectan al rendimiento del modelo.

Estado del arte

Desde su introducción, las GANs han sido objeto de numerosas investigaciones debido a su capacidad para generar datos sintéticos de alta calidad. Estas redes han permitido avances importantes en áreas como la edición de imágenes, la creación de rostros humanos artificiales y la generación de contenido en videojuegos y cine [4], [5].

Sin embargo, su entrenamiento es notoriamente difícil, ya que implica mantener un equilibrio entre dos redes que aprenden simultáneamente. Uno de los problemas más comunes es el colapso modal, que ocurre cuando el generador produce una variedad limitada de salidas, ignorando otras posibles representaciones del conjunto de datos. Este fenómeno reduce la diversidad de las muestras generadas y limita la utilidad del modelo [1].

Otro desafío significativo es el desbalance entre el generador y el discriminador. Si uno de los modelos aprende más rápido que el otro, puede dominar el proceso de entrenamiento, impidiendo que ambos mejoren conjuntamente. Este desequilibrio puede llevar a una mala convergencia o incluso a la ausencia total de convergencia [2], [6].

Además, el uso de funciones de activación inadecuadas, como la función sigmoide en capas intermedias, puede provocar el desvanecimiento de gradientes. Este problema ocurre cuando los gradientes se vuelven extremadamente pequeños, dificultando la actualización efectiva de los pesos y, por ende, el aprendizaje del modelo.

Para abordar estos problemas, se han propuesto diversas soluciones. Por ejemplo, las Wasserstein GANs (WGANs) introducen una función de pérdida basada en la distancia de Wasserstein, proporcionando gradientes más estables y mejorando la convergencia. Asimismo, técnicas como la normalización espectral se han utilizado para estabilizar el entrenamiento del discriminador.

A pesar de estos avances, estudios recientes han demostrado que muchas de estas mejoras no generalizan bien y que el rendimiento de las GANs depende en gran medida del conjunto de datos, la arquitectura elegida y la configuración de los hiperparámetros [3]. Por lo tanto, es esencial comprender a fondo los problemas inherentes al entrenamiento de las GANs y desarrollar enfoques más robustos y generalizables.

Desarrollo del problema y discusión de resultados: 

Vamos a enfocar el trabajo analizando en un código ejecutable [7] los distintos problemas que pueden surgir al trabajar con GANs (Generative adversarial networks). Hemos utilizado el dataset de MNIST [8] normalizando las imágenes cargadas, del rango [0, 1] al rango  [-1, 1] pues después nuestro modelo funcionará mejor si están centradas en el 0:

Como se trata de un Dataset sencillo, formado por imágenes de baja resolución (escala de grises) y con baja varianza intraclases; vamos a utilizar Perceptores Multicapa (MLP) tanto para el Generador como para el Discriminador.

MLP [9]

A la hora de desarrollar el Generador, programamos una red neuronal (MLP) que toma un vector aleatorio (ruido) y genera una imagen de tamaño (1, 28, 28). Usa capas Linear (combinaciones lineales para conectar neuronas) y LeakyReLU (función de activación donde se ajustan los pesos) con normalización por lotes (BatchNorm1d) para mejorar el entrenamiento. La última capa usa Tanh para producir valores en [-1, 1] (acorde a la normalización de las imágenes MNIST).

En cuanto al discriminador, deberemos ahora programar una red discriminadora la cual a través de las imágenes falsas generadas por el Generador, deberá distinguirlas entre reales o falsas. Volvemos a emplear capas lineales y funciones de activación RELU pero en este caso la última capa usa una función de activación Sigmoide, ideal para la clasificación 1 imagen verdadera 0 imagen falsa.

Ambas redes son heredadas de las redes Generator y Discriminator del módulo nn de Pytorch [10]  solo que cambiando sus estructuras básica y los métodos forward

Una vez tenemos ambas redes, inicializamos la red general. Es decir, la GAN con una función de pérdida Binaria (BCELoss del módulo nn).

Posteriormente, tenemos que entrenar la red para poder trabajar con ella y ver los  inconvenientes que pueden surgir si lo hacemos incorrectamente. En un periodo de 50 épocas, entrenamos con todas las imágenes del dataset, por un lado el discriminador y por otro lado el generador, además analizamos su rendimiento época a época. Calculamos las funciones de pérdida:

  • Discriminador: del dataset antes cargado, sacamos una etiqueta verdadera y una falsa (1, 0). Seguidamente, del dataset sacamos una imagen verdadera y vemos como la discrimina el discriminador frente a la etiqueta verdadera (función de pérdida de la verdadera). Luego, mediante ruido gaussiano, generamos una imagen falsa (uso del Generador) y calculamos su función de pérdida comparándola con la etiqueta falsa. Finalmente computamos la función de pérdida definitiva como el promedio de ambas.
  • Generador: Calculamos la función de pérdida del generador simplemente comparando la imagen generada a partir del ruido, con la verdadera del dataset.

Importante mencionar que es tras el cálculo de cada función de pérdida (tanto en la red generadora como discriminadora), cuando realizamos el entrenamiento. Actualizamos los pesos mediante el Descenso del Gradiente. Obtenemos el siguiente gráfico evolución de la pérdida del Discriminador y Generador por época.

Viendo la pérdida del discriminador se mantiene estable, en torno a 0.6 y 0.7, y viendo la pérdida del generador, tiene más oscilaciones, pero también tiende a estabilizarse en el rango [0.7, 1.1], lo que es típico mientras aprende a producir imágenes más realistas. Esta evolución sugiere que el entrenamiento es razonablemente estable y ambos modelos están compitiendo de forma equilibrada.

Hemos podido observar el correcto funcionamiento de una GAN con un dataset MNIST. Pero nos gustaría profundizar en los inconvenientes que pueden tener las GAN’s en algunas situaciones concretas o con algunas configuraciones previas erróneas. Uno de los problemas principales de estas redes neuronales es el tiempo, y esto lo hemos podido comprobar en la ejecución anterior, que para completar el entrenamiento entero han pasado 12 minutos, bastante tiempo a pesar de emplear muchos recursos en ello (GPU de Google Colab + CPU del dispositivo Torch).

Para mostrar otros 3 inconvenientes hemos generado 3 experimentos y hemos ejecutado el código anterior con cada actualización errónea (15 épocas en vez de 50 para demostración).

  • Desbalance en tasas de aprendizaje: hacemos que el discriminador aprenda demasiado rápido subiendo su tasa de aprendizaje y provocando que el generador nunca aprenda (no genere imágenes parecidas a las reales).
  • Colapso modal (ruido fijo): Simulamos el colapso inicializando siempre con la misma entrada de ruido, el generador se estanca y siempre produce imágenes reales.
  • Gradientes desvanecidos por funciones de activación pobres: Funciones de activación como la Sigmoid en capas intermedias hace que los gradientes se vuelvan muy pequeños y por ende la red deja de aprender (no se actualizan los pesos). Para ello crearemos un nuevo generador que sustituya las capas LeakyReLU por Sigmoides.

Por último compararemos las funciones de pérdida y las imágenes cada 5 épocas por cada experimento para ver visualmente la evolución del generador ante estos inconvenientes.

Experimento desbalance de entrenamiento de la red generadora

Se pueden ver imágenes muy ruidosas o completamente aleatorias. El generador no logra aprender una representación coherente del espacio de datos y el discriminador se estanca debido a su alto aprendizaje, por ello la función de pérdida se satura y está siempre en 50. La cuadrícula de imágenes muestra patrones que parecen ruido blanco.

Experimento colapso modal:

Se ven imágenes repetitivas o muy similares, a menudo centradas en una sola clase (por ejemplo, el número “3”). Mejora de calidad en términos visuales, pero baja diversidad. El modelo parece generar dígitos legibles, pero siempre los mismos o con pequeñas variaciones. Las funciones de pérdida oscilan entre valores muy cercanos (0.6 — 0.7 (D) y 0.7 – 0.8 (G)).

Experimento activación pobre o gradientes desvanecidos:

Se observan imágenes con un patrón muy tenue, borroso o con puntos repetitivos. Falta de contraste, estructura o forma reconocible. La función de pérdida del discriminador evoluciona de manera razonable en cambio la del generador sube sin control (el generador no aprende debido a los gradientes pobres).

Conclusión:

A lo largo del artículo hemos podido observar cómo las redes generativas antagónicas (GANs) pueden sufrir problemas significativos que comprometen su rendimiento comparándola con una red bien balanceada. A través de los tres experimentos realizados: desbalance entre generador y discriminador, colapso modal y gradientes desvanecidos; hemos simulado errores frecuentes que degradan la calidad de las imágenes generadas y los resultados esperados.

Aunque en estos experimentos los errores han sido forzados de manera intencionada y controlada para ilustrar sus efectos, es importante destacar que todos ellos pueden surgir de forma natural en escenarios reales si no se presta atención a ciertos detalles clave o por la propia naturaleza de estas redes. Por ejemplo, el colapso modal puede surgir incluso con entradas de ruido aleatorias si el generador no lo aprovecha correctamente (se queda estancado en una imagen que engaña), o si el discriminador no tiene mecanismos para identificar la falta de diversidad. 

Otra desventaja de estas redes que ha estado presente transversalmente durante el trabajo es el tiempo de entrenamiento el cual aumenta exponencialmente cuando aumentamos la complejidad de los datos y la densidad del modelo. 

En definitiva, estos problemas son comportamientos propios del diseño de las GANs y sus variedades y hemos de conocerlos y tenerlos en cuenta para evitar caer en soluciones engañosas.

Referencias

[1] MathWorks, “Redes Generativas Antagónicas (GAN),”. Disponible en: https://la.mathworks.com/discovery/generative-adversarial-networks.html

[2] IEBSchool, “¿Qué son las GAN? Las redes generativas que crean contenido realista,” Disponible en: https://www.iebschool.com/hub/redes-generativas-antagonicas-tecnologia/

[3] Imagenes apartado de introducción: https://drive.google.com/file/d/1hG5iBGN-eoPrnZYo-BDefeuKs947fBq_/view?usp=drive_link

[4] TechAffinity, “Redes Generativas Antagónicas: ¿Qué son y cómo funcionan?,” 2021. Disponible en: https://techaffinity.com/blog/redes-adversarias-generativas/

[5] Wikipedia, “Red generativa adversativa,”. Disponible en: https://es.wikipedia.org/wiki/Red_generativa_adversativa

[6] Keep Coding, “Redes Generativas Antagónicas (GAN): Guía 2025,”. Disponible en: https://keepcoding.io/blog/que-son-redes-generativas-antagonicas/

[7] Notebook, “Código GANs” . Disponible (con ejemplo extendido) en https://colab.research.google.com/drive/1PVajOyfbCdDjSPVI-ysbeibpDzduM80O?usp=sharing

[8] MNIST Dataset. Kaggle. Disponible en https://www.kaggle.com/datasets/hojjatk/mnist-dataset

[9] Kishore, N. G. Multi Layer Perceptron. LinkedIn. Recuperado de https://www.linkedin.com/pulse/multi-layer-perceptron-kishore-ng-wvrcc/

[10] PyTorch. torch.nn — PyTorch 2.0 documentation. Disponible en https://docs.pytorch.org/docs/stable/nn.html

Créditos:
Sergi Jabega Bolívar: Introducción y Estado del Arte.
Nacho Moyano Fernández: Desarrollo del problema y discusión de resultados.
Sergio González Gironés: Extrapolación de los experimentos al dataset CIFAR-10 (en el nootebook) y Conclusiones.
Juan Pérez Picciolato: Desarrollo del problema y discusión de resultados y Conclusiones.

Modelos Generativos para Síntesis y Mejora de Imágenes Médicas

Introducción

En el campo de la imagen médica, la posibilidad de transformar una modalidad en otra, como generar imágenes de tomografía computarizada (CT) a partir de resonancia magnética (MRI) o tomografía por emisión de positrones (PET) se está convirtiendo en una herramienta revolucionaria. Modelos como las redes generativas antagónicas (GANs) permiten esta conversión de forma precisa y sin necesidad de someter al paciente a múltiples escaneos, lo que reduce la exposición a radiación [1], ahorra costes clínicos y facilita el uso de sistemas diseñados específicamente para trabajar con imágenes CT. Además, estas imágenes sintéticas permiten ampliar conjuntos de datos para entrenar algoritmos, mejorar la planificación quirúrgica o radioterápica y avanzar hacia una medicina más personalizada y eficiente [2]. La generación de CT sintéticas a partir de MRI o PET representa así una solución elegante y práctica a varios de los retos actuales en diagnóstico por imagen.

Para entender la aplicación de esta GAN en la transformación de imágenes médicas lo primero que tendremos que hacer será aprender las características del formato de imágenes que vamos a utilizar:

Imágenes por Resonancia Magnética (MRI)

La resonancia magnética se utiliza para visualizar tejidos blandos con gran detalle, cómo el cerebro, los músculos o los ligamentos, sin necesidad de radiación ionizante. Es especialmente útil en neurología y traumatología.

Tomografía por Emisión de Positrones (PET)

Las imágenes PET permiten observar procesos metabólicos en el cuerpo, siendo muy eficaces para detectar tumores activos y hacer seguimiento en tratamientos oncológicos. Proporcionan una visión funcional más que estructural.

Tomografía Computarizada (CT)

La CT permite visualizar con alta resolución huesos, pulmones y vasos sanguíneos, siendo fundamental en urgencias médicas y en la planificación de tratamientos como la radioterapia. Emplea rayos X y produce imágenes detalladas del cuerpo.

Arquitectura

La arquitectura de MedCycleGAN surge como una combinación estratégica entre la estructura de entrenamiento no pareado de CycleGAN y la potencia generativa de MedGAN [3]. El objetivo es obtener imágenes sintéticas de alta calidad sin la necesidad de datasets emparejados, una limitación importante en entornos médicos reales.

Dataset y configuración

En esta implementación, los modelos fueron entrenados con 1595 imágenes por dominio, sin emparejamiento directo. El entrenamiento sigue el flujo estándar de CycleGAN, pero se beneficia de la mayor capacidad de modelado de CasNet para refinar progresivamente los detalles anatómicos de las imágenes generadas

Generadores con arquitectura CasNet

El elemento central del modelo generador es CasNet (Cascaded U-Net), introducido originalmente en MedGAN. Esta arquitectura consiste en una secuencia de U-Nets encadenadas, donde la salida de una U-Net es usada como entrada de la siguiente. Cada U-Net tiene la capacidad de preservar detalles espaciales mediante skip connections, lo que favorece la reconstrucción estructural en imágenes médicas. En el modelo original, se empleaban 6 U-Nets, pero en esta implementación se ha reducido a 3 U-Nets para disminuir la carga computacional sin comprometer drásticamente la calidad [3].

Formalmente, si denotamos una U-Net como UUU, y una entrada xxx del dominio fuente (por ejemplo, MR), el generador actúa como:

donde GGG representa el generador completo. Cada U-Net es un autoencoder con convoluciones convolutivas y deconvolutivas simétricas, seguidas de normalización y activaciones ReLU o LeakyReLU.

El código que utilizamos para el generador está compuesto por las siguientes celdas las cuales las explicaremos una a una tras mostrarlas:

Esto reduce el tamaño espacial sin sesgo pero aumenta la profundidad también. Se utiliza la normalización por lotes para estabilizar el entrenamiento.

Esta función ayuda a reconstruir detalles finos que se pierden en el encoding. Utiliza Conv2DTranspose para aumentar la resolución.

Construimos una U-Net completa aplicando 8 bloques encoder (el último sin conexión skip), reconstruyendo la imagen pasando por 7 bloques decoder y rehusando los skip connections.

Define los tamaños de los encoder y decoder, y construye un modelo de Keras.

Funciona de manera que, si tienes una imagen de entrada de tamaño 256×256, este generador la transforma mediante 3 pasos U-Net, comprimiendo y descomprimiendo con saltos de conexión, buscando generar una imagen sintética coherente con los datos reales.

Discriminador

El discriminador en MedCycleGAN se mantiene deliberadamente ligero, con tres capas convolucionales, lo que recuerda a la arquitectura de PatchGAN utilizada en CycleGAN. Su función no es clasificar la imagen entera como real o falsa, sino verificar patches locales, lo cual es más efectivo en imágenes médicas donde los detalles estructurales finos son relevantes [4]. Esta elección arquitectónica reduce significativamente el tiempo de entrenamiento y evita el sobreajuste, especialmente con datasets pequeños.

Flujo cíclico y consistencia

Como en CycleGAN, se utiliza un enfoque bidireccional:

  • Un generador G: X→ Y : X (por ejemplo, MR → CT)
  • Un generador inverso F: Y→X
  • Dos discriminadores Dx y Dy ​ para cada dominio.

Se aplica una pérdida adversarial sobre cada par (G, Dy) y (F, Dx), y una pérdida de consistencia cíclica

Esto obliga al sistema a mantener información relevante entre las transformaciones, asegurando que la ida y vuelta entre dominios no distorsione los datos originales.

Nuestro código del discriminador aplica una arquitectura tipo PatchGAN, evaluando pequeñas regiones de la imagen para determinar si son reales o generadas.

Usa convoluciones con normalización y activación LeakyReLU para extraer características, terminando con una salida sigmoid que da probabilidades por parche.

Esta combinación permite generar imágenes de alta calidad con coherencia visual y detalles consistentes.

Entrenamiento

El entrenamiento se basó en una arquitectura tipo CyvleGAN con dos generadores y dos discriminadores, permitiendo la conversión bidireccional entre dominios de imagen.

Se utilizaron pérdidas adversariales junto con pérdidas de ciclo y de identidad para asegurar coherencia estructural y fidelidad en la transformación. 

El optimizador Adam, con parámetros ajustados, garantiza una convergencia estable. Cada paso de entrenamiento actualiza todos los modelos simultáneamente usando tf.GradientTape y los checkpoints permiten continuar el entrenamiento sin pérdidas. 

Los resultados visuales por época muestran una mejora progresiva en la calidad de las imágenes generadas.

Testing MR images

La figura muestra imágenes reales de resonancia magnética frente a las generadas por el modelo. Se aprecia que el modelo reproduce con buena fidelidad la estructura cerebral, lo que demuestra su capacidad para generar imágenes médicamente coherentes a partir de datos sintéticos.

Testing PET images

Las imágenes muestran comparaciones entre datos PET reales (izquierda) y generados (derecha). El modelo logra replicar correctamente las regiones de mayor actividad metabólica, conservando la estructura general y la distribución de intensidades, clave para el análisis funcional.

Discusión

Los resultados obtenidos con imágenes MR y PET muestran que el modelo MedCycleGAN es capaz de generar imágenes sintéticas con una estructura anatómica y funcional coherente en comparación con las imágenes reales. En el caso de las MR, las imágenes generadas preservan bien los contornos cerebrales y detalles relevantes, lo que sugiere una buena capacidad del modelo para mantener la integridad espacial.

Para las PET, aunque la resolución original es menor y el ruido es más evidente, las imágenes generadas reproducen con acierto las zonas de alta actividad metabólica, lo cual es esencial en contextos oncológicos o neurológicos. Esto indica que el modelo no solo transfiere el estilo, sino también información clave para el análisis clínico.

En conjunto, estos resultados apoyan la utilidad del modelo como herramienta para aumentar la resolución, generar datos sintéticos para entrenamiento y reducir la necesidad de escaneos múltiples, con un impacto potencial en la mejora de calidad diagnóstica y eficiencia clínica.

BIBLIOGRAFÍA

1. Osuala, R. et al. (2022). medigan: a Python library of pretrained generative models for medical image synthesis. arXiv. https://arxiv.org/abs/2203.13765

2. Khader, F. et al. (2022). Medical diffusion: Denoising diffusion probabilistic models for 3D medical image generation. arXiv. https://arxiv.org/abs/2211.07804

3. Armanious, K., Jiang, C., Fischer, M., Küstner, T., Hepp, T., Nikolaou, K., … & Yang, B. (2020). MedGAN: Medical Image Translation using GANs. Computerized Medical Imaging and Graphics, 79, 101684. https://doi.org/10.1016/j.compmedimag.2020.101684 

4. Zhu, J. Y., Park, T., Isola, P., & Efros, A. A. (2017). Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks. In ICCV 2017. https://arxiv.org/abs/1703.10593

Datasets

Imágenes MRI y PET descargadas en OASIS 3, requiere un registro para descargarlas https://sites.wustl.edu/oasisbrains/home/oasis-3

Imágenes CT descargadas de Qure.ai https://web.archive.org/web/20220816011051/http://headctstudy.qure.ai/


Este blog ha sido creado por Antonio Verdú, José Ángel Bello y Jaime Sichar


Superresolución de Imágenes con SRGAN

Introducción

La superresolución de imágenes (SR) es el proceso por el cual una imagen de baja resolución se convierte en una de alta resolución con el mínimo de distorsión o pérdida de información posible. Este problema ha sido muy estudiado en visión por computadora debido a sus numerosas aplicaciones prácticas. Por ejemplo, la superresolución es clave para restaurar material audiovisual antiguo, mejorar la claridad de imágenes médicas, e incluso potenciar la calidad de imágenes de seguridad.

En los últimos años, los métodos basados en aprendizaje profundo han logrado avances significativos en SR. Inicialmente, la mayoría de las redes se entrenaban minimizando el error cuadrático medio (MSE) entre la imagen generada y la original de alta resolución, optimizando así métricas como PSNR (pico de relación señal-ruido). Aunque esto producía imágenes con buen promedio de error, a menudo resultaban borrosas y con falta de detalles de textura, porque el MSE tiende a promediar las posibles soluciones. Este fenómeno motivó la búsqueda de enfoques alternativos centrados en la calidad perceptual. En este contexto surge SRGAN (Super-Resolution Generative Adversarial Network), propuesta por Ledig et al. en 2017, que combina redes generativas adversarias (GAN) con una función de pérdida perceptual para lograr
imágenes foto-realistas en superresolución.

A continuación, se introduce SRGAN y cómo ha marcado un hito en el ámbito de la superresolución de imágenes, enfocándose en sus aportes técnicos y resultados.

Estado del Arte

Antes de SRGAN, los métodos más comunes para la superresolución incluían técnicas de interpolación y enfoques basados en patches. Estos métodos tradicionales son rápidos, pero no son capaces de reconstruir detalles pequeños, produciendo imágenes borrosas o con artefactos. La llegada del deep learning lo cambió todo: las redes neuronales convolucionales (CNN) aprendieron a mapear directamente imágenes de baja resolución (LR) a alta resolución (HR) usando datos de entrenamiento, logrando reconstruir patrones y texturas que no estaban en la entrada. En 2014, Dong et al. presentaron SRCNN, la primera CNN aplicada a superresolución de imagen, con un rendimiento muy superior a métodos previos basados en interpolación tanto en calidad como en eficiencia. SRCNN utilizaba una arquitectura de 3 capas convolucionales para aprender la relación entre patches LR y HR, sirviendo como base para los modelos posteriores.

Más tarde, se profundizó en redes más profundas y eficientes. En 2016, Kim et al. introdujeron VDSR (Very Deep SR), una red de 20 capas parecida a VGG que incorporó aprendizaje residual (skip connections) para facilitar la convergencia. VDSR alcanzó mejoras significativas en precisión respecto a SRCNN, y gracias a la conexión residual podía entrenarse mucho más rápido, hasta 10^4 veces más rápido en convergencia. Otros trabajos notables de esa época incluyen FSRCNN, una variante rápida y compacta de SRCNN, y métodos recursivos profundos como DRCN, que también mejoraron las métricas de calidad.

Todos estos modelos mencionados, priorizaron exactitud numérica sobre fidelidad visual, llevando a que las imágenes superresueltas fueran suaves y no tuvieran un aspecto natural. SRGAN se impuso como un gran cambio: en vez de mejorar el PSNR, generó imágenes más realistas al ojo humano, aunque no coincidan exactamente píxel a píxel con la imagen original. Para ello, SRGAN introdujo la idea de combinar una pérdida adversarial de las GAN con una pérdida perceptual basada en características de alto nivel. En su evaluación, SRGAN obtuvo puntajes de opinión perceptual (MOS) mucho más cercanos a los de las imágenes originales que cualquier método anterior, a pesar de tener valores PSNR algo menores. Este modelo permitió que se desarrollasen nuevos modelos como ESRGAN en 2018 que elimina mejor rtefactos y mejora la función de pérdida.

Desarrollo

SRGAN está compuesto por dos redes principales que se entrenan de forma adversaria: un generador G y un discriminador D.

El generador toma como entrada una imagen de baja resolución (por ejemplo 32×32 píxeles) y produce una versión de alta resolución (por ejemplo 128×128 siendo el factor de escala es 4x). Para lograr esto, G utiliza una arquitectura de red residual profunda inspirada en ResNet . En concreto, el generador de SRGAN contiene múltiples bloques residuales con capas convolucionales de filtros pequeños (3×3) y activaciones PReLU, junto a normalización por lotes. Estos bloques aprenden las características de alto nivel necesarias para recrear los detalles que faltan.

Además, el generador incluye capas de upsampling aprendidas: en lugar de interpolación fija, utiliza capas de pixel shuffle para aumentar la resolución de forma eficiente y sin artefactos.

Gracias a la combinación de convoluciones profundas + bloques residuales + pixel shuffle, el generador puede mapear la imagen de baja resolución a una de alta resolución llenando bordes, texturas y detalles finos de manera coherente.

Por su parte, el discriminador de SRGAN es una CNN que recibe imágenes (ya sean las generadas por el generador o imágenes de alta resolución reales) y aprende a clasificarlas como reales o falsas. La arquitectura del discriminador típicamente consta de varias capas convolucionales con funciones de activación LeakyReLU, seguidas de capas densas hacia la salida que emite la probabilidad de que la imagen sea real.

Un detalle importante es que el discriminador de SRGAN opera a nivel de patches de imagen, lo que le permite concentrarse en patrones locales de textura para determinar la autenticidad. Durante el entrenamiento, el discriminador va mejorando su capacidad para distinguir, lo cual a su vez obliga al generador a producir imágenes cada vez más realistas.

Un aspecto clave de SRGAN es su función de pérdida perceptual, que combina dos términos:

  • Pérdida adversarial: Proveniente de la GAN (minimizando la función de ganancia del discriminador). El generador es penalizado si el discriminador logra distinguir sus imágenes de las reales. De este modo, aprende a engañar produciendo imágenes con apariencias estadísticas similares a las fotos reales.
  • Pérdida de contenido (perceptual): Calculada en un espacio de características de alto nivel. Concretamente, utiliza una red pre-entrenada (VGG19) para extraer características tanto de la imagen generada como de la imagen original, y calcula el error MSE en esas representaciones profundas.
  • Pérdida de contenido (MSE):
  • Pérdida perceptual total:

En resumen, la combinación de la pérdida adversarial y la perceptual ayudan a SRGAN a generar imágenes cada vez más realistas. Durante el entrenamiento, se alterna la optimización del generador (minimizando la pérdida combinada) y el discriminador (maximizando su precisión de clasificación), en un proceso típico de entrenamiento GAN.

Ejemplo cualitativo de SRGAN: Comparativa de una imagen de flores ampliada 4x mediante interpolación bicúbica (arriba izquierda), por una red SRResNet (arriba derecha) optimizada solo con pérdida de contenido (MSE), por SRGAN (abajo izquierda) optimizado con pérdida perceptual adversaria, y la imagen HR original (abajo derecha).

A simple vista, el resultado de SRGAN muestra detalles de textura mucho más realistas (en los pétalos y hojas) que la versión bicúbica, que está más borrosa, acercándose más al aspecto de la imagen original. Esto demuestra cómo la optimización adversarial de SRGAN produce imágenes visualmente más nítidas, incluso cuando las métricas tradicionales como PSNR pueden ser similares a las de métodos bicúbicos. En resumen, SRGAN preserva mejor los bordes y texturas finas que la interpolación estándar, logrando una super-resolución más realista.

Materiales Usados

Este bloque descarga el dataset DIV2K, prepara las rutas, redimensiona las imágenes a baja resolución y las normaliza para alimentar al modelo.

Definición del modelo SRGAN con parámetros clave como altura, anchura y bloques residuales. Se instancian los componentes y se prepara el dataloader.

Implementación del generador con bloques residuales y capas de upsampling (pixel shuffle), y del discriminador con convoluciones que distinguen entre imágenes reales y generadas.

Proceso de entrenamiento por épocas: se generan imágenes, se calculan las pérdidas (GAN y perceptual), y se guarda la evolución de las curvas de pérdida.

Esta celda permite visualizar resultados (input LR, salida generada, ground truth HR) y guardar los pesos y arquitectura del modelo entrenado.

Resultados

Para evaluar el desempeño del modelo SRGAN, se ha aplicado el proceso de superresolución a tres imágenes seleccionadas que representan distintos tipos de contenido visual: un castillo (escena con líneas definidas), un arco chino (estructura con detalles finos), y un hombre (rostro humano con textura suave).

En la imagen del castillo, la versión generada por SRGAN logra restaurar las líneas arquitectónicas con gran fidelidad. Las torres, las ventanas y los detalles en las piedras aparecen más definidos en comparación con la imagen de baja resolución. Se reduce el desenfoque, y se observa una gran mejora en el contraste entre las estructuras del castillo y el cielo. Esto muestra que el modelo es efectivo para restaurar bordes y formas rectilíneas.

Esta imagen representa un desafío mayor por la presencia de ornamentos complejos y patrones decorativos. Aún así, SRGAN consigue recuperar muchos de los detalles, como las curvas y estructuras finas que desaparecen en la imagen de baja resolución. Aunque no se restaura con una precisión perfecta, la imagen generada resulta con muchas más información visual.

La imagen del rostro humano es clave para evaluar la capacidad perceptual del modelo, ya que el ojo humano es muy sensible a las distorsiones en rostros. En este caso, SRGAN reconstruye con éxito las facciones faciales, ojos, nariz y boca con gran naturalidad. A diferencia de la imagen LR, donde los rasgos están borrosos, la versión de SRGAN muestra una textura de piel más definida y una iluminación coherente.

Conclusión

SRGAN ha supuesto un avance enorme en superresolución de imágenes al priorizar la calidad visual sobre métricas como el error promedio. Con su arquitectura GAN y el uso de una pérdida perceptual, genera texturas de alta frecuencia y produce imágenes muy realistas. Modelos posteriores, como ESRGAN, han refinado su rendimiento y estabilidad. Sin embargo, su uso plantea desafíos como la generación de artefactos o la fidelidad en contextos críticos. Aun así, SRGAN ha demostrado que es posible mejorar la calidad de imágenes más allá de los límites físicos de sensores, asentando las bases para nuevas aplicaciones avanzadas en visión por computadora.

Bibliografía

  • Ledig, C., Theis, L., Huszár, F., Caballero, J., Aitken, A. P., Tejani, A., … & Shi, W. (2017). Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network. arXiv preprint arXiv:1609.04802v5. Recuperado de https://arxiv.org/pdf/1609.04802v5

Trabajo realizado por Mónica Fernández, Juan José López, Alberto Sánchez

GANs para traducción Imagen a Imagen: Coloración

INTRODUCCIÓN

Las GANs (o Generative Adversarial Networks) son una familia de modelos de Inteligencia Artificial en los que dos redes neuronales, conocidas como Generador y Discriminador, compiten entre sí siguiendo una dinámica de “policía y falsificador” para generar datos sintéticos, los cuales ofrecen resultados muy prometedores.

Entre los usos de estas redes se encuentran la generación de imágenes, la simulación de datos médicos o la traducción de imagen a imagen. Es sobre esto último sobre lo que nos centraremos a partir de ahora.

Más concretamente, exploraremos la utilidad de un tipo de GANs más avanzado (Conditional GANs) para colorear imágenes en escala de grises, con el posible objetivo de restauración de imágenes históricas.

ESTADO DEL ARTE

GANs y CGANs

Desde su aparición en 2014, las GANs se han impuesto como una de las formas más eficaces de entrenar modelos generativos. Estas se componen de dos redes adversarias:

  • Un generador G, que crea datos sintéticos a partir de ruido.
  • Un discriminador D, que estima la probabilidad de que los datos pertenezcan al dataset de entrenamiento frente a que sean generados por G.

Ambas redes se entrenan simultáneamente en un juego de suma cero, en el que el G aprende la distribución de los datos de entrada para generar salidas lo más factibles posible y D aprende a diferenciar los datos sintéticos de los reales. El Discriminador intenta minimizar sus errores de detección y el Generador intenta maximizarlos para imágenes sintéticas:

Aunque en la práctica rara vez es así, este juego tiene un equilibrio de Nash en el que los datos generados son perfectamente indistinguibles de los reales.

Un problema de las GANs es que, aunque el generador aprende la distribución de los datos de entrada, no tenemos control sobre los datos generados.

Para abordar este problema surgieron las GANs condicionales (CGANs por sus siglas en inglés), que introducen tanto en el generador como en el discriminador una nueva condición como dato de entrada.

Esta condición bien puede ser una etiqueta de clase, una parte de los datos o datos de otro tipo (por ejemplo, usar un prompt de texto para generar imágenes).

En las CGANs, el generador no solo aprende la distribución de los datos de entrada, sino que también genera datos consistentes con la condición de entrada al combinar ésta con la prior (normalmente ruido gaussiano) en un nuevo espacio latente conjunto. El entrenamiento sigue la misma dinámica que en las GANs tradicionales, aunque en la función de pérdida se añade la condición y:

Este tipo de arquitecturas son especialmente eficaces para la traducción de imagen a imagen, en las que dada una imagen de entrada la tarea es generar una imagen relacionada pero con otras características. En nuestro ejemplo, dada una imagen en escala de grises queremos obtener la misma imagen a color.

Pix2Pix

Una red muy conocida en el ámbito de la traducción de imagen a imagen es Pix2Pix.

Esta fue presentada en 2016 como una red de propósito general. Es decir, que la misma arquitectura se puede entrenar para distintas tareas y con distintos dominios de entrada.

Veamos más detalladamente de qué se compone esta red:

Arquitectura del generador

El generador consiste en una U-Net, una red convolucional originalmente desarrollada para la segmentación de imágenes biomédicas. Sigue una estructura codificador-decodificador (capas de reducción para representar la entrada en un espacio latente y capas de expansión para reconstruir la imagen) modificada en el que se hace uso de skip connections para mantener la información más detallada de capas anteriores.

Nota: en este diagrama, x es la imagen de entrada con la condición, e y es la imagen de salida.

Arquitectura del discriminador

Para el discriminador se hace uso de una Patch GAN, que evalúa la imagen en pequeños trozos (patches) y luego calcula la media de todos los trozos para obtener la probabilidad de que la imagen sea real.

Función de pérdida

Sea la función de pérdida de una GAN Condicional:

Pix2Pix añade un nuevo término de regularización que mide la diferencia entre la imágen generada y la imágen original:

Finalmente, se pondera esta regularización L1 y se combina con la función de pérdida de la GAN para obtener la función de coste final.

DESARROLLO

Para nuestra tarea, hemos hecho uso de una red Pix2Pix adaptada para poder entrenarse con cualquier dataset de imágenes.

Primero, tomamos una colección de imágenes (estas será nuestra ground truth) y la duplicamos en otro fichero con las imágenes a escala de grises.

Empezamos haciendo un resample para que las imágenes tengan todas el mismo tamaño (512×512). Después, dividimos en un conjunto de entrenamiento y en uno de test con proporción 80-20 y guardamos las imágenes en un dataset. Ahora que ya tenemos los datos con los que vamos a trabajar, procedemos a la creación del modelo:

Definimos las capas de upsample y downsample:

Definimos el generador:

Y el discriminador:

Por último, definimos sus funciones de pérdida:

Y ya tenemos todo lo necesario para comenzar el entrenamiento.

Hemos entrenado el modelo dos veces para probar la generalidad de la arquitectura:

-Un dataset con 702 fotos de perros

-Un dataset de 2032 fotos de arte

Por motivos prácticos y de limitaciones temporales, entrenamos los modelos con 20 épocas, lo que tardó un par de horas con la T4 de Google Collab. Los resultados los comentaremos a continuación.

RESULTADOS

Probaremos ahora a pasarle nuevas imágenes al modelo. Aquí se muestran algunas comparaciones entre la imagen original (ground truth), y la imagen generada a color a partir de la muestra en escala de grises.

DISCUSIÓN

Teniendo en cuenta las limitaciones del dataset y del entorno de Google Colab (561 imágenes para un entrenamiento con 20 épocas), los resultados son bastante satisfactorios. Más allá de métricas y errores cuantitativos, visualmente se puede apreciar que las imágenes se colorean de forma razonable, incluso cuando ve imágenes ajenas al dataset original. Esto Indica una buena generalización del modelo para fotos de perros y no solo limitada a los datos vistos durante el entrenamiento.

No obstante, las imágenes resultantes son bastante oscuras y con una paleta muy homogénea. Esta escasez de color podría deberse a una falta de datos/épocas durante el entrenamiento o a una falta de diversidad de color en los datos de entrada, y no lo abordaremos aquí. Sin embargo, el problema de la oscuridad se puede mitigar de manera directa, aplicando una transformación logarítmica a las imágenes de salida.

Como podremos comprobar, los resultados han mejorado. Si queremos resultados aún mejores, deberíamos ajustar la transformación logarítmica para cada imagen hasta lograr el resultado óptimo. Por otra parte, el dataset de obras de arte cuenta con más imágenes y una variedad de colores más amplia, así que no encontramos estos problemas en la misma medida.

A la vista de estos resultados, podemos concluir que Pix2Pix es un modelo adecuado para tareas de coloración de imágenes, y que con más recursos es razonable esperar unos resultados mucho mejores.

MATERIALES

BIBLIOGRAFÍA

Aparte de los recursos ya mencionados en el apartado de Materiales:

  • Mirza, M., & Osindero, S. (2014). Conditional Generative Adversarial Nets [Preprint]. arXiv. [Última vez visitado: 15 de mayo 2025] https://arxiv.org/pdf/1411.1784

Este artículo ha sido desarrollado por Jorge Martínez, Sergio Manrique, Lijun Zhou y David Fernández

Colorización de imágenes usando Generative Adversarial Networks

Introducción

A lo largo de este trabajo vamos a intentar llevar a cabo la colorización de imágenes en blanco y negro de manera que se parezcan lo máximo posible a la realidad. Para la realización de esta investigación, hemos decidido utilizar un dataset llamado PETS, que contiene 7390 imágenes de mascotas en diversos ambientes. El motivo que nos llevó a utilizar este dataset es, simplemente, que no hemos encontrado ningún trabajo previo que lo utilizase con esta finalidad. Además, observamos que contenía una gran variedad de imágenes diferentes entre sí, por lo que es apto para el objetivo de esta investigación.

Para la colorización de las imágenes en blanco y negro, hemos utilizado como inspiración el código propuesto en el artículo de Medium llamado Colorizing black & white images with U-Net and Conditional GAN – a tutorial.

Estado del arte

La colorización de imágenes usando sistemas automáticos no es un proceso sencillo por la gran subjetividad de colores que se pueden apreciar en una imagen y el rango de sensibilidad que pueda medir en cada píxel. Con las Generative Adversarial Networks se puede aproximar al problema desde un punto de vista novedoso con grandes resultados.

La arquitectura pix2pix (Isola et al, 2017) de las GAN permite el aprendizaje directo entre la imagen de entrada y la de salida lo que agiliza el proceso y mejora los resultados obtenidos, esto no solo se ha visto reflejado en la colorización de imágenes sino en todos aquellos procesos de aprendizaje automático relativos a imágenes o vídeos.

Kamyar Nazeri, Eric Ng y Mehran Ebrahimi (Nazeri, Ng & Ebrahimi, 2018) crearon las bases de una Deep Convolutional GAN para el proceso de colorear imágenes automáticamente usando como entrada imágenes en escalas de grises de los conjuntos de entrenamientos públicos CIFAR-10 y Places365. La mayor ventaja de este modelo se basa en la función de coste para limitar el entrenamiento y que la parte generadora no cree colores irreales.

Rahul Reddy Pasham, Sameer Md y Ashwini K. (Ashwini, Pasham & Sameer, 2022) también utilizaron GANs en el problema de colorear imágenes y en su caso destacaron las capas de activaciones LeakyReLu y tanh y la capacidad de colorear imágenes a pesar de ser datos no etiquetados.

El mayor reto de las GANS en el proyecto de colorización de imágenes actualmente es la generación precisa de colores.

Desarrollo

LAB

En el espacio LAB (Shariatnia, 2020), al igual que en RGB, cada píxel se representa con tres valores. El primer canal, L, codifica la luminosidad (Lightness) del píxel. El segundo, A, representa la mezcla entre verde y rojo, y el tercero, B, indica la mezcla entre amarillo y azul.

Se utiliza este espacio de color en lugar de RGB porque la imagen que se le proporciona al modelo para entrenar debe estar en blanco y negro. Al usar LAB, se puede enviar directamente el canal correspondiente a la luminosidad, sin necesidad de convertir la imagen a escala de grises. De este modo, el modelo solo necesita predecir los canales A y B. Esto reduce el número de combinaciones posibles: de 256³ (alrededor de 17 millones) en el espacio RGB a 256² (65.536) al predecir únicamente dos canales de color.

GAN

Las GANs (Generative Adversarial Networks) son una red neuronal compuesta por dos modelos que compiten entre sí: un generador, que aprende a crear datos falsos que imitan los datos reales, y un discriminador, que intenta distinguir entre datos reales y generados. 

Ambos se entrenan simultáneamente en un proceso de competencia: el generador mejora para engañar al discriminador, y el discriminador mejora para no ser engañado. Con el tiempo, esta dinámica hace que el generador produzca datos cada vez más realistas.

Si el entrenamiento del generador es muy bueno puede generar imágenes que al discriminador le sean difíciles de clasificar, el objetivo es que la precisión no disminuya a medida que mejora la generación de imágenes (Google Developers, s.f.).

Generador

Nuestro generador U-Net sigue una arquitectura encoder-decoder con skip-connections. Podemos destacar varias cosas de la arquitectura. En primer lugar, el uso de LeakyReLU en la parte del encoder con una slope de 0.2 y de ReLU normal en la parte del decoder (Nazeri, Ng & Ebrahimi, 2018). Por otro lado, el uso de función de activación tanh en la última capa (Isola et al., 2017; Ashwini, Pasham & Sameer, 2022) y, por último, la utilización de Batch Normalization, que nos ayuda a evitar que el entrenamiento de la GAN converja a una serie de parámetros que siempre devuelven el mismo output.  Este escenario se llama mode-collapse o the Helvetica scenario (Nazeri, Ng & Ebrahimi, 2018).

Patch Discriminator

Un Patch Discriminator es un tipo de discriminador usado en GANs (por ejemplo en la arquitectura Pix2Pix) que evalúa si pequeñas subregiones de la imagen parecen realistas.

En lugar de dar un único valor de salida , el Patch Discriminator produce una matriz de valores, donde cada valor indica si una pequeña subregión de la imagen se considera real o falso.

Es una buena idea usarlo para colorización por varios motivos: hace que el discriminador se enfoque en los detalles locales, lo que provoca que el generador acierte en cada parte de la imagen. Además, tiene menos parámetros que un discriminador global y permite un entrenamiento más estable al evaluar diferentes regiones de la imagen.

Función de pérdida

En nuestra función de pérdida, debemos destacar la aplicación de One Sided Label Smoothing; ya que, de esta manera, evitamos que la red emita outputs extremadamente seguros y aprenda mejor a la hora de realizar el entrenamiento (Nazeri, Ng & Ebrahimi, 2018). El smoothing lo realizamos en la etiqueta positiva (pasamos de 1 a 0.9) y la etiqueta negativa la dejamos intacta.

La función de pérdida establece dos modos. El modo vanilla introduce el uso de Binary Cross Entropy con Logistic Loss, mientras que el modo lsgan introduce Mean Squared Error Loss.

Esta función de pérdida guía tanto al discriminador como al generador en su entrenamiento: el discriminador aprende a diferenciar imágenes reales de generadas, mientras que el generador intenta engañarlo generando imágenes que el discriminador clasifique como reales.

Nuestro modelo

El primer paso es obtener las imágenes en el formato adecuado; en este caso, utilizamos imágenes de tamaño 256×256 en el espacio de color LAB en lugar de RGB. 

En el método __init__, se definen e inicializan el generador y el discriminador. Se configuran las pérdidas GAN y L1 (coherencia de color), y se establecen los optimizadores Adam para ambos modelos.

El método optimize gestiona el entrenamiento. Primero, se pasa la imagen en escala de grises al generador, obteniendo fake_color.

Luego, se entrena el discriminador (backward_D):

  • Se le alimentan las imágenes generadas (fake_color), marcadas como “falsas” .
  • Se le alimentan imágenes reales del conjunto de entrenamiento, marcadas como “reales”.
  • Se calcula la pérdida promedio de “falsas” y “reales”, y se retropropaga para actualizar los pesos del discriminador.

A continuación, se entrena el generador (backward_G):

  • Se alimentan al discriminador las imágenes generadas, pero con etiquetas “reales” para calcular la pérdida adversarial (engañar al discriminador).
  • Se calcula la pérdida L1, que mide la diferencia a nivel de píxel con las imágenes reales (multiplicada por 100).
  • La suma de la pérdida adversarial y la L1 es la pérdida total del generador, que se utiliza para actualizar sus pesos mediante retropropagación.

Finalmente, optimize coordina todo el ciclo de entrenamiento: primero genera la predicción, luego optimiza el discriminador y, a continuación, optimiza el generador, repitiendo este proceso para cada lote del conjunto de entrenamiento. Este proceso debe evitar el mode-collapse, un escenario en el que el generador converge a una serie de parámetros que siempre devuelven el mismo output, lo que limita la diversidad de las imágenes generadas (Shariatnia, 2020).
El código entrena el modelo durante 50 épocas utilizando el conjunto de datos de entrenamiento. En cada época, se procesan los lotes (batches) del conjunto de entrenamiento, y en cada iteración, el modelo optimiza tanto el generador como el discriminador. El generador crea imágenes coloreadas a partir de las imágenes en escala de grises, mientras que el discriminador evalúa si las imágenes generadas son reales o no. Las pérdidas de ambos modelos se registran, y cada 350 iteraciones se visualiza el rendimiento del modelo y se imprime el estado de las pérdidas. El objetivo es que, con el tiempo, el generador aprenda a crear imágenes más realistas y el discriminador mejore su capacidad para distinguir entre imágenes reales y generadas.

Materiales

En este apartado, vamos a compartir el código más importante y necesario para realizar esta tarea de colorización de imágenes en blanco y negro.

El generador U-Net de nuestra GAN (se necesita tener instalada la librería PyTorch de Python, entre otras):

class UnetBlock(nn.Module):
    def __init__(self, nf, ni, submodule=None, input_c=None, dropout=False,
                 innermost=False, outermost=False):
        super().__init__()
        self.outermost = outermost
        if input_c is None: input_c = nf
        downconv = nn.Conv2d(input_c, ni, kernel_size=4,
                             stride=2, padding=1, bias=False)
        downrelu = nn.LeakyReLU(0.2, True)
        downnorm = nn.BatchNorm2d(ni)
        uprelu = nn.ReLU(True)
        upnorm = nn.BatchNorm2d(nf)

        if outermost:
            upconv = nn.ConvTranspose2d(ni * 2, nf, kernel_size=4,
                                        stride=2, padding=1)
            down = [downconv]
            up = [uprelu, upconv, nn.Tanh()] #Utilizamos función de activación tanh en la última capa como se indica en Image Colorization using Generative Adversarial Networks
            model = down + [submodule] + up
        elif innermost:
            upconv = nn.ConvTranspose2d(ni, nf, kernel_size=4,
                                        stride=2, padding=1, bias=False)
            down = [downrelu, downconv]
            up = [uprelu, upconv, upnorm]
            model = down + up
        else:
            upconv = nn.ConvTranspose2d(ni * 2, nf, kernel_size=4,
                                        stride=2, padding=1, bias=False)
            down = [downrelu, downconv, downnorm]
            up = [uprelu, upconv, upnorm]
            if dropout: up += [nn.Dropout(0.5)]
            model = down + [submodule] + up
        self.model = nn.Sequential(*model)

    def forward(self, x):
        if self.outermost:
            return self.model(x)
        else:
            return torch.cat([x, self.model(x)], 1)

class Unet(nn.Module):
    def __init__(self, input_c=1, output_c=2, n_down=8, num_filters=64):
        super().__init__()
        unet_block = UnetBlock(num_filters * 8, num_filters * 8, innermost=True)
        for _ in range(n_down - 5):
            unet_block = UnetBlock(num_filters * 8, num_filters * 8, submodule=unet_block, dropout=True)
        out_filters = num_filters * 8
        for _ in range(3):
            unet_block = UnetBlock(out_filters // 2, out_filters, submodule=unet_block)
            out_filters //= 2
        self.model = UnetBlock(output_c, out_filters, input_c=input_c, submodule=unet_block, outermost=True)

    def forward(self, x):
        return self.model(x)

Nuestro Patch Discriminator:

class PatchDiscriminator(nn.Module):
    def __init__(self, input_c, num_filters=64, n_down=3):
        super().__init__()
        model = [self.get_layers(input_c, num_filters, norm=False)]
        model += [self.get_layers(num_filters * 2 ** i, num_filters * 2 ** (i + 1), s=1 if i == (n_down-1) else 2)
                          for i in range(n_down)] 
        model += [self.get_layers(num_filters * 2 ** n_down, 1, s=1, norm=False, act=False)] 
        self.model = nn.Sequential(*model)

    def get_layers(self, ni, nf, k=4, s=2, p=1, norm=True, act=True): 
        layers = [nn.Conv2d(ni, nf, k, s, p, bias=not norm)]          
        if norm: layers += [nn.BatchNorm2d(nf)]
        if act: layers += [nn.LeakyReLU(0.2, True)]
        return nn.Sequential(*layers)

    def forward(self, x):
        return self.model(x)

La función de pérdida:

class GANLoss(nn.Module):
    def __init__(self, gan_mode='vanilla', real_label=0.9, fake_label=0.0): #Aplicamos un One-Sided Label Smoothing como se indica en Image Colorizarion using Generative Adversarial Networks
        super().__init__()
        self.register_buffer('real_label', torch.tensor(real_label))
        self.register_buffer('fake_label', torch.tensor(fake_label))
        if gan_mode == 'vanilla':
            self.loss = nn.BCEWithLogitsLoss()
        elif gan_mode == 'lsgan':
            self.loss = nn.MSELoss()

    def get_labels(self, preds, target_is_real):
        if target_is_real:
            labels = self.real_label
        else:
            labels = self.fake_label
        return labels.expand_as(preds)

    def __call__(self, preds, target_is_real):
        labels = self.get_labels(preds, target_is_real)
        loss = self.loss(preds, labels)
        return loss

La inicialización del modelo y la definición del mismo:

def init_weights(net, init='norm', gain=0.02):

    def init_func(m):
        classname = m.__class__.__name__
        if hasattr(m, 'weight') and 'Conv' in classname:
            if init == 'norm':
                nn.init.normal_(m.weight.data, mean=0.0, std=gain)
            elif init == 'xavier':
                nn.init.xavier_normal_(m.weight.data, gain=gain)
            elif init == 'kaiming':
                nn.init.kaiming_normal_(m.weight.data, a=0, mode='fan_in')

            if hasattr(m, 'bias') and m.bias is not None:
                nn.init.constant_(m.bias.data, 0.0)
        elif 'BatchNorm2d' in classname:
            nn.init.normal_(m.weight.data, 1., gain)
            nn.init.constant_(m.bias.data, 0.)

    net.apply(init_func)
    print(f"model initialized with {init} initialization")
    return net

def init_model(model, device):
    model = model.to(device)
    model = init_weights(model)
    return model

class MainModel(nn.Module):
    def __init__(self, net_G=None, lr_G=2e-4, lr_D=2e-4, #Utilizamos initial learning rate de 2x10-4 como se indica en Image Colorization using Generative Adversarial Networks
                 beta1=0.5, beta2=0.999, lambda_L1=100.): #Utilizamos lambda = 100 y beta1 = 0.5 (para reducir el momento) como indica la misma fuente
        super().__init__()

        self.device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        print(self.device)
        self.lambda_L1 = lambda_L1

        if net_G is None:
            self.net_G = init_model(Unet(input_c=1, output_c=2, n_down=8, num_filters=64), self.device)
        else:
            self.net_G = net_G.to(self.device)
        self.net_D = init_model(PatchDiscriminator(input_c=3, n_down=3, num_filters=64), self.device)
        self.GANcriterion = GANLoss(gan_mode='vanilla').to(self.device)
        self.L1criterion = nn.L1Loss()
        self.opt_G = optim.Adam(self.net_G.parameters(), lr=lr_G, betas=(beta1, beta2))
        self.opt_D = optim.Adam(self.net_D.parameters(), lr=lr_D, betas=(beta1, beta2))

    def set_requires_grad(self, model, requires_grad=True):
        for p in model.parameters():
            p.requires_grad = requires_grad

    def setup_input(self, data):
        self.L = data['L'].to(self.device)
        self.ab = data['ab'].to(self.device)

    def forward(self):
        self.fake_color = self.net_G(self.L)

    def backward_D(self):
        fake_image = torch.cat([self.L, self.fake_color], dim=1)
        fake_preds = self.net_D(fake_image.detach())
        self.loss_D_fake = self.GANcriterion(fake_preds, False)
        real_image = torch.cat([self.L, self.ab], dim=1)
        real_preds = self.net_D(real_image)
        self.loss_D_real = self.GANcriterion(real_preds, True)
        self.loss_D = (self.loss_D_fake + self.loss_D_real) * 0.5
        self.loss_D.backward()

    def backward_G(self):
        fake_image = torch.cat([self.L, self.fake_color], dim=1)
        fake_preds = self.net_D(fake_image)
        self.loss_G_GAN = self.GANcriterion(fake_preds, True)
        self.loss_G_L1 = self.L1criterion(self.fake_color, self.ab) * self.lambda_L1
        self.loss_G = self.loss_G_GAN + self.loss_G_L1
        self.loss_G.backward()

    def optimize(self):
        self.forward()
        self.net_D.train()
        self.set_requires_grad(self.net_D, True)
        self.opt_D.zero_grad()
        self.backward_D()
        self.opt_D.step()

        self.net_G.train()
        self.set_requires_grad(self.net_D, False)
        self.opt_G.zero_grad()
        self.backward_G()
        self.opt_G.step()

El bucle de entrenamiento (con 50 épocas):

def train_model(model, train_dl, epochs, display_every=350):
    data = next(iter(val_dl)) 
    for e in range(epochs):
        loss_meter_dict = create_loss_meters() 
        i = 0                                 
        for data in tqdm(train_dl):
            model.setup_input(data)
            model.optimize()
            update_losses(model, loss_meter_dict, count=data['L'].size(0)) 
            i += 1
            if i % display_every == 0:
                print(f"\nEpoch {e+1}/{epochs}")ç
                print(f"Iteration {i}/{len(train_dl)}")
                log_results(loss_meter_dict) 
                visualize(model, data, save=False) 

model = MainModel()
train_model(model, train_dl, 50)

Resultados

La primera fila son las imágenes que se introducen al generador en blanco y negro. La segunda fila son el resultado de la colorización por parte del generador y la tercera fila son las imágenes originales.

Discusión

Podemos observar que la colorización se ha realizado correctamente en todas las imágenes, aunque existen ligeros defectos en algunas de ellas. En la segunda imagen desde la izquierda, el suelo no se ha coloreado correctamente en ciertas zonas. Por otro lado, en la segunda imagen desde la derecha, el perro presenta una mancha verde en la cabeza. Esto se puede deber a que la imagen presenta una gran cantidad de este color y pueden ocurrir errores por este motivo. Por último, en la imagen de la derecha, parece que se ha aplicado un filtro sepia y el resultado queda entre medias de la imagen real y de la imagen en blanco y negro.

Referencias


Este entrada ha sido realizada por Mario Gutiérrez, Diego Rivero y Alejandro Tapia.

Fusión de Imágenes Visibles e Infrarrojas mediante U-Net: Aplicaciones en Visión Nocturna y Seguridad

1. Introducción

En muchas situaciones reales, como la vigilancia nocturna o la conducción con poca visibilidad, es clave disponer de imágenes que ofrezcan tanto los detalles visuales del espectro visible como la capacidad del infrarrojo para ver en la oscuridad. Sin embargo, por separado, cada tipo de cámara tiene sus limitaciones: las visibles no funcionan bien sin luz y las infrarrojas no muestran bien los contornos ni las texturas. Por eso surge la fusión de imágenes, una técnica que combina lo mejor de ambas para obtener una imagen única, más completa y útil.

Esta fusión consiste en integrar imágenes captadas por distintos sensores para conservar la información más relevante de cada una. Se usa en múltiples ámbitos como la visión nocturna, la seguridad, la medicina o los sistemas de navegación autónoma. El desafío está en combinar esas imágenes sin perder calidad ni introducir errores visuales, algo que no es sencillo.

Las redes neuronales, y en particular U-Net, resultan muy útiles para fusionar imágenes, ya que su estructura en forma de U con conexiones internas permite combinar eficazmente tanto los detalles finos como la forma general de cada imagen.

En este proyecto, vamos a desarrollar un sistema de fusión de imágenes visibles e infrarrojas usando U-Net en TensorFlow. Evaluaremos su rendimiento tanto visualmente como con métricas objetivas como SSIM y PSNR, y compararemos sus resultados frente a métodos clásicos para ver si realmente ofrece una mejora significativa.

2. Estado del arte

La fusión de imágenes ha sido una herramienta clave en el procesamiento de señales. Inicialmente, se utilizaban técnicas matemáticas tradicionales como la transformada wavelet, el análisis de componentes principales (PCA) y la transformada de Laplace. Estas técnicas se basaban en descomponer las imágenes en diferentes componentes para luego combinarlas según ciertos criterios (como, la varianza) pero tenían ciertas limitaciones al preservar simultáneamente detalles finos y estructuras globales.

Con la llegada del aprendizaje profundo, las redes neuronales convolucionales (CNN) revolucionaron este campo. Estas redes pueden aprender automáticamente qué características conservar y cómo combinarlas, sin necesidad de definir reglas manualmente. Esto ha permitido resultados más adaptativos y robustos frente a variaciones en las condiciones de entrada.

En particular, la arquitectura U-Net, ha demostrado ser especialmente eficaz para tareas de procesamiento de imágenes donde es crucial mantener tanto la resolución espacial como el contexto semántico. Su diseño de encoder-decoder con conexiones de salto (skip connections) permite preservar detalles a diferentes escalas. Esto la convierte en una candidata ideal para la fusión de imágenes visibles e infrarrojas.

Investigaciones recientes han adaptado U-Net para esta tarea. Por ejemplo, Zhang et al. (2021) integraron mecanismos de atención para mejorar la selección de características. Ma et al. (2020) destacaron su equilibrio entre calidad y eficiencia computacional. Además, el repositorio IVIF_ZOO ofrece implementaciones de U-Net evaluadas en benchmarks como TNO y RoadScene.

3. Fundamentos matemáticos

U-Net es una arquitectura de red neuronal convolucional que se ha convertido en una herramienta muy versátil en el ámbito del procesamiento de imágenes. Aunque fue concebida originalmente para tareas de segmentación médica, su capacidad para preservar detalles finos mientras captura el contexto global la ha hecho popular en muchos otros escenarios, como la reconstrucción y, en este caso, la fusión de imágenes visibles e infrarrojas.

Su estructura, con forma de “U”, consta de dos partes simétricas:

  • Un codificador (encoder), que realiza una serie de convoluciones y max-pooling para capturar el contexto global de la imagen, reduciendo su resolución.
  • Un decodificador (decoder), que realiza upsampling progresivo (mediante convoluciones transpuestas) para reconstruir una imagen de la misma dimensión original.

Lo más distintivo de esta red son las llamadas conexiones de salto, que permiten transmitir directamente la información desde las capas del codificador a las correspondientes del decodificador. Gracias a estas conexiones, se consigue combinar de forma eficaz tanto los detalles locales como la estructura general de la imagen, algo fundamental cuando se fusionan fuentes tan distintas como el espectro visible y el infrarrojo.

En este proyecto, implementamos U-Net en TensorFlow/Keras para combinar imágenes de dos canales (visible e infrarrojo) en una imagen fusionada de un solo canal. Como no existe una imagen ideal de referencia, se usó como guía la fusión por máximo por píxel entre los dos canales.

Para este proyecto empleamos el dataset LLVIP, una colección específicamente diseñada para condiciones de baja iluminación, que contiene pares de imágenes visibles e infrarrojas capturadas de forma sincronizada. Este conjunto resulta especialmente adecuado para tareas de fusión de imágenes multiespectrales, ya que refleja escenarios reales donde la información visual y térmica debe combinarse para obtener una visión más completa.

La evaluación de los resultados se realizó utilizando dos métricas: SSIM que mide la similitud estructural entre la imagen fusionada y una de las originales, capturando aspectos como el contraste, la luminancia y la textura; y PSNR que cuantifica la fidelidad de la señal en términos de error cuadrático medio. Ambas métricas fueron calculadas respecto a las imágenes visibles e infrarrojas por separado, lo que nos permitió analizar qué tipo de información retiene mejor el modelo en la imagen resultante.

4. Implementación

Para este proyecto se ha utilizado el dataset LLVIP, un conjunto de datos en abierto que contiene imágenes visibles e infrarrojas de personas en entornos con baja iluminación. Las imágenes fueron preprocesadas adaptándolas en tamaño a 256×256 píxeles, normalizadas al rango [0,1], y combinadas como canales de entrada a la red.

El modelo se implementó en TensorFlow/Keras siguiendo una arquitectura U-Net, compuesta por un codificador, un cuello de botella y un decodificador con conexiones de salto. La salida generada es una imagen fusionada a nivel de píxel.

El entrenamiento se llevó a cabo en Google Colab durante 20 épocas, utilizando el optimizador Adam y la función de pérdida MSE. Como métricas de evaluación se emplearon SSIM y PSNR.

Se utilizaron herramientas auxiliares como OpenCV, Matplotlib, Pandas y scikit-image. Todo el código ejecutable y los resultados se encuentran disponibles en el archivo entregado: pasd.zip, que incluye el notebook completo y los ficheros necesarios para su reproducción.

5. Resultados

Para evaluar la calidad de las imágenes fusionadas, se calcularon las métricas SSIM y PSNR comparando cada imagen fusionada con sus respectivas versiones visibles e infrarrojas.

Los valores obtenidos indican que la imagen fusionada conserva principalmente la estructura del canal infrarrojo, lo cual es adecuado para aplicaciones como la visión nocturna.

Sin embargo, también se observa que la similitud con la imagen visible es más baja, lo que sugiere que el modelo tiende a priorizar el contenido térmico. Esto puede ser una ventaja en contextos de vigilancia, pero en aplicaciones donde los detalles visuales sean importantes (como el reconocimiento facial o la navegación autónoma diurna), podría requerir un ajuste de pesos o entrenamiento más equilibrado.

6. Discusión

Los resultados obtenidos muestran que el modelo basado en U-Net es capaz de realizar una fusión efectiva entre imágenes visibles e infrarrojas, preservando especialmente la información térmica, tal como reflejan los altos valores de SSIM y PSNR frente al canal infrarrojo. Este comportamiento es deseable en aplicaciones donde el contenido térmico es prioritario, como en seguridad nocturna o detección de personas en condiciones adversas.

Sin embargo, también se ha observado que la similitud con la imagen visible es notablemente más baja. Este fenómeno puede explicarse por dos razones principales: por un lado, la imagen infrarroja tiende a dominar la estructura global en la fusión; por otro, al utilizarse como supervisión una imagen construida mediante el máximo por píxel entre los dos canales, el modelo tiende a favorecer la información del canal con mayor intensidad, que suele ser el térmico.

Entre las principales limitaciones encontradas destaca el tamaño efectivo del dataset. Aunque LLVIP es una base de datos estándar, el número de imágenes disponibles tras el preprocesado y la división en entrenamiento y prueba puede ser insuficiente para entrenar redes profundas que generalicen bien a nuevas escenas. Además, se ha trabajado con una resolución fija de 256×256 píxeles para simplificar el entrenamiento, lo que puede haber afectado a la calidad visual en detalles finos, como bordes o texturas.

A pesar de los buenos resultados, este trabajo deja abiertas varias vías de mejora. Usar otros datasets como TNO o RoadScene podría aumentar la capacidad de generalización. También se podrían probar funciones de pérdida más perceptuales o modelos como GANs para obtener fusiones más realistas.

Además, sería interesante explorar arquitecturas más avanzadas, como Attention U-Net o redes con ramas separadas para cada canal, e incluso probar con Transformers. Por último, aplicar técnicas de postprocesado ayudaría a mejorar bordes, contraste y detalles finos en las imágenes fusionadas.

7. Conclusiones

En este proyecto hemos abordado la fusión de imágenes visibles e infrarrojas usando redes neuronales profundas, concretamente la arquitectura U-Net. Los resultados muestran que este enfoque permite combinar eficazmente la información visual y térmica, generando imágenes más completas que las captadas por sensores individuales. El modelo, implementado en TensorFlow/Keras y entrenado con el dataset LLVIP, logró buenas puntuaciones en SSIM y PSNR, lo que confirma su efectividad.

8. Referencias

  • Artículos científicos y papers citados
  1. Ronneberger, O., Fischer, P., & Brox, T. (2015): U-Net: Convolutional Networks for Biomedical Image Segmentation https://arxiv.org/abs/1505.04597
  2. Zhang et al. (2021): IFCNN: A general image fusion framework based on convolutional neural network https://doi.org/10.1016/j.inffus.2020.10.011
  3. Ma et al. (2020): Infrared and Visible Image Fusion via Detail-Preserving Deep Neural Network https://doi.org/10.1109/TIP.2020.2972127
  • Datasets
  1. LLVIP Dataset – Low-Light Visible and Infrared Person Dataset
    https://github.com/dawnlh/LLVIP
  • Repositorios relacionados
  1. IVIF_ZOO – Infrared and Visible Image Fusion Models
    https://github.com/RollingPlain/IVIF_ZOO


Trabajo realizado por Julia Galán, Sara Reyes y Silvia Cordero.

PASD 2025.