{"cells":[{"metadata":{},"cell_type":"markdown","source":"* https://www.kaggle.com/aleksandradeis/globalwheatdetection-eda\n\n* https://www.kaggle.com/shonenkov/training-efficientdet","execution_count":null},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os\nimport cv2\nimport re\nimport random\nimport numpy as np\nimport pandas as pd\n\n# For Visualization\nimport plotly.express as px\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\n# For Image Augmentation\nimport albumentations as A\nfrom PIL import Image,ImageDraw\nfrom ast import literal_eval\n\n# For parallel processing\nfrom joblib import Parallel,delayed\n\n# For Object Detection\nimport torch\nimport torchvision\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset,DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.rpn import AnchorGenerator","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_model(filepath):\n    checkpoint = torch.load(filepath)\n    model = checkpoint['model']\n    model.load_state_dict(checkpoint['state_dict'])\n    for parameter in model.parameters():\n        parameter.requires_grad = False\n    \n    model.eval()\n    \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.chdir('/kaggle/input/global-wheat-detection')\nos.listdir()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test=os.listdir('test')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train=pd.read_csv('train.csv')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['x_min']=train['bbox'].apply(lambda x:float(re.findall(r'[0-9.]+',x.split(',')[0])[0]))\ntrain['y_min']=train['bbox'].apply(lambda x:float(re.findall(r'[0-9.]+',x.split(',')[1])[0]))\ntrain['box_width']=train['bbox'].apply(lambda x:float(re.findall(r'[0-9.]+',x.split(',')[2])[0]))\ntrain['box_height']=train['bbox'].apply(lambda x:float(re.findall(r'[0-9.]+',x.split(',')[3])[0]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train.drop('bbox',axis=1,inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train['box_area']=train['box_width']*train['box_height']\ntrain['x_max']=train['x_min']+train['box_width']\ntrain['y_max']=train['y_min']+train['box_height']","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(f'No of Unique Images are {train.image_id.nunique()}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Visualizing Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def show_images(df,rows,cols,title,linecolor):\n    \"\"\" Function to show images with detected objects\"\"\"\n    fig, axs = plt.subplots(rows, cols, figsize=(10,10))\n    \n    for row in range(rows):\n        for col in range(cols):\n            idx = np.random.randint(len(df), size=1)[0]\n            images=df.iloc[idx].image_id\n\n            path=os.path.join('train',images+'.jpg')\n            image=Image.open(path)\n\n            objects=train[train['image_id']==images][['x_min','x_max','y_min','y_max']].values\n            # Drawing on the Image\n            draw=ImageDraw.Draw(image)\n\n            for box in objects:\n                draw.rectangle([box[0],box[2],box[1],box[3]],width=10,outline=linecolor)\n            plt.figure(figsize=(10,10))\n            axs[row,col].imshow(image)\n            axs[row,col].axis('off')\n    plt.suptitle(title)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# No of Bounding Boxes per Image\ntrain['count']=train.apply(lambda row: 1 if np.isfinite(row.width) else 0, axis=1)\ntrain_images_spikes= train.groupby('image_id')['count'].sum().reset_index()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualizing Spikes\ncounts,bins=np.histogram(train_images_spikes['count'],bins=range(0,117,4))\nlabels=[]\nfor i in range(0,len(bins)-1):\n    labels.append(f'({bins[i]}-{bins[i+1]}]')\npx.bar(x=labels,y=counts,labels={'x':'Range of Wheats per Images','y':'count'},title=\"Number of wheat spikes per image\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualizing Images with Higher spikes\nshow_images(train_images_spikes[train_images_spikes['count']>50],3,3,'Images with Higher Spikes','red')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sns.distplot(train['box_area'],kde=False,bins=100)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"show_images(train[train['box_area']>500000],3,3,'Images with large bounding box','red')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":" So we need to delete boxes with large areas","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"image_transforms=transforms.Compose([\n    transforms.ToTensor(),\n    transforms.Normalize([0.485,0.456,0.406],\n                            [0.229,0.224,0.225])\n])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Spliting the dataset\ntrain_set,val_set=train_test_split(train,test_size=0.15,random_state=1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class DatasetGenerator(Dataset):\n    \n    def __init__(self,dataset,transforms=None,test=False):\n        super().__init__()\n        self.dataset=dataset # Train dataset which contains boxes\n        self.transforms=transforms # Image Transformation\n        self.test=test # Test set\n    \n    def __getitem__(self,index):\n        image_id = self.dataset.iloc[index]['image_id']\n        img_path=os.path.join(f'train/{image_id}.jpg')\n        img=Image.open(img_path)\n        \n        # Convert everything into a torch tensor\n        boxes=torch.tensor(self.dataset[self.dataset['image_id']==image_id]\n                           [['x_min','y_min','x_max','y_max']].values,dtype=torch.float32)\n        \n        # Classes\n        labels=torch.ones((boxes.shape[0]),dtype=torch.int64)\n        iscrowd=torch.zeros((boxes.shape[0],), dtype=torch.int64)        \n        target={}\n        \n        target['boxes']=boxes\n        target['labels']=labels\n        target['image_id']=torch.tensor([index])\n        target['area']=torch.tensor(self.dataset[self.dataset['image_id']==image_id]['box_area'].values,\n                                    dtype=torch.float32)\n        target['iscrowd']=iscrowd\n        \n        if self.transforms is not None:\n            img=self.transforms(img)\n        return img,target\n    \n    def __len__(self):\n        return self.dataset['image_id'].nunique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = DatasetGenerator(\n    dataset=train_set,\n    transforms=image_transforms,\n    test=False,\n)\n\nvalidation_dataset = DatasetGenerator(\n    dataset=val_set,\n    transforms=image_transforms,\n    test=True,\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))\n\ntrain_loader=DataLoader(train_dataset,batch_size=4,shuffle=False,num_workers=4,collate_fn=collate_fn)\ntest_loader=DataLoader(validation_dataset,batch_size=4,shuffle=False,num_workers=4,collate_fn=collate_fn)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Loading Pretrained FasterRCNN Model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"DEVICE=torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\nNUM_EPOCHS=1\nLR=0.005","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# load a model pre-trained pre-trained on COCO\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)\n\n# replace the classifier with a new one, that has\n# num_classes which is user-defined\nnum_classes = 2  # 1 class (Wheat spikes) + background\n# get number of input features for the classifier\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n# replace the pre-trained head with a new one\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Train","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"model=model.to(DEVICE)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Averager:\n    def __init__(self):\n        self.current_total = 0.0\n        self.iterations = 0.0\n\n    def send(self, value):\n        self.current_total += value\n        self.iterations += 1\n\n    @property\n    def value(self):\n        if self.iterations == 0:\n            return 0\n        else:\n            return 1.0 * self.current_total / self.iterations\n\n    def reset(self):\n        self.current_total = 0.0\n        self.iterations = 0.0","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_loss=0\nval_loss=0\nepochs=list(range(NUM_EPOCHS))\n\n# construct an optimizer\nparams = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.SGD(params, lr=LR,\n                            momentum=0.9, weight_decay=0.0005)\n# and a learning rate scheduler\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,\n                                               step_size=3,\n                                               gamma=0.1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loss_hist = Averager()\nitr = 1\n\nfor epoch in range(NUM_EPOCHS):\n    loss_hist.reset()\n    \n    for images, targets in train_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        loss_value = losses.item()\n\n        loss_hist.send(loss_value)\n\n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step()\n        del images,targets\n\n        if itr % 50 == 0:\n            print(f\"Iteration #{itr} loss: {loss_value}\")\n\n        itr += 1\n    \n    # update the learning rate\n    if lr_scheduler is not None:\n        lr_scheduler.step()\n\n    print(f\"Epoch #{epoch} loss: {loss_hist.value}\") \n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.chdir('/kaggle/working')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"checkpoint={'model':model,\n           'state_dict':model.state_dict()}\n\n\ntorch.save(checkpoint, 'fasterrcnn_resnet50_fpn.pth')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\"\"\"model=load_model('fasterrcnn_resnet50_fpn.pth')\n\nmodel=model.to(DEVICE)\n\nbox=[]\nwith torch.no_grad():\n    for img_name in test:\n        img_path=os.path.join(f'test/{img_name}')\n        img=Image.open(img_path)\n\n        img=image_transforms(img)\n        img=img.unsqueeze(0)\n\n        img=img.to(DEVICE)\n\n        output=model(img)\n        output=output[0]['boxes'].cpu().detach().flatten().tolist()\n        boxes=''\n        for i in output:\n            boxes=boxes+str(i)+' '\n        box.append(boxes)\n        del img,boxes,output,img_path\n\nprediction=pd.DataFrame({'image_id':test,'PredictionString':box})\n\nos.chdir('/kaggle/working')\n\n#prediction.to_csv('submission.csv',index=False)\"\"\"","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}