SRGAN Colmare il Divario tra le Immagini a Bassa e Alta Risoluzione

SRGAN colmare il divario risoluzione immagini

Introduzione

Immagina uno scenario in cui trovi un vecchio album fotografico di famiglia nascosto in una soffitta polverosa. Pulirai immediatamente la polvere e con grande entusiasmo sfoglierai le pagine. E troverai una foto di molti anni fa. Ma ancora, non sarai felice perché l’immagine è sbiadita e sfocata. Sforzerai gli occhi per trovare i volti e i dettagli nella foto. Questo è lo scenario dei tempi passati. Grazie alle nuove tecnologie di oggi, abbiamo la Super-Resolution Generative Adversarial Network (SRGAN) per convertire le immagini a bassa risoluzione in immagini ad alta risoluzione. In questo articolo, impareremo di più su SRGAN e lo implementeremo per il miglioramento del codice QR.

Origine: Vecteezy

Obiettivi di Apprendimento

In questo articolo, impareremo:

  • Cosa è la super risoluzione e come differisce dallo zoom normale
  • Alcuni approcci per la super risoluzione e i loro tipi
  • Approfondiremo gli SRGAN, la loro funzione di perdita, la loro architettura e alcune delle loro applicazioni
  • Implementazione per il miglioramento del codice QR utilizzando SRGAN e una descrizione dettagliata ad esso

Questo articolo è stato pubblicato come parte del Data Science Blogathon.

Cos’è la Super Risoluzione?

In molti film di investigazione criminale, spesso ci troviamo di fronte a uno scenario tipico in cui i detective controllano le registrazioni delle telecamere a circuito chiuso per le prove. E c’è una scena in cui qualcuno trova un’immagine piccola e oscura e la renderà chiara ingrandendola e migliorandola. Pensate sia possibile? Sì, possiamo farlo con l’aiuto della super risoluzione. Le tecniche di super risoluzione possono migliorare le immagini sfocate catturate dalle telecamere a circuito chiuso, fornendo loro immagini più dettagliate.

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

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

Il processo di ingrandimento e miglioramento delle immagini è chiamato Super Risoluzione. Questo implica la generazione di una versione ad alta risoluzione di un’immagine o di un video dal rispettivo input a bassa risoluzione. Lo scopo è di recuperare i dettagli mancanti, migliorare la nitidezza e migliorare la qualità visiva. Se si ingrandisce semplicemente l’immagine senza migliorarla, si otterrà un’immagine sfocata come mostrato nelle immagini sottostanti. Il miglioramento avviene con la super risoluzione. Ha molte applicazioni in molti domini, tra cui la fotografia, i sistemi di sorveglianza, le immagini mediche, le immagini satellitari e molte altre.

………..

Approcci Tradizionali alla Super Risoluzione

Gli approcci tradizionali si concentrano principalmente sull’individuazione dei valori dei pixel mancanti e sul miglioramento della risoluzione dell’immagine. Ci sono due approcci: metodi basati sull’interpolazione e metodi basati sulla regolarizzazione.

Metodi Basati sull’Interpolazione

Nei primi tempi della super risoluzione, si concentravano sui metodi basati sull’interpolazione e lo scopo era di stimare i valori dei pixel mancanti e quindi ingrandire l’immagine. Fanno ciò con l’assunzione che i valori dei pixel vicini avranno valori di pixel simili. Utilizzano questi valori per stimare i valori mancanti. I metodi di interpolazione più comunemente utilizzati includono l’interpolazione bicubica, bilineare e del vicino più vicino. Ma i risultati sono insoddisfacenti. Ciò ha portato a immagini sfocate. Questi metodi sono efficienti nei calcoli, rendendoli adatti per compiti di risoluzione di base e situazioni con risorse di calcolo limitate.

Metodi basati su regolarizzazione

D’altra parte, i metodi basati su regolarizzazione mirano a migliorare i risultati di super-risoluzione introducendo vincoli o priorità aggiuntivi nel processo di ricostruzione dell’immagine. Queste tecniche sfruttano le caratteristiche statistiche dell’immagine per aumentare l’accuratezza delle immagini ricostruite preservando i dettagli fini. Ciò ha fornito maggiore controllo sul processo di ricostruzione e migliora la nitidezza e i dettagli dell’immagine. Ma qui ci sono alcune limitazioni come la gestione di contenuti di immagini complessi che porta a una sovrasmorzatura in alcuni casi.

