{"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_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np\nimport pandas as pd \nimport matplotlib.pyplot as plt\nimport torch \nimport torch.nn as nn \nfrom torch.utils.data import Dataset,DataLoader\nfrom torchvision.utils import make_grid as vutils\nfrom torchvision.datasets import ImageFolder\nfrom torchvision import transforms\nfrom torch.optim import lr_scheduler\nfrom torch.nn import functional as F\nimport matplotlib.patches as patches\nimport random\nimport os\nimport cv2\nimport torch.optim as optim \nfrom tqdm import tqdm\nimport time\nimport copy\nfrom PIL import Image\nimport joblib\nimport math","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:51.446754Z","iopub.execute_input":"2022-04-05T16:52:51.447168Z","iopub.status.idle":"2022-04-05T16:52:52.023161Z","shell.execute_reply.started":"2022-04-05T16:52:51.447091Z","shell.execute_reply":"2022-04-05T16:52:52.022451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seed=42\nrandom.seed(seed)\nos.environ['PYTHONHASHSEED'] = str(seed)\nnp.random.seed(seed)\ntorch.manual_seed(seed)\ntorch.cuda.manual_seed(seed)\ntorch.backends.cudnn.deterministic = True\ndevice=torch.device(\"cuda\") if torch.has_cuda else torch.device(\"cpu\")\nlr=0.001\nepochs=19\nbatch_size=16\ngamma = 0.5\ncsv_combine = pd.read_csv(\"../input/165-different-snakes-species/Csv/train.csv\")\ncsv_test = pd.read_csv(\"../input/165-different-snakes-species/Csv/test.csv\") \nimage_dim = 418","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.028271Z","iopub.execute_input":"2022-04-05T16:52:52.028655Z","iopub.status.idle":"2022-04-05T16:52:52.113812Z","shell.execute_reply.started":"2022-04-05T16:52:52.028618Z","shell.execute_reply":"2022-04-05T16:52:52.113152Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class_id = {}\nfor i,cl in enumerate(csv_combine.class_id.unique()):\n    class_id[cl] = i\nnclass = i+1 ","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.114895Z","iopub.execute_input":"2022-04-05T16:52:52.115136Z","iopub.status.idle":"2022-04-05T16:52:52.120866Z","shell.execute_reply.started":"2022-04-05T16:52:52.115102Z","shell.execute_reply":"2022-04-05T16:52:52.120167Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_set = np.random.randint(0, len(csv_combine)-1, 2000)\ncsv_train = csv_combine.drop(val_set).reset_index().drop(columns = \"index\")\ncsv_val = csv_combine.iloc[val_set].reset_index().drop(columns = \"index\")\ntrain_size = len(csv_train)\nval_size = len(csv_val)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.123390Z","iopub.execute_input":"2022-04-05T16:52:52.124069Z","iopub.status.idle":"2022-04-05T16:52:52.141714Z","shell.execute_reply.started":"2022-04-05T16:52:52.124032Z","shell.execute_reply":"2022-04-05T16:52:52.141023Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"csv_train.head()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.144208Z","iopub.execute_input":"2022-04-05T16:52:52.144414Z","iopub.status.idle":"2022-04-05T16:52:52.164564Z","shell.execute_reply.started":"2022-04-05T16:52:52.144375Z","shell.execute_reply":"2022-04-05T16:52:52.163918Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"csv_val.head()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.165790Z","iopub.execute_input":"2022-04-05T16:52:52.166192Z","iopub.status.idle":"2022-04-05T16:52:52.182549Z","shell.execute_reply.started":"2022-04-05T16:52:52.166156Z","shell.execute_reply":"2022-04-05T16:52:52.181904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"csv_test.head()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.183815Z","iopub.execute_input":"2022-04-05T16:52:52.184256Z","iopub.status.idle":"2022-04-05T16:52:52.199016Z","shell.execute_reply.started":"2022-04-05T16:52:52.184222Z","shell.execute_reply":"2022-04-05T16:52:52.198375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(\"Species\".ljust(97)+\"No Of Images\")\nfor i in csv_train.binomial.unique():\n    print(\"{} {}\".format(i.ljust(100),sum(csv_train.binomial == i)))","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:52.199863Z","iopub.execute_input":"2022-04-05T16:52:52.200034Z","iopub.status.idle":"2022-04-05T16:52:53.123092Z","shell.execute_reply.started":"2022-04-05T16:52:52.200012Z","shell.execute_reply":"2022-04-05T16:52:53.122453Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# imagefolder = ImageFolder(\"../input/165-different-snakes-species/train\", transform=transforms.ToTensor())\n# image_dataloader=DataLoader(imagefolder, batch_size=64, shuffle=True, num_workers=0)\n\n# def batch_mean_and_sd(loader):  \n#     cnt = 0\n#     fst_moment = torch.empty(3)\n#     snd_moment = torch.empty(3)\n\n#     for images, _ in tqdm(loader):\n#         b, c, h, w = images.shape\n#         nb_pixels = b * h * w\n#         sum_ = torch.sum(images, dim=[0, 2, 3])\n#         sum_of_square = torch.sum(images ** 2,\n#                                   dim=[0, 2, 3])\n#         fst_moment = (cnt * fst_moment + sum_) / (cnt + nb_pixels)\n#         snd_moment = (cnt * snd_moment + sum_of_square) / (cnt + nb_pixels)\n#         cnt += nb_pixels\n\n#     mean, std = fst_moment, torch.sqrt(snd_moment - fst_moment ** 2)        \n#     return mean,std\n\n# mean, std = batch_mean_and_sd(image_dataloader)\n#\n# calculated mean and standard deviation\n# mean = [0.4718, 0.4429, 0.3738] , Std = [0.2519, 0.2388, 0.2393]","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:53.124276Z","iopub.execute_input":"2022-04-05T16:52:53.124646Z","iopub.status.idle":"2022-04-05T16:52:53.136018Z","shell.execute_reply.started":"2022-04-05T16:52:53.124613Z","shell.execute_reply":"2022-04-05T16:52:53.135390Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transformation = {\n    \"transformation_image\": transforms.Compose([\n            transforms.ToTensor(),\n            transforms.Resize(size=(image_dim,image_dim)),\n            transforms.Normalize((0.4718, 0.4429, 0.3738),(0.2519, 0.2388, 0.2393))\n        ])\n}    \n\ntransform_aug = transforms.Compose([\n    transforms.RandomRotation(360)\n])\n","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:53.137495Z","iopub.execute_input":"2022-04-05T16:52:53.138452Z","iopub.status.idle":"2022-04-05T16:52:53.149653Z","shell.execute_reply.started":"2022-04-05T16:52:53.138415Z","shell.execute_reply":"2022-04-05T16:52:53.148772Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Dataset_receiver(Dataset):\n    def __init__(self, csv, traindir, device, transform, class_id, aug = None):\n        self.csv = csv\n        self.traindir = traindir\n        self.transform =transform\n        self.device = device\n        self.class_id = class_id\n        self.aug = aug\n    def __len__(self):\n        return len(self.csv)\n    def __getitem__(self, idx):\n        \n        csv = self.csv.iloc[[idx]]\n        cl = csv[\"class_id\"].values[0]\n        location = self.traindir + \"/\" + str(cl) + \"/\" + csv[\"UUID\"].values[0] + \".jpg\"\n        bbox = []\n        image = Image.open(location)\n        key = str(cl) + csv[\"UUID\"].values[0]\n        if self.aug != None:\n            image = self.aug(image)\n            \n        image = np.array(image)\n\n        \n        # now [x center , y center , width , height]  \n        shape = image.shape[0]\n        try:\n            x,y,width,height = [csv.X, csv.Y, csv.width, csv.height] * shape\n            x0 ,y0 = int(x-(width/2)) ,int(y-(height/2))\n            x1 ,y1 = int(x+(width/2)) ,int(y+(height/2))\n\n            if x0 < 0:\n                x0=0\n            if x1 > shape:\n                x1 = shape\n            if y0 < 0:\n                y0 = 0\n            if y1 > shape:\n                y1 = shape\n\n            processed_image = self.transform[\"transformation_image\"](image[y0:y1, x0:x1])\n            return processed_image, torch.tensor(self.class_id[cl]) \n        except:\n            processed_image = self.transform[\"transformation_image\"](image)\n            return processed_image, torch.tensor(self.class_id[cl])\n","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:53.150993Z","iopub.execute_input":"2022-04-05T16:52:53.152032Z","iopub.status.idle":"2022-04-05T16:52:53.168603Z","shell.execute_reply.started":"2022-04-05T16:52:53.151995Z","shell.execute_reply":"2022-04-05T16:52:53.167838Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset_aug = Dataset_receiver(csv_train, \"../input/165-different-snakes-species/train/\", device, transformation, class_id, transform_aug)\ntrain_dataset_normal = Dataset_receiver(csv_train, \"../input/165-different-snakes-species/train/\", device, transformation, class_id)\ntest_dataset = Dataset_receiver(csv_test, \"../input/165-different-snakes-species/test/\", device, transformation, class_id)\n\ntrain_dataset = train_dataset_aug + train_dataset_normal\nval_dataset = Dataset_receiver(csv_val, \"../input/165-different-snakes-species/train/\", device, transformation, class_id)\n\ntrain_dataloader = DataLoader(train_dataset, batch_size = batch_size, shuffle = True)\nval_dataloader = DataLoader(val_dataset, batch_size = batch_size)\ntest_dataloader = DataLoader(test_dataset, batch_size = batch_size)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:53.169879Z","iopub.execute_input":"2022-04-05T16:52:53.170303Z","iopub.status.idle":"2022-04-05T16:52:53.194558Z","shell.execute_reply.started":"2022-04-05T16:52:53.170273Z","shell.execute_reply":"2022-04-05T16:52:53.193595Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a,_ = next(iter(train_dataloader))\nplt.figure(figsize=(20,20))\nplt.title(\"Training Dataset\")\nplt.imshow(torch.swapdims(torch.swapdims(vutils(a,8,2),0,2),0,1))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:53.200772Z","iopub.execute_input":"2022-04-05T16:52:53.201100Z","iopub.status.idle":"2022-04-05T16:52:54.494998Z","shell.execute_reply.started":"2022-04-05T16:52:53.200995Z","shell.execute_reply":"2022-04-05T16:52:54.494351Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a,_ = next(iter(val_dataloader))\nplt.figure(figsize=(20,20))\nplt.title(\"Validation Dataset\")\nplt.imshow(torch.swapdims(torch.swapdims(vutils(a,8,2),0,2),0,1))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:54.495903Z","iopub.execute_input":"2022-04-05T16:52:54.496111Z","iopub.status.idle":"2022-04-05T16:52:55.744757Z","shell.execute_reply.started":"2022-04-05T16:52:54.496083Z","shell.execute_reply":"2022-04-05T16:52:55.743108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"a,_ = next(iter(test_dataloader))\nplt.figure(figsize=(20,20))\nplt.title(\"Test Dataset\")\nplt.imshow(torch.swapdims(torch.swapdims(vutils(a,8,2),0,2),0,1))\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:55.746010Z","iopub.execute_input":"2022-04-05T16:52:55.746459Z","iopub.status.idle":"2022-04-05T16:52:56.742215Z","shell.execute_reply.started":"2022-04-05T16:52:55.746422Z","shell.execute_reply":"2022-04-05T16:52:56.741577Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class GeM(nn.Module):\n    def __init__(self, p=3, eps=1e-6):\n        super(GeM, self).__init__()\n        self.p = nn.Parameter(torch.ones(1)*p)\n        self.eps = eps\n\n    def forward(self, x):\n        return self.gem(x, p=self.p, eps=self.eps)\n        \n    def gem(self, x, p=3, eps=1e-6):\n        return F.avg_pool2d(x.clamp(min=eps).pow(p), (x.size(-2), x.size(-1))).pow(1./p)\n        \n    def __repr__(self):\n        return self.__class__.__name__ + \\\n                '(' + 'p=' + '{:.4f}'.format(self.p.data.tolist()[0]) + \\\n                ', ' + 'eps=' + str(self.eps) + ')'","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.743340Z","iopub.execute_input":"2022-04-05T16:52:56.743692Z","iopub.status.idle":"2022-04-05T16:52:56.753428Z","shell.execute_reply.started":"2022-04-05T16:52:56.743660Z","shell.execute_reply":"2022-04-05T16:52:56.752365Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class arcFace(nn.Module):\n    \n    def __init__(self, in_features, out_features, m=0.50, ls_eps=0.0):\n        super(arcFace, self).__init__()\n        self.in_features = in_features\n        self.out_features = out_features\n        self.weight = nn.Parameter(torch.FloatTensor(in_features, out_features))\n        nn.init.xavier_uniform_(self.weight)\n        \n    def forward(self, x):\n        x_norm = F.normalize(x)\n        W_norm = F.normalize(self.weight, dim=0)\n        return x_norm @ W_norm","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.754892Z","iopub.execute_input":"2022-04-05T16:52:56.755196Z","iopub.status.idle":"2022-04-05T16:52:56.764061Z","shell.execute_reply.started":"2022-04-05T16:52:56.755164Z","shell.execute_reply":"2022-04-05T16:52:56.763287Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SnakeModel(nn.Module):\n    \n    def __init__(self, embeddingSize):\n        super(SnakeModel, self).__init__()\n        self.model = torch.hub.load('NVIDIA/DeepLearningExamples:torchhub', 'nvidia_efficientnet_widese_b4', pretrained=True)\n        self.model.classifier.dropout = nn.Identity()\n        #self.model.classifier.pooling = GeM()\n        self.model.classifier.fc = nn.Linear(self.model.classifier.fc.in_features, embeddingSize)\n        self.arc = arcFace(embeddingSize,  nclass)\n        \n    def forward(self, images):\n        embedding = self.model(images)\n        output = self.arc(embedding)\n        return output","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.765675Z","iopub.execute_input":"2022-04-05T16:52:56.765949Z","iopub.status.idle":"2022-04-05T16:52:56.777109Z","shell.execute_reply.started":"2022-04-05T16:52:56.765912Z","shell.execute_reply":"2022-04-05T16:52:56.776329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def arcface_loss(cosine, targ, m=.4):\n    # this prevents nan when a value slightly crosses 1.0 due to numerical error\n    cosine = cosine.clip(-1+1e-7, 1-1e-7) \n    # Step 3:\n    arcosine = cosine.arccos()\n    # Step 4:\n    arcosine += F.one_hot(targ, num_classes = nclass) * m\n    # Step 5:\n    cosine2 = arcosine.cos()\n    # Step 6:\n    return F.cross_entropy(cosine2, targ)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.778802Z","iopub.execute_input":"2022-04-05T16:52:56.779154Z","iopub.status.idle":"2022-04-05T16:52:56.786889Z","shell.execute_reply.started":"2022-04-05T16:52:56.779114Z","shell.execute_reply":"2022-04-05T16:52:56.786058Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, criterion, optimizer, scheduler, num_epochs=25, verbose = 1):\n    since = time.time()\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                dataloaders=train_dataloader\n                model.train()  # Set model to training mode\n                dataset_sizes=train_size*2\n            else:\n                dataloaders=val_dataloader\n                model.eval()   # Set model to evaluate mode\n                dataset_sizes=val_size\n                \n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # Iterate over data.\n            if verbose == 1:\n                loop = tqdm(dataloaders)\n            else:\n                loop = dataloaders\n            for inputs, labels in loop:\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n\n                # zero the parameter gradients\n                optimizer.zero_grad()\n\n                # forward\n                # track history if only in train\n                with torch.set_grad_enabled(phase == 'train'):\n                    outputs = model(inputs)\n                    _, preds = torch.max(outputs, 1)\n                    loss = criterion(outputs, labels)\n\n                    # backward + optimize only if in training phase\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                # statistics\n                running_loss += loss.item()* inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n                if verbose == 1:\n                    loop.set_postfix(loss=loss.item())\n            if phase == 'train':\n                scheduler.step()\n\n            epoch_loss = running_loss / dataset_sizes\n            epoch_acc = running_corrects.double() / dataset_sizes\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(\n                phase, epoch_loss, epoch_acc))\n\n            # deep copy the model\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model\n\ndef accuracy(dataloader, model):\n    model.eval()\n    result = []\n    output = []\n    label = []\n    with torch.no_grad():\n        for i, j in dataloader:\n            out = model(i.to(device))\n            out = out.argmax(dim = 1).to(torch.device(\"cpu\"))\n            result += (j == out).tolist()\n            output += out.tolist()\n            label += j.tolist()\n    print(\"Accuarcy Of the Test set: \",sum(result)/len(result))  \n    return output, label\n            ","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.788566Z","iopub.execute_input":"2022-04-05T16:52:56.789002Z","iopub.status.idle":"2022-04-05T16:52:56.810815Z","shell.execute_reply.started":"2022-04-05T16:52:56.788965Z","shell.execute_reply":"2022-04-05T16:52:56.810077Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = SnakeModel(128)\nmodel = model.to(device)\n\ncriterion = arcface_loss\n\noptimizer = optim.Adam(model.parameters(), lr=lr)\n\nscheduler = lr_scheduler.StepLR(optimizer, step_size=3, gamma=gamma)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:56.812175Z","iopub.execute_input":"2022-04-05T16:52:56.813159Z","iopub.status.idle":"2022-04-05T16:52:59.354676Z","shell.execute_reply.started":"2022-04-05T16:52:56.813116Z","shell.execute_reply":"2022-04-05T16:52:59.353905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = train_model(model, criterion, optimizer, scheduler, num_epochs=epochs, verbose = 1)\noutput, label = accuracy(test_dataloader, model)\noutput, label = np.array(output), np.array(label)","metadata":{"execution":{"iopub.status.busy":"2022-04-05T16:52:59.357948Z","iopub.execute_input":"2022-04-05T16:52:59.358157Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"count = 0\nfor i in list(class_id.values()):\n    temp = label[np.array(label) == i] == output[np.array(label) == i]\n    print(\"For label {} , acc: {}\".format(i,sum(temp)/len(temp)))\n    if (sum(temp)/len(temp)) < 0.5 :\n        count += 1\nprint(\"Class with accuracy less than 50% :\",count)    \ntorch.save(model,'model_snakes.pt')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}