Allena il tuo primo modello GAN! -Parliamo di Gans

Contenuti

Questo articolo è stato pubblicato nell'ambito del Blogathon sulla scienza dei dati

“Generative Adversarial Networks è l'idea più interessante degli ultimi dieci anni in Machine Learning” – Yann LeCun

introduzione

comprensione matematica e pratica di esso, ma prima, se vuoi dare un'occhiata alle basi di GAN, puoi continuare con il seguente link:

Let’s Talk about GANs

La maggior parte dei giganti della tecnologia (come Google, Microsoft, Amazon, eccetera.) stanno lavorando duramente per applicare i GAN all'uso pratico, alcuni di questi casi d'uso sono:

  1. Adobe: usando GAN per il tuo Photoshop di nuova generazione.
  2. Google: utilizzando GAN per la generazione del testo.
  3. IBM: uso del GAN ​​per l'aumento dei dati (per generare immagini sintetiche per addestrare i tuoi modelli di classificazione).
  4. Scatta Chat / Tic toc: per creare più filtri immagine (che potresti aver già visto).
  5. Disney: uso di GAN per la super risoluzione (miglioramento della qualità del video) per i tuoi film.

Qualcosa di speciale nei GAN è che queste aziende dipendono da loro per il loro futuro., Non credi??

Quindi, Cosa ti impedisce di acquisire la conoscenza di questa tecnologia epica? ti rispondo, qualunque, hai solo bisogno di un vantaggio e questo articolo lo farebbe. Discutiamo prima la matematica dietro Generator e Discriminator.

Operazione matematica del discriminatore:

L'unico scopo del Discriminatore è classificare le immagini vere e false. Per la classificazione, utilizza una rete neurale convoluzionale (CNN) tradizionale con una specifica funzione di costo. Il processo di formazione del discriminatore funziona come segue:

88437discriminatore-2252383
Fonte: deeplearning.ai

Dove X e Y sono rispettivamente caratteristiche ed etichette di input, l'uscita è rappresentata da (?) e i parametri di rete sono rappresentati da (?).

I GAN di addestramento necessitano di una serie di immagini di addestramento e delle rispettive etichette, queste immagini come funzionalità di input vanno alla CNN, con un set di parametri inizializzati. Questa CNN genera output moltiplicando la matrice del peso (W) con caratteristiche di ingresso (X) e aggiungendo un bias (B) su di esso e convertendolo in una matrice non lineare passandolo a una funzione di attivazione.

Questo output è noto come output previsto., quindi la perdita viene calcolata in base ai parametri di peso che vengono regolati nella rete per ridurre al minimo la perdita.

Funzionamento matematico del generatore:

L'obiettivo del generatore è generare un'immagine falsa dalla distribuzione data (set di immagini), lo fa con la seguente procedura:

42922generatore-1051664
Fonte: deeplearning.ai

Viene passato un insieme di vettori di input (rumore casuale) attraverso la rete neurale del generatore, che crea un'immagine completamente nuova moltiplicando la matrice del peso del generatore con il rumore in ingresso.

Questa immagine generata funziona come input per il discriminatore che è addestrato a classificare immagini false e reali.. Quindi la perdita viene calcolata per le immagini generate, in base a quali parametri vengono aggiornati per il generatore finché non otteniamo una buona precisione.

Una volta che siamo soddisfatti della precisione del generatore, Salviamo i pesi del Generatore ed eliminiamo il Discriminatore dalla rete, e usiamo quella matrice di peso per generare più nuove immagini passandole ogni volta una matrice di rumore casuale diversa.

Perdita di entropia incrociata binaria per GAN:

Per ottimizzare i parametri GAN, abbiamo bisogno di una funzione di costo che dica alla rete quanto deve migliorare semplicemente calcolando la differenza tra il valore effettivo e quello previsto. La funzione di perdita utilizzata nei GAN è chiamata entropia incrociata binaria ed è rappresentata come:

76148screenshot202021-05-2220at203-57-2320pm-8133743
Fonte: deeplearning.ai

Dove m è la dimensione del lotto, e(io) è il valore effettivo del tag, h è il valore dell'etichetta previsto, X(io) è la caratteristica di ingresso e rappresenta il parametro.

Dividiamo questa funzione di costo in sottoparti per capire meglio. La formula data è la combinazione di due termini in cui uno viene utilizzato quando è efficace quando l'etichetta è “0” e l'altro è importante quando l'etichetta è “1”. Il primo termine è:

14807screenshot202021-05-2220at204-08-1220pm-9857183
Fonte: deeplearning.ai

se il valore reale è “1” e il valore previsto è “~ 0” in questo caso, dal log (~ 0) tende all'infinito negativo o molto alto, e se il valore previsto è anche “~ 1”, poi il log ( ~ 1) sarebbe vicino a “0” o molto meno, quindi questo termine aiuta a calcolare la perdita per i valori dell'etichetta “1”.

