SRGANs Acortando la Brecha Entre Imágenes de Baja y Alta Resolución

SRGANs Reducing the Gap Between Low and High Resolution Images.

Introducción

Imagina un escenario en el que encuentras un álbum de fotos antiguas de la familia escondido en un ático polvoriento. Inmediatamente limpiarás el polvo y con gran emoción pasarás las páginas. Y encontraste una foto de hace muchos años. Pero aún así, no estás contento porque la imagen está descolorida y borrosa. Forzarás tus ojos para encontrar los rostros y detalles en la imagen. Este es el escenario de antaño. Gracias a las nuevas tecnologías de hoy en día tenemos la Red Generativa Antagónica de Super-Resolución (SRGAN) para convertir imágenes de baja resolución en imágenes de alta resolución. En este artículo, aprenderemos más sobre SRGAN e implementaremos su uso para mejorar los códigos QR.

Fuente: Vecteezy

Objetivos de aprendizaje

En este artículo, aprenderemos:

  • Sobre la super-resolución y cómo es diferente del zoom normal
  • Algunos enfoques para la super-resolución y sus tipos
  • A profundizar en SRGAN, su función de pérdida, su arquitectura y algunas de sus aplicaciones
  • La implementación para la mejora de QR utilizando SRGAN y una descripción detallada del proceso

Este artículo fue publicado como parte del Data Science Blogathon.

¿Qué es la Super Resolución?

En muchas películas de investigación criminal, a menudo nos encontramos con un escenario típico en el que los detectives revisan las imágenes de las cámaras de seguridad para encontrar evidencia. Y hay una escena en la que alguien encuentra una imagen pequeña y oculta y la hace más clara acercándola y mejorándola. ¿Crees que es posible? Sí, podemos hacerlo con la ayuda de la super-resolución. Las técnicas de super-resolución pueden mejorar las imágenes borrosas capturadas por las cámaras de seguridad, proporcionándoles detalles visuales más detallados.

…………………………………………………………………………………………………………………………………………………………..

…………………………………………………………………………………………………………………………………………………………..

El proceso de aumentar la resolución y mejorar las imágenes se llama Super Resolución. Consiste en generar una versión de alta resolución de una imagen o video a partir de una entrada de baja resolución. El objetivo es recuperar detalles faltantes, mejorar la nitidez y mejorar la calidad visual. Si solo acercas la imagen sin mejorarla, obtendrás una imagen borrosa como se muestra en las imágenes de abajo. La mejora tiene lugar con la super-resolución. Tiene muchas aplicaciones en muchos dominios, incluyendo fotografía, sistemas de vigilancia, imágenes médicas, imágenes satelitales y muchos más.

………..

Enfoques tradicionales para la Super Resolución

Los enfoques tradicionales se centran principalmente en estimar los valores de píxeles faltantes y mejorar la resolución de la imagen. Existen dos enfoques: métodos basados en interpolación y métodos basados en regularización.

Métodos basados en Interpolación

En los primeros días de la super-resolución, se centraron en los métodos basados en interpolación y el objetivo es estimar los valores de píxeles faltantes y luego ampliar la imagen. Hacer esto con la suposición de que los valores de píxeles vecinos tendrán valores de píxeles similares. Usa estos valores para estimar los valores faltantes. Los métodos de interpolación más comúnmente utilizados incluyen la interpolación bicúbica, bilineal y de vecino más cercano. Pero los resultados son insatisfactorios. Esto llevó a imágenes borrosas. Estos métodos son eficientes para calcular, lo que los hace adecuados para tareas básicas de resolución y situaciones con recursos computacionales limitados.

Métodos basados en Regularización

Por otro lado, los métodos basados en regularización tienen como objetivo mejorar los resultados de la super-resolución introduciendo restricciones adicionales o prioridades en el proceso de reconstrucción de la imagen. Estas técnicas aprovechan las características estadísticas de una imagen para aumentar la precisión de las imágenes reconstruidas mientras se preservan los detalles finos. Esto ha proporcionado un mayor control sobre el proceso de reconstrucción y mejora la nitidez y los detalles de la imagen. Pero aquí hay algunas limitaciones como el manejo de contenido de imagen complejo porque esto conduce a una sobre suavización en algunos casos.

A pesar de que estos enfoques tradicionales tienen algunas limitaciones, mostraron un camino para la aparición de métodos poderosos para la super-resolución.