Anche se questi approcci tradizionali hanno alcune limitazioni, hanno mostrato la strada per la comparsa di potenti metodi per la super-risoluzione.

Fonte: Rapid API

Approcci basati sull’apprendimento per la super-risoluzione

Gli approcci basati sull’apprendimento sono diventati una soluzione potente ed efficace per la super-risoluzione. Ha permesso la generazione di immagini ad alta risoluzione altamente dettagliate. Ci sono due principali approcci basati sull’apprendimento: Super-Risoluzione di Immagini Singole (SISR) e Reti Avversariali Generative (GAN).

Super-Risoluzione di Immagini Singole

La Super-Risoluzione di Immagini Singole si concentra sull’apprendimento di una funzione di mappatura che mappa direttamente da immagini a bassa risoluzione ad immagini ad alta risoluzione. Utilizza reti neurali convoluzionali (CNN). I ricercatori addestrano queste reti utilizzando insiemi di dati su larga scala che includono coppie di immagini a bassa risoluzione e ad alta risoluzione. Queste reti imparano i modelli sottostanti e le relazioni tra le basse risoluzioni e le alte risoluzioni delle immagini in modo che generino risultati di alta qualità. L’architettura dei modelli SISR consiste in un encoder e un decoder.

Qui l’encoder cattura le caratteristiche dell’immagine a bassa risoluzione e poi passa attraverso il decoder per aumentarlo e raffinare quelle caratteristiche per ottenere un’immagine ad alta risoluzione. Le metriche di perdita comunemente utilizzate per misurare la differenza tra immagini reali e generate includono l’errore quadratico medio (MSE) e il rapporto segnale-rumore di picco (PSNR). Minimizzando queste funzioni di perdita durante l’addestramento, la rete imparerà a produrre immagini ad alta risoluzione che mimano da vicino le immagini ad alta risoluzione originali.

Reti Avversariali Generative (GAN)

D’altra parte, le Reti Avversariali Generative (GAN) hanno introdotto un framework di apprendimento avversario e hanno portato progressi nella super-risoluzione. Due parti compongono le GAN. Consistono in una rete discriminatrice e una rete generativa. La rete generativa prende un’immagine a bassa risoluzione in ingresso e cerca di produrre un’uscita ad alta risoluzione. La rete discriminatrice cerca di distinguere tra immagini ad alta risoluzione artificialmente create e immagini ad alta risoluzione effettive. I metodi di super-risoluzione basati su GAN hanno mostrato risultati impressionanti nella generazione di immagini realistiche. In confronto ai metodi tradizionali, sono in grado di catturare modelli complessi e creare texture fini. Super-Resolution Generative Adversarial Networks (SRGAN) è una popolare implementazione di GAN per compiti di super-risoluzione.

Super-Resolution Generative Adversarial Network(SRGAN)

Nel mondo di oggi, le immagini ad alta qualità sono molto importanti in molti domini. Ma non sempre è possibile ottenere immagini ad alta risoluzione a causa di molte limitazioni. Qui diventa rilevante la super-risoluzione. Converte i contenuti a bassa risoluzione in contenuti ad alta risoluzione. Per superare le limitazioni degli approcci tradizionali, sono emersi approcci basati sull’apprendimento per la super-risoluzione, e l’utilizzo di GAN è uno di questi.

SRGAN è una combinazione di reti avversariali generative (GAN) e reti neurali convoluzionali profonde (CNN) e produce immagini ad alta risoluzione altamente realistiche da immagini a bassa risoluzione. Come sappiamo, la rete generativa avversaria (SRGAN) è composta da due parti. Sono un generatore e un discriminatore. Sia il generatore che il discriminatore imparano lavorando l’uno contro l’altro. Come sappiamo, lo scopo del generatore è quello di generare immagini ad alta risoluzione indistinguibili dalle immagini ad alta risoluzione di ground truth. E lo scopo del discriminatore è quello di distinguere le immagini del generatore dalle immagini reali. Questo si chiama addestramento avversario. Il generatore cerca sempre di ingannare il discriminatore generando immagini ad alta risoluzione super realistiche. Impara a catturare i dettagli molto fini e le caratteristiche visive generali dell’immagine. Il discriminatore fornisce un feedback al generatore sulle immagini generate e attraverso la retropropagazione il generatore migliora e cerca di minimizzare la perdita.

Perdita percettiva

