{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load in \n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the \"../input/\" directory.\n# For example, running this (by clicking run or pressing Shift+Enter) will list the files in the input directory\n\nimport os\nprint(os.listdir(\"../input\"))\n\n# Any results you write to the current directory are saved as output.","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"import matplotlib as mpl\nimport matplotlib.pyplot as plt\nimport seaborn as sb  # Importing seaborn for plotting\n\nfrom PIL import Image\n\nimport tqdm  # For ProgressBar\nimport time  # For recording time\n\nfrom torch.utils.data.dataset import Dataset\n\nfrom torchvision import transforms\nfrom torchvision.transforms import ToTensor\nfrom torch.utils.data import DataLoader\n\nimport torch\nfrom torch import nn # python module\nimport torch.nn.functional as F # Regular function\n\nimport tensorflow as tf\n\nimport skimage.transform\n#from sklearn.model_selection import train_test_split\n\nimport shutil  # For Copying files(checkpoints)\n\nfrom sklearn.metrics import classification_report  # For getting a report from the net","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6aed20f6b7cae0dec5cf5879771c5be7dcfc17d1"},"cell_type":"code","source":"class DriverImageDataset(Dataset):\n    \"\"\"DriverImageDataset.\"\"\"\n\n    def __init__(self, root_dir = '../input', csv_file = 'driver_imgs_list.csv', download = False,\n                 train = True , transform = None, newShape = None, evalData = None, \n                 rand_state = 2, limit = None):\n        \"\"\"\n        Args:\n            csv_file (string): Path to the csv file with annotations.\n            root_dir (string): Directory with all the images.\n            download(boolean): Download the data first in active path.\n            train   (boolean): If True (default), returns train data, and test data otherwise.\n            newShape  (tuple): Resize images to the given new shape for instance: (28, 28)\n            transform (callable, optional): Optional transform to be applied on a sample.\n            limit     (tuple): Picking images based on the given tuple \n                               i.e. limit = (starts, ends (not, included))\n            rand_state  (int): int or numpy.random.RandomState, optional Seed for the \n                                random number generator (if int), or numpy RandomState object.\n        \"\"\"\n        if download:\n            !pip install kaggle\n            !kaggle competitions download -c state-farm-distracted-driver-detection\n        \n        self._root_dir_       = root_dir\n        self._transform_      = transform\n        self._newShape_       = newShape\n        self._cvs_file_path_  = os.path.join(root_dir, csv_file)\n        self._isTrain_        = train\n        self._dataPath_       = os.path.join(root_dir, 'train')\n        self.driver_imgs_list = pd.read_csv(self._cvs_file_path_)\n        if not self._isTrain_:\n            self._isTrain_        = False\n            self._dataPath_       = os.path.join(self._root_dir_, 'test')\n            self.driver_imgs_list = pd.DataFrame({'img':os.listdir(self._dataPath_)})\n        # Shuffles the self.driver_imgs_list\n        self.__shuffle__(rand_state, limit)    \n        \n    def __len__(self):\n        return len(self.driver_imgs_list)\n\n    def __getitem__(self, idx):\n        img_name = ''\n        label = 0\n        if self._isTrain_:\n            class_name = self.driver_imgs_list.iloc[idx, 1]\n            img_name = os.path.join(self._dataPath_, class_name, self.driver_imgs_list.iloc[idx, 2])\n            label    = int(class_name[1])\n        else:\n            img_name = os.path.join(self._dataPath_, self.driver_imgs_list.iloc[idx, 0])\n        img = Image.open(img_name)\n        #img = img.convert('RGB')\n        if self._newShape_:\n            img = img.resize(self._newShape_)\n        if self._transform_:\n            img = self._transform_(img)\n        if not self._isTrain_:\n            return img\n        label = torch.from_numpy(np.asarray(label))\n        return img, label\n    \n    def __shuffle__(self, rand_state, limit):\n        self.driver_imgs_list = self.driver_imgs_list.sample(frac = 1, \\\n                                    random_state = rand_state).reset_index(drop = True)\n        if limit:\n            self.driver_imgs_list = self.driver_imgs_list.iloc[limit[0]: limit[1]]. \\\n                                    reset_index(drop = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9a3fb0b6f64177309e347f25fcc2a0dbd0c69449"},"cell_type":"code","source":"def show_batch(images, targets = None, predictions = None):\n    '''This method gets a list of images with their target value\n       and plot them in equal rows and column.\n       Also can get the predictions values and show them with targets.\n       images(list) : List of images\n       targets(list): Labels for each image\n       predictions(list): If not None, is list of predicted values\n                          corresponding with each given image'''\n    plt.figure(figsize = (15, 15))\n    ncols = np.ceil(np.sqrt(len(images)))\n    nrows = np.ceil(len(images) / ncols)\n    for i in range(len(images)):\n        plt.subplot(nrows, ncols, i + 1)\n        plt.imshow(images[i][0].numpy().squeeze())\n        plt.xticks([]); plt.yticks([]); #plt.axis('off');\n        if predictions is not None:\n            plt.xlabel(\"P:{}, T:{}\".format( predictions[i].numpy(), \\\n                                           targets[i].numpy(), fontsize = 'small'))\n        elif targets is not None:\n            plt.xlabel(\"T:{}\".format(targets[i].numpy()))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"13e02ae72cd0f02d7e4a12a639b286b7a215e8d3"},"cell_type":"code","source":"new_shape = (int(640 / 5), int(480 / 5))  # 1/5th of original shape\nnew_shape","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"52e47fd28a4dab0c589672ed1a147fe1d2a975e9"},"cell_type":"code","source":"# Hyperparameters\nBATCH_SIZE    = 64 #256\nLEARNING_RATE = 0.001\nWORKERS       = 2 #10\n\nnumTrainImgs = len(pd.read_csv('../input/driver_imgs_list.csv'))\n# For picking 5% of train data as an Evaluation Data\nevalData_start = numTrainImgs - int(numTrainImgs * 0.05)\n\n# Reading Data sets\ntrainData = DriverImageDataset(root_dir='../input', train = True, download = False, \n            transform = ToTensor(), newShape = new_shape , limit = (0, evalData_start))\nevalData  = DriverImageDataset(root_dir='../input', train = True, download = False, \n            transform = ToTensor(), newShape = new_shape , limit = (evalData_start, numTrainImgs))\ntestData  = DriverImageDataset(root_dir='../input', train = False, download = False, \n                               transform = ToTensor(), newShape = new_shape)\n\n# Checking if it picked all train images as evalData + trainData\nassert numTrainImgs == len(evalData) + len(trainData) \n\n# Setting Data Loaders\ntrain_loader = DataLoader(trainData, batch_size = BATCH_SIZE, \n                          num_workers = WORKERS, shuffle = True)\neval_loader  = DataLoader(evalData, batch_size = BATCH_SIZE, \n                          num_workers = WORKERS, shuffle = True)\ntest_loader  = DataLoader(testData, batch_size = BATCH_SIZE, \n                          num_workers = WORKERS, shuffle = True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3dc6c1bb6c8e99c39f34c7104f174573db4ad853"},"cell_type":"code","source":"class simpleCNN(nn.Module):\n    def __init__(self, shape = (3, new_shape[0], new_shape[1]), num_classes = 10):\n        super().__init__()\n    \n        self.layer1 = nn.Conv2d(3, 128, (3, 3), padding = 1)\n        self.layer2 = nn.Conv2d(128, 128, (3, 3), padding = 1)\n        self.layer3 = nn.Linear(32 * 24 * 128, num_classes)\n        \n    \n    def forward(self, x):\n        x = self.layer1(x)\n        x = F.relu(x)\n        x = F.max_pool2d(x, 2)\n        \n        x = self.layer2(x)\n        x = F.relu(x)\n        x = F.max_pool2d(x, 2)\n        \n        x = x.reshape(-1, 32 * 24 * 128)\n        y = self.layer3(x)\n        \n        return y  # Will learn to treat 'a' as the natural parameters of a multinomial distr. ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"47adc78693c56bd9a1fcf2ea2d351320cfb0296d"},"cell_type":"code","source":"cNN_net = simpleCNN()\n\nprint(cNN_net)\nprint(\"----\")\nprint(list(cNN_net.state_dict())) # Assign names to each one of group of tensor parameters\nprint(\"----\")\nprint(cNN_net.parameters)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"77eea3bc26bd5aa474767c12e360d67ab4a2a0b0"},"cell_type":"code","source":"import torch.cuda\nprint(torch.cuda.is_available())\n\nif torch.cuda.is_available():\n    def togpu(x):\n        return x.cuda()\n    def tocpu(x):\n        return x.cpu()\nelse:\n    def togpu(x):\n        return x\n    def tocpu(x):\n        return x","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"5e4f0fb4710239711864a3de034828ef4482a766"},"cell_type":"code","source":"net = togpu(cNN_net)\n\ncriterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(params = net.parameters(), lr = LEARNING_RATE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f3137e6d0c4f8c3b576575e09eba652af568d4f7"},"cell_type":"code","source":"def compute_eval_loss(net, criterion, loader):\n    # Evaluate the model\n    with torch.no_grad():\n        eval_loss = 0.0\n        for i, data in tqdm.tqdm(enumerate(loader), desc = 'Evaluating', \n                                 total = len(loader), leave = False):\n            inputs, labels = data\n            inputs, labels = togpu(inputs), togpu(labels)\n            outputs = net(inputs)               # Predict\n            loss = criterion(outputs, labels)   # Grade / Evaluate\n            eval_loss += loss.item()\n    eval_loss /= len(test_loader)\n    return eval_loss","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"2bd838faeefcf3f3657086f4415b244291bd474b"},"cell_type":"code","source":"def run_simpleCNN(net, optimizer, criterion, epoch = 2, best_eval_loss = float('inf')):\n    for epoch in tqdm.tnrange(epoch):\n        running_loss = 0.0\n        tstart = time.time()\n        for _, data in tqdm.tqdm(enumerate(train_loader), total = len(train_loader), leave = False):\n            # get the inputs\n            inputs, labels = data\n        \n            # Move inputs to the GPU\n            inputs, labels = togpu(inputs), togpu(labels)\n\n            # zero the parameter gradients\n            optimizer.zero_grad()\n\n            # forward + backward + optimize\n            outputs = net(inputs)               # Predict\n            loss = criterion(outputs, labels)   # Grade / Evaluate\n            loss.backward()                     # Determine how each parameter effected the loss\n            optimizer.step()                    # Update parameters \n\n            # print statistics\n            running_loss += loss.item()\n        tend = time.time()\n    \n        # Save parameters\n        running_loss /= len(train_loader)\n        # This is for where we can stop\n        eval_loss = compute_eval_loss(net, criterion, eval_loader)  \n        torch.save(dict(epoch = epoch, \n                     loss = eval_loss,\n                    parameters = net.state_dict(),\n                    optimizer  = optimizer.state_dict()),\n                   'simpleCNN-checkpoint.pth.tar')\n    \n        if eval_loss < best_eval_loss:\n            best_eval_loss = eval_loss\n            best_epoch = epoch\n            shutil.copyfile('simpleCNN-checkpoint.pth.tar', 'simpleCNN-best.pth.tar')\n        \n        print(\"Epoch {: 4}   loss: {: 2.5f}  time: {}\".format(epoch, \n                                                          running_loss / len(train_loader), \n                                                          tend-tstart))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"7fd34c353d1aa9dec49af646f80fa2e93478f723"},"cell_type":"code","source":"import sys, os\ndef resume(model, optimizer, fn = 'checkpoint.pth.tar'):\n    '''\n        Loads a torch net from the given file.\n    '''\n    if os.path.isfile(fn):\n        print(\"=> loading checkpoint '{}'\".format(fn))\n        checkpoint  = torch.load(fn)\n        start_epoch = checkpoint['epoch']\n        best_loss   = checkpoint['loss']\n        ehist       = checkpoint.get('ehist', [])\n        thist       = checkpoint.get('thist', [])\n        optimizer.load_state_dict(checkpoint['optimizer'])\n        print(\"=> Loaded checkpoint '{}' (epoch {})\".format(fn, checkpoint['epoch']))\n    else:\n        start_epoch = 0\n        ehist = []\n        thist = []\n        print (\"=> no checkpoint found at '{}'\".format(fn))\n    return start_epoch, best_loss, ehist, thist\n\n# Qualitative assessment (By Numbers)\ndef report(net, evalData):\n    predictions = np.zeros(len(evalData)) \n    targets = np.zeros(len(evalData))\n\n    for i  in tqdm.tnrange(len(evalData)):\n        x, t = evalData[i]\n        # I have to add one extra axis at the beginning by None\n        p = tocpu(net(togpu(x[None,...]))).argmax(1)[0]  \n        predictions[i] = int(p) # Changing Tensors into integers\n        targets[i] = t \n\n    # Showing classification metrics\n    print(classification_report(targets, predictions))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f4f0791f2f90b55c365e3d347dec328095a24a58"},"cell_type":"code","source":"b_loss = float('inf')  # Assign infinity\nrun_simpleCNN(net, optimizer, criterion, epoch = 100, best_eval_loss = b_loss)\nepoch, b_loss, ehist, thist = resume(net, optimizer, fn = 'simpleCNN-best.pth.tar')\nreport(net, evalData)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"dedca9fbf3a6978ba5e01727025fa02c4a2f2c15"},"cell_type":"code","source":"submission_02 = pd.DataFrame({'img':testData.driver_imgs_list.iloc[:, 0], \n                              'c0':np.zeros(len(testData)),\n                              'c1':np.zeros(len(testData)),\n                              'c2':np.zeros(len(testData)),\n                              'c3':np.zeros(len(testData)),\n                              'c4':np.zeros(len(testData)),\n                              'c5':np.zeros(len(testData)),\n                              'c6':np.zeros(len(testData)),\n                              'c7':np.zeros(len(testData)),\n                              'c8':np.zeros(len(testData)),\n                              'c9':np.zeros(len(testData)) })\n\nfor i  in tqdm.tnrange(len(testData)):\n        x = testData[i]\n        # I have to add one extra axis at the beginning by None\n        p = tocpu(net(togpu(x[None,...]))).argmax(1)[0]\n        p = int(p) # Changing Tensors into integers\n        submission_02.at[i, 'c' + str(p)] = 1.0\n        \n    \nsubmission_02","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"66a931f091c62027662143234195aa8f8502881f"},"cell_type":"code","source":"submission_02.to_csv('submission_02_01.csv', index = False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c257f3ad14bc997ff9607bd31dcceb1d7264ac57"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}