Fuente: Rapid API

Enfoques basados en el Aprendizaje para la Super-resolución

Los enfoques basados en el aprendizaje se han convertido en una solución poderosa y efectiva para la super-resolución. Esto ha permitido la generación de imágenes de alta resolución altamente detalladas. Hay dos enfoques principales basados en el aprendizaje: Super-Resolución de una sola imagen (SISR) y Redes Generativas Antagónicas (GANs).

Super-Resolución de una sola imagen

La Super-Resolución de una sola imagen se centra en aprender una función de asignación que mapea directamente de imágenes de baja resolución a alta resolución. Utiliza redes neuronales convolucionales (CNNs). Los investigadores entrenan estas redes utilizando conjuntos de datos a gran escala que incluyen pares de imágenes de baja resolución y alta resolución. Estas redes aprenden los patrones subyacentes y las relaciones entre las bajas y altas resoluciones de las imágenes para que generen resultados de alta calidad. La arquitectura de los modelos SISR consiste en un codificador y un decodificador.

Aquí, el codificador captura la característica de la imagen de baja resolución y luego se pasa a través del decodificador para aumentarla y refinar esas características para obtener una imagen de alta resolución. Las métricas de pérdida comúnmente utilizadas para medir la diferencia entre imágenes reales y generadas incluyen el Error Cuadrático Medio (MSE) y la Relación Señal-Ruido Pico (PSNR). Al minimizar estas funciones de pérdida durante el entrenamiento, la red aprenderá a producir imágenes de alta resolución que imiten de cerca las imágenes de alta resolución originales.

Redes Generativas Antagónicas (GANs)

Por otro lado, las Redes Generativas Antagónicas (GANs) han introducido un marco de aprendizaje antagónico y han traído avances en la super-resolución. Dos partes conforman las GANs. Consisten en una red discriminadora y una red generadora. La red generadora toma una imagen de baja resolución como entrada e intenta producir una salida de alta resolución. La red discriminadora se esfuerza por distinguir entre imágenes de alta resolución creadas artificialmente e imágenes de alta resolución reales. Los métodos de super-resolución basados en GAN han mostrado resultados impresionantes en la generación de imágenes realistas. En comparación con los métodos tradicionales, son más capaces de capturar patrones complejos y crear texturas finas. Super-Resolution Generative Adversarial Networks (SRGANs) es una implementación popular de GANs para tareas de super-resolución.

Red Generativa Antagónica de Super-Resolución (SRGAN)

En el mundo actual, las imágenes de alta calidad son muy importantes en muchos dominios. Pero no siempre es posible tomar imágenes de alta resolución debido a muchas limitaciones. Aquí es donde la super-resolución se volvió relevante. Convierte el contenido de baja resolución en contenido de alta resolución. Para superar las limitaciones de los enfoques tradicionales, han surgido enfoques de super-resolución basados en el aprendizaje, y el uso de GAN es uno de ellos.

SRGAN es una combinación de redes generativas antagónicas (GANs) y redes neuronales convolucionales profundas (CNNs) y produce imágenes de alta resolución altamente realistas a partir de imágenes de baja resolución. Como sabemos, Generative Adversarial Network (SRGAN) consta de dos partes. Son un generador y un discriminador. Tanto el generador como el discriminador aprenden trabajando uno contra el otro. Como sabemos, el objetivo del generador es generar imágenes de alta resolución que sean indistinguibles de las imágenes de alta resolución de referencia. Y el objetivo del discriminador es distinguir las imágenes del generador de las imágenes reales. Esto se llama Entrenamiento Antagónico. El generador siempre intenta engañar al discriminador generando imágenes de alta resolución súper realistas. Aprende a capturar los detalles muy finos y las características visuales generales de la imagen. El discriminador proporciona retroalimentación al generador sobre las imágenes generadas y, a través de la retropropagación, el generador aprende mejor y trata de minimizar la pérdida.

Pérdida Perceptual

Utilice la función de pérdida en el caso de SRGANs que es Pérdida Perceptual, la combinación de dos pérdidas diferentes. Son la pérdida de contenido y la pérdida adversaria.

  • Pérdida de Contenido: Antes de SRGAN, se utilizaba el error cuadrático medio entre y_fake e y_real para calcular la función de pérdida. Pero este enfoque pierde mucha información de alta frecuencia incluso si puede lograr una alta relación señal-ruido. Como resultado, los autores del documento deciden utilizar la pérdida de varias capas de VGG. Las capas de activación ReLU de la red VGG pre-entrenada de 19 capas actúan como base para esta pérdida de VGG, que es la distancia euclidiana entre representaciones de características. Después del entrenamiento, extraemos un mapa de características de una capa específica del modelo VGG. La comparación del mapa de características ocurre con la imagen real.