Usa la funzione di perdita nel caso di SRGAN, che è la perdita percettiva, la combinazione di due diverse perdite. Sono perdita di contenuto e perdita avversaria.

  • Perdita di contenuto: Prima di SRGAN, si utilizzava l’errore quadratico medio tra y_fake e y_real per calcolare la funzione di perdita. Ma questo approccio perde molte informazioni ad alta frequenza anche se può raggiungere un alto rapporto segnale-rumore. Pertanto, gli autori dell’articolo decidono di optare per la perdita di diverse VGG layer. Le layer di attivazione ReLU della rete VGG pre-addestrata a 19 layer fungono da base per questa perdita VGG che è la distanza euclidea tra le rappresentazioni delle caratteristiche. Dopo l’addestramento, estraiamo una mappa delle caratteristiche da uno specifico layer del modello VGG. La comparazione della mappa delle caratteristiche avviene con l’immagine effettiva.
Fonte: arxiv.org
  • Perdita avversariale: L’utilizzo della perdita avversariale incoraggia il generatore a produrre immagini di super-risoluzione altamente realistiche. Il calcolo della perdita avversariale si basa sulle previsioni fatte dal discriminatore. Il generatore cerca di minimizzare questa perdita, mentre il discriminatore cerca di massimizzarla. Gli SRGAN consentono alla rete generatrice di apprendere e creare immagini super-risolte che sembrano visivamente vere immagini ad alta risoluzione includendo la perdita avversariale.
Fonte: arxiv.org

La perdita complessiva per la super-risoluzione (perdita percettiva) è

Fonte: arxiv.org

Architettura di SRGANs

Architettura del generatore

Inizia prendendo un’immagine a bassa risoluzione come input e invia questa immagine di input attraverso il layer convoluzionale che utilizza 64 filtri di dimensione 9 per 9. Successivamente, la funzione ReLU parametrica la riceve come input. I valori vengono quindi inviati ai blocchi residui, dove le operazioni comuni sono raggruppate insieme, formando un blocco residuo. Questa sequenza di operazioni viene ripetuta per ogni blocco attraversato. All’interno del blocco residuo, abbiamo un layer convoluzionale che utilizza 64 pixel di dimensione 3 per 3. Successivamente, viene applicato il livello di normalizzazione batch alla funzione ReLU parametrica. Questo è seguito da un altro layer convoluzionale, che a sua volta è seguito dalla normalizzazione batch.

Infine, viene eseguita una somma elementare con l’input del blocco residuo. L’output di questo blocco viene inviato al blocco successivo e ripete gli stessi passaggi. Questo continua fino all’ultimo blocco residuo. Come indicato nell’articolo originale degli autori, abbiamo in totale 16 blocchi residui in SRGANs. Lo scopo di questi blocchi residui è di estrarre le caratteristiche dall’immagine di input.

Dopo i blocchi residui, abbiamo un altro layer convoluzionale e un layer di normalizzazione batch. Successivamente, l’output della prima funzione ReLU parametrica è di nuovo sottoposto a una somma elementare. Segue il blocco di aumento della risoluzione in cui avviene lo shuffle dei pixel per aumentare gradualmente la risoluzione dell’immagine. Ha due blocchi di aumento della risoluzione. Termina con un layer convoluzionale e un’immagine di super-risoluzione verrà generata come output.

Fonte: arxiv.org

Architettura del discriminatore

Una rete discriminante è solo una rete neurale convoluzionale di classificazione delle immagini (CNN). È responsabile della differenziazione tra le immagini generate e le vere immagini ad alta risoluzione. Impara a classificare le immagini di input. In primo luogo, viene applicato un layer convoluzionale all’immagine di input, che sia essa una vera immagine ad alta risoluzione o un’immagine generata dal generatore ad alta risoluzione. Questo layer estrae le caratteristiche dall’immagine di input, che vengono quindi passate attraverso la funzione Leaky ReLU. Passato attraverso diversi blocchi discriminanti che contengono un layer convoluzionale, una normalizzazione batch e una Leaky ReLU. Infine, passa attraverso il layer denso seguito da Leaky ReLu e un altro layer denso per ottenere un output. Come sappiamo, si tratta di una classificazione tra le immagini ad alta risoluzione originali e quelle generate dal generatore.

Origine: arxiv.org

