<jupyter_start><jupyter_text>Redes Adversariales GenerativasUna red adversarial generativa es un mecanismo de DL no supervisado desarrollado en 2014 por el grupo de trabajo de <NAME>. La red adversarial generativa consiste de dos redes neuronales (generadora y discriminante) que compiten en un juego de engaño. Este tipo de redes aprende a generar nuevos datos usando los features extraídos del conjunto de datos de entrenamiento, estos datos son evaluados por la red discriminante al ser clasificados entre 'real' o 'fake'. El objetivo es generar datos que se parezcan tanto a los reales que el discriminador los clasifique como 'real'.![](https://miro.medium.com/max/1838/1*5rMmuXmAquGTT-odw-bOpw.jpeg)En el [artículo principal](https://arxiv.org/pdf/1406.2661.pdf) puede encontrar más referencias a cerca del funcionamiento de las GANs.<jupyter_code>#-- Descomprimimos el dataset
# !rm -r mnist
# !unzip /content/drive/MyDrive/Colab/IntroDeepLearning_202102/mnist.zip
#--- Buscamos las direcciones de cada archivo de imagen
from glob import glob

train_files = glob('./mnist/train/*/*.png')
valid_files = glob('./mnist/valid/*/*.png')
test_files = glob('./mnist/test/*/*.png')

#--- Ordenamos los datos de forma aleatoria para evitar sesgos
import numpy as np

np.random.shuffle(train_files)
np.random.shuffle(valid_files)
np.random.shuffle(test_files)

import torchvision.transforms as transforms

#--- Transformamos los datos para adaptarlos a la entrada de nuestro discriminador
data_transform = transforms.Compose([
                 transforms.Grayscale(3), #Dado que MNIST tiene un solo canal, lo cambiamos a 3 para no tener que modificar más capas en el modelo
                 transforms.ToTensor(),
                 transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
                 ])

#--- Cargamos los datos de entrenamiento en listas
from PIL import Image

N_train = len(train_files)
X_train = []
Y_train = []

for i, train_file in enumerate(train_files):
  target = int(train_file.split('/')[3])
  if target == 8:
    Y_train.append( target )
    X_train.append( np.array(data_transform(Image.open(train_file) )))

#--- Cargamos los datos de testeo en listas
N_test = len(test_files)
X_test = []
Y_test = []

#- Tomamos unicamente el # 8
for i, test_file in enumerate(test_files):
  test = int(test_file.split('/')[3])
  if target == 8:  
    Y_test.append( target )
    X_test.append( np.array(data_transform(Image.open(test_file)) ))

#--- Convetimos las listas con los datos a tensores de torch
import torch
from torch.autograd import Variable

X_train = Variable(torch.from_numpy(np.array(X_train))).float()
Y_train = Variable(torch.from_numpy(np.array(Y_train))).long()

X_test = Variable(torch.from_numpy(np.array(X_test))).float()
Y_test = Variable(torch.from_numpy(np.array(Y_test))).long()

#-- Creamos el DataLoader
batch_size = 100

train_ds = torch.utils.data.TensorDataset(X_train, Y_train)
train_dl = torch.utils.data.DataLoader(train_ds, batch_size=batch_size)
#-- Visualizamos uno de los objetos
import matplotlib.pyplot as plt

def denorm(x):
    out = (x + 1) / 2
    return out

for img_batch, label_batch in train_dl:
    plt.imshow(denorm(img_batch[0][0]), cmap='gray')
    break
#--- Seleccionamos el dispositivo
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
device
#-- Definimos input y hidden size para una red MLP
image_size = 28*28*3
hidden_size = 512<jupyter_output><empty_output><jupyter_text>El DiscriminadorEl discriminador toma una imagen como entrada. e intenta clasificarla como real o generada. El discriminador toma una imagen de tamaño (3,28,28) y lo convierte a un tensor de tamaño (1, 1 , 1).<jupyter_code>import torch

#-- Definimos el discriminador
D = torch.nn.Sequential(
  torch.nn.Linear(image_size, hidden_size),
  torch.nn.LeakyReLU(0.2),
  torch.nn.Linear(hidden_size, hidden_size),
  torch.nn.LeakyReLU(0.2),
  torch.nn.Linear(hidden_size, 1),
  torch.nn.Sigmoid()
)

#-- Lo cargamos al dispositivo
D.to(device)<jupyter_output><empty_output><jupyter_text>ReLU, ELU y LeakyReLULa función de activación ReLU tiene algunas variantes, que cambian el valor 0 en el segmento negativo. Estas variantes permiten la relajación en la condición de activación.![](https://www.researchgate.net/profile/Aditi-Shenoy-3/publication/334389306/figure/fig8/AS:779352161677313@1562823443351/Illustration-of-output-of-ELU-vs-ReLU-vs-Leaky-ReLU-function-with-varying-input-values.ppm)  El generadorLa entrada del generador es un vector de números aleatorios que son usados como semilla para la generación de imágenes. El generador puede convertir un tensor de tamaño (latent_size, 1 , 1) a una imagen de tamaño (3,28,28).<jupyter_code>#-- Definimos el espacio latente
latent_size = 64
#-- Definimos el generador 
G = torch.nn.Sequential(
  torch.nn.Linear(latent_size, hidden_size),
  torch.nn.ReLU(),
  torch.nn.Linear(hidden_size, hidden_size),
  torch.nn.ReLU(),
  torch.nn.Linear(hidden_size, image_size),
  torch.nn.Tanh()
)

#-- Lo cargamos al dispositivo
G.to(device)
#--- Probamos el generador
y = G(torch.randn(2, latent_size))
gen_imgs = y.reshape((-1, 28,28)).detach()
plt.imshow(gen_imgs[0], cmap='gray')
# Definimos el criterio y los optimizadores para el discriminador y el generador
criterion = torch.nn.BCELoss()
d_optimizer = torch.optim.Adam(D.parameters(), lr=0.0002)
g_optimizer = torch.optim.Adam(G.parameters(), lr=0.0002)
#--- Reseteamos los gradientes del discriminador y el generador
def reset_grad():
    d_optimizer.zero_grad()
    g_optimizer.zero_grad()

def train_discriminator(images):
    # Definimos los objetivos reales y falsos
    real_labels = torch.ones(batch_size, 1).to(device)
    fake_labels = torch.zeros(batch_size, 1).to(device)
        
    # Loss para imágenes reales
    outputs = D(images)
    d_loss_real = criterion(outputs, real_labels)
    real_score = outputs

    # Loss para imágenes falsas
    z = torch.randn(batch_size, latent_size).to(device)
    fake_images = G(z)
    outputs = D(fake_images)
    d_loss_fake = criterion(outputs, fake_labels)
    fake_score = outputs

    # Combinamos las perdidas
    d_loss = d_loss_real + d_loss_fake
  
    # Backpropagation
    reset_grad()
    d_loss.backward()
    d_optimizer.step()
    
    return d_loss, real_score, fake_score

def train_generator():
    # Generamos una imagen falsa
    z = torch.randn(batch_size, latent_size).to(device)
    fake_images = G(z)
    labels = torch.ones(batch_size, 1).to(device)
    g_loss = criterion(D(fake_images), labels)

    # Backpropagation
    reset_grad()
    g_loss.backward()
    g_optimizer.step()
    return g_loss, fake_images
#-- Definimos el número de épocas
n_epoch = 400

d_losses, g_losses, accs_real, accs_fake = [], [], [], []

iter = 0

for epoch in range(n_epoch):
  for batch_id, (images, _) in enumerate(train_dl):
    
    # Load a batch & transform to vectors
    images = images.reshape(batch_size, -1).to(device)
    
    # Train the discriminator and generator
    d_loss, acc_real, acc_fake = train_discriminator(images)
    g_loss, fake_images = train_generator()
    
    # Inspect the losses
    iter +=1

    if iter % 100 == 99:
      d_losses.append(d_loss.item())
      g_losses.append(g_loss.item())
      accs_real.append(acc_real.mean().item())
      accs_fake.append(acc_fake.mean().item())
      
      print('Epoch [{}/{}], iter: {}, d_loss: {:.4f}, g_loss: {:.4f}, acc_real: {:.4f}, acc_fake: {:.4f}'
      .format(epoch+1, n_epoch, iter+1, d_loss.item(), g_loss.item(), 
              acc_real.mean().item(), acc_fake.mean().item() ))

      sample_vectors = torch.randn(batch_size, latent_size).to(device)

      fake_images = G(sample_vectors)
      fake_images = fake_images.reshape(fake_images.size(0), 3, 28, 28)

      plt.imshow(denorm(fake_images[0].detach().permute(1, 2, 0).numpy()))
      
      plt.axis(False)
      plt.show()
      print('\n')
#-- Graficamos Loss y Accuracy
fig = plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
plt.plot(d_losses, '-')
plt.plot(g_losses, '-')
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['Discriminator', 'Generator'])
plt.title('Losses')
plt.subplot(1,2,2)
plt.plot(accs_real, '-')
plt.plot(accs_fake, '-')
plt.xlabel('epoch')
plt.ylabel('score')
plt.legend(['Real Score', 'Fake score'])
plt.title('Scores')
plt.show()
#-- Comparamos nuestros resultados
G.eval()
fake_images = G(sample_vectors)
fake_images = fake_images.reshape(fake_images.size(0), 3, 28, 28)

fig = plt.figure(figsize=(15,5))
plt.subplot(1,2,1)
plt.imshow(denorm(fake_images[0].detach().permute(1, 2, 0).numpy()))
plt.axis(False)
plt.subplot(1,2,2)
plt.imshow(denorm(img_batch[0][0]), cmap='gray')
plt.axis(False)
plt.show()<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12801187621331506, 'fraction_numerical': 0.023866620988923146, 'mean_word_length': 4.2727272727272725, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 14, 'https://': 3, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '459459', 'license': 'MIT', 'n_tokens_mistral': 3371, 'n_tokens_neox': 3164, 'n_words': 742, 'path': 'notebooks/16_Generacion_Datos_GAN_Linear.ipynb', 'repo_name': 'aherrera3/IntroDeepLearning_202102', 'size': '8765'}