{"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":"!pip install --no-deps '../input/weightedboxesfusion/' > /dev/null","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-06-25T01:33:39.111319Z","iopub.execute_input":"2023-06-25T01:33:39.111683Z","iopub.status.idle":"2023-06-25T01:34:03.740058Z","shell.execute_reply.started":"2023-06-25T01:33:39.111627Z","shell.execute_reply":"2023-06-25T01:34:03.738671Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import StratifiedKFold\nfrom torch.utils.data import Dataset,DataLoader\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom glob import glob\nimport torch\nimport cv2","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-06-25T01:34:03.742478Z","iopub.execute_input":"2023-06-25T01:34:03.742921Z","iopub.status.idle":"2023-06-25T01:34:06.588914Z","shell.execute_reply.started":"2023-06-25T01:34:03.742857Z","shell.execute_reply":"2023-06-25T01:34:06.588108Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\n\nmarking = pd.read_csv('../input/global-wheat-detection/train.csv')\n\nbboxs = np.stack(marking['bbox'].apply(lambda x: np.fromstring(x[1:-1], sep=',')))\nfor i, column in enumerate(['x', 'y', 'w', 'h']):\n    marking[column] = bboxs[:,i]\nmarking.drop(columns=['bbox'], inplace=True)\n\nmarking.head()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:06.592613Z","iopub.execute_input":"2023-06-25T01:34:06.592924Z","iopub.status.idle":"2023-06-25T01:34:07.592948Z","shell.execute_reply.started":"2023-06-25T01:34:06.592875Z","shell.execute_reply":"2023-06-25T01:34:07.591904Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"marking['source'].hist(bins=15);","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:07.594264Z","iopub.execute_input":"2023-06-25T01:34:07.594631Z","iopub.status.idle":"2023-06-25T01:34:07.842783Z","shell.execute_reply.started":"2023-06-25T01:34:07.594582Z","shell.execute_reply":"2023-06-25T01:34:07.841679Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Stratify KFold\n\nstratified distribution on 5 folds","metadata":{}},{"cell_type":"code","source":"%%time\n\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\ndf_folds = marking[['image_id']].copy()\ndf_folds.loc[:, 'bbox_count'] = 1\ndf_folds = df_folds.groupby('image_id').count()\ndf_folds.loc[:, 'source'] = marking[['image_id', 'source']].groupby('image_id').min()['source']\ndf_folds.loc[:, 'stratify_group'] = np.char.add(\n    df_folds['source'].values.astype(str),\n    df_folds['bbox_count'].apply(lambda x: f'_{x // 15}').values.astype(str)\n)\ndf_folds.loc[:, 'fold'] = 0\n\nfor fold_number, (train_index, val_index) in enumerate(skf.split(X=df_folds.index, y=df_folds['stratify_group'])):\n    df_folds.loc[df_folds.iloc[val_index].index, 'fold'] = fold_number","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:07.846312Z","iopub.execute_input":"2023-06-25T01:34:07.846818Z","iopub.status.idle":"2023-06-25T01:34:08.335739Z","shell.execute_reply.started":"2023-06-25T01:34:07.846762Z","shell.execute_reply":"2023-06-25T01:34:08.334797Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_folds.head()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:08.337500Z","iopub.execute_input":"2023-06-25T01:34:08.338142Z","iopub.status.idle":"2023-06-25T01:34:08.351171Z","shell.execute_reply.started":"2023-06-25T01:34:08.338074Z","shell.execute_reply":"2023-06-25T01:34:08.350029Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare Dataset\n\n","metadata":{}},{"cell_type":"code","source":"def get_valid_transforms():\n    return A.Compose([\n            A.Resize(height=512, width=512, p=1.0),\n            ToTensorV2(p=1.0),\n        ], p=1.0)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:08.352802Z","iopub.execute_input":"2023-06-25T01:34:08.353688Z","iopub.status.idle":"2023-06-25T01:34:08.360292Z","shell.execute_reply.started":"2023-06-25T01:34:08.353207Z","shell.execute_reply":"2023-06-25T01:34:08.359231Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"DATA_ROOT_PATH = '../input/global-wheat-detection/test'\n\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, image_ids, transforms=None):\n        super().__init__()\n        self.image_ids = image_ids\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        image = cv2.imread(f'{DATA_ROOT_PATH}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n        if self.transforms:\n            sample = {'image': image}\n            sample = self.transforms(**sample)\n            image = sample['image']\n        return image, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:08.362195Z","iopub.execute_input":"2023-06-25T01:34:08.363056Z","iopub.status.idle":"2023-06-25T01:34:08.373875Z","shell.execute_reply.started":"2023-06-25T01:34:08.362786Z","shell.execute_reply":"2023-06-25T01:34:08.373153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataset = DatasetRetriever(\n    image_ids=np.array([path.split('/')[-1][:-4] for path in glob(f'{DATA_ROOT_PATH}/*.jpg')]),\n    transforms=get_valid_transforms()\n)\n\ndef collate_fn(batch):\n    return tuple(zip(*batch))\n\ndata_loader = DataLoader(\n    dataset,\n    batch_size=2,\n    shuffle=False,\n    num_workers=4,\n    drop_last=False,\n    collate_fn=collate_fn\n)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:08.375098Z","iopub.execute_input":"2023-06-25T01:34:08.375679Z","iopub.status.idle":"2023-06-25T01:34:08.390413Z","shell.execute_reply.started":"2023-06-25T01:34:08.375628Z","shell.execute_reply":"2023-06-25T01:34:08.389672Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load Pretrained Models","metadata":{}},{"cell_type":"code","source":"import gc\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\nfrom torchvision.models.detection.rpn import AnchorGenerator\n\n\ndef load_net(checkpoint_path):\n    net = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=False, pretrained_backbone=False)\n    num_classes = 2  # 1 class (wheat) + background\n    # get number of input features for the classifier\n    in_features = net.roi_heads.box_predictor.cls_score.in_features\n    # replace the pre-trained head with a new one\n    net.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n\n    checkpoint = torch.load(checkpoint_path)\n    net.load_state_dict(checkpoint)\n    net = net.cuda()\n    net.eval()\n\n    del checkpoint\n    gc.collect()\n    return net\n\nmodels = [\n    load_net('../input/wheat-fasterrcnn-folds/fold0-best1.bin'),\n    load_net('../input/wheat-fasterrcnn-folds/fold1-best1.bin'),\n    load_net('../input/wheat-fasterrcnn-folds/fold2-best1.bin'),\n    load_net('../input/wheat-fasterrcnn-folds/fold3-best1.bin'),\n    load_net('../input/wheat-fasterrcnn-folds/fold4-best1.bin'),\n]","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:08.392429Z","iopub.execute_input":"2023-06-25T01:34:08.392974Z","iopub.status.idle":"2023-06-25T01:34:22.583457Z","shell.execute_reply.started":"2023-06-25T01:34:08.392783Z","shell.execute_reply":"2023-06-25T01:34:22.582204Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## WBF & Ensemble methods ","metadata":{}},{"cell_type":"code","source":"from ensemble_boxes import *\n\ndevice = torch.device('cuda:0')\n\ndef make_ensemble_predictions(images):\n    images = list(image.to(device) for image in images)    \n    result = []\n    for net in models:\n        outputs = net(images)\n        result.append(outputs)\n    return result\n\ndef run_wbf(predictions, image_index, image_size=512, iou_thr=0.55, skip_box_thr=0.7, weights=None):\n    boxes = [prediction[image_index]['boxes'].data.cpu().numpy()/(image_size-1) for prediction in predictions]\n    scores = [prediction[image_index]['scores'].data.cpu().numpy() for prediction in predictions]\n    labels = [np.ones(prediction[image_index]['scores'].shape[0]) for prediction in predictions]\n    boxes, scores, labels = weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    boxes = boxes*(image_size-1)\n    return boxes, scores, labels","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:22.584872Z","iopub.execute_input":"2023-06-25T01:34:22.585261Z","iopub.status.idle":"2023-06-25T01:34:22.599254Z","shell.execute_reply.started":"2023-06-25T01:34:22.585211Z","shell.execute_reply":"2023-06-25T01:34:22.597835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nfor j, (images, image_ids) in enumerate(data_loader):\n    if j > 0:\n        break\npredictions = make_ensemble_predictions(images)\n\ni = 1\nsample = images[i].permute(1,2,0).cpu().numpy()\nboxes, scores, labels = run_wbf(predictions, image_index=i)\nboxes = boxes.astype(np.int32).clip(min=0, max=511)\n\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    cv2.rectangle(sample,\n                  (box[0], box[1]),\n                  (box[2], box[3]),\n                  (220, 0, 0), 2)\n    \nax.set_axis_off()\nax.imshow(sample);","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:22.600881Z","iopub.execute_input":"2023-06-25T01:34:22.601492Z","iopub.status.idle":"2023-06-25T01:34:24.656352Z","shell.execute_reply.started":"2023-06-25T01:34:22.601320Z","shell.execute_reply":"2023-06-25T01:34:24.655372Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Inference","metadata":{}},{"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    return \" \".join(pred_strings)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:24.657750Z","iopub.execute_input":"2023-06-25T01:34:24.658260Z","iopub.status.idle":"2023-06-25T01:34:24.667602Z","shell.execute_reply.started":"2023-06-25T01:34:24.658187Z","shell.execute_reply":"2023-06-25T01:34:24.666371Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"results = []\n\nfor images, image_ids in data_loader:\n    predictions = make_ensemble_predictions(images)\n    for i, image in enumerate(images):\n        boxes, scores, labels = run_wbf(predictions, image_index=i)\n        boxes = (boxes*2).astype(np.int32).clip(min=0, max=1023)\n        image_id = image_ids[i]\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        results.append(result)","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:24.669710Z","iopub.execute_input":"2023-06-25T01:34:24.670029Z","iopub.status.idle":"2023-06-25T01:34:28.205660Z","shell.execute_reply.started":"2023-06-25T01:34:24.669979Z","shell.execute_reply":"2023-06-25T01:34:28.204173Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Submission","metadata":{}},{"cell_type":"code","source":"test_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-06-25T01:34:28.207504Z","iopub.execute_input":"2023-06-25T01:34:28.207898Z","iopub.status.idle":"2023-06-25T01:34:28.485954Z","shell.execute_reply.started":"2023-06-25T01:34:28.207844Z","shell.execute_reply":"2023-06-25T01:34:28.485061Z"},"trusted":true},"execution_count":null,"outputs":[]}]}