{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"}],"dockerImageVersionId":30887,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"### 1. Preprocessing data","metadata":{}},{"cell_type":"code","source":"import json\nimport pandas as pd\n\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nimport seaborn as sns","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:03.874088Z","iopub.execute_input":"2025-02-10T18:13:03.874385Z","iopub.status.idle":"2025-02-10T18:13:04.638670Z","shell.execute_reply.started":"2025-02-10T18:13:03.874361Z","shell.execute_reply":"2025-02-10T18:13:04.637964Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df = pd.read_csv('../input/global-wheat-detection/train.csv')\ndf.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:04.639860Z","iopub.execute_input":"2025-02-10T18:13:04.640298Z","iopub.status.idle":"2025-02-10T18:13:04.825202Z","shell.execute_reply.started":"2025-02-10T18:13:04.640264Z","shell.execute_reply":"2025-02-10T18:13:04.824341Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df.info()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:04.826704Z","iopub.execute_input":"2025-02-10T18:13:04.826924Z","iopub.status.idle":"2025-02-10T18:13:04.856330Z","shell.execute_reply.started":"2025-02-10T18:13:04.826905Z","shell.execute_reply":"2025-02-10T18:13:04.855336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"df['bbox'] = df['bbox'].apply(json.loads)\nfig, ax = plt.subplots(1,2,figsize=(10,10))\nax = ax.flatten()\n\nimage = plt.imread('../input/global-wheat-detection/train/{}.jpg'.format(df.image_id.iloc[0]))\nax[0].imshow(image)\n\nfor xmin,ymin,width,height in df.bbox[df.image_id == df.image_id.iloc[0]]:\n    rect = patches.Rectangle((xmin, ymin), width, height, linewidth=2, edgecolor='r', facecolor='none')\n    ax[1].add_patch(rect)\n    ax[1].imshow(image)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:04.857317Z","iopub.execute_input":"2025-02-10T18:13:04.857613Z","iopub.status.idle":"2025-02-10T18:13:13.909523Z","shell.execute_reply.started":"2025-02-10T18:13:04.857591Z","shell.execute_reply":"2025-02-10T18:13:13.908414Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"#### Create label for Faster RCNN ","metadata":{}},{"cell_type":"code","source":"%%writefile create_label.py\n\nimport os\nimport json\nimport pandas as pd\n\nimport torch\n\ndef create_label():\n    df = pd.read_csv(\"../input/global-wheat-detection/train.csv\")\n    df['bbox'] = df['bbox'].apply(json.loads)\n    labels = []\n    image_id = list(df['image_id'].unique())\n    for name in image_id:\n        bbox = df[df.image_id==name]['bbox']\n        bbox_list = [[xmin,ymin,xmin+w,ymin+h] for xmin,ymin,w,h in bbox]\n        labels.append({\n            'boxes': bbox_list,\n            'labels': [1 for _ in range(len(bbox_list))],\n            'image_id': name})\n    #print(len(labels))\n    return labels,image_id","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:13.910789Z","iopub.execute_input":"2025-02-10T18:13:13.911130Z","iopub.status.idle":"2025-02-10T18:13:13.917600Z","shell.execute_reply.started":"2025-02-10T18:13:13.911101Z","shell.execute_reply":"2025-02-10T18:13:13.916732Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 2. Crete Dataset and Dataloader","metadata":{}},{"cell_type":"code","source":"%%writefile dataset.py\n\nimport os\nimport cv2\nfrom PIL import Image\nimport numpy as np\nimport torch\nfrom create_label import create_label\nfrom torch.utils.data import Dataset,DataLoader\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\ndef collate_fn(batch):\n    images, labels = zip(*batch)\n    return list(images), list(labels)\n\nclass MyDataset(Dataset):\n    def __init__(self,root,transform=None):\n        dataset,image_id = create_label()\n        self.labels = dataset\n        self.transform = transform\n        self.image_id = image_id\n        self.images_path = [os.path.join(root,i)+'.jpg' for i in self.image_id]\n        \n    def __len__(self):\n        return len(self.labels)\n        \n    def __getitem__(self,item):\n        image = cv2.imread(self.images_path[item])\n        #print(self.images_path[item])\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        image = Image.fromarray(image)\n        labels = self.labels[item]\n\n        if self.transform:\n            # augmented = self.transform(image=image, bboxes=labels['boxes'], labels=labels['labels'])\n            # image = augmented['image']\n\n            # labels = {\n            #     'boxes' : torch.tensor(augmented['bboxes'], dtype=torch.float32),\n            #     'labels' : torch.tensor(augmented['labels'], dtype=torch.int64),\n            #     'image_id' : labels['image_id']\n            # }\n            image = self.transform(image)\n            labels = {\n                'boxes': torch.tensor(labels['boxes'], dtype = torch.float32),\n                'labels': torch.tensor(labels['labels'], dtype = torch.int64)\n            }\n            \n        return image, labels\n\nif __name__ == '__main__':\n    train_root = '../input/global-wheat-detection/train'\n    \n    # train_transform = A.Compose([\n    #     A.HorizontalFlip(p=0.5),  \n    #     A.RandomBrightnessContrast(p=0.3),\n    #     A.MotionBlur(p=0.2),\n    #     A.Normalize(mean=(0, 0, 0), std=(1, 1, 1)),\n    #     ToTensorV2()], bbox_params=A.BboxParams(format='pascal_voc', label_fields=['labels']))\n\n    train_transform = Compose([\n        ToTensor()\n    ])\n    \n    train_data = MyDataset(root=train_root,transform = train_transform)    \n    train_loader = DataLoader(dataset=train_data,batch_size=16,shuffle=True,collate_fn=collate_fn)\n\n    # for i,j in train_loader:\n    #     print(j[2])\n    #     break","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:13.918471Z","iopub.execute_input":"2025-02-10T18:13:13.918749Z","iopub.status.idle":"2025-02-10T18:13:13.933233Z","shell.execute_reply.started":"2025-02-10T18:13:13.918727Z","shell.execute_reply":"2025-02-10T18:13:13.932373Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 3. Model","metadata":{}},{"cell_type":"code","source":"pip install -q pprintpp","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:13.934078Z","iopub.execute_input":"2025-02-10T18:13:13.934360Z","iopub.status.idle":"2025-02-10T18:13:17.280689Z","shell.execute_reply.started":"2025-02-10T18:13:13.934339Z","shell.execute_reply":"2025-02-10T18:13:17.279395Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport shutil\nimport numpy as np\nimport torch\nfrom dataset import MyDataset\nfrom torch.utils.data import DataLoader,Subset\nfrom torchvision.transforms import Compose,ToTensor,RandomAffine,ColorJitter,RandomHorizontalFlip\nfrom torchvision.models.detection import fasterrcnn_mobilenet_v3_large_320_fpn,fasterrcnn_resnet50_fpn\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom argparse import ArgumentParser\nfrom tqdm import tqdm\nfrom torch.utils.tensorboard import SummaryWriter\nfrom torchmetrics.detection.mean_ap import MeanAveragePrecision\nfrom pprintpp import pprint\nimport random\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\ndef get_arg():\n    parser = ArgumentParser(description='Faster RCNN')\n    parser.add_argument('--epochs','-e',type=int,default=10)\n    parser.add_argument('--ratio','-r',type=float,default=0.8)\n    parser.add_argument('--batch_size', '-b', type=int, default=16)\n    parser.add_argument('--log', '-l', type=str, default='tensorboard')\n    parser.add_argument('--checkpoint', '-c', type=str, default=None)\n    parser.add_argument('--trained', '-t', type=str, default='trained')\n    args, unknown = parser.parse_known_args()  \n    return args\n\ndef collate_fn(batch):\n    images, labels = zip(*batch)\n    return list(images), list(labels)\n\nif __name__ == '__main__':\n    arg = get_arg()\n\n    if not os.path.isdir(arg.trained):\n        os.makedirs(arg.trained)\n    if os.path.isdir(arg.log):\n        shutil.rmtree(arg.log)\n\n    writer = SummaryWriter(arg.log)\n    device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n    train_root = '../input/global-wheat-detection/train' \n\n    # train_transform = A.Compose([\n    #     A.HorizontalFlip(p=0.5),  \n    #     A.RandomBrightnessContrast(p=0.2),\n    #     A.MotionBlur(p=0.2),\n    #     A.Normalize(mean=(0, 0, 0), std=(1, 1, 1)),\n    #     ToTensorV2()], bbox_params=A.BboxParams(format='pascal_voc', label_fields=['labels']))\n\n    train_transform = Compose([\n        # ColorJitter(\n        #     brightness=0.125,\n        #     contrast=0.5,\n        #     saturation=0.5,\n        #     hue=0.05\n        # ),\n        ToTensor()\n    ])\n\n    train_data = MyDataset(root=train_root,transform = train_transform)\n    \n    ratio = arg.ratio\n    random.seed(42)\n    index_data = [i for i in range(0,len(train_data))]\n    random.shuffle(index_data)\n\n    train_size = int(ratio * len(index_data))\n    train_index = index_data[:train_size]\n    val_index = index_data[train_size:]\n    train = Subset(train_data,train_index)\n    val = Subset(train_data,val_index)\n    \n    train_loader = DataLoader(dataset=train,batch_size=16,shuffle=True,collate_fn=collate_fn)\n    val_loader = DataLoader(dataset=val,batch_size=16,shuffle=False,collate_fn=collate_fn)\n\n    model = fasterrcnn_mobilenet_v3_large_320_fpn(weights='DEFAULT',\n                                              trainable_backbone_layers=6)\n    in_features = model.roi_heads.box_predictor.cls_score.in_features\n    model.roi_heads.box_predictor = FastRCNNPredictor(in_channels=in_features,num_classes=2)\n    model.to(device)\n\n    optimizer = torch.optim.Adam(params=model.parameters(),lr=0.001)\n\n    if arg.checkpoint:\n        checkpoint = torch.load(arg.checkpoint,map_location=lambda storage, loc: storage.cuda(torch.cuda.current_device()))\n        model.load_state_dict(checkpoint['model'])\n        optimizer.load_state_dict(checkpoint['optimizer'])\n        start_epoch = checkpoint['epoch']\n        best_map = checkpoint['best_map']\n    else:\n        start_epoch = 0\n        best_map = 0.0\n\n    train_step = len(train)/arg.batch_size\n    val_step = len(val)/arg.batch_size\n\n    for epoch in range(start_epoch,arg.epochs):\n        model.train()\n        train_loss = []\n        progress_bar = tqdm(train_loader)\n        for iteration,(image,label) in enumerate(progress_bar):\n            image = [i.to(device) for i in image]\n            target = [{'boxes':i['boxes'].to(device),'labels':i['labels'].to(device)} for i in label]\n            losses = model(image,target)\n            final_loss = sum([loss for loss in losses.values()])\n\n            optimizer.zero_grad()\n            final_loss.backward()\n            optimizer.step()\n\n            train_loss.append(final_loss.item())\n            mean_loss = np.mean(train_loss)\n            writer.add_scalar('train_loss',mean_loss,global_step=epoch*train_step+iteration)\n            progress_bar.set_description('Epoch: {}/{} | Loss: {:4f}'.format(epoch+1,arg.epochs,mean_loss))\n\n        model.eval()\n        val_loss = []\n        progress_bar = tqdm(val_loader)\n        metric = MeanAveragePrecision(iou_type=\"bbox\")\n        for iteration,(image,label) in enumerate(progress_bar):\n            image = [i.to(device) for i in image]\n            pred = []\n            act = []\n            with torch.no_grad():\n                outputs = model(image)\n                for i in outputs:\n                    pred.append({\n                        'boxes':i['boxes'].to('cpu'),\n                        'scores':i['scores'].to('cpu'),\n                        'labels':i['labels'].to('cpu')\n                    })\n                for i in label:\n                    act.append({\n                        'boxes':i['boxes'],\n                        'labels':i['labels']\n                    })\n            metric.update(pred, act)\n        result = metric.compute()\n        pprint(result)\n        writer.add_scalar('val_map',result['map'],epoch)\n        progress_bar.set_description('val_map: {:4f}'.format(result['map']))\n\n        checkpoint = {\n            'model': model.state_dict(),\n            'optimizer': optimizer.state_dict(),\n            'epoch': epoch+1,\n            'best_map': result['map']\n        }\n        torch.save(checkpoint,'{}/last.pt'.format(arg.trained))\n        if result['map'] > best_map:\n            best_map = result['map']\n            torch.save(checkpoint,'{}/best.pt'.format(arg.trained))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:13:17.282957Z","iopub.execute_input":"2025-02-10T18:13:17.283249Z","iopub.status.idle":"2025-02-10T18:39:53.179799Z","shell.execute_reply.started":"2025-02-10T18:13:17.283212Z","shell.execute_reply":"2025-02-10T18:39:53.178749Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### 4. Test","metadata":{}},{"cell_type":"code","source":"import cv2\nimport matplotlib.pyplot as plt\n\ntest_root = '../input/global-wheat-detection/test'\npath = os.listdir(test_root)\nimages_path = []\nfor i in path:\n    image_path = os.path.join(test_root,i)\n    images_path.append(image_path)\n        \nmodel = fasterrcnn_mobilenet_v3_large_320_fpn(num_classes=2)\n\noptimizer = torch.optim.SGD(params=model.parameters(),lr=0.001,momentum=0.9)\n\ncheckpoint = torch.load('trained/best.pt',map_location=lambda storage, loc: storage.cuda(torch.cuda.current_device()),weights_only=True)\nmodel.load_state_dict(checkpoint['model'])\noptimizer.load_state_dict(checkpoint['optimizer'])\n    \nmodel.double().to(device)\nmodel.eval()\n\n#submit = []\n\ncount = 0\nthreshold = 0.5\nfor index,image in enumerate(images_path):\n    text = path[index].replace('.jpg',' ')\n    ori_image = cv2.imread(image)\n    image = cv2.cvtColor(ori_image,cv2.COLOR_BGR2RGB)\n    image = np.transpose(image,(2,0,1))/255.\n    image = [torch.from_numpy(image).to(device)]\n    with torch.no_grad():\n        output = model(image)\n        count +=1\n        for i in output:\n            boxes = i['boxes']\n            scores = i['scores']\n            labels = i['labels']\n            for b,s,l in zip(boxes,scores,labels):\n                xmin,ymin,xmax,ymax = b\n                if s > threshold:\n                    cv2.rectangle(ori_image,(int(xmin),int(ymin)),(int(xmax),int(ymax)),(255,0,0),3)\n                    cv2.putText(ori_image,str('{:.2f}'.format(s.item())),(int(xmin), int(ymin)), cv2.FONT_HERSHEY_SIMPLEX ,\n                                1, (0, 255, 0), 3, cv2.LINE_AA)\n\n                    #text += '{} {} {} {}'.format(s,xmin,ymin,xmax-xmin,ymax-ymin)\n            #submit.append(text)\n            \n            cv2.imwrite(\"prediction_{}.jpg\".format(count), ori_image)\n\nfig ,ax = plt.subplots(3,3,figsize=(12,12))\nax = ax.flatten()\n\nfor index,ax_i in enumerate(ax):\n    image = plt.imread('../working/prediction_{}.jpg'.format(index+1))\n    ax_i.imshow(image)\n    ax_i.axis('off')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-02-10T18:39:53.181343Z","iopub.execute_input":"2025-02-10T18:39:53.181693Z","iopub.status.idle":"2025-02-10T18:39:56.445464Z","shell.execute_reply.started":"2025-02-10T18:39:53.181659Z","shell.execute_reply":"2025-02-10T18:39:56.444158Z"}},"outputs":[],"execution_count":null}]}