Fuente: arxiv.org
  • Pérdida Adversaria: El uso de la pérdida adversaria anima al generador a producir imágenes de super-resolución altamente realistas. El cálculo de la pérdida adversaria se basa en las predicciones hechas por el discriminador. El generador intenta minimizar esta pérdida, mientras que el discriminador intenta maximizarla. SRGANs permiten que la red generadora aprenda y cree imágenes super-resueltas que se ven visualmente como imágenes de alta resolución reales al incluir la pérdida adversaria.
Fuente: arxiv.org

La pérdida general para la super-resolución (pérdida perceptual) es

Fuente: arxiv.org

Arquitectura de SRGANs

Arquitectura del Generador

Comienza tomando una imagen de baja resolución como entrada y envía esta imagen de entrada a través de la capa de convolución que utiliza 64 filtros de tamaño 9 por 9. A continuación, la función ReLU paramétrica la recibe como entrada. Los valores se envían luego a los bloques residuales, donde las operaciones comunes se agrupan juntas, formando un bloque residual. Esta secuencia de operaciones se repite para cada bloque por el que pasa. Dentro del bloque residual, tenemos una capa de convolución que utiliza 64 píxeles de tamaño 3 por 3. Después de la ReLU paramétrica, se aplica una capa de normalización de lotes. Esto es seguido por otra capa de convolución, que a su vez es seguida por normalización de lotes.

Finalmente, se realiza una suma de elementos con la entrada del bloque residual. La salida de este bloque se envía al siguiente bloque y repite los mismos pasos. Esto continúa hasta el último bloque residual. Como se menciona en el documento original de los autores, tenemos un total de 16 bloques residuales en SRGANs. El propósito de estos bloques residuales es extraer características de la imagen de entrada.

Después de los bloques residuales, tenemos otra capa de convolución y una capa de normalización de lotes. A continuación, la salida de la primera función ReLU paramétrica se somete nuevamente a una suma de elementos. Luego viene el bloque de aumento de muestreo donde ocurre el reordenamiento de píxeles para aumentar gradualmente la resolución de la imagen. Tiene dos bloques de aumento de muestreo. Termina con una capa de convolución y se generará una imagen de super-resolución como salida.

Fuente: arxiv.org

Arquitectura del Discriminador

Una red discriminadora es solo una red neuronal convolucional de clasificación de imágenes (CNN). Es responsable de diferenciar entre las imágenes de alta resolución generadas y las imágenes de alta resolución reales. Aprende a clasificar las imágenes de entrada. En primer lugar, se aplica una capa de convolución a la imagen de entrada, ya sea una imagen de alta resolución real o una imagen de alta resolución generada por el generador. Esta capa extrae características de la imagen de entrada, que luego se pasan a través de la función Leaky ReLU. Pasado por varios bloques del discriminador que contienen una capa de convolución, normalización de lotes y Leaky ReLU. Finalmente, se pasa a través de la capa densa seguida de Leaky ReLu y otra capa densa para obtener una salida. Como sabemos, es una clasificación entre las imágenes de alta resolución originales y las imágenes de alta resolución generadas por el generador.

Fuente: arxiv.org

Aplicaciones de SRGANs

  • Ampliación de Imágenes y Vídeos: La primera y más importante aplicación de SRGANs es la ampliación de imágenes y vídeos. Esto es muy útil en varios campos como los medios digitales, el entretenimiento, etc. donde la calidad juega un papel importante. Los SRGANs pueden mejorar los detalles, la nitidez y la calidad visual general del contenido de baja resolución.
  • Vigilancia y Seguridad: En la vigilancia y seguridad, se utilizan SRGANs para proporcionar imágenes de alta resolución al mejorar las imágenes de CCTV de baja resolución. Esto ayuda en una investigación mejor y más rápida al mejorar la claridad de detalles importantes como las matrículas, las imágenes de los sospechosos y muchos más.
  • Imágenes Médicas: Los SRGANs han mostrado resultados maravillosos en el campo de la imagen médica. Se utilizan para mejorar imágenes médicas de baja resolución, como imágenes de resonancia magnética o ecografías, y mejorar la precisión del diagnóstico. Obtener imágenes de alta resolución ayudó a los médicos a entender los detalles más finos del problema del paciente y esto ayudó a proporcionar mejores tratamientos.
  • Imágenes Satelitales: Las imágenes satelitales siempre tienen una resolución más baja debido a limitaciones técnicas. Por lo tanto, se utilizan SRGANs para aumentar la resolución de estas imágenes de baja resolución y esto permitió un mejor análisis y una mejor comprensión de las características geográficas, los patrones climáticos y muchos más.

