{"cells":[{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"id":"YTb4OudX0qkw"},"cell_type":"code","source":"import pandas as pd\n\nimport numpy as np\n\nfrom PIL import Image, ImageDraw\nfrom glob import glob\nimport matplotlib.pyplot as plt\nimport os\n\nimport torch\nimport torchvision\n#from torchvision import transforms\nfrom torch.utils.data import DataLoader, Dataset\n\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.rpn import AnchorGenerator\n\nfrom tqdm.notebook import tqdm\n\nimport time\n\n\nimport albumentations as A\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"QoUJilAt0qk3"},"cell_type":"code","source":"root_dir = '/kaggle/input/global-wheat-detection/'\ndrive_dir = '/kaggle/working/'\ntrain_dir = root_dir+'train/'\ntest_dir = root_dir+'test/'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"id":"Tz5NR_j10qk-"},"cell_type":"code","source":"train_frame = pd.read_csv(root_dir+'train.csv')\n\nunique_image_count = len(train_frame['image_id'].unique())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"Ttpt8inE0qlH"},"cell_type":"code","source":"train_glob = glob(train_dir + '*')\ntest_glob = glob(test_dir + '*')","execution_count":null,"outputs":[]},{"metadata":{"id":"wO_zMfk60qlM"},"cell_type":"markdown","source":"Unique images with bounding box and without bounding box","execution_count":null},{"metadata":{"trusted":true,"id":"x07w-bbu0qlN","outputId":"5407ea3a-836b-44b9-8a87-ea1e90fffac9"},"cell_type":"code","source":"print (\"Images with BBox {}\" .format((unique_image_count)))\nprint (\"Images without BBox {}\" .format(len(train_glob) - unique_image_count))","execution_count":null,"outputs":[]},{"metadata":{"id":"_Q6RzmOB0qlR"},"cell_type":"markdown","source":"Source of the image","execution_count":null},{"metadata":{"id":"97_h729r0qlS"},"cell_type":"markdown","source":"# **x,y,w,h from bbox (its a string)**","execution_count":null},{"metadata":{"trusted":true,"id":"r6d1g4-r0qlT"},"cell_type":"code","source":"train_frame[['xmin','ymin','w','h']] = pd.DataFrame(train_frame.bbox.str.strip('[]').str.split(',').tolist()).astype(float)\n\ntrain_frame['xmax'], train_frame['ymax'], train_frame['area'] = train_frame['xmin'] + train_frame['w'], train_frame['ymin'] + train_frame['h'], train_frame['w'] * train_frame['h']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"qnPiHjc70qlb","outputId":"35eebe61-6856-4cd4-f24b-719577228da5"},"cell_type":"code","source":"train_frame[\"class\"] = 1\ntrain_frame.describe()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"zvEQjMUl0qlg"},"cell_type":"code","source":"def show_image(image_id ):\n\n    fig, axs = plt.subplots(1,2, figsize = (24,24))\n    axs = axs.flatten()\n    \n    bbox = train_frame[train_frame['image_id'] == image_id]\n    \n    img_path = os.path.join(train_dir, image_id +'.jpg')\n    \n    image = Image.open(img_path)\n    image2 = torch.from_numpy(np.array(image).astype('float32')) / 255.\n    \n    print(\"Image shape{}\".format(image2.shape))\n    \n    \n    axs[0].set_title('Original Image')\n    axs[0].imshow(image2)\n    \n    for idx, row in bbox.iterrows():\n        x1 = row['xmin']\n        y1 = row['ymin']\n        x2 = row['xmax']\n        y2 = row['ymax']\n        label = 'Wheat' if row['class'] == 1 else 'background'\n        \n        image_wth_bb = ImageDraw.Draw(image)\n        image_wth_bb.rectangle([(x1,y1),(x2,y2)],width = 5, outline = 'red')\n        image_wth_bb.text([(x1,y1-10)], label)\n        \n    axs[1].set_title('Image with BoundingBox')\n    image_wth_bb = torch.from_numpy(np.array(image).astype('float32')) / 255.\n    axs[1].imshow(image_wth_bb)\n    \n    plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"_j7QkdXx0qli","outputId":"ce5f591f-2e13-4f96-f6d8-04c2281522fa"},"cell_type":"code","source":"show_image(train_frame.image_id.unique()[1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"BaVgd-ls0qlt"},"cell_type":"code","source":"class WheatDetectionDataset(Dataset):\n    \"\"\"Global Wheat Detection Dataset\"\"\"\n    \n    def __init__(self,pd_frame, img_dir, transforms = 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            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        \n        self.globalwheat_frame = pd_frame\n        self.image_ids = list(self.globalwheat_frame['image_id'].unique())\n        self.img_dir = img_dir\n        self.transforms = transforms\n        \n    \n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, idx):\n        \n        image_id = self.image_ids[idx]\n        image_data = self.globalwheat_frame.loc[self.globalwheat_frame['image_id'] == image_id]\n        \n        b_boxes = torch.as_tensor(np.array(image_data[['xmin', 'ymin', 'xmax', 'ymax']]), dtype = torch.float32)\n        area = torch.tensor(np.array(image_data['area']), dtype=torch.int64)\n        labels = torch.ones((image_data.shape[0],), dtype=torch.int64)\n        crowd = torch.zeros((image_data['class'].shape[0],), dtype=torch.uint8)\n        \n        target = {}\n        \n        target['boxes'] = b_boxes\n        target['area'] = area\n        target['labels'] = labels\n        target['crowd'] = crowd\n        \n        img_path = os.path.join(self.img_dir, image_id + '.jpg')\n        \n        image = Image.open(img_path)\n        image = np.array(image).astype('float32') / 255.\n        \n\n        \n        if self.transforms:\n            #image, target = self.transforms(image, target)\n            image_transforms = {\n                                'image': image,\n                                'bboxes': target['boxes'],\n                                'labels': labels\n                                }\n            image_transforms = self.transforms(**image_transforms)\n            image = image_transforms['image']\n            \n            target['boxes'] = torch.as_tensor(image_transforms['bboxes'], dtype=torch.float32)\n\n       \n        #else:\n        image = torch.from_numpy(image.transpose(2,0,1))\n       \n    \n        return image, target","execution_count":null,"outputs":[]},{"metadata":{"id":"7LYZV7fjHK61","trusted":true},"cell_type":"code","source":"def get_train_transform():\n    return A.Compose([\n       # A.Resize(p=1, height=512, width=512),\n        #A.RandomCrop( height=512, width=512,p=.5),\n        A.ToGray(p=0.5),\n        A.Flip(p=.5),\n        A.RandomBrightnessContrast(p=.5),\n        A.RandomGamma(p=0.5),\n        A.MotionBlur(p=.5),\n        A.HueSaturationValue(p=0.5),\n        A.GaussNoise(p=.5),\n        #A.ShiftScaleRotate(p=0.5),\n        A.RandomSunFlare(p=.5),\n        A.RandomBrightnessContrast(p=0.3),\n        A.GaussNoise(p=.5),\n        A.RGBShift(r_shift_limit=30, g_shift_limit=30, b_shift_limit=30, p=0.3)\n        \n        #ToTensor()\n    ], bbox_params={'format': 'pascal_voc', 'label_fields': ['labels']})","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_test_transform():\n    return A.Compose([\n        # A.Resize(512, 512),\n        ToTensorV2(p=1.0)\n    ])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"JAKWOvno0qlv"},"cell_type":"code","source":"def get_wheat_dataset_frame(csv):\n    globalwheat_frame = pd.read_csv(csv)\n    \n    globalwheat_frame[['xmin','ymin','w','h']] = pd.DataFrame(globalwheat_frame.bbox.str.strip('[]').str.split(',').tolist()).astype(float)\n    globalwheat_frame['xmax'], globalwheat_frame['ymax'], globalwheat_frame['area'] = globalwheat_frame['xmin'] + globalwheat_frame['w'], globalwheat_frame['ymin'] + globalwheat_frame['h'], globalwheat_frame['w'] * globalwheat_frame['h']\n    globalwheat_frame[\"class\"] = 1\n    \n    return globalwheat_frame","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"DwsqSfRW0qly"},"cell_type":"code","source":"#414\n\ndef get_model_weight():\n    return '../input/gwd-starter-weigths/resnet50_pretrainedGWD-8-colab-1-1e-3-epoch-600 last.pth'\n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"T-UOvfba0ql1"},"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"nw3KgOCj0ql6"},"cell_type":"code","source":"\ndef model_fasterrcnn_resnet50(pretrained = False, pretrained_backbone = True):\n    \n    model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=pretrained,  pretrained_backbone=pretrained_backbone)\n    num_classes = 2  \n    in_features = model.roi_heads.box_predictor.cls_score.in_features\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"id":"RZJBB0cCp81w"},"cell_type":"markdown","source":"### **Data Loading using DataLoader**","execution_count":null},{"metadata":{"trusted":true,"id":"evbEWB-00ql8"},"cell_type":"code","source":"wheat_frame = get_wheat_dataset_frame(root_dir+'train.csv')\nwheatds = WheatDetectionDataset(wheat_frame,train_dir, get_train_transform())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"0Gi0NVFv0ql-"},"cell_type":"code","source":"train_dl = DataLoader(wheatds, batch_size = 16, num_workers=8, shuffle = True, collate_fn=collate_fn)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"UudxudR00qmA","outputId":"4c7e54fb-a52d-40a5-8605-0f3b966458b5"},"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\ntorch.cuda.empty_cache()\nprint(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def save_checkpoint(epoch,model,optimizer,scheduler, loss, PATH):\n    torch.save({\n            'epoch': epoch,\n            'model': model.state_dict(),\n            'optimizer': optimizer.state_dict(),\n            'scheduler': scheduler.state_dict(),\n            'loss': loss,\n            \n            }, PATH)","execution_count":null,"outputs":[]},{"metadata":{"id":"UtEj2Warqm2J"},"cell_type":"markdown","source":"### **Training**","execution_count":null},{"metadata":{"trusted":true,"id":"sQNkz8q60qmD"},"cell_type":"code","source":"def train(data_loader, epoch, resume_training = False):\n        \n    model = model_fasterrcnn_resnet50(pretrained = not resume_training)\n    model.to(device)\n    params = [p for p in model.parameters() if p.requires_grad]\n    optimizer = torch.optim.AdamW(params, lr=7e-04, weight_decay=1e-04)\n    scheduler = torch.optim.lr_scheduler.OneCycleLR(optimizer, max_lr=7e-04, steps_per_epoch=len(data_loader), epochs=epoch)\n    model.parameters\n    total_train_loss = []\n    initial = 0\n    \n    if resume_training:\n        checkpoint = torch.load(get_model_weight())\n        model.load_state_dict(checkpoint['model'])\n        total_train_loss = checkpoint['loss']\n        optimizer.load_state_dict(checkpoint['optimizer'])\n        scheduler.load_state_dict(checkpoint['scheduler'])\n        initial = checkpoint['epoch'] + 1\n        return total_train_loss, initial\n     \n        \n    \n\n\n    \n    itr = 1\n    avg_loss = 0\n    for epoch in tqdm(range(initial,epoch)):\n        \n        print(f'Epoch :{epoch + 1}')\n        start_time = time.time()\n        train_loss = []\n        model.train()\n        \n        for images, targets in tqdm(data_loader):\n            \n            images = list(image.to(device) for image in images)\n            targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n            loss_dict = model(images, targets)\n\n            losses = sum(loss for loss in loss_dict.values())\n            \n            loss_value = losses.item()\n            \n            train_loss.append(loss_value)\n            optimizer.zero_grad()\n            losses.backward()\n            optimizer.step()\n            scheduler.step()\n            \n            \n            if itr % 50 == 0:\n                print(f\"Iteration #{itr} loss: {loss_value:.4f}\")\n\n            itr += 1\n    \n        \n\n        epoch_train_loss = np.mean(train_loss)\n        total_train_loss.append(epoch_train_loss)\n        print(f'Epoch train loss is {epoch_train_loss:.4f}')\n        time_elapsed = time.time() - start_time\n        print('{:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n        \n        if epoch % 5 == 0:\n            save_checkpoint(epoch, model, optimizer, scheduler, total_train_loss, drive_dir+'resnet50_pretrainedGWD-7smallDS-colab-1-600+.pth')\n          \n       \n        plt.figure(figsize=(12,6))\n        plt.title('Train Loss', fontsize= 20)\n        plt.plot(total_train_loss)\n        plt.xlabel('iterations')\n        plt.ylabel('loss') \n        plt.show()\n\n    save_checkpoint(epoch, model, optimizer, scheduler, total_train_loss, drive_dir+'resnet50_pretrainedGWD-7smallDS-colab-1-600'+str(epoch)+'.pth')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"d7cV2ZZd0qmF","outputId":"1e623454-afa9-470e-efd2-f531d5e2e8e1"},"cell_type":"code","source":"#loss, epoch = train(train_dl, 600, True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"plt.figure(figsize=(12,6))\nplt.title('Train Loss', fontsize= 20)\nplt.plot(loss)\nplt.xlabel('epoch')\nplt.ylabel('loss') \nplt.show()","execution_count":null},{"metadata":{"trusted":true,"id":"bva16Lmo0qmL","outputId":"f5428788-6485-4ea5-f78c-5cf3157e1da4"},"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\ntorch.cuda.empty_cache()\n\nprint(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"2jTqn35w0qmP"},"cell_type":"code","source":"class WheatDetectionDataset_Test(Dataset):\n    \"\"\"Global Wheat Detection Dataset\"\"\"\n    \n    def __init__(self,pd_frame, img_dir, transforms = 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            transform (callable, optional): Optional transform to be applied\n                on a sample.\n        \"\"\"\n        \n        self.globalwheat_frame = pd_frame\n        self.image_ids = list(self.globalwheat_frame['image_id'].unique())\n        self.img_dir = img_dir\n        self.transforms = transforms\n        \n    \n    def __len__(self):\n        return len(self.image_ids)\n    \n    def __getitem__(self, idx):\n        \n        image_id = self.image_ids[idx]\n        image_data = self.globalwheat_frame.loc[self.globalwheat_frame['image_id'] == image_id]\n        \n              \n        img_path = os.path.join(self.img_dir, image_id + '.jpg')\n        \n        image = Image.open(img_path)\n        image = np.array(image).astype('float32') / 255.\n        image = torch.from_numpy(image.transpose(2,0,1))\n        \n        if self.transforms:\n            \n            image_transforms = {\n                                'image': image\n                               }\n            \n            image_transforms = self.transforms(**image_transforms)\n            image = image_transforms['image']\n            \n        \n        \n        return image, image_id\n            \n            \n    \n    ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"8j_IXkcN0qmR"},"cell_type":"code","source":"test_frame = pd.read_csv(root_dir+'/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"us_5R12a0qmS"},"cell_type":"code","source":"wheat_detection_test = WheatDetectionDataset_Test(test_frame,test_dir, None )\n\ntest_dl = DataLoader(\n    wheat_detection_test,\n    batch_size=4,\n    shuffle=False,\n    num_workers=4,\n    drop_last=False,\n    collate_fn=collate_fn\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"1K618UhQ0qmW"},"cell_type":"code","source":"def format_prediction_string(boxes, scores):\n    pred_strings = []\n    for j in zip(scores, boxes):\n        pred_strings.append(\"{0:.4f} {1} {2} {3} {4}\".format(j[0], j[1][0], j[1][1], \n                                                             j[1][2], j[1][3]))\n\n    return \" \".join(pred_strings)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"oxJ6MZWY0qmb"},"cell_type":"code","source":"detection_threshold = 0.7\nresults = []\n\ndef predict_result(dataloader, sub_csv = False):\n    \n  \n    \n    model = model_fasterrcnn_resnet50(pretrained=False, pretrained_backbone=False)\n    model.load_state_dict(torch.load(get_model_weight())['model'])\n    model.eval()\n    model.to(device)\n    \n    \n    for images, image_ids in dataloader:\n        \n        images = list(image.to(device)for image in images)\n        outputs = model(images)\n        \n        for i, image in enumerate(images):\n            \n            boxes = outputs[i]['boxes'].data.cpu().numpy()\n            scores = outputs[i]['scores'].data.cpu().numpy()\n            \n            boxes = boxes[scores >= detection_threshold].astype(np.int32)\n            scores = scores[scores >= detection_threshold]\n            \n            image_id = image_ids[i]\n                \n            boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n            boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n            \n            if sub_csv:\n                result = {\n                    'image_id' : image_id,\n                    'PredictionString' : format_prediction_string(boxes, scores)\n                    \n                }\n                \n                results.append(result)\n            \n            \n        img_path = os.path.join(test_dir, image_id + '.jpg')\n        \n        image = Image.open(img_path)\n        \n        \n       \n        \n        for b,s in zip(boxes, scores):\n            \n            image_wth_bb = ImageDraw.Draw(image)\n            image_wth_bb.rectangle([(b[0],b[1]),(b[0]+b[2],b[1]+b[3])],width = 2, outline = 'red')\n            image_wth_bb.text([(b[0],b[1])], '{:.2}'.format(s))\n        \n        image_wth_bb = torch.from_numpy(np.array(image).astype('float32')) / 255.\n        plt.figure(figsize=(12,12))\n        plt.imshow(image_wth_bb)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"hkTEtOu_0qmd"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"rsqoDP4O0qmf","outputId":"f40f824d-33e4-43b5-d22b-ef21a551b7f3"},"cell_type":"code","source":"predict_result(test_dl, sub_csv=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"hZYRURwV0qmi"},"cell_type":"code","source":"test_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"results","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}