{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Proyecto 1\n* Alexander Kalen\n* Alberto Landi","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport matplotlib.pyplot as plt\nimport torch\nimport time\n\nprint(f'Using PyTorch v{torch.__version__}')\n\n\nt0= time.clock()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Procesamiento de Datos","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"#Cargamos la data para Training\n\nimport pandas as pd\ntrain_data = pd.read_csv(\"../input/digit-recognizer/train.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Cargamos el device donde se va a trabajar\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n#Se construye la Transformacion usando TorchVision\n\nimport torchvision.transforms as transforms\nfrom   PIL import Image\ntransform = transforms.Compose([\n        transforms.ToTensor(),\n        transforms.Normalize((0.5,), (0.5,)) #---> Hiperparametro por defecto de MNIST\n    ])\n\n#Con esta funcion extraemos los valores y labels del dataset en el pandas dataframe\n\ndef obtener_valores(df):\n   \n    labels = []\n    index = 0\n    if 'label' in df.columns: # Se recorren las columnas del archivo de entrada para obtener los labels\n        labels = [v for v in df.label.values]\n        index = 1\n        \n    # Se recorren los diferentes valores del archivo de entrada para transformalos en data usable para la rn\n    datas = []\n    for i in range(df.pixel0.size):\n        data = df.iloc[i].astype(float).values[index:] \n        data = np.reshape(data, (28,28)) #--> Aseguramos que este correcto el valor de la matriz de valores\n        data = transform(data).type('torch.FloatTensor') #--> Transformamos la data\n        if len(labels) > 0:\n            datas.append([data, labels[i]])\n        else:\n            datas.append(data)\n\n    return datas","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size  = 64   \nvalidation  = 0.15\nnum_classes = 10\n\n#Cargamos la data\n\nX_train = obtener_valores(train_data)\n\n#Dividimos la data (split) entre el el training y el validation(test)\nm = len(X_train)\nindices   = list(range(m))\nsplit = int(np.floor(validation* m))  \nindex_train, index_test = indices[split:], indices[:split] #---> Split\n\n# Define los samplers para obtener los batches de el train y validation loader\nfrom torch.utils.data.sampler import SubsetRandomSampler\ntrain_sampler = SubsetRandomSampler(index_train)\nvalid_sampler = SubsetRandomSampler(index_test)\n\n# Construimos los data loaders\ntrain_loader = torch.utils.data.DataLoader(X_train, batch_size=batch_size,\n                    sampler=train_sampler)\nvalid_loader = torch.utils.data.DataLoader(X_train, batch_size=batch_size, \n                    sampler=valid_sampler)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Arquitectura","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.nn as nn\n\n#Calculamos el Tamano del output 'nxn' con stride:\n\ndef stride_tam(in_layers, stride, padding, tam_kernel, tam_pool):\n    return int((1 + (in_layers - tam_kernel + (2 * padding)) / stride) / tam_pool)\n\nclass Net(nn.Module): \n    \n    \n    def __init__(self):\n        super(Net, self).__init__()\n        \n        #Pasandole tuplas correspondientes a los canales de entrada, tamaño del kernel y pool\n        #definimos diferentes valores para nuestra arquitectura que nos permiten construir modelos para\n        #nuestra arquitectura.\n\n        #### ARQUITECTURA ####\n        \n        inputs     = [1,16,32,64]\n        tam_kernel = [5,5,3]\n        tam_pool   = [2,2,2]\n        \n        #####################\n\n        layers_conv = []\n        self.out   = 28         #--> inicializamos en 28 para caclular el output layer de cada layer\n        self.depth = inputs[-1] #--> Ultimo layer \n        \n        for i in range(len(tam_kernel)):\n            \n            padding = int(tam_kernel[i]/2)\n\n            # Output para cada layer\n            self.out = stride_tam(self.out, 1, padding, tam_kernel[i], tam_pool[i])\n            \n            #Utilizamos 1x1 Convolution Arquitecture Tecnique:\n\n            # Convolutional layer 1\n            layers_conv.append(nn.Conv2d(inputs[i], inputs[i+1], tam_kernel[i], \n                                       1, padding=padding))\n            layers_conv.append(nn.BatchNorm2d(inputs[i+1])) #--> BathNorm\n            layers_conv.append(nn.ReLU())\n            \n            \n            # maxpool layer\n            layers_conv.append(nn.MaxPool2d(tam_pool[i],tam_pool[i]))\n\n        self.convolutional_layers = nn.Sequential(*layers_conv)\n                \n        # Fully connected Layers\n        fc_layers = []\n        fc_layers.append(nn.Dropout(p=0.2))\n        fc_layers.append(nn.Linear(self.depth*self.out*self.out, 256))\n        fc_layers.append(nn.Dropout(p=0.2))\n        fc_layers.append(nn.Linear(256, 128))\n        fc_layers.append(nn.Dropout(p=0.2))\n        fc_layers.append(nn.Linear(128, 64))\n        fc_layers.append(nn.Dropout(p=0.2))\n        fc_layers.append(nn.Linear(64, 10))\n\n        self.fully_connected_layers = nn.Sequential(*fc_layers)\n\n    def forward(self, x):\n        \n        x = self.convolutional_layers(x)\n        \n        #Aplanamos\n        x = x.view(-1, self.depth*self.out*self.out)\n        \n        x = self.fully_connected_layers(x)\n        return x\n    \n\nmodel = Net()\nmodel","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Entenamiento del Modelo","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.optim as optim\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(model.parameters(), lr= 0.00069) #--> Hiperparametro","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Nota --> Revisar que diga cuda al correr esta celda (GPU)\n\nepochs = 20\n\nvalid_loss_min = np.Inf\n\nprint(device)\nmodel.to(device)\ntLoss, vLoss = [], []\nfor epoch in range(epochs):\n\n    train_loss = 0.0\n    valid_loss = 0.0\n    \n#Training\n    \n    model.train()\n    for data, target in train_loader:\n        \n        # Utilizamos GPU para agilizar el entrenamiento\n        data   = data.to(device)\n        target = target.to(device)\n        optimizer.zero_grad()\n        output = model(data)\n        loss = criterion(output, target)\n        loss.backward()\n        optimizer.step()\n        train_loss += loss.item()*data.size(0)\n        \n#Validamos\n\n    model.eval()\n    for data, target in valid_loader:\n       \n        # Utilizamos GPU para agilizar el entrenamiento\n        data   = data.to(device)\n        target = target.to(device)\n        output = model(data)\n        loss = criterion(output, target)\n        valid_loss += loss.item()*data.size(0)\n    \n    \n    train_loss = train_loss/len(train_loader.dataset)\n    valid_loss = valid_loss/len(valid_loader.dataset)\n    tLoss.append(train_loss)\n    vLoss.append(valid_loss)\n        \n    print('Epoch: {} \\tTraining Loss: {:.6f} \\tValidation Loss: {:.6f}'.format(\n        epoch + 1, train_loss, valid_loss))\n    \n    # Salvamos el modelo con el Validation Loss mas bajo (Early Stopping)\n    if valid_loss <= valid_loss_min:\n        print('Mejora ({:.6f} --> {:.6f}).  Saving model ...'.format(\n        valid_loss_min,\n        valid_loss))\n        torch.save(model.state_dict(), 'modelo_optimo.pt')\n        valid_loss_min = valid_loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#Loss\nplt.plot(tLoss, label='Training Loss')\nplt.plot(vLoss, label='Validation Loss')\nplt.legend();\n\nmodel.load_state_dict(torch.load('modelo_optimo.pt'));\n\ntest_loss  = 0.0\nY_hat      = [0]*10\nY          = [0]*10\n\nmodel.eval()\n\nfor data, target in valid_loader:\n\n    data   = data.to(device)\n    target = target.to(device)\n    output = model(data)\n    loss = criterion(output, target)\n    test_loss += loss.item()*data.size(0)\n    _, pred = torch.max(output, 1)    \n    correct_tensor = pred.eq(target.data.view_as(pred))\n    correct = np.squeeze(correct_tensor.numpy()) if device == \"cpu\" else np.squeeze(correct_tensor.cpu().numpy())\n\n    for i in range(target.size(0)):\n        label = target.data[i]\n        Y_hat[label] += correct[i].item()\n        Y[label] += 1\n\ntest_loss = test_loss/len(valid_loader.dataset)\nprint('Test Loss: {:.6f}\\n'.format(test_loss))\n\nprint('Test Accuracy por Digito:')\n\nfor i in range(10):\n    if Y[i] > 0:\n        print('Test Accuracy of %3s: %.2f%% (%2d/%2d)' % (\n            i, 100 * Y_hat[i] / Y[i],\n            np.sum(Y_hat[i]), np.sum(Y[i])))\n    else:\n        print('Test Accuracy of %3s: N/A (no training examples)' % (classes[i]))\n\nprint('\\nTest Accuracy (Overall): %.4f%% (%2d/%2d)' % (\n    100. * np.sum(Y_hat) / np.sum(Y),\n    np.sum(Y_hat), np.sum(Y)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Testing","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test_data        = pd.read_csv(\"../input/digit-recognizer/test.csv\")\nX_test           = obtener_valores(test_data)\ntest_loader      = torch.utils.data.DataLoader(X_test, batch_size=batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"t1 = time.clock() - t0\n\nImageId, Label = [],[]\n\nfor data in test_loader:\n    data = data.to(device)\n    salida = model(data)\n    _, pred = torch.max(salida, 1)\n    \n    for i in range(len(pred)):        \n        ImageId.append(len(ImageId)+1)\n        Label.append(pred[i].cpu().numpy())\n\nsub = pd.DataFrame(data={'ImageId':ImageId, 'Label':Label})\nsub.describe\n\nprint(\"Tiempo pasado: \", t1)\n\n#Hacemos submit\nsub.to_csv(\"submission.csv\", index=False)","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}