Implementación para la Mejora de QR utilizando SRGANs

En este proyecto, utilizaremos SRGANs para la implementación. Este proyecto trata sobre la mejora de códigos QR donde se pasará una imagen de baja resolución y borrosa de un código QR como entrada y nuestro modelo dará una imagen clara de alta solución del código QR.

Puede descargar el conjunto de datos de códigos QR aquí .

Comencemos importando algunas bibliotecas necesarias.

import tensorflow as tf
import numpy as np
import pandas as pd
import cv2 
import os
import matplotlib.pyplot as plt
from keras.models import Sequential
from keras import layers, Model
from sklearn.model_selection import train_test_split
from keras import Model
from keras.layers import Conv2D
from keras.layers import PReLU
from keras.layers import BatchNormalization
from keras.layers import Flatten
from keras.layers import UpSampling2D
from keras.layers import LeakyReLU
from keras.layers import Dense
from keras.layers import Input
from keras.layers import add
from tqdm import tqdm

Instale todos los paquetes faltantes usando pip.

!pip install opencv-python
!pip install tqdm
!pip install scikit-image

Ahora itere sobre los archivos en un directorio, lea un archivo de imagen usando OpenCV y muéstrela usando matplotlib. Primero, asigne la ruta donde se almacenan las imágenes. Romperemos el ciclo después de una iteración. Por lo tanto, solo se mostrará una imagen.

datadir = r'ruta-al-conjunto-de-datos'
# iterando solo sobre un elemento
for img in os.listdir(datadir): 
        img_array = cv2.imread(os.path.join(datadir,img) ,cv2.IMREAD_GRAYSCALE) 
        plt.imshow(img_array, cmap='gray') 
        plt.show()  

        break  

Crear Datos de Entrenamiento

Ahora tenemos que procesar todas las imágenes en el directorio y crear datos de entrenamiento. Para ello, tenemos que declarar dos listas: array y array_small. Estas se inicializan para almacenar imágenes redimensionadas. Se importa el módulo ‘tqdm’ para mostrar una barra de progreso mientras se itera sobre las imágenes. En la función create_training_data, iteraremos sobre cada imagen en el directorio. Para cada imagen, primero la leeremos usando imread() y luego la redimensionaremos a (128,128) usando las funciones resize(). Luego, agregue la imagen redimensionada a la lista de arrays. Y luego rediménsionela a (32,32) y agréguela a la lista array_small. Repita el proceso para cada imagen en el directorio.

array = []
array_small =[]
from tqdm import tqdm
def create_training_data():
        for img in tqdm(list(os.listdir(datadir))):  # iterar sobre cada imagen por perros y gatos
            try:
                img_array = cv2.imread(datadir+'/'+img ,cv2.IMREAD_COLOR)  # convertir a array
                new_array = cv2.resize(img_array, (128, 128))  # redimensionar para normalizar el tamaño de los datos
                array.append([new_array]) 
                array_small.append([cv2.resize(img_array, (32,32),
                               interpolation=cv2.INTER_AREA)]) # añadir esto a nuestros datos de entrenamiento
            except Exception as e:  # en interés de mantener la salida limpia...
                pass
create_training_data()
Fuente: Autor

Encontremos la longitud del arreglo. Esto significa que tenemos un total de 10000 imágenes.

len(array)

#10000

Para verificar si los pasos de procesamiento y cambio de tamaño de imagen son exitosos, necesitamos crear dos listas vacías más: X y Xs. Y agregar todas las imágenes de alta resolución a X y las imágenes de baja resolución a Xs. Luego, graficar una figura con imágenes de alta y baja resolución. Antes de eso, convertir ambas listas en arreglos.

X =  []
Xs = []
for features in array:
    X.append(features)
for features in array_small:
    Xs.append(features)
