{"cells":[{"metadata":{},"cell_type":"markdown","source":"# PROYECTO #1 Computación Emergente\n> 1. Beltrán, Mariangli\n1. Simoes, Diego"},{"metadata":{},"cell_type":"markdown","source":"NOTA: Se deberá encender el GPU antes de correr el proyecto. Si desea correr por CPU se indican de esta forma: #*** las líneas de código a omitir (comentar) - son 7"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nfrom pathlib import Path\nimport torch\nfrom torch.utils.data import Dataset,DataLoader\nfrom torchvision import transforms\nfrom torch import optim\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nprint(f'Using PyTorch v{torch.__version__}')\n\n\nfrom sklearn.model_selection import train_test_split\n\nimport matplotlib.pyplot as plt\n%matplotlib inline\n\nimport time\nfrom time import process_time\nt0 = time.process_time()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Procesamiento de Datos\nSe explican herramientas y tácticas empleadas para preprocesar los datos. Variables de entrada al modelo,normalización, estandarización, etc.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"#Cargando la data .npz correspondientes para el Training del modelo\n\ntrain_img = np.load(\"../input/kuzushiji/kmnist-train-imgs.npz\")[\"arr_0\"]\nlabel_train = np.load(\"../input/kuzushiji/kmnist-train-labels.npz\")[\"arr_0\"]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Separando los datos\nprint(\"Antes:\" ,train_img.shape)\n#Como requerimos dividir en entrenamiento de X y Y; y validación de X y Y se procede \ntrain_img, test_img, label_train,label_test=train_test_split(train_img,label_train,test_size = 0.20) #Se emplea el 20% como tamaño del Set de Validación\n#Imprimimos para confirmar\nprint(\"Entrenamiento: \", train_img.shape)\nprint(\"Validacion: \", test_img.shape)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Procesando los datos\ndef proceso_img(dataset,labels):\n    \"\"\"Como la mateamtica para las redes neuronales es continua, no discreta,\n    y esto se aproxima meejor con numero puntos flotantes.Las entradas, salidas y\n    y pesos de una red son numeros continuos. https://stackoverflow.com/questions/59986353/why-do-i-have-to-convert-uint8-into-float32\"\"\"\n    \n    new_data = dataset.astype('float32')\n    new_data = new_data / 255 #Normalizamos pasando los valores a un rango entre 1 y 0\n    new_data = np.reshape(new_data,(len(new_data,),1,28,28))\n    new_labels = labels.astype('int64')\n    return new_data, new_labels\n    \ntrain_img,label_train = proceso_img(train_img,label_train)\ntest_img,label_test = proceso_img(test_img,label_test)\n\n#Como Pytorch no permite alimentarlo directamente con arrays de Numpy, se transforma el conjunto de datos en Tensores de torch\nX_train_img=torch.Tensor(train_img)\n\"\"\" Para operaciones entre tensores, la regla es estricta. \n    Ambos tensores de la operación deben tener el mismo tipo de datos, o veremos mensajes de error\n    https://jdhao.github.io/2017/11/15/pytorch-datatype-note/ \"\"\"\ny_train_img=torch.Tensor(label_train).type(torch.LongTensor)\nX_valid_img=torch.Tensor(test_img)\ny_valid_img=torch.Tensor(label_test).type(torch.LongTensor)\n\nprint(\"Set de entrenamiento:  \"+str(X_train_img.shape))\nprint(\"Etiquetas de entrenamiento:  \"+str(y_train_img.shape))    \nprint(\"Set de validacion:  \"+str(X_valid_img.shape)) \nprint(\"Etiquetas de validacion :  \"+str(y_valid_img.shape)) \n\n#Cargamos el device donde se va a trabajar\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(device)\n\ntrain_dataset = torch.utils.data.TensorDataset(X_train_img, y_train_img)\ntrainloader = torch.utils.data.DataLoader(train_dataset, batch_size=400, shuffle = False)\n\nvalid_dataset = torch.utils.data.TensorDataset(X_valid_img, y_valid_img)\nvalidloader = torch.utils.data.DataLoader(valid_dataset, batch_size = 400, shuffle = False)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Arquitectura del Modelo\nSe explica la arquitectura utilizada del modelo de DeepLearning. \n\n*Especificando elementos vistos en clase y otros relevantes (número de capas, numero de neuronas, funciones de\nactivación, regularización, etc.)*"},{"metadata":{"trusted":true},"cell_type":"code","source":"# Modelo de Convolutional Neural Network - CNN\nclass CNN(nn.Module):\n    def __init__(self):\n        \n        super(CNN, self).__init__()\n        self.layer1 = nn.Sequential(\n            nn.Conv2d(1, 16, kernel_size=5, stride=1, padding=0), # output dim =(24*24*16)\n            nn.BatchNorm2d(16),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2,stride=2)) # output dim = (12*12*16)\n        self.layer2 = nn.Sequential(\n            nn.Conv2d(16, 32, kernel_size=4, stride=2, padding=1), # output dim = (6*6*32)\n            nn.BatchNorm2d(32),\n            nn.ReLU(),\n            nn.MaxPool2d(kernel_size=2,stride=2), # output dim = (3*3*32)\n            nn.Dropout(p=0.2)) \n        \n        self.fc1 = nn.Sequential( \n             nn.Linear(288, 100),\n             nn.ReLU(),\n             nn.Linear(100,420 ),\n             nn.ReLU(),\n             nn.Linear(420,10),\n             nn.LogSoftmax(dim=1)\n             \n            )\n        \n    def forward(self, x):\n        h1 = self.layer1(x)\n        h2 = self.layer2(h1)\n        h2 = h2.view(h2.size(0), -1)\n        h3 = self.fc1(h2)\n        return h3","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Entrenamiento del modelo \n\nSe explican los elementos de entrenamiento del modelo (learning rate, epochs, algoritmo de optimización, etc.)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"model = CNN()\ncriterion = nn.CrossEntropyLoss() #Función de Costo\nmodel.cuda() #***\noptimizer = optim.Adam(model.parameters(), lr = 0.003) #Optimizador Adam pasandole los parámetros del Modelo, con un Learning Rate de 0.003\n\nepochs = 30\ntraining_loss=[]\nvalid_loss=[]\ntraining_accuracy=[]\nvalid_accuracy=[]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for epoch in range (epochs):\n    \"\"\" model.train() estabelce los modulos en la red en modo de entrenamiento.\n    Es decir, le comenta a nuestro modelo que estamos en la fase de entrenamiento, \n    por lo que el modelo mantiene activa algunas capas.\"\"\"\n    model.train() \n    running_loss=0\n    accuracy=0\n    steps=0\n    \n    for i, (images, labels) in enumerate(trainloader):\n        images=images.cuda() #***\n        labels=labels.cuda() #***\n        output=model(images)\n        loss=criterion(output,labels)\n        optimizer.zero_grad()\n        \"\"\" necesitamos establecer los gradientes en cero antes de comenzar\n        a hacer la propagación hacia atrás porque PyTorch acumula los gradientes\n        en las pasadas posteriores hacia atrás. Por eso se apliza zer.grad() \"\"\"\n        \n        loss.backward() # Calcula la derivada de la pérdida w.r.t. los parámetros (o cualquier cosa que requiera gradientes) usando retropropagación.\n        optimizer.step() # Hace que el optimizador dé un paso basado en los gradientes de los parámetros.\n        \n        running_loss += loss.item() # El método extrae el valor de la pérdida como un flotante de Python\n        \n        _, predicted = torch.max(output, 1)\n        accuracy += (predicted == labels).sum()\n        steps += 1\n        \n    training_loss.append(running_loss/steps)\n    training_accuracy.append(100 * accuracy.cpu().numpy()/len(train_dataset))\n    model.eval()\n    with torch.no_grad():\n        iter_loss = 0\n        accuracy = 0\n        steps = 0\n    \n        for i, (images, labels) in enumerate(validloader):\n            images=images.cuda() #***\n            labels=labels.cuda() #***\n            output = model(images)\n            loss = criterion(output, labels)\n        \n            iter_loss += loss.item()\n            _, predicted = torch.max(output, 1)\n            accuracy += (predicted == labels).sum()\n            steps += 1\n            \n        valid_loss.append(iter_loss/steps)\n        valid_accuracy.append(100 * accuracy.cpu().numpy()/len(valid_dataset))\n                \n    print ('Epoch {}/{}, Training Loss: {:.3f}, Training Accuracy: {:.2f}%, Validation Loss: {:.3f}, Validation Acc: {:.2f}%'\n            .format(epoch+1, epochs, training_loss[-1], training_accuracy[-1], valid_loss[-1], valid_accuracy[-1]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(training_accuracy, color='red', label=\"Training acc\")\nplt.plot(valid_accuracy, color='blue',label=\"Validation acc\")\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.plot(training_loss, color='red', label=\"Training loss\")\nplt.plot(valid_loss, color='blue',label=\"Validation loss\")\nplt.legend()\nplt.show()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Testing + Resultado de modelo\n\nDetalle del resultado del modelo específicamente en: accuracy en entrenamiento y validación (ARRIBA), resultado en leaderboard de Kaggle (EN INFORME), tiempo de ejecución del notebook y cualquier otro indicador que sea relevante"},{"metadata":{"trusted":true},"cell_type":"code","source":"t1 = time.process_time() - t0\n\n#Cargando la data .npz correspondientes para el Testing\nt2 = time.process_time()\ntesting_img = np.load(\"../input/kuzushiji/kmnist-test-imgs.npz\")[\"arr_0\"]\nlabel_testing = np.load(\"../input/kuzushiji/kmnist-test-labels.npz\")[\"arr_0\"]\n\n\nnew_testing_img,new_testing_label=proceso_img(testing_img,label_testing)\nX_testing = torch.Tensor(new_testing_img)\ny_testing = torch.Tensor(new_testing_label).type(torch.LongTensor)\n\nprint('test data shape' +str(X_testing.shape))\nprint('test labels shape' +str(y_testing.shape))\n\ntest_dataset = torch.utils.data.TensorDataset(X_testing, y_testing)\ntestloader = torch.utils.data.DataLoader(test_dataset, batch_size = 300, shuffle=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.eval()\n\nwith torch.no_grad():\n    accuracy = 0\n    total = 0\n    test_loss = 0\n    \n    for images, labels in testloader:\n        images=images.cuda() #***\n        labels=labels.cuda() #***\n        output = model(images)\n        loss = criterion(output, labels)\n        test_loss += loss.item()\n        test_loss = test_loss/len(testloader)\n        _, predicted = torch.max(output.data, 1)\n        total += labels.size(0)\n        accuracy += (predicted == labels).sum().item()\n        test_accuracy = (100*accuracy)/total\n    t3 = time.process_time() - t2\n    t4 = time.process_time() - t0\n    print('Test Loss: {:.4f}, Test Accuracy: {:.2f}%'.format(test_loss, test_accuracy))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"Tiempo (s) transcurrido de Entrenamiento: \", t1)\nprint(\"Tiempo (s) transcurrido de Testing: \", t3)\nprint(\"Tiempo (s) transcurrido del Notebook: \", t4)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat":4,"nbformat_minor":4}