Applicazioni di SRGANs

  • Upscaling di immagini e video: La prima e più importante applicazione di SRGANs è l’upscaling di immagini e video. Questo è molto utile in vari campi come i media digitali, l’intrattenimento, ecc. dove la qualità svolge un ruolo importante. SRGANs possono migliorare i dettagli, la nitidezza e la qualità visiva complessiva di contenuti a bassa risoluzione.
  • Sorveglianza e sicurezza: Nella sorveglianza e nella sicurezza, SRGANs sono utilizzati per fornire riprese ad alta risoluzione migliorando le riprese CCTV a bassa risoluzione. Ciò aiuta in una migliore e più rapida indagine migliorando la chiarezza di dettagli importanti come le targhe, le immagini dei sospetti e molti altri.
  • Imaging medico: SRGANs hanno mostrato risultati meravigliosi nel campo dell’imaging medico. Vengono utilizzati per migliorare le immagini mediche a bassa risoluzione, come le scansioni MRI o le immagini ad ultrasuoni, e migliorano l’accuratezza diagnostica. Ottenere immagini ad alta risoluzione ha aiutato i medici a comprendere i dettagli più fini del problema del paziente e questo ha aiutato a fornire migliori trattamenti.
  • Immagini satellitari: Le immagini satellitari hanno sempre una risoluzione più bassa a causa di limitazioni tecniche. Quindi, SRGANs vengono utilizzati per aumentare la risoluzione di queste immagini a bassa risoluzione e ciò ha permesso una migliore analisi e una migliore comprensione delle caratteristiche geografiche, dei modelli meteorologici e di molti altri.

Implementazione per l’Enhancement QR utilizzando SRGANs

In questo progetto, utilizzeremo SRGANs per l’implementazione. Questo progetto riguarda il miglioramento del codice QR dove un’immagine a bassa risoluzione e sfocata di un codice QR verrà passata come input e il nostro modello fornirà un’immagine chiara ad alta soluzione del codice QR.

Puoi scaricare il dataset di codici QR qui.

Iniziamo importando alcune librerie necessarie.

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

Installa tutti i pacchetti mancanti utilizzando pip.

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

Ora iteriamo sui file in una directory, leggiamo un file immagine utilizzando OpenCV e lo visualizziamo utilizzando matplotlib. Quindi, innanzitutto, assegniamo il percorso in cui sono memorizzate le immagini. Interrompiamo il ciclo dopo una sola iterazione. Quindi verrà visualizzata solo un’immagine.

datadir = r'path-to-dataset'
# iteriamo solo su 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  

Creare i dati di formazione

Ora dobbiamo elaborare tutte le immagini nella directory e creare i dati di formazione. Per questo, dobbiamo dichiarare due liste: array e array_small. Questi vengono inizializzati per memorizzare le immagini ridimensionate. Il modulo ‘tqdm’ viene importato per visualizzare una barra di avanzamento durante l’iterazione delle immagini. Nella funzione create_training_data, itereremo su ogni immagine nella directory. Per ogni immagine, prima la leggeremo utilizzando imread () e quindi la ridimensioneremo a (128,128) usando le funzioni resize (). Quindi, aggiungere l’immagine ridimensionata all’elenco di array. E quindi ridimensionarlo a (32,32) e aggiungerlo all’elenco di array_small. Ripeti il processo per ogni immagine nella directory.

array = []
array_small =[]
from tqdm import tqdm
def create_training_data():
        for img in tqdm(list(os.listdir(datadir))):  # iteriamo su ogni immagine per cani e gatti
            try:
                img_array = cv2.imread(datadir+'/'+img ,cv2.IMREAD_COLOR)  # convertire in array
                new_array = cv2.resize(img_array, (128, 128))  # ridimensionare per normalizzare la dimensione dei dati
                array.append([new_array]) 
                array_small.append([cv2.resize(img_array, (32,32),
                               interpolation=cv2.INTER_AREA)]) # aggiungi questo ai nostri dati di formazione
            except Exception as e:  # nell'interesse di mantenere pulita l'output...
                pass
create_training_data()
Fonte: Autore

Troviamo la lunghezza dell’array. Ciò significa che abbiamo un totale di 10000 immagini.

len(array)

#10000

Per verificare se i passaggi di elaborazione e ridimensionamento dell’immagine sono riusciti, dobbiamo creare altre due liste vuote: X e Xs. E aggiungere tutte le immagini ad alta risoluzione a X e le immagini a bassa risoluzione a Xs. Quindi tracciare una figura con entrambe le immagini ad alta e bassa risoluzione. Prima di ciò, converti entrambe le liste in array.

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()

Data Augmentation

Aumentiamo tutti i dati che abbiamo. Possiamo usare ImageDataGenerator() per creare immagini aumentate. Dopo aver creato le immagini, ridimensionarle e salvarle in una directory separata.