plt.figure(figsize=(16, 8))
X = np.array(X).reshape(-1, 128, 128, 3)
Xs = np.array(Xs).reshape(-1, 32, 32, 3)
plt.subplot(231)
plt.imshow(X[0], cmap = 'gray')
plt.subplot(233)
plt.imshow(Xs[0], cmap = 'gray')
plt.show()

Aumento de datos

Aumentemos todos los datos que tenemos. Podemos usar ImageDataGenerator() para crear imágenes aumentadas. Después de crear las imágenes, cambiar su forma y guardarlas en un directorio separado.

#aumentando los datos
from tensorflow.keras.preprocessing.image import ImageDataGenerator 
from skimage import io
datagen = ImageDataGenerator(        
        rotation_range = 40,
        shear_range = 0.2,
        zoom_range = 0.2,
        horizontal_flip = True,
        brightness_range = (0.5, 1.5))

for a in X:
 i = 0
 a = a.reshape((1, ) + a.shape)
 for batch in datagen.flow(a, batch_size=1,  save_to_dir= r'C:\Users\Admin\Downloads\QR\augmented', 
 save_prefix='ag', save_format='png'):    
  try:
    i += 1   
    if i>= 10:
      break 
  except Exception:
    print("error")
    pass

Tenemos que crear datos de entrenamiento para imágenes aumentadas similares a cómo lo hemos hecho para los datos originales. Y luego, crear dos listas más: X1 y Xs1 para almacenar datos aumentados y luego graficar la figura para entender. Luego, concatenar las listas de datos originales y las listas de datos aumentados.

array=[]
array_small=[]
datadir = r'C:\Users\Admin\Downloads\QR\augmented'
create_training_data()

X1 =  []
Xs1 = []
for features in array:
    X1.append(features)
for features in array_small:
    Xs1.append(features)
X1 = np.array(X1).reshape(-1, 128, 128, 3)
Xs1 = np.array(Xs1).reshape(-1, 32, 32, 3)
plt.figure(figsize=(16, 8))
plt.subplot(231)
plt.imshow(X1[0], cmap = 'gray')
plt.subplot(233)
plt.imshow(Xs1[0], cmap = 'gray')
plt.show()

X=np.concatenate((X,X1), axis = 0)
Xs=np.concatenate((Xs,Xs1), axis=0)
X.shape

Es hora de dividir nuestros datos en conjuntos de entrenamiento y validación. El test_size representa que el 33% de los datos deben asignarse al conjunto de validación, mientras que el 67% se asigna al conjunto de entrenamiento. El random_state establece la semilla aleatoria para garantizar la reproducibilidad de la división.

from sklearn.model_selection import train_test_split
X_train,X_valid,y_train, y_valid = train_test_split(Xs, X, test_size = 0.33, random_state = 12)
X_train.shape

Definir generador

Construyamos el generador. Primero, definamos el bloque residual, que es un bloque de construcción fundamental en muchas arquitecturas de aprendizaje profundo. Luego, defina el bloque de aumento, que es responsable de aumentar la resolución del tensor de entrada. Finalmente, defina un generador que tome 3 parámetros de entrada. Son input y los parámetros adicionales res_range y upscale_range que controlan el número de bloques residuales y bloques de aumento en la red, respectivamente.

def res_block(input_dim):
    model = Conv2D(64, (3,3), padding = 'same' )(input_dim)
    model = BatchNormalization()(model)
    model = PReLU(shared_axes = [1,2])(model)
    model = Conv2D(64, (3,3), padding = 'same' )(model)
    model = BatchNormalization()(model)
    return add([input_dim, model])
def upscale_block(input_dim):
    model = Conv2D(256,(3,3), strides=1, padding = 'same')(input_dim)
    model = UpSampling2D(size = (2,2))(model)
    model = PReLU(shared_axes=[1, 2])(model)
    return model
def generator(input, res_range = 1,upscale_range=1):
    model = Conv2D(64,(9,9), strides=1, padding = 'same')(input)
    model = PReLU(shared_axes = [1,2])(model)
    model1 = model
    for i in range(res_range):
        model = res_block(model)
    model = Conv2D(64, (3,3), padding = 'same' )(model)
    model = BatchNormalization()(model)
    model = add([model,model1])
    for i in range(upscale_range):
        model  =upscale_block(model)
    output = Conv2D(3, (9,9),  padding='same')(model)
    return Model(input, output)

