{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport torch\nimport torchvision\nimport matplotlib.pyplot as plt\nimport matplotlib\nimport matplotlib.image as im\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import transforms, utils\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor, FasterRCNN\nfrom torchvision.models.detection.backbone_utils import resnet_fpn_backbone\nfrom PIL import Image\nimport albumentations as A\n\n\"\"\"\nPeak at data - note only 3.3k unique images not alot which means will have to augment the images with albumentations library\n\"\"\"\ntrain_df = pd.read_csv(\"/kaggle/input/global-wheat-detection/train.csv\")\n\nprint(len(train_df[\"image_id\"].unique()))\n\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nPeak at image\n\"\"\"\n\nimgs_df=train_df[\"image_id\"].unique()\n\nimage_id = imgs_df[45]\n\nimg = im.imread(\"/kaggle/input/global-wheat-detection/train/\" + image_id +\".jpg\")\n\nboxes = list(train_df[\"bbox\"][ train_df[\"image_id\"]==image_id ].values)\n\nbox=[]\nfor i,l in enumerate(boxes): \n    b=[float(num) for num in l[1:-1].split(\",\")] \n    #boxes[i]=[b[0],b[1],b[0]+b[2],b[1]+b[3]]\n    #box.append([b[0],b[1],b[0]+b[2],b[1]+b[3]])\n    box.append(b)\n\ndef print_im(image,bboxes):\n    \n    fig, ax = plt.subplots(figsize=(10, 10))\n    ax.imshow(image)\n    for c in bboxes:\n        rect = matplotlib.patches.Rectangle((c[0],c[1]),c[2],c[3],linewidth=1,edgecolor='r',facecolor='none')\n        ax.add_patch(rect)\n    plt.show()\n    \n###----------------------\n\n#format sets the format for the bounding boxes\ntransform = A.Compose([\n    #A.RandomCrop(width=450, height=450),\n    A.Resize(512, 512),\n    A.VerticalFlip(p=1),\n    #A.HorizontalFlip(p=1),\n    A.RandomBrightnessContrast(p=0.2),\n], bbox_params=A.BboxParams(format='coco', label_fields=['class_labels']))\n#bbox_params=A.BboxParams(format='coco', min_area=1024, min_visibility=0.1, label_fields=['class_labels']))\n\ntransformed = transform( image=img, bboxes=box, class_labels=[\"wheat\"]*len(box) )\ntransformed_image = transformed['image']\ntransformed_bboxes = transformed['bboxes']\n\n#print_im(img,box)\nprint_im(transformed_image,transformed_bboxes)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define DataSet"},{"metadata":{"trusted":true},"cell_type":"code","source":"class ImageDataset(Dataset):\n    def __init__(self, root=\"/kaggle/input/global-wheat-detection/\", tt=\"train\",transforms_tt=True):\n        \n        df=pd.read_csv(\"{}{}.csv\".format(root,tt))\n        \n        self.root = root\n        self.transforms = transforms\n        self.imgs = df[\"image_id\"].unique()\n        self.df=df\n        self.tt=tt\n        self.transform=None\n        if transforms_tt is True:\n            self.transform=A.Compose( [  A.Resize(512, 512),\n                                         A.VerticalFlip(p=0.25),\n                                         A.HorizontalFlip(p=0.25),\n                                         A.RandomBrightnessContrast(p=0.2)],\n                                         #ToTensorV2], \n                                      bbox_params=A.BboxParams(format='coco', label_fields=['class_labels']))\n\n    def __getitem__(self, idx):\n        # load images ad masks\n        image_id = self.imgs[idx]\n        \n        _image = im.imread(\"/kaggle/input/global-wheat-detection/{}/{}.jpg\".format(self.tt,image_id))\n        #image = Image.open( \"/kaggle/input/global-wheat-detection/{}/{}.jpg\".format(self.tt,image_id) )\n        \n        records = self.df[\"bbox\"][self.df['image_id'] == image_id].values\n        boxes=[]\n        for i,l in enumerate(records): \n            b=[float(num) for num in l[1:-1].split(\",\")] \n            boxes.append ( b )\n        \n        #area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        target = {}\n        target[\"labels\"] = torch.ones((records.shape[0],), dtype=torch.int64)\n        #target[\"area\"] = area\n        target[\"iscrowd\"] = torch.zeros((records.shape[0],), dtype=torch.int64)\n        \n        if self.transforms is not None:\n            transformed = self.transform( image=_image, bboxes=boxes, class_labels=[\"wheat\"]*len(boxes) )\n            img = transformed['image']\n            img=torchvision.transforms.functional.to_tensor(img)\n            transformed_bboxes = transformed['bboxes']\n            bboxes=[]\n            for b in transformed_bboxes:\n                bboxes.append([b[0],b[1],b[0]+b[2],b[1]+b[3]])\n            target[\"boxes\"]=torch.as_tensor(bboxes, dtype=torch.float32)\n            \n        if self.transform is None:\n            bboxes=[]\n            for b in boxes:\n                bboxes.append([b[0],b[1],b[0]+b[2],b[1]+b[3]])\n            target[\"boxes\"]=bboxes\n            img=torchvision.transforms.functional.to_tensor(_image)\n        \n        del records\n        del _image\n        \n        return img, target\n\n    def __len__(self):\n        return len(self.imgs)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = ImageDataset()\ndata_loader = DataLoader(dataset,batch_size=50,collate_fn=lambda batch: list(zip(*batch)) )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nCheck.\n\"\"\"\ndataset = ImageDataset()\ndata_loader = DataLoader(dataset,batch_size=50,collate_fn=lambda batch: list(zip(*batch)) )\n\nimages, targets= next(iter(data_loader))\n\nidx=45\n\nimg= images[idx].permute(1,2,0).numpy()\n\nprint(img.shape)\n\nfig, ax = plt.subplots(figsize=(10, 10))\n\nax.imshow(img)\n\nboxes=targets[idx][\"boxes\"].numpy()\n\nfor c in boxes:\n    rect = matplotlib.patches.Rectangle((c[0],c[1]),c[2]-c[0],c[3]-c[1],linewidth=1,edgecolor='r',facecolor='none')\n    ax.add_patch(rect)\n\n\nplt.show()\n        ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Define Model"},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nDownload and set up model\n\"\"\"     \nmodel=torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True, progress=True, pretrained_backbone=True)\n\nnum_classes = 2  # 1 class (wheat) + background\nin_features = model.roi_heads.box_predictor.cls_score.in_features\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch import optim\n\ndataset = ImageDataset()\ndata_loader = DataLoader(dataset,batch_size=10,collate_fn=lambda batch: list(zip(*batch)) )\n\nEPOCHS=16\n\nmodel = model.to(device)\nmodel.train()\n\n\nparams = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=0.0008, momentum=0.9, weight_decay=0.0005)\n#scheduler = optim.lr_scheduler.ReduceLROnPlateau(optimizer, 'min', patience=5,cooldown=20,factor=0.65,min_lr=0.00001,verbose=True)\n\nprint(\"Begin training\")\nlossAvg,lossPer=[],[]\nfor epoch in range(EPOCHS):\n    total_loss,count=0,0\n    for batch in data_loader:\n        #check if targets is a list\n        images,targets=batch\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        losses = sum(loss for loss in loss_dict.values())\n        \n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step()\n        \n        if count%10==0:\n            #scheduler.step(losses)\n            print(\"loss: {}\".format( losses.item() ))\n            lossPer.append(losses.item())\n        count+=1\n        total_loss+=losses.item()\n    g=total_loss/count \n    lossAvg.append( g )\n    print(\"END EPOCH #{} avg: {}\".format(epoch,total_loss/count))\n            \n            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# print(lossA[:-10])\n\n# plt.plot(lossA[60:])\n# plt.show()\n# plt.plot(lossA[600:])\n# plt.show()\n# plt.plot(lossA[:-600])\n# plt.show()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# test_imgs=[]\n# for file in os.listdir(\"/kaggle/input/global-wheat-detection/test/\"):\n#     test_imgs.append(file)\n\n# img = im.imread(\"/kaggle/input/global-wheat-detection/test/{}\".format(test_imgs[0]))\n# img = list(img)\n# torch.onnx.export(model,[img], \"dml-frcnn-trained.onnx\")","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Evaluate"},{"metadata":{"trusted":true},"cell_type":"code","source":"test_imgs=[]\nfor file in os.listdir(\"/kaggle/input/global-wheat-detection/test/\"):\n    test_imgs.append(file)\n\nEPOCHS=1\n\nmodel = model.to(device)\nmodel.eval()\n\n\nprint(\"Begin testing\")\n\npredsA=[]\nfor image_id in test_imgs:\n    \n    img = im.imread(\"/kaggle/input/global-wheat-detection/test/{}\".format(image_id))\n    print( img.shape )\n    img=torchvision.transforms.functional.to_tensor(img).to(device)\n    \n    preds = model([img])[0][\"boxes\"]\n    \n    predsA.append( preds.detach().cpu().numpy() )\n    \n\n\n\ntorch.save(model.state_dict(), 'fasterRCNN_101.pth')\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import matplotlib\n\n\nfig, ax = plt.subplots(10,figsize=(60,60))\n\nfor i,boxes in enumerate(predsA):\n    img = im.imread(\"/kaggle/input/global-wheat-detection/test/{}\".format(test_imgs[i]))\n    ax[i].imshow(img)\n    for c in boxes:\n        rect = matplotlib.patches.Rectangle((c[0],c[1]),c[2]-c[0],c[3]-c[1],linewidth=1,edgecolor='r',facecolor='none')\n        ax[i].add_patch(rect)\n\nplt.show()\n\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"\nsubmission is space delimited\n\"\"\"\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"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], j[1][2], j[1][3]))\n\n    return \" \".join(pred_strings)\n\n\ndetection_threshold = 0.5\nresults = []\n\npredsA=[]\nfor image_id in test_imgs:\n    \n    img = im.imread(\"/kaggle/input/global-wheat-detection/test/{}\".format(image_id))\n    print( img.shape )\n    img=torchvision.transforms.functional.to_tensor(img).to(device)\n    \n    outputs = model([img])\n\n    boxes = outputs[0]['boxes'].data.cpu().numpy()\n    scores = outputs[0]['scores'].data.cpu().numpy()\n\n    boxes = boxes[scores >= detection_threshold].astype(np.int32)\n    scores = scores[scores >= detection_threshold]\n\n    boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n    boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n\n    result = {\n        'image_id': image_id,\n        'PredictionString': format_prediction_string(boxes, scores)\n    }\n\n\n    results.append(result)\n        \n        \ntest_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\n\n\nprint( test_df.head() )\n\n\ntest_df.to_csv('submission.csv', index=False)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print( test_df.head() )","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from IPython.display import FileLink\nFileLink(r'fasterRCNN_101.pth')","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}