#aumentiamo i dati
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

Dobbiamo creare dati di formazione per le immagini aumentate in modo simile a come abbiamo fatto per i dati originali. E poi creare altre due liste: X1 e Xs1 per memorizzare i dati aumentati e quindi tracciare la figura per capire. Quindi concatenare le liste di dati originali e le liste di dati aumentati.

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

È ora di dividere tutti i nostri dati in set di formazione e di convalida. La test_size rappresenta che il 33% dei dati dovrebbe essere allocato al set di convalida, mentre il 67% è allocato al set di formazione. random_state imposta il seme casuale per garantire la riproducibilità della divisione.

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

Definire il Generatore

Costruiamo il generatore. Quindi definire prima il blocco residuale che è un blocco fondamentale in molte architetture di deep learning. Quindi definisci il blocco di aumento che è responsabile dell’aumento della risoluzione del tensore di input. Infine, definisci un generatore che prende 3 parametri di input. Sono l’input e i parametri aggiuntivi res_range e upscale_range che controllano il numero di blocchi residui e blocchi di aumento nella rete, rispettivamente.

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)

Definire il Discriminatore

Ora costruiamo la seconda parte della GAN, ovvero il discriminatore. In primo luogo viene definito il blocco del discriminatore, ovvero un blocco convoluzionale utilizzato nel discriminatore. Successivamente, viene definita la rete del discriminatore. Prende un tensore di input e costruisce l’architettura del discriminatore. Applica una convoluzione 2D con 64 filtri e una dimensione del kernel di (3,3), applica la funzione di attivazione LeakyReLU, aggiunge alcuni blocchi del discriminatore, appiattisce il tensore di output, applica uno strato completamente connesso con 1024 unità, applica la funzione di attivazione LeakyReLU con un alpha di 0,2, ed emette un’unica unità con una funzione di attivazione sigmoide, rappresentando l’output del discriminatore. Infine, la funzione restituisce un oggetto ‘Model’ Keras con i tensori di input e di output.

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)

Definire il Modello VGG

Il nostro prossimo passo è costruire un modello VGG. Inizializza un modello VGG19 pre-addestrato sul dataset ImageNet utilizzando la funzione VGG19. Infine, la funzione restituisce un oggetto Model Keras con i tensori di input e di output.

Poi dobbiamo creare un modello combinato con il generatore, il discriminatore e i livelli VGG19. Prende in input il modello generatore, il modello discriminatore, il modello VGG19, l’input a bassa risoluzione e l’input ad alta risoluzione. Passa l’input a bassa risoluzione attraverso il modello generatore per generare un output ad alta risoluzione. Successivamente, il modello VGG19 (vgg) viene utilizzato per estrarre le caratteristiche dall’immagine ad alta risoluzione generata. Il modello del discriminatore viene impostato come non addestrabile in quanto l’intenzione è di addestrare solo la parte generatrice del modello. La validità dell’immagine generata viene calcolata passando l’immagine generata (gen_img) attraverso il modello del discriminatore (disc_model). Unendo i livelli del generatore, del discriminatore e del VGG19, il modello risultante può essere utilizzato per addestrare il generatore a produrre immagini ad alta risoluzione

#introduzione del livello 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)


# Definizione del modello combinato
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])

Costruzione di SRGAN

Crea ora il generatore finale della rete. Per farlo, imposta tutti gli input, costruisci un generatore, un discriminatore e un livello VGG19, e infine crea il modello combinato (modello GAN). Quindi, impostare la forma delle immagini di addestramento ad alta risoluzione, ovvero y_train, e la forma delle immagini di addestramento a bassa risoluzione, ovvero X_train. Quindi, utilizzando le funzioni generator e discriminator, creare il generatore e il discriminatore rispettivamente. Creare un livello VGG19 utilizzando la funzione build_vgg. Infine, usando la funzione create_comb, creare un modello GAN. Il modello GAN combina il generatore, il discriminatore e i livelli VGG19 in un singolo modello per l’addestramento.

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 SRGAN utilizzando la funzione di perdita di entropia incrociata binaria e la funzione di perdita di errore quadratico medio e l’ottimizzatore Adam. Utilizzare la prima funzione di perdita per l’output del discriminatore (validità) e utilizzare la seconda funzione di perdita per l’output del generatore (gen_features).

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