Definir Discriminador

Ahora construyamos la segunda parte del GAN, que es el discriminador. En primer lugar, se define el bloque del discriminador, que es un bloque convolucional utilizado en el discriminador. A continuación, se define la red del discriminador. Toma un tensor de entrada y construye la arquitectura del discriminador. Se aplica una convolución 2D con 64 filtros y un tamaño de kernel de (3, 3), se aplica la función de activación LeakyReLU, se agregan algunos bloques del discriminador, se aplana el tensor de salida, se aplica una capa completamente conectada con 1024 unidades, se aplica la función de activación LeakyReLU con un alpha de 0.2 y se produce una unidad única con la función de activación sigmoide, que representa la salida del discriminador. Finalmente, la función devuelve un objeto ‘Model’ de Keras con los tensores de entrada y salida.

def discrim_block(input_dim, fmaps = 64, strides = 1):
    model = Conv2D(fmaps, (3,3), padding = 'same', strides  = strides)(input_dim)
    model = BatchNormalization()(model)
    model = LeakyReLU()(model)
    return model
def discriminator(input):
    model = Conv2D(64,(3,3),padding='same')(input)
    model = LeakyReLU()(model)
    model = discrim_block(model, strides = 2)
    model = discrim_block(model, fmaps  = 128)
    model = discrim_block(model, fmaps = 128, strides = 2)
    model = discrim_block(model, fmaps=256)
    model = discrim_block(model, fmaps=256, strides=2)
    model = discrim_block(model, fmaps=512)
    model = discrim_block(model, fmaps=512, strides=2)
    model = Flatten()(model)
    model = Dense(1024)(model)
    model = LeakyReLU(alpha = 0.2)(model)
    out = Dense(1, activation='sigmoid')(model)
    return Model(input, out)

Definir Modelo VGG

Nuestro siguiente paso es construir un modelo VGG. Inicializa un modelo VGG19 pre-entrenado en el conjunto de datos ImageNet utilizando la función VGG19. Finalmente, la función devuelve un objeto Model de Keras con los tensores de entrada y salida.

Luego tenemos que crear un modelo combinado con el generador, el discriminador y las capas VGG19. Toma las entradas: el modelo generador, el modelo discriminador, el modelo VGG19, la entrada de baja resolución y la entrada de alta resolución. Pasa la entrada de baja resolución a través del modelo generador para generar una salida de alta resolución. A continuación, se utiliza el modelo VGG19 (vgg) para extraer características de la imagen de alta resolución generada. El modelo del discriminador se establece como no entrenable, ya que la intención es entrenar solo la parte del modelo generador. La validez de la imagen generada se calcula pasando la imagen generada (gen_img) a través del modelo del discriminador (disc_model). Al combinar las capas del generador, el discriminador y VGG19, el modelo resultante se puede utilizar para entrenar el generador para producir imágenes de alta resolución.

#introduciendo la capa vgg19
from tensorflow.keras.applications.vgg19 import VGG19
def build_vgg(hr_shape):
    vgg = VGG19(weights="imagenet", include_top=False, input_shape=hr_shape)

    return Model(inputs=vgg.inputs, outputs=vgg.layers[10].output)


# Definir modelo combinado
def create_comb(gen_model, disc_model, vgg, lr_ip, hr_ip):
    gen_img = gen_model(lr_ip)

    gen_features = vgg(gen_img)

    disc_model.trainable = False
    validity = disc_model(gen_img)

    return Model(inputs=[lr_ip, hr_ip], outputs=[validity, gen_features])

Construyendo SRGAN

Ahora crea la red generadora final. Para ello, establece todas las entradas, construye un generador, discriminador y una capa VGG19, y finalmente crea el modelo combinado (modelo GAN). Primero establece la forma de las imágenes de entrenamiento de alta resolución, que es y_train, y establece la forma de las imágenes de entrenamiento de baja resolución, que es X_train. Luego, utilizando las funciones del generador y del discriminador, crea el generador y el discriminador, respectivamente. Crea una capa VGG19 utilizando la función build_vgg. Finalmente, utilizando la función create_comb, crea un modelo GAN. El modelo GAN combina el generador, el discriminador y las capas VGG19 en un solo modelo para el entrenamiento.

hr_shape = (y_train.shape[1], y_train.shape[2], y_train.shape[3])
lr_shape = (X_train.shape[1], X_train.shape[2], X_train.shape[3])