53011screenshot202021-05-2220at204-08-2320pm-7031126
Fonte: deeplearning.ai

Se il valore effettivo è “0” e il valore previsto è “~ 1”, quindi accedi (1- (~ 1)) risulterebbe in infinito negativo o molto alto, e se il valore previsto è “~ 0”, allora il termine produrrebbe risultati "~ 0" o molto meno perdite, quindi questo termine viene utilizzato per i valori dei tag effettivi "0".

Qualsiasi termine di perdita restituirebbe valori negativi nel caso in cui la previsione fosse sbagliata, la combinazione di questi termini si chiama entropia (perdita logaritmica). Ma visto che è negativo, per renderlo maggiore di "1" applichiamo un segno negativo (può essere visto nella formula principale), applicare questo segno negativo è cosa fa Entropia incrociata (perdita logaritmica negativa).

Addestriamo il primo modello GAN:

Creeremo un modello GAN che potrebbe generare cifre scritte a mano dalla distribuzione dei dati MNIST utilizzando il modulo PyTorch.

Primo, importiamo i moduli richiesti:

%matplotlib in linea
importa numpy come np
importare la torcia
importa matplotlib.pyplot come plt

Quindi leggeremmo i dati dal sottomodulo fornito da PyTorch chiamato set di dati.

# numero di sottoprocessi da utilizzare per il caricamento dei dati
num_lavoratori = 0
# quanti campioni per batch caricare
batch_size = 64
# convertire i dati in torcia.FloatTensor
transform = trasforma.ToTensor()
# ottenere i set di dati di allenamento
train_data = set di dati.MNIST(radice="dati", treno=Vero,
                                   download=Vero, trasformare=trasformare)
# preparare il caricatore di dati
train_loader = torch.utils.data.DataLoader(train_data, batch_size=batch_size,
                                           num_workers=num_workers)

Visualizza i dati

Dal momento che creeremmo il nostro modello nel framework PyTorch che utilizza i tensori, trasformeremmo i nostri dati in tenditori torcia. Se vuoi visualizzare i dati, puoi andare avanti e utilizzare il seguente frammento di codice:

# ottenere un batch di immagini di allenamento
dataiter = iter(train_loader)
immagini, etichette = dataiter.next()
immagini = immagini.numpy()
# ottieni un'immagine dal batch
img = np.squeeze(immagini[0])
fig = plt.figure(dimensione del fico = (3,3)) 
ax = fig.add_subplot(111)
ax.imshow(img, cmap='grigio')
64254screenshot202021-05-2320at2012-39-2020pm-6073823
Fonte: Udacity.com

discriminato

Ora è il momento di definire la rete dei discriminatori, che è la combinazione di diversi strati della CNN.

import torcia.nn come nn
import torcia.nn.funzionale come F
discriminatore di classe(nn.Modulo):
    def __init__(se stesso, input_size, nascosto_dime, output_size):
        super(Discriminatore, se stesso).__dentro__()
        # definire livelli lineari nascosti
        self.fc1 = nn.Lineare(input_size, nascosto_dim*4)
        self.fc2 = nn.Lineare(nascosto_dim*4, nascosto_dim*2)
        self.fc3 = nn.Lineare(nascosto_dim*2, nascosto_dime)
        # strato finale completamente connesso
        self.fc4 = nn.Lineare(nascosto_dime, output_size)
        # strato di eliminazione
        self.dropout = nn.dropout(0.3)
    def avanti(se stesso, X):
        # immagine piatta
        x = x.vista(-1, 28*28)
        # tutti i livelli nascosti
        x = F.leaky_relu(self.fc1(X), 0.2) # (ingresso, pendenza_negativa=0.2)
        x = self.dropout(X)
        x = F.leaky_relu(self.fc2(X), 0.2)
        x = self.dropout(X)
        x = F.leaky_relu(self.fc3(X), 0.2)
        x = self.dropout(X)
        # strato finale
        out = self.fc4(X)
        tornare fuori

Il codice sopra segue la tradizionale architettura Python orientata agli oggetti. fc1, fc2, fc3, fc3 sono i livelli completamente connessi. Quando passiamo le nostre entità di input, passa attraverso tutti questi livelli a partire da fc1, Alla fine, abbiamo un livello di abbandono che viene utilizzato per affrontare il problema del sovradattamento.

Nello stesso codice, vedrai una funzione chiamata forward (se stesso, X), questa funzione è l'implementazione dell'effettivo meccanismo di propagazione in avanti in cui ogni strato (fc1, fc2, fc3 e fc4) è seguito da una funzione trigger (saltando_relu ) per convertire l'output del liner in non lineare.