Dividi i dati di addestramento in batch per l’addestramento del modello SRGAN. Sono stati creati due elenchi vuoti, train_lr_batches e train_hr_batches, per memorizzare rispettivamente i batch di immagini a bassa risoluzione e ad alta risoluzione. All’interno del ciclo, viene estratto il batch di immagini ad alta risoluzione (y_train[start_idx:end_idx]) dal dataset y_train e aggiunto all’elenco train_hr_batches. Allo stesso modo, il batch di immagini a bassa risoluzione (X_train[start_idx:end_idx]) viene estratto dal dataset X_train e aggiunto all’elenco train_lr_batches.

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

Addestramento

Il nostro prossimo passo è l’addestramento di questo modello SRGAN. Iterare il numero di volte specificato dall’utente per la variabile epochs. Creare fake_label, che è un array numpy riempito di zeri, che rappresenta le etichette per le immagini false (generate), e real_label, che è un array numpy riempito di uno, che rappresenta le etichette per le immagini reali. Quindi, sono stati creati due elenchi vuoti, g_losses e d_losses, per memorizzare rispettivamente le perdite del generatore e del discriminatore.

In questo processo, il generatore genera immagini false e addestra il discriminatore utilizzando sia le immagini false che quelle reali. La rete VGG è responsabile dell’estrazione delle caratteristiche dalle immagini ad alta risoluzione. Dopo aver iterato attraverso tutti i batch, calcoliamo le perdite medie del generatore e del discriminatore. L’addestramento del modello SRGAN avviene aggiornando il discriminatore e il generatore in modo avversario e tracciando le loro perdite.

epochs = 1
#Enumerate training over epochs
for e in range(epochs):
    
    fake_label = np.zeros((batch_size, 1)) 
    real_label = np.ones((batch_size,1))
    
    g_losses = []
    d_losses = []
    
    #Enumerate training over batches.
    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("epoca:", e+1 ,"g_loss:", g_loss, "d_loss:", d_loss)

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

Salvare il modello generatore addestrato.

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

Test

Il nostro ultimo passo è verificare il nostro SRGAN. Ora utilizziamo il modello generatore addestrato per produrre immagini ad alta risoluzione e confrontarle con le immagini a bassa risoluzione e ad alta risoluzione originali.

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('Immagine a bassa risoluzione')
plt.imshow(src_image[0,:,:,:], cmap = 'gray')
plt.subplot(232)
plt.title('Immagine a super-risoluzione')
plt.imshow(cv2.cvtColor(gen_image[0,:,:,:], cv2.COLOR_BGR2GRAY),cmap = 'gray')
plt.subplot(233)
plt.title('Immagine ad alta risoluzione originale')
plt.imshow(tar_image[0,:,:,:], cmap = 'gray')

plt.show()

Conclusione

Abbiamo implementato con successo SRGAN per l’ottimizzazione dei codici QR. Il risultato che abbiamo ottenuto qui è dopo solo una epoca. Possiamo osservare il cambiamento nelle risoluzioni, ha quasi raggiunto l’immagine ad alta risoluzione originale. Immagina se avessimo addestrato per almeno 10 epoche. Questo è il potere di SRGAN. SRGAN è emerso come un cambiamento di gioco nel campo della super-risoluzione delle immagini. Questi sono i modelli più avanzati e potenti per la generazione di immagini ad alta risoluzione.

Punti Chiave

  • SRGAN (Super-Resolution Generative Adversarial Networks) è un approccio all’avanguardia per le attività di super-risoluzione.
  • Utilizza la perdita percettiva che è una combinazione di perdita di contenuto e perdita avversaria. Ciò aiuta a generare immagini ad alta risoluzione altamente realistiche.
  • Ricercatori e sviluppatori hanno accesso a modelli SRGAN pre-addestrati come ESRGAN, SRResNet e SRGAN (originale). Utilizza questi modelli per le loro attività affinandoli.
  • Finora abbiamo acquisito molte conoscenze riguardo a SRGAN e abbiamo anche visto il potere di SRGAN implementandolo per l’ottimizzazione dei codici QR e i risultati sono eccezionali.
  • Mentre i ricercatori continuano a esplorare e modificare l’architettura, le funzioni di perdita e le strategie di addestramento di SRGAN, possiamo aspettarci risultati ancora più impressionanti in futuro.

Domande frequenti

Se hai domande, contattami su LinkedIn.

I media mostrati in questo articolo non sono di proprietà di Analytics Vidhya e sono utilizzati a discrezione dell’autore.