lr_ip = Input(shape=lr_shape)
hr_ip = Input(shape=hr_shape)

generator = generator(lr_ip, res_range = 16, upscale_range=2)
generator.summary()

discriminator = discriminator(hr_ip)
discriminator.compile(loss="binary_crossentropy", optimizer="adam", metrics=['accuracy'])
discriminator.summary()

vgg = build_vgg((128,128,3))
print(vgg.summary())
vgg.trainable = False

gan_model = create_comb(generator, discriminator, vgg, lr_ip, hr_ip)

Compila el SRGAN utilizando la entropía cruzada binaria y las funciones de pérdida de error cuadrático medio y el optimizador Adam. Utiliza la primera función de pérdida para la salida del discriminador (validez) y utiliza la segunda función de pérdida para la salida del generador (gen_features).

gan_model.compile(loss=["binary_crossentropy", "mse"], loss_weights=[1e-3, 1], optimizer="adam")
gan_model.summary()

Divide los datos de entrenamiento en lotes para entrenar el modelo SRGAN. Creamos dos listas vacías, train_lr_batches y train_hr_batches, para almacenar los lotes de imágenes de baja resolución y alta resolución, respectivamente. Dentro del bucle, se extrae el lote de imágenes de alta resolución (y_train[start_idx:end_idx]) del conjunto de datos y se agrega a la lista train_hr_batches. De manera similar, se extrae el lote de imágenes de baja resolución (X_train[start_idx:end_idx]) del conjunto de datos X_train y se agrega a la lista train_lr_batches.

tamaño_lote = 1  
train_lr_batches = []
train_hr_batches = []
for it in range(int(y_train.shape[0] / tamaño_lote)):
    start_idx = it * tamaño_lote
    end_idx = start_idx + tamaño_lote
    train_hr_batches.append(y_train[start_idx:end_idx])
    train_lr_batches.append(X_train[start_idx:end_idx])

Entrenamiento

Nuestro siguiente paso es entrenar este modelo SRGAN. Iteramos el número de épocas. Creamos fake_label, que es una matriz numpy llena de ceros, que representa las etiquetas para las imágenes falsas (generadas), y real_label, que es una matriz numpy llena de unos, que representa las etiquetas para las imágenes reales. Luego, se crean dos listas vacías, g_losses y d_losses, para almacenar las pérdidas del generador y del discriminador, respectivamente.

Durante este proceso, el generador genera imágenes falsas y entrena el discriminador utilizando tanto las imágenes falsas como las imágenes reales. La red VGG es responsable de extraer características de las imágenes de alta resolución. Después de iterar a través de todos los lotes, calculamos las pérdidas promedio del generador y del discriminador. El entrenamiento del modelo SRGAN se realiza actualizando el discriminador y el generador de manera adversa y realizando un seguimiento de sus pérdidas.

épocas = 1
#Enumeramos el entrenamiento por épocas
for e in range(épocas):
    
    fake_label = np.zeros((tamaño_lote, 1)) 
    real_label = np.ones((tamaño_lote,1))
    
    g_losses = []
    d_losses = []
    
    #Enumeramos el entrenamiento por lotes.
    for b in tqdm(range(len(train_hr_batches))):
        lr_imgs = train_lr_batches[b]
        hr_imgs = train_hr_batches[b] 
        
        fake_imgs = generator.predict_on_batch(lr_imgs) 
        
        discriminator.trainable = True
        d_loss_gen = discriminator.train_on_batch(fake_imgs, fake_label)
        d_loss_real = discriminator.train_on_batch(hr_imgs, real_label)
        
        discriminator.trainable = False
        d_loss = 0.5 * np.add(d_loss_gen, d_loss_real) 
        image_features = vgg.predict(hr_imgs)
        g_loss, _, _ = gan_model.train_on_batch([lr_imgs, hr_imgs], [real_label, image_features])
        d_losses.append(d_loss)
        g_losses.append(g_loss)
        
    g_losses = np.array(g_losses)
    d_losses = np.array(d_losses)
    
    g_loss = np.sum(g_losses, axis=0) / len(g_losses)
    d_loss = np.sum(d_losses, axis=0) / len(d_losses)
    
    print("época:", e+1 ,"g_loss:", g_loss, "d_loss:", d_loss)

    if (e+1) % 5 == 0:
        generator.save("gen_e_"+ str(e+1) +".h5")

