{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"%matplotlib inline\n\nimport os\nimport time\nimport copy\nimport pandas as pd\nimport numpy as np\n\nfrom random import seed\nfrom random import randint\nimport random\n\nimport torch\nfrom torch import nn\nfrom torch import optim\nimport torch.nn.functional as F\nfrom torchvision import datasets, transforms, models\n\nfrom PIL import Image\nfrom matplotlib import pyplot as plt\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\n\nfrom tqdm import tqdm_notebook as tqdm\n\n\ninput_dir = os.path.join('..','input','imet-2019-fgvc6')\ntrain_dir = os.path.join(input_dir,'train')\ntest_dir  = os.path.join(input_dir,'test')\nlabels_csv= os.path.join(input_dir,'labels.csv')\ntrain_csv = os.path.join(input_dir,'train.csv')\nresnet_weights_path = os.path.join('..','input','resnet50','resnet50.pth')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def seed_all(seed=27):\n    \"\"\"https://pytorch.org/docs/stable/notes/randomness.html\"\"\"\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\nseed_all(27)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BATCH_SIZE = 128\nNUM_EPOCHS = 20\nPERCENTILE = 99.7\nLEARNING_RATE = 0.0001\nDISABLE_TQDM = True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv(labels_csv)\nattribute_dict = dict(zip(df.attribute_id,df.attribute_name))\ndel df,labels_csv","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"tag_count = 0 \nculture_count = 0\nfor idx,data in attribute_dict.items():\n    if data.split(\"::\")[0] == 'tag':\n        tag_count+=1\n    if data.split(\"::\")[0] == 'culture':\n        culture_count+=1\nprint('total_categories: {0}\\ntag_categories: {1} \\nculture_categories: {2} ' \\\n      .format(len(attribute_dict),tag_count,culture_count))\n#cross check your results\nassert tag_count+culture_count == len(attribute_dict)\noutput_dim = len(attribute_dict) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv(train_csv)\nlabels_dict = dict(zip(df.id,df.attribute_ids))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"idx = len(os.listdir(train_dir))\nnumber = randint(0,idx)\nimage_name = os.listdir(train_dir)[number]\ndef imshow(image):\n    plt.figure(figsize=(6, 6))\n    plt.imshow(image)\n    plt.show()\n# Example image\nx = Image.open(os.path.join(train_dir,image_name))\nfor i in labels_dict[os.listdir(train_dir)[number].split('.')[0]].split():\n    print(attribute_dict[int(i)])\nnp.array(x).shape\nimshow(x)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# need to add more transforms here\ndata_transforms = transforms.Compose([\n        transforms.Resize((224,224)),\n        transforms.ToTensor(),\n    ])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Custom Dataset class"},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.utils import data\nclass ImageData(data.Dataset):\n    def __init__(self,df,dirpath,transform,test = False):\n        self.df = df\n        self.test = test\n        self.dirpath = dirpath\n        self.conv_to_tensor = transform\n        #image data \n        if not self.test:\n            self.image_arr = np.asarray(str(self.dirpath)+'/'+self.df.iloc[:, 0]+'.png')\n        else:\n            self.image_arr = np.asarray(str(self.dirpath)+'/'+self.df.iloc[:, 0])\n        \n        #labels data\n        if not self.test:\n             self.label_df = self.df.iloc[:,1]\n        \n        # Calculate length of df\n        self.data_len = len(self.df.index)\n\n    def __len__(self):\n        return self.data_len\n    \n    def __getitem__(self, idx):\n        image_name = self.image_arr[idx]\n        img = Image.open(image_name)\n        img_tensor = self.conv_to_tensor(img)\n        if not self.test:\n            image_labels = self.label_df[idx]\n            label_tensor = torch.zeros((1, output_dim))\n            for label in image_labels.split():\n                label_tensor[0, int(label)] = 1\n            image_label = torch.tensor(label_tensor,dtype= torch.float32)\n            return (img_tensor,image_label.squeeze())\n        return (img_tensor)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv(train_csv)\n# if you want to run on less data to quickly check\n#df = pd.read_csv(train_csv).head(5000)\nfrom sklearn.model_selection import train_test_split\ntrain_df,val_df = train_test_split(df, test_size=0.20)\ntrain_df = train_df.reset_index(drop=True)\nval_df = val_df.reset_index(drop=True)\nprint(f\"Validation_Data Length: {len(val_df)}\\n Train_Data Length: {len(train_df)}\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Train dataset\ntrain_dataset = ImageData(train_df,train_dir,data_transforms)\ntrain_loader = data.DataLoader(dataset=train_dataset,batch_size=BATCH_SIZE,shuffle=False)\n\n# validation dataset\nval_dataset = ImageData(val_df,train_dir,data_transforms)\nval_loader = data.DataLoader(dataset=val_dataset,batch_size=BATCH_SIZE,shuffle=False)\n\n# test dataset\ntest_df = pd.DataFrame(os.listdir(test_dir))\ntest_dataset = ImageData(test_df,test_dir,data_transforms,test = True)\ntest_loader = data.DataLoader(dataset=test_dataset,batch_size=BATCH_SIZE,shuffle=False)\n\ndataloaders_dict = {'train':train_loader, 'val':val_loader}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"features, labels = next(iter(train_loader))\nprint(f'Train Features: {features.shape}\\nTrain Labels: {labels.shape}')\nprint()\nfeatures, labels = next(iter(val_loader))\nprint(f'Validation Features: {features.shape}\\nValidation Labels: {labels.shape}')\nprint()\nfeatures = next(iter(test_loader))\nprint(f'Test Features: {features.shape}\\n')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Model Using Resnet50"},{"metadata":{"trusted":true},"cell_type":"code","source":"resnet_cls = models.resnet50()\nresnet_cls.load_state_dict(torch.load(resnet_weights_path))\n\nclass AvgPool(nn.Module):\n    def forward(self, x):\n        return F.avg_pool2d(x, x.shape[2:])\n    \nclass ResNet50(nn.Module):\n    def __init__(self,num_outputs):\n        super(ResNet50,self).__init__()\n        self.resnet = resnet_cls\n        layer4 = self.resnet.layer4\n        self.resnet.layer4 = nn.Sequential(\n                                    nn.Dropout(0.5),\n                                    layer4\n                                    )\n        self.resnet.avgpool = AvgPool()\n        self.resnet.fc = nn.Linear(2048, num_outputs)\n        for param in self.resnet.parameters():\n            param.requires_grad = False\n\n        for param in self.resnet.layer4.parameters():\n            param.requires_grad = True\n\n        for param in self.resnet.fc.parameters():\n            param.requires_grad = True\n            \n    def forward(self,x):\n        out = self.resnet(x)\n        return out\n    \nNeuralNet = ResNet50(num_outputs = output_dim) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"NeuralNet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"total_params = sum(p.numel() for p in NeuralNet.parameters())\nprint(f'{total_params:,} total parameters.')\ntotal_trainable_params = sum(p.numel() for p in NeuralNet.parameters() if p.requires_grad)\nprint(f'{total_trainable_params:,} training parameters.')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"TRAINING\")\nprint(\"training examples: \",len(train_dataset))\nprint(\"batch size: \",BATCH_SIZE)\nprint(\"batches available: \",len(train_loader))\nprint()\nprint(\"TESTING\")\nprint(\"validation examples: \",len(val_dataset))\nprint(\"batch size: \",BATCH_SIZE)\nprint(\"batches available: \",len(val_loader))\nprint()\nprint(\"VALIDATION\")\nprint(\"testing examples: \",len(test_dataset))\nprint(\"batch size: \",BATCH_SIZE)\nprint(\"batches available: \",len(test_loader))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train the Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"NeuralNet = NeuralNet.to(device)\noptimizer = optim.Adam(NeuralNet.parameters(),lr = LEARNING_RATE)\nloss_func = torch.nn.BCEWithLogitsLoss()\nscheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer,patience = 2)\nbest_loss = np.inf\nfor epoch in range(NUM_EPOCHS):\n    for phase in ['train', 'val']:\n        start_time = time.time()\n        if phase == 'train':\n            NeuralNet.train()\n        else:\n            NeuralNet.eval()\n            \n        running_loss = 0.0\n        for images_batch, labels_batch in tqdm(dataloaders_dict[phase],disable = DISABLE_TQDM):\n            images_batch = images_batch.to(device)\n            labels_batch = labels_batch.to(device)\n            \n            optimizer.zero_grad()\n            \n            with torch.set_grad_enabled(phase == 'train'):\n                pred_batch = NeuralNet(images_batch)\n                loss = loss_func(pred_batch,labels_batch)\n                \n            if phase == 'train':\n                loss.backward()\n                optimizer.step()\n                \n            running_loss += loss.item() * images_batch.size(0)    \n        epoch_loss = running_loss / len(dataloaders_dict[phase].dataset)            \n\n        if phase == 'val' and epoch_loss < best_loss:            \n            print(\"model val_loss Improved from {:.8f} to {:.8f}\".format(best_loss,epoch_loss))\n            best_loss = epoch_loss\n            best_model_wts = copy.deepcopy(NeuralNet.state_dict())\n        \n        if phase == 'val':\n            scheduler.step(epoch_loss)\n        \n        elapsed_time = time.time()-start_time\n        print(\"Phase: {} | Epoch: {}/{} | {}_loss:{:.8f} | Time: {:.4f}s\".format(phase,\n                                                                              epoch+1,\n                                                                              NUM_EPOCHS,\n                                                                              phase,\n                                                                              epoch_loss,\n                                                                              elapsed_time))\nNeuralNet.load_state_dict(best_model_wts)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Predictions from the model"},{"metadata":{"trusted":true},"cell_type":"code","source":"NeuralNet.eval()\npredictions = np.zeros((len(test_dataset), output_dim))\ni = 0\nfor test_batch in tqdm(test_loader,disable = DISABLE_TQDM):\n    test_batch = test_batch.to(device)\n    batch_prediction = NeuralNet(test_batch).detach().cpu().numpy()\n    predictions[i * BATCH_SIZE:(i+1) * BATCH_SIZE, :] = batch_prediction\n    i+=1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Generating submission "},{"metadata":{"trusted":true},"cell_type":"code","source":"predicted_class_idx = []\nfor i in range(len(predictions)):         \n    idx_list = np.where(predictions[i] > np.percentile(predictions[i],PERCENTILE))    \n    predicted_class_idx.append(idx_list[0])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df['attribute_ids'] = predicted_class_idx\ntest_df['attribute_ids'] = test_df['attribute_ids'].apply(lambda x : ' '.join(map(str,list(x))))\ntest_df = test_df.rename(columns={0: 'id'})\ntest_df['id'] = test_df['id'].apply(lambda x : x.split('.')[0])\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df.to_csv('submission.csv',index = False)","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}