Modello del generatore

Dopo di che, verificheremo il segmento Generator di GAN:

generatore di classe(nn.Modulo):
    def __init__(se stesso, input_size, nascosto_dime, output_size):
        super(Generatore, se stesso).__dentro__()
        # definire livelli lineari nascosti
        self.fc1 = nn.Lineare(input_size, nascosto_dime)
        self.fc2 = nn.Lineare(nascosto_dime, nascosto_dim*2)
        self.fc3 = nn.Lineare(nascosto_dim*2, nascosto_dim*4)
        # strato finale completamente connesso
        self.fc4 = nn.Lineare(nascosto_dim*4, output_size)
        # strato di eliminazione
        self.dropout = nn.dropout(0.3)
    def avanti(se stesso, X):
        # tutti i livelli nascosti
        x = F.leaky_relu(self.fc1(X), 0.2) # (ingresso, pendenza_negativa=0.2)
        x = self.dropout(X)
        x = F.leaky_relu(self.fc2(X), 0.2)
        x = self.dropout(X)
        x = F.leaky_relu(self.fc3(X), 0.2)
        x = self.dropout(X)
        # strato finale con tanh applicato
        out = F.tanh(self.fc4(X))
        tornare fuori

Anche la rete del generatore è costruita dagli strati completamente connessi, Funzioni Leaky Relu Trigger e Dropout. L'unica cosa che lo rende diverso da Discriminator è che l'output dipende dal parametro output_size (qual è la dimensione dell'immagine da generare).

Ottimizzazione degli iperparametri

Gli iperparametri che useremo per addestrare i GAN sono:

# Iperparametri discriminatori
# Dimensione dell'immagine in ingresso al discriminatore (28*28)
input_size = 784
# Dimensione dell'uscita del discriminatore (Vero o falso)
d_output_size = 1
# Dimensione dell'ultimo livello nascosto nel discriminatore
d_hidden_size = 32
# Iperparami del generatore
# Dimensione del vettore latente da dare al generatore
z_size = 100
# Dimensione dell'uscita del discriminatore (immagine generata)
g_output_size = 784
# Dimensione del primo livello nascosto nel generatore
g_hidden_size = 32

Crea un'istanza dei modelli

E infine, l'intera rete sarebbe simile a questo:

# istanziare discriminatore e generatore
D = discriminatore(input_size, d_hidden_size, d_output_size)
G = Generatore(z_size, g_hidden_size, g_output_size)
# controlla che siano come ti aspetti
Stampa(D)
Stampa( )
Stampa(G)

99398screenshot202021-05-2320at2012-35-1020pm-3329328
Fonte: Udacity.com

Calcola perdite

Abbiamo definito il Generatore e il Discriminatore ora è il momento di definire le tue perdite in modo che quelle reti migliorino nel tempo. Per il GAN ​​avremmo due perdite reali di funzione di perdita e una falsa perdita che si definirebbe così:

# Calcola perdite
def real_loss(D_out, liscio=Falso):
    batch_size = D_out.size(0)
    # levigatura dell'etichetta
    se liscio:
        # liscio, etichette reali = 0.9
        etichette = torch.ones(dimensione del lotto)*0.9
    altro:
        etichette = torch.ones(dimensione del lotto) # etichette reali = 1
    # perdita numericamente stabile
    criterio = nn.BCEWithLogitsLoss()
    # calcolare la perdita
    perdita = criterio(D_out.squeeze(), etichette)
    perdita di ritorno
def fake_loss(D_out):
    batch_size = D_out.size(0)
    etichette = torcia.zero(dimensione del lotto) # etichette false = 0
    criterio = nn.BCEWithLogitsLoss()
    # calcolare la perdita
    perdita = criterio(D_out.squeeze(), etichette)
    perdita di ritorno

Ottimizzatori

Una volta definite le perdite, sceglieremmo un ottimizzatore adatto per l'allenamento:

importa torch.optim come optim
# Ottimizzatori
lr = 0.002
# Crea ottimizzatori per il discriminatore e il generatore
d_optimizer = optim.Adam(D.parametri(), lr)
g_optimizer = optim.Adam(G.parametri(), lr)

Formazione modello

Poiché abbiamo definito Generator e Discriminator entrambe le reti, le sue funzioni di perdita come ottimizzatori, ora useremmo i tempi e altre caratteristiche per allenare tutta la rete.

importa sottaceti come pkl
# iperparametri di allenamento
num_epoche = 100
# tenere traccia della perdita e generato, "impostore" campioni
campioni = []
perdite = []
print_ogni = 400
# Ottieni alcuni dati fissi per il campionamento. Queste sono immagini che si tengono
# costante durante l'allenamento, e ci permettono di ispezionare le prestazioni del modello
sample_size=16
fixed_z = np.random.uniform(-1, 1, taglia=(misura di prova, z_size))
fixed_z = torcia.from_numpy(fixed_z).galleggiante()
# allenare la rete
D.train()
G.treno()
per epoca in gamma(num_epoche):
    per batch_i, (real_images, _) in enumerare(train_loader):
        batch_size = real_images.size(0)
        ## Importante passaggio di ridimensionamento ## 
        immagini_reali = immagini_reali*2 - 1  # ridimensionare le immagini di input da [0,1) a [-1, 1)
        # ============================================
        #            FORMARE IL DISCRIMINATORE
        # ============================================
        d_optimizer.zero_grad()
        # 1. Allenati con immagini reali
        # Calcola le perdite del discriminatore su immagini reali 
        # liscia le vere etichette
        D_reale = D(real_images)
        d_real_loss = real_loss(D_real, liscio=Vero)
        # 2. Allenati con immagini false
        # Genera immagini false
        # i gradienti non devono fluire durante questo passaggio
        con torcia.no_grad():
            z = np.random.uniform(-1, 1, taglia=(dimensione del lotto, z_size))
            z = torcia.from_numpy(Insieme a).galleggiante()
            fake_images = G(Insieme a)
        # Calcola le perdite del discriminatore su immagini false
        D_falso = D(fake_images)
        d_fake_loss = fake_loss(D_falso)
        # somma le perdite ed esegui il backprop
        d_loss = d_real_loss + d_fake_loss
        d_loss.indietro()
        d_optimizer.step()
        # =========================================
        #            ALLENA IL GENERATORE
        # =========================================
        g_optimizer.zero_grad()
        # 1. Allenati con immagini false ed etichette capovolte
        # Genera immagini false
        z = np.random.uniform(-1, 1, taglia=(dimensione del lotto, z_size))
        z = torcia.from_numpy(Insieme a).galleggiante()
        fake_images = G(Insieme a)
        # Calcola le perdite del discriminatore su immagini false 
        # usando etichette capovolte!
        D_falso = D(fake_images)
        g_loss = real_loss(D_falso) # usa la perdita reale per capovolgere le etichette
        # eseguire backprop
        g_loss.indietro()
        g_optimizer.step()
        # Stampa alcune statistiche di perdita
        se batch_i % print_ogni == 0:
            # discriminatore di stampa e perdita del generatore
            Stampa('Epoca [{:5D}/{:5D}] | d_loss: {:6.4F} | g_loss: {:6.4F}'.formato(
                    epoca+1, num_epoche, d_loss.item(), g_loss.item()))
    ## DOPO OGNI EPOCA##
    # aggiungere la perdita del discriminatore e la perdita del generatore
    perdite.append((d_loss.item(), g_loss.item()))
    # generare e salvare il campione, immagini false
    G.eval() # modalità eval per la generazione di campioni
    campioni_z = G(fixed_z)
    campioni.append(campioni_z)
    G.treno() # torna alla modalità allenamento
# Salva i campioni del generatore di formazione
con aperto('train_samples.pkl', 'wb') come f:
    pkl.dump(campioni, F)

Una volta eseguito lo snippet di codice sopra, il processo di formazione comincerebbe così:

54477screenshot202021-05-2320at2012-36-2120pm-1797165
Fonte: Udacity.com

Genera immagini

Finalmente, quando il modello è addestrato, puoi usare il generatore addestrato per produrre le nuove immagini scritte a mano.

# generato casualmente, nuovi vettori latenti
sample_size=16
rand_z = np.random.uniform(-1, 1, taglia=(misura di prova, z_size))
rand_z = torcia.from_numpy(rand_z).galleggiante()
G.eval() # modalità di valutazione
# campioni generati
rand_images = G(rand_z)
# 0 indica il primo set di campioni nell'elenco passato in
# e abbiamo solo un lotto di campioni, qui
view_samples(0, [rand_images])

L'output generato con il seguente codice vorrebbe qualcosa del genere:

77359screenshot202021-05-2320at2012-37-2120pm-6412238
Fonte: Udacity.com

Quindi, ora che hai il tuo modello GAN addestrato, puoi usare questo modello per allenarti su un diverso set di immagini, per produrre nuove immagini invisibili.

Riferimenti:

1. Apprendimento profondo di Udacity: https://www.udacity.com/

2. Intelligenza artificiale di apprendimento profondo: https://www.deeplearning.ai/

Grazie per aver letto questo articolo. Se hai imparato qualcosa di nuovo, sentiti libero di commentare, alla prossima volta! !!! ❤️

Il supporto mostrato in questo articolo non è di proprietà di DataPeaker e viene utilizzato a discrezione dell'autore.

Iscriviti alla nostra Newsletter

Non ti invieremo posta SPAM. Lo odiamo quanto te.