Guarda el modelo del generador entrenado.

generator.save("generator"+ str(e+1) +".h5")

Pruebas

Nuestro último paso es comprobar nuestro SRGAN. Ahora usemos el modelo del generador entrenado para producir imágenes de super-resolución y compararlas con las imágenes de baja resolución y de alta resolución originales.

from tensorflow.keras.models import load_model
from numpy.random import randint

[X1, X2] = [X_valid, y_valid]
ix = randint(0, len(X1), 1)
src_image, tar_image = X1[ix], X2[ix]
gen_image = generator.predict(src_image)

plt.figure(figsize=(16, 8))
plt.subplot(231)
plt.title('Imagen de baja resolución')
plt.imshow(src_image[0,:,:,:], cmap = 'gray')
plt.subplot(232)
plt.title('Imagen de super-resolución')
plt.imshow(cv2.cvtColor(gen_image[0,:,:,:], cv2.COLOR_BGR2GRAY),cmap = 'gray')
plt.subplot(233)
plt.title('Imagen de alta resolución original')
plt.imshow(tar_image[0,:,:,:], cmap = 'gray')

plt.show()

Conclusión

Hemos implementado con éxito SRGAN para el mejoramiento de códigos QR. El resultado que obtuvimos aquí es después de solo una época. Podemos observar el cambio en las resoluciones, casi alcanzó la imagen original de alta resolución. Imagina si hubiéramos entrenado durante al menos 10 épocas. Ese es el poder de los SRGAN. Los SRGAN han surgido como un cambio de juego en el campo de la super-resolución de imágenes. Estos son los modelos más avanzados y poderosos para generar imágenes de súper resolución.

Aspectos destacados

  • Los SRGANs (Generative Adversarial Networks de súper resolución) son un enfoque de vanguardia para tareas de super-resolución.
  • Utiliza la pérdida perceptual que es una combinación de pérdida de contenido y pérdida adversarial. Esto ayuda a generar imágenes de alta resolución altamente realistas.
  • Los investigadores y desarrolladores tienen acceso a modelos SRGAN pre-entrenados como ESRGAN, SRResNet y SRGAN (original). Utiliza estos modelos para sus tareas afinándolos.
  • Hasta ahora, hemos adquirido mucho conocimiento sobre SRGANs y también vimos el poder de SRGAN al implementarlo para mejoras en QR y los resultados son sobresalientes.
  • A medida que los investigadores continúan explorando y modificando la arquitectura, las funciones de pérdida y las estrategias de entrenamiento de los SRGANs, podemos esperar resultados aún más impresionantes en el futuro.

Preguntas frecuentes

Si tienes alguna consulta, por favor contáctame en LinkedIn.

Los medios mostrados en este artículo no son propiedad de Analytics Vidhya y se utilizan a discreción del autor.

We will continue to update Zepes; if you have any questions or suggestions, please contact us!

Share:

Was this article helpful?

93 out of 132 found this helpful

Discover more

Inteligencia Artificial

Investigadores de Apple y CMU revelan el Aprendiz de IU Sin Fin Revolucionando la accesibilidad de las aplicaciones a través del Aprendizaje Automático Continuo

El aprendizaje automático se está integrando cada vez más en una amplia gama de campos. Su uso generalizado se extien...

Aprendizaje Automático

Entrena un Modelo de Lenguaje Grande en una sola GPU de Amazon SageMaker con Hugging Face y LoRA.

Esta publicación está coescrita con Philipp Schmid de Hugging Face. Todos hemos escuchado sobre el progreso en el cam...

Inteligencia Artificial

Predicción Conformal para la Clasificación de Aprendizaje Automático Desde Cero

Esta publicación de blog está inspirada en el libro de Chris Molner Introducción a la Predicción Conformal con Python...

Inteligencia Artificial

Google DeepMind utilizó un gran modelo de lenguaje para resolver un problema matemático insoluble

Tuvieron que desechar la mayor parte de lo que producían, pero había oro entre la basura.

Inteligencia Artificial

Una Bendición y un Monstruo Los Anunciantes Aceptan Cautelosamente la Inteligencia Artificial

Muchos anuncios son más fáciles de hacer con la tecnología en constante mejora. También representa una amenaza para u...

Ciencia de Datos

La guía de campo de datos sintéticos

Si quieres trabajar con datos, ¿cuáles son tus opciones? Aquí tienes una respuesta lo más general posible podrías obt...