<jupyter_start><jupyter_text>Creamos nuestra clase de datos:<jupyter_code>links_csv = ['https://raw.githubusercontent.com/HackSpacePeru/Datasets_intro_Data_Science/master/train1.csv',
'https://raw.githubusercontent.com/HackSpacePeru/Datasets_intro_Data_Science/master/train2.csv',
'https://raw.githubusercontent.com/HackSpacePeru/Datasets_intro_Data_Science/master/train3.csv',
'https://raw.githubusercontent.com/HackSpacePeru/Datasets_intro_Data_Science/master/train4.csv',]

class MNISTDataset(Dataset):
  def __init__(self, links_csv, mode='train'):
    self.mode = mode #
    list_df = [pd.read_csv(link) for link in links_csv]
    data = pd.concat(list_df)

    """
    <---------------------------- Preprocesamiento de Datos -------------------------------------->
    """

    if self.mode == 'train':
      self.features = data.drop('label',axis=1).values/255.0
      self.target = data['label'].values
      #Reshaping
      self.target = self.target.reshape((-1,1)) #Dejando q se reeshapee solo

    else:
      self.features = data.values/255.0

  def __len__(self):
    return len(self.features)

  def __getitem__(self, idx):
    if self.mode=='train':
      feat = torch.Tensor(self.features[idx])
      oupt = torch.Tensor(self.target[idx])

      return {'features':feat,
              'target':oupt,}
      
    else:
      feat = torch.Tensor(self.features[idx])
      return {'features':feat}
train[0]['features'].shape
test_links = ['https://raw.githubusercontent.com/HackSpacePeru/Datasets_intro_Data_Science/master/test.csv']

train = MNISTDataset(links_csv = links_csv, mode='train')
test = MNISTDataset(links_csv=test_links, mode='test')
#Ahora vamos a crear los DataLoades para poder obtener los batchs.

train_loader = DataLoader(train, batch_size=64, shuffle = True)
test_loader = DataLoader(test, batch_size=64, shuffle =True)<jupyter_output><empty_output><jupyter_text>Modelling MultiLayerPerceptron (MLP)Vamos a ver que primero haremos una clase heredada de la clase nn.Module, y también usaremos super() para poder heredar los atributos de la clase nn.Module. Así tendremos acceso y más flexibilidad para extender esta clase nn.Module.  Definiendo el modelo:<jupyter_code>import torch.nn as nn

class MLP(nn.Module):
  def __init__(self, i, u, v, o):
    """
    Donde i,u,v,o son los números de neuronas de 
    entrada y salida que tendrá mi red.
    """
    super(MLP, self).__init__()
    self.relu_layer = nn.ReLU()
    self.dense_1 = nn.Linear(i, u)
    self.b1 = nn.BatchNorm1d(20)
    self.dense_2 = nn.Linear(u,v)
    self.dense_output = nn.Linear(v, o)


  def forward(self, x):
    x = self.relu_layer(self.dense_1(x)) # activation( Capa )
    x = self.b1(x) #Batch Layer
    x = self.relu_layer(self.dense_2(x)) # Activation(Capa)

    logits = self.dense_output(x)

    return logits<jupyter_output><empty_output><jupyter_text>Inicializando la red:<jupyter_code>from torch.optim import Adam

#Usamos el GPU
if torch.cuda.is_available() == True:
    device = torch.device('cuda')
else:
    device = torch.device('cpu')
    
red_neuronal = MLP(i=784, u = 20, v=20, o = 10).to(device) #Acá puedo definir los layers <- Notar nombre de objeto.

optimizer = Adam(params=red_neuronal.parameters(), lr=0.01)
print(red_neuronal) #Imprimimos la arquitectura
#Definimos nuestra función de pérdida

def accuracy(y_true, y_pred):
  y_true = y_true.long().squeeze()
  y_pred = torch.argmax(y_pred, axis=1)
  return (y_true == y_pred).float().sum()/len(y_true)

def cross_entropy_loss(y_true, y_pred):
  y_true = y_true.long().squeeze()
  return nn.CrossEntropyLoss()(y_pred, y_true)<jupyter_output><empty_output><jupyter_text>Entrenando<jupyter_code>#Esto también usualmente se pone dentro de una función: training_loop.

import time
start = time.time()
print("STARTING TRAINING ...\n")

train_losses, valid_losses = [], []
train_acc, valid_acc = [], []

for epoch in range(20): #Definiendo 20 epocas.
  red_neuronal = red_neuronal.train()
  print("Epoch: {}".format(epoch+1))
  batch_train_losses, batch_train_acc = [], []

  batch = 0
  for train_batch in train_loader: #Objeto DataLoader

    train_X, train_y = train_batch.values()

    train_X = train_X.to(device)
    train_y = train_y.to(device)

    train_preds = red_neuronal.forward(train_X)
    train_loss = cross_entropy_loss(train_y, train_preds)

    train_accuracy = accuracy(train_y, train_preds)

    optimizer.zero_grad() # Limpio las gradientes
    train_loss.backward() # Hago el calculo de las nuevas gradientes

    optimizer.step() #Utilizo estas gradientes para hacer el backpropagation

    train_loss = np.round(train_loss.item(), 3)
    train_accuracy = np.round(train_accuracy.item(),3)

    end = time.time()
    batch = batch + 1
    log = batch % 10 == 0

    time_delta = np.round(end - start, 3)

    batch_train_losses.append(train_loss)
    batch_train_acc.append(train_accuracy)

    logs = "Batch: {} || Train Loss: {} || Train Acc: {} || Time: {} s"
    
    if log:
        print(logs.format(batch, train_loss, train_accuracy, time_delta))

  #Hasta acá solo hemos entrenado. Aún no evaluamos con respecto al test. 

  train_losses.append(np.mean(batch_train_losses))
  train_acc.append(np.mean(batch_train_acc))<jupyter_output><empty_output><jupyter_text>Guardamos el modelo.Esto lo podemos hacer de dos formas:    - Serializando: Que implica guardalos como un objeto pickle y abrir también con ello.        - Guardando solo el state_dict: Que es guardar los parámetros del modelo e importar        todos estos junto con la arquitectura sola del modelo. En este caso estamos optando guardar también el estado del optimizador.                Guardar el estado del optimizador es útil pues podemos reentrenar la red luego.<jupyter_code>state_dict = {
    'epoch':epoch,
    'state_dict': red_neuronal.state_dict(),
    'optimizer': optimizer.state_dict()
}

torch.save(state_dict, 'mnist_model_state_dict.pt')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.12808460634547592, 'fraction_numerical': 0.009232835319791842, 'mean_word_length': 4.032094594594595, 'pattern_counts': {'":': 0, '<': 23, '<?xml version=': 0, '>': 22, 'https://': 5, 'lorem ipsum': 0, 'www.': 0, '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': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '82249', 'license': 'MIT', 'n_tokens_mistral': 2170, 'n_tokens_neox': 2098, 'n_words': 458, 'path': 'Pytorch Training/Pytorch_MNIST.ipynb', 'repo_name': 'PBenavides/Kaggle_competitions', 'size': '5957'}