{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install '/kaggle/input/pytorch-15/pytorch_1.5/torch-1.5.0cu101-cp37-cp37m-linux_x86_64.whl'\n!pip install '/kaggle/input/pytorch-15/pytorch_1.5/torchvision-0.6.0cu101-cp37-cp37m-linux_x86_64.whl'\n!pip install '/kaggle/input/pytorch-15/pytorch_1.5/yacs-0.1.7-py3-none-any.whl'\n!pip install '/kaggle/input/pytorch-15/pytorch_1.5/fvcore-0.1.1.post200513-py3-none-any.whl'\n!pip install '/kaggle/input/pycocotools/pycocotools-2.0-cp37-cp37m-linux_x86_64.whl'\n!pip install '/kaggle/input/detectron2/detectron2-0.1.3cu101-cp37-cp37m-linux_x86_64.whl'","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import os\nimport copy\nimport cv2\nimport random\nimport itertools\nimport torch\nimport pycocotools\nimport detectron2\n\nimport numpy as np \nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\nfrom pathlib import Path\nfrom collections import defaultdict\n\nfrom detectron2.config import get_cfg\nfrom detectron2 import model_zoo\nfrom detectron2.engine import DefaultPredictor, DefaultTrainer\nfrom detectron2.utils.visualizer import Visualizer, ColorMode\nfrom detectron2.structures import BoxMode\nfrom detectron2.data import datasets, DatasetCatalog, MetadataCatalog, build_detection_train_loader, build_detection_test_loader\nfrom detectron2.data import transforms as T\nfrom detectron2.data import detection_utils as utils\nfrom detectron2.evaluation import COCOEvaluator, verify_results\nfrom detectron2.modeling import GeneralizedRCNNWithTTA\nfrom detectron2.data.transforms import TransformGen\nfrom detectron2.utils.logger import setup_logger\nsetup_logger()\n\nfrom fvcore.transforms.transform import TransformList, Transform, NoOpTransform\nfrom contextlib import contextmanager\n\nimport torch.nn as nn","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames[:20]:\n        print(os.path.join(dirname, filename))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_dir = Path('/kaggle/input/global-wheat-detection')\ntrain_img_dir = Path(data_dir / 'train')\ntest_img_dir = Path(data_dir / 'test')\n\nsub_path = Path(data_dir / 'sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df = pd.read_csv(data_dir / 'train.csv')\nsub_df = pd.read_csv(sub_path)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## EDA","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Number of instances\ndf.shape[0]","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# Groupby image_id to get an image per row\nunique_images = df.groupby('image_id')[['bbox', 'source']].agg(lambda x: list(x)).reset_index()\nunique_images.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Number of images\nprint(f'Number of unique images: {unique_images.shape[0]}')","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Number of bounding boxes per image","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"cnt = {}\n\nfor idx, row in unique_images.iterrows(): \n    length = len(unique_images.bbox.iloc[idx])\n    image_id = unique_images.image_id.iloc[idx]\n    cnt.update({image_id: length})\n\ndf_count_bbox = pd.Series(data=cnt)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(f'Average number of bboxes per image: {df_count_bbox.values.mean()}')\nprint(f'Max number of bboxes: {df_count_bbox.values.max()}')\nprint(f'Min number of bboxes: {df_count_bbox.values.min()}')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Distribution of the number of instances per image\nplt.figure(figsize=(10, 5))\nsns.distplot(df_count_bbox)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Create Detectron2 dataset dict ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_wheat_dict(df, img_folder):\n    \n    grps = df['image_id'].unique().tolist()\n    df_group = df.groupby('image_id')\n    dataset_dicts = []\n    \n    for idx, image_name in enumerate(tqdm(grps)):\n        \n        # Get all instances of an image\n        group = df_group.get_group(image_name)\n        \n        record = defaultdict()\n        \n        # Full image path \n        file_path = os.path.join(img_folder, image_name + '.jpg')\n        \n        record['height'] = int(group['height'].values[0])\n        record['width'] = int(group['width'].values[0])\n        record['file_name'] = file_path\n        record['image_id'] = idx\n        \n        objs = []\n        \n        # Iterate over the group's rows as namedtuples\n        for row in group.itertuples():\n            \n            # Each bbox row is a list of strings - We need it to be a list of ints\n            # First we get the string part from the list\n            box = row.bbox[1:-1]\n            \n            # Convert the string to a list of floats\n            box = list(map(float, box.split(', ')))\n            \n            # Convert to int\n            x, y, w, h = list(map(int, box))\n            \n            xmin, ymin, xmax, ymax = x, y, x+w, y+h\n            \n            poly = [\n                (xmin, ymin), (xmax, ymin),\n                (xmax, ymax), (xmin, ymax)\n            ]\n            poly = list(itertools.chain.from_iterable(poly))\n            \n            obj = {\n                'bbox': [xmin, ymin, xmax, ymax], # change to XYXY format. Original was in XYWH\n                'bbox_mode': BoxMode.XYXY_ABS,\n                'segmentation': [poly],\n                'category_id': 0, # only 1 category for this dataset\n                'iscrowd': 0\n                  }\n            \n            objs.append(obj)\n        record['annotations'] = objs\n        dataset_dicts.append(record)\n\n    return dataset_dicts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# https://www.kaggle.com/nxhong93/wheat-detectron2/\n\nclass CutOut(Transform):\n    \n    def __init__(self, box_size=50, prob_cutmix=0.8):\n        super().__init__()\n        \n        self.box_size = box_size\n        self.prob_cutmix = prob_cutmix\n        \n    def apply_image(self, img):\n        \n        if random.random() > self.prob_cutmix:\n            \n            h, w = img.shape[:2]\n            num_rand = np.random.randint(10, 20)\n            for num_cut in range(num_rand):\n                x_rand, y_rand = random.randint(0, w-self.box_size), random.randint(0, h-self.box_size)\n                img[x_rand:x_rand+self.box_size, y_rand:y_rand+self.box_size, :] = 0\n        \n        return np.asarray(img)\n    \n    def apply_coords(self, coords):\n        return coords.astype(np.float32)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## DatasetMapper","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class DatasetMapper:\n    \"\"\"\n    A callable which takes a dataset dict in Detectron2 Dataset format,\n    and map it into a format used by the model.\n\n    This is a custom version of the DatasetMapper. The only different with Detectron2's \n    DatasetMapper is that we extract attributes from our dataset_dict. \n    \"\"\"\n\n    def __init__(self, cfg, is_train=True):\n        if cfg.INPUT.CROP.ENABLED and is_train:\n            self.crop_gen = T.RandomCrop(cfg.INPUT.CROP.TYPE, cfg.INPUT.CROP.SIZE)\n            logging.getLogger(__name__).info(\"CropGen used in training: \" + str(self.crop_gen))\n        else:\n            self.crop_gen = None\n        \n        self.tfm_gens = [T.RandomBrightness(0.8, 1.8),\n                         T.RandomContrast(0.6, 1.3),\n                         T.RandomSaturation(0.8, 1.4),\n                         T.RandomRotation(angle=[90, 90]),\n                         T.RandomLighting(0.7),\n                         T.RandomFlip(prob=0.4, horizontal=False, vertical=True),\n                         T.RandomCrop('relative_range', (0.4, 0.6)),\n                         CutOut()\n                        ]\n\n        # self.tfm_gens = utils.build_transform_gen(cfg, is_train)\n\n        # fmt: off\n        self.img_format     = cfg.INPUT.FORMAT\n        self.mask_on        = cfg.MODEL.MASK_ON\n        self.mask_format    = cfg.INPUT.MASK_FORMAT\n        self.keypoint_on    = cfg.MODEL.KEYPOINT_ON\n        self.load_proposals = cfg.MODEL.LOAD_PROPOSALS\n        # fmt: on\n        if self.keypoint_on and is_train:\n            # Flip only makes sense in training\n            self.keypoint_hflip_indices = utils.create_keypoint_hflip_indices(cfg.DATASETS.TRAIN)\n        else:\n            self.keypoint_hflip_indices = None\n\n        if self.load_proposals:\n            self.min_box_side_len = cfg.MODEL.PROPOSAL_GENERATOR.MIN_SIZE\n            self.proposal_topk = (\n                cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TRAIN\n                if is_train\n                else cfg.DATASETS.PRECOMPUTED_PROPOSAL_TOPK_TEST\n            )\n        self.is_train = is_train\n\n    def __call__(self, dataset_dict):\n        \"\"\"\n        Args:\n            dataset_dict (dict): Metadata of one image, in Detectron2 Dataset format.\n\n        Returns:\n            dict: a format that builtin models in detectron2 accept\n        \"\"\"\n        dataset_dict = copy.deepcopy(dataset_dict)  # it will be modified by code below\n        # USER: Write your own image loading if it's not from a file\n        image = utils.read_image(dataset_dict[\"file_name\"], format=self.img_format)\n        utils.check_image_size(dataset_dict, image)\n\n        if \"annotations\" not in dataset_dict:\n            image, transforms = T.apply_transform_gens(\n                ([self.crop_gen] if self.crop_gen else []) + self.tfm_gens, image\n            )\n        else:\n            # Crop around an instance if there are instances in the image.\n            # USER: Remove if you don't use cropping\n            if self.crop_gen:\n                crop_tfm = utils.gen_crop_transform_with_instance(\n                    self.crop_gen.get_crop_size(image.shape[:2]),\n                    image.shape[:2],\n                    np.random.choice(dataset_dict[\"annotations\"]),\n                )\n                image = crop_tfm.apply_image(image)\n            image, transforms = T.apply_transform_gens(self.tfm_gens, image)\n            if self.crop_gen:\n                transforms = crop_tfm + transforms\n\n        image_shape = image.shape[:2]  # h, w\n\n        # Pytorch's dataloader is efficient on torch.Tensor due to shared-memory,\n        # but not efficient on large generic data structures due to the use of pickle & mp.Queue.\n        # Therefore it's important to use torch.Tensor.\n        dataset_dict[\"image\"] = torch.as_tensor(np.ascontiguousarray(image.transpose(2, 0, 1)))\n\n        # USER: Remove if you don't use pre-computed proposals.\n        if self.load_proposals:\n            utils.transform_proposals(\n                dataset_dict, image_shape, transforms, self.min_box_side_len, self.proposal_topk\n            )\n\n        if not self.is_train:\n            # USER: Modify this if you want to keep them for some reason.\n            dataset_dict.pop(\"annotations\", None)\n            dataset_dict.pop(\"sem_seg_file_name\", None)\n            return dataset_dict\n\n        if \"annotations\" in dataset_dict:\n            # USER: Modify this if you want to keep them for some reason.\n            for anno in dataset_dict[\"annotations\"]:\n                if not self.mask_on:\n                    anno.pop(\"segmentation\", None)\n                if not self.keypoint_on:\n                    anno.pop(\"keypoints\", None)\n\n            # USER: Implement additional transformations if you have other types of data\n            annos = [\n                utils.transform_instance_annotations(\n                    obj, transforms, image_shape, keypoint_hflip_indices=self.keypoint_hflip_indices\n                )\n                for obj in dataset_dict.pop(\"annotations\")\n                if obj.get(\"iscrowd\", 0) == 0\n            ]\n            instances = utils.annotations_to_instances(\n                annos, image_shape, mask_format=self.mask_format\n            )\n            # Create a tight bounding box from masks, useful when image is cropped\n            if self.crop_gen and instances.has(\"gt_masks\"):\n                instances.gt_boxes = instances.gt_masks.get_bounding_boxes()           \n                          \n            dataset_dict[\"instances\"] = utils.filter_empty_instances(instances)\n            \n             # USER: Remove if you don't do semantic/panoptic segmentation.\n        if \"sem_seg_file_name\" in dataset_dict:\n            with PathManager.open(dataset_dict.pop(\"sem_seg_file_name\"), \"rb\") as f:\n                sem_seg_gt = Image.open(f)\n                sem_seg_gt = np.asarray(sem_seg_gt, dtype=\"uint8\")\n            sem_seg_gt = transforms.apply_segmentation(sem_seg_gt)\n            sem_seg_gt = torch.as_tensor(sem_seg_gt.astype(\"long\"))\n            dataset_dict[\"sem_seg\"] = sem_seg_gt\n\n        return dataset_dict","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Custom Trainer","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class WheatTrainer(DefaultTrainer):\n    \n    @classmethod\n    def build_train_loader(cls, cfg):\n        return build_detection_train_loader(cfg, mapper=DatasetMapper(cfg))\n    \n    @classmethod\n    def build_test_loader(cls, cfg, dataset_name):\n        return build_detection_test_loader(cfg, dataset_name, mapper=DatasetMapper(cfg))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def train_test_datasets(df, n_sample_size=-1, train_test_split=0.8):\n    \n    # Option to set a smaller df size for testing\n    if n_sample_size == -1:\n        n_sample_size = df.shape[0]\n    elif n_sample_size != -1:\n        n_sample_size = df[:n_sample_size].shape[0]\n\n    # Split df into train / test dataframes\n    n_train = round(n_sample_size * train_test_split)\n    n_test = n_sample_size - n_train\n\n    df_train = df[:n_train].copy()\n    df_test = df[-n_test:].copy()\n    \n    return df_train, df_test","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Use for creating an evaluation set\n#df_train, df_test = train_test_datasets(df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def register_dataset(df, dataset_label='wheat_train', image_dir=train_img_dir):\n    \n    # Register dataset - if dataset is already registered, give it a new name    \n    try:\n        DatasetCatalog.register(dataset_label, lambda d=df: get_wheat_dict(df, image_dir))\n        MetadataCatalog.get(dataset_label).thing_classes = ['wheat']\n    except:\n        # Add random int to dataset name to not run into 'Already registered' error\n        n = random.randint(1, 1000)\n        dataset_label = dataset_label + str(n)\n        DatasetCatalog.register(dataset_label, lambda d=df: get_wheat_dict(df, image_dir))\n        MetadataCatalog.get(dataset_label).thing_classes = ['wheat']\n        \n    return MetadataCatalog.get(dataset_label), dataset_label","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Register train dataset\nmetadata, train_dataset = register_dataset(df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Register test dataset\nmetadata, test_dataset = register_dataset(sub_df, dataset_label='wheat_test', image_dir=test_img_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"wheat_dict = get_wheat_dict(df, train_img_dir)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Visualize image and bbox\nimport random\nfor d in random.sample(wheat_dict, 2):\n    plt.figure(figsize=(10,10))\n    img = cv2.imread(d[\"file_name\"])\n    visualizer = Visualizer(img[:, :, ::-1], metadata, scale=0.5)\n    vis = visualizer.draw_dataset_dict(d)\n    plt.imshow(vis.get_image()[:, :, ::-1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"MODEL_USE = 'faster_rcnn'\nif MODEL_USE == 'faster_rcnn':\n    MODEL_PATH = 'COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/faster-rcnn-10000/model_final_faster_rcnn_10000.pth'\nelif MODEL_USE == 'retinanet':\n    MODEL_PATH = 'COCO-Detection/retinanet_R_101_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/model-final-30000/model_0019999.pth' # Previously pretrained on 10000 iterations \nelif MODEL_USE == 'mask_rcnn':\n    MODEL_PATH = 'COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml'\n    WEIGHT_PATH = 'COCO-InstanceSegmentation/mask_rcnn_R_101_FPN_3x.yaml'\nelif MODEL_USE == 'cascade_mask_rcnn':\n    MODEL_PATH = 'Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/model-cascade-10000/model_final_cascade_10000.pth'\n\ndef cfg_setup():\n    \n    cfg = get_cfg()\n    cfg.merge_from_file(model_zoo.get_config_file(MODEL_PATH))\n    cfg.MODEL.WEIGHTS = WEIGHT_PATH # model_zoo.get_checkpoint_url(WEIGHT_PATH)  \n    cfg.MODEL.RETINANET.NUM_CLASSES = 1\n    cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 512\n    cfg.MODEL.ROI_HEADS.NUM_CLASSES = 1\n\n    cfg.DATASETS.TRAIN = (train_dataset,)\n    cfg.DATASETS.TEST = ()\n    cfg.DATALOADER.NUM_WORKERS = 4\n\n    cfg.SOLVER.IMS_PER_BATCH = 4\n    cfg.SOLVER.LR_SCHEDULER_NAME = 'WarmupCosineLR'\n    cfg.SOLVER.BASE_LS = 0.0002\n#     cfg.SOLVER.WARMUP_ITERS = 4500\n#     cfg.SOLVER.WARMUP_METHOD = \"linear\"\n    cfg.SOLVER.MAX_ITER = 500\n    os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)\n        \n    return cfg","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cfg = cfg_setup()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainer = WheatTrainer(cfg)    ","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Augmentation Visualization","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"from detectron2.data import detection_utils as utils\n\ntrain_data_loader = trainer.build_train_loader(cfg)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"data_iter = iter(train_data_loader)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch = next(data_iter)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"rows, cols = 2, 2\nplt.figure(figsize=(20,20))\n\nfor i, per_image in enumerate(batch[:4]):\n    \n    plt.subplot(rows, cols, i+1)\n    \n    # Pytorch tensor is in (C, H, W) format\n    img = per_image[\"image\"].permute(1, 2, 0).cpu().detach().numpy()\n    img = utils.convert_image_to_rgb(img, cfg.INPUT.FORMAT)\n\n    visualizer = Visualizer(img, metadata=metadata, scale=0.5)\n\n    target_fields = per_image[\"instances\"].get_fields()\n    labels = None\n    vis = visualizer.overlay_instances(\n        labels=labels,\n        boxes=target_fields.get(\"gt_boxes\", None),\n        masks=target_fields.get(\"gt_masks\", None),\n        keypoints=target_fields.get(\"gt_keypoints\", None),\n    )\n    plt.imshow(vis.get_image()[:, :, ::-1])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainer.resume_or_load(resume=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"trainer.train()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def cfg_test():\n    cfg = get_cfg()\n    cfg.merge_from_file(model_zoo.get_config_file(MODEL_PATH))\n    cfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, 'model_final.pth')\n    cfg.DATASETS.TEST = (test_dataset,)\n    cfg.MODEL.RETINANET.NUM_CLASSES = 1\n    cfg.MODEL.RETINANET.SCORE_THRESH_TEST = 0.5\n    \n    return cfg\n\ncfg = cfg_test()\npredict = DefaultPredictor(cfg)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def visual_predict(dataset):\n    for sample in dataset:\n        im = cv2.imread(sample['file_name'])\n        output = predict(im)\n        \n        v = Visualizer(im[:, :, ::-1], metadata=metadata, scale=0.5)\n        v = v.draw_instance_predictions(output['instances'].to('cpu'))\n        plt.figure(figsize = (10, 10))\n        plt.imshow(cv2.cvtColor(v.get_image()[:, :, ::-1], cv2.COLOR_BGR2RGB))\n        plt.show()\n        \nwheat_test_dict = get_wheat_dict(df[:50], train_img_dir)\nvisual_predict(wheat_test_dict)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Evaluation","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"# from detectron2.evaluation import COCOEvaluator, inference_on_dataset\n    \n# evaluator = COCOEvaluator(test_dataset, cfg, False, output_dir=\"./output\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# val_loader = build_detection_test_loader(cfg, test_dataset) ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# inference_on_dataset(trainer.model, val_loader, evaluator)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Submission","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def submit():\n    for idx, row in tqdm(sub_df.iterrows(), total=len(sub_df)):\n        img_path = os.path.join(test_img_dir, row.image_id + '.jpg')\n        \n        img = cv2.imread(img_path)\n        outputs = predict(img)['instances']\n        boxes = [i.cpu().detach().numpy() for i in outputs.pred_boxes]\n        scores = outputs.scores.cpu().detach().numpy()\n        list_str = []\n        for box, score in zip(boxes, scores):\n            box[3] -= box[1]\n            box[2] -= box[0]\n            box = list(map(int,box))\n            score = round(score, 4)\n            list_str.append(score)\n            list_str.extend(box)\n        sub_df.loc[idx, 'PredictionString'] = ' '.join(map(str, list_str))\n        \n    return sub_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df = submit()\nsub_df.to_csv('submission.csv', index=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"sub_df","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}