{"cells":[{"metadata":{"trusted":true,"_kg_hide-output":true,"_kg_hide-input":true},"cell_type":"code","source":"!pip install '/kaggle/input/torch-15/torch-1.5.0cu101-cp37-cp37m-linux_x86_64.whl'\n!pip install '/kaggle/input/torch-15/torchvision-0.6.0cu101-cp37-cp37m-linux_x86_64.whl'\n!pip install '/kaggle/input/torch-15/yacs-0.1.7-py3-none-any.whl'\n!pip install '/kaggle/input/torch-15/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":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom torch.utils.data import Dataset\nimport cv2\nimport matplotlib.patches as mpatches\nimport matplotlib.pyplot as plt\nimport itertools\nimport detectron2\nfrom detectron2.utils.logger import setup_logger\nsetup_logger()\nfrom detectron2.structures import BoxMode\nfrom detectron2.data import DatasetCatalog, MetadataCatalog\nfrom detectron2.engine import DefaultTrainer\nfrom detectron2.engine import DefaultPredictor\nfrom detectron2.config import get_cfg\nfrom detectron2.utils.visualizer import Visualizer,VisImage\nfrom detectron2 import model_zoo\nfrom detectron2.evaluation import COCOEvaluator, inference_on_dataset\nfrom detectron2.data import build_detection_test_loader,build_detection_train_loader\nfrom detectron2.evaluation import COCOEvaluator, DatasetEvaluators, verify_results\nimport detectron2.data.transforms as T\nfrom detectron2.data import detection_utils as utils\nfrom detectron2.data import DatasetMapper\nimport copy\nimport torch\nimport warnings\nfrom PIL import ImageFile","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Data importation","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"class data(Dataset):\n    def __init__(self,folder,csv_file):\n        self.ids=os.listdir(folder)\n        self.classes=[\"wheat\"]\n        self.num_classes=len(self.classes)\n        self.num_images=len(self.ids)\n        self.df=pd.read_csv(csv_file)\n    def __len__(self):\n        return self.num_images\n    \n    def __getitem__(self,item):\n        id=self.ids[item]\n        image_path=os.path.join(folder,id)\n        image=cv2.imread(image_path)\n        image=cv2.cvtColor(image,cv2.COLOR_BGR2RGB)\n        height=image.shape[0]\n        width=image.shape[1]\n        annotation=self.df[self.df[\"image_id\"]==id[:-4]]\n        bbox = list(annotation[\"bbox\"])\n        objects=[]\n        dicts={}\n        label=0\n        dicts[\"filename\"]=image_path\n        dicts[\"height\"]=height\n        dicts[\"width\"]=width\n        dicts[\"image_id\"]=id\n        dicts[\"image\"]=image\n        for i in range(len(bbox)):\n            b=bbox[i]\n            b=b.strip('[')\n            b=b.strip(']')\n            b=b.split(\",\")\n            b=[float(k) for k in b]\n            b[2]=b[0]+b[2]\n            b[3]=b[1]+b[3]\n            b.append(label)\n            objects.append(b)\n        dicts[\"annotations\"]=np.array(objects)\n        return dicts\n            ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"csv_file=\"../input/global-wheat-detection/train.csv\"\nfolder=\"../input/global-wheat-detection/train\"\ndataset=data(folder,csv_file)\nlen(dataset)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"item=np.random.choice(len(dataset),1,replace=False)\ndicts=dataset[item[0]]\nimage=dicts[\"image\"]\nlabel=dicts[\"annotations\"]\nfig,ax=plt.subplots(figsize=(12,12))\nax.imshow(image.astype('uint8'))\nfor i in range(len(label)):\n    data=label[i]\n    xmin,ymin,xmax,ymax=data[0],data[1],data[2],data[3]\n    rect = mpatches.Rectangle((xmin, ymin), xmax - xmin, ymax - ymin,\n                                  fill=False, edgecolor=\"blue\", linewidth=2)\n    ax.add_patch(rect)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Detectron2 data format","execution_count":null},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"def get_wheat_dicts(mode):\n    if mode==\"train\":\n        items=[i for i in range(0,len(dataset)-10)]\n    else:\n        items=[i for i in range(len(dataset)-10,len(dataset))]\n    dataset_dicts = []\n    for item in items:\n        data=dataset[item]\n        record = {}\n        record[\"file_name\"] = data[\"filename\"]\n        record[\"image_id\"] = data[\"image_id\"]\n        record[\"height\"] = data[\"height\"]\n        record[\"width\"] = data[\"width\"]\n        annos=data[\"annotations\"]\n        objs = []\n        for i in range(len(annos)):\n            anno=annos[i]\n            xmin = int(anno[0])\n            ymin = int(anno[1])\n            xmax = int(anno[2])\n            ymax = int(anno[3])\n            label=int(anno[4])\n\n            poly = [\n          (xmin, ymin), (xmax, ymin),\n          (xmax, ymax), (xmin, ymax)\n                                      ]\n            poly = list(itertools.chain.from_iterable(poly))\n            obj = {\n                \"bbox\": [xmin,ymin,xmax,ymax],\n                \"bbox_mode\": BoxMode.XYXY_ABS,\n                 \"segmentation\": [poly],\n                \"category_id\": label,\n                \"iscrowd\": 0\n            }\n            objs.append(obj)\n        record[\"annotations\"] = objs\n        dataset_dicts.append(record)\n    return dataset_dicts","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset_dicts=get_wheat_dicts(mode=\"val\")\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for d in [\"train\",\"val\"]:\n    DatasetCatalog.register(\"wheat_\" + d, lambda d=d: get_wheat_dicts(d))\n    MetadataCatalog.get(\"wheat_\" + d).set(thing_classes=dataset.classes)\nwheat_metadata = MetadataCatalog.get(\"wheat_train\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"markdown","source":"# Mapper","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                        ]\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        return dataset_dict","execution_count":null,"outputs":[]},{"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":{},"cell_type":"markdown","source":"# Training","execution_count":null},{"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/detectron2-faster-rcnn-101/model_final_f6e8b1.pkl'\n    MODEL_PATH = 'COCO-Detection/faster_rcnn_X_101_32x8d_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/detectron2modelszoo/faster-rcnn-X101-FPN.pkl'\nelif MODEL_USE == 'retinanet':\n    MODEL_PATH = 'COCO-Detection/retinanet_R_101_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/detectron2-models-zoo/retinanet-R101.pkl' # Previously pretrained on 10000 iterations \nelif MODEL_USE == 'mask_rcnn':\n    MODEL_PATH = 'COCO-InstanceSegmentation/mask_rcnn_X_101_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/detectron2-models-zoo/mask-rcnn-X101-FPN.pkl'\nelif MODEL_USE == 'cascade_mask_rcnn':\n    MODEL_PATH = 'Misc/cascade_mask_rcnn_R_50_FPN_3x.yaml'\n    WEIGHT_PATH = '/kaggle/input/detectron2modelszoo/cascade-rcnn.pkl'\n\ndef config_cfg():\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 = len(dataset.classes)\n    cfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = 512\n    cfg.MODEL.ROI_HEADS.NUM_CLASSES = len(dataset.classes)\n\n    cfg.DATASETS.TRAIN = (\"wheat_train\",)\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.MAX_ITER = 10000\n    os.makedirs(cfg.OUTPUT_DIR, exist_ok=True)\n        \n    return cfg\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cfg = config_cfg()\n#trainer = WheatTrainer(cfg)\ntrainer=DefaultTrainer(cfg)\ntrainer.resume_or_load(resume=False)\ntrainer.train()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Load the pretrained model","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"cfg = get_cfg()\ncfg.merge_from_file(model_zoo.get_config_file(MODEL_PATH))\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = len(dataset.classes)\ncfg.MODEL.WEIGHTS = os.path.join(cfg.OUTPUT_DIR, \"model_final.pth\")\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.5\ncfg.MODEL.RETINANET.NUM_CLASSES = len(dataset.classes)\ncfg.MODEL.RETINANET.SCORE_THRESH_TEST = 0.45\ncfg.DATASETS.TEST = (\"wheat_val\", )\npredictor = DefaultPredictor(cfg)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"classes=dataset.classes\ndef visualize_predictions(input_folder):\n    image_names=os.listdir(input_folder)\n    for name in image_names:\n        image_path=os.path.join(input_folder,name)\n        im=cv2.imread(image_path)\n        outputs = predictor(im)\n        instances=outputs[\"instances\"].to(\"cpu\")\n        results=instances.get_fields()\n        boxes=results[\"pred_boxes\"]\n        boxes=np.array(boxes.tensor)\n        scores=results['scores']\n        pred_classes=results[\"pred_classes\"]\n        for i in range(len(boxes)):\n            xmin = int(boxes[i][0])\n            ymin = int(boxes[i][1])\n            xmax = int(boxes[i][2])\n            ymax = int(boxes[i][3])\n            color = (0,0,0)\n            cv2.rectangle(im, (xmin, ymin), (xmax, ymax), color, 4)\n            text_size = cv2.getTextSize(classes[pred_classes[i]] + ' : %.2f' % scores[i],\n                                        cv2.FONT_HERSHEY_PLAIN, 1, 1)[0]\n            cv2.rectangle(im, (xmin, ymin), (xmin + text_size[0] + 3, ymin + text_size[1] + 4),\n                          color, -1)\n            cv2.putText(\n                    im, classes[pred_classes[i]] + ' : %.2f' % scores[i],\n                   (xmin, ymin + text_size[1] + 4), cv2.FONT_HERSHEY_PLAIN, 1,\n                   (255, 255, 255), 2)\n        plt.figure(figsize = (12, 12))\n        plt.imshow(im)\n    return ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"input_folder=\"../input/global-wheat-detection/test\"\nvisualize_predictions(input_folder)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def submit():\n    image_names=os.listdir(input_folder)\n    predictions=[]\n    for name in image_names:\n        prediction=[]\n        image_path=os.path.join(input_folder,name)\n        im=cv2.imread(image_path)\n        outputs = predictor(im)\n        instances=outputs[\"instances\"].to(\"cpu\")\n        results=instances.get_fields()\n        boxes=results[\"pred_boxes\"]\n        boxes=np.array(boxes.tensor)\n        scores=results['scores']\n        pred_classes=results[\"pred_classes\"]\n        for i in range(len(boxes)):\n            score=round(float(scores[i]),4)\n            xmin = int(boxes[i][0])\n            ymin = int(boxes[i][1])\n            xmax = int(boxes[i][2])\n            ymax = int(boxes[i][3])\n            width=xmax-xmin\n            height=ymax-ymin\n            prediction.append(str(score))\n            prediction.append(str(xmin))\n            prediction.append(str(ymin))\n            prediction.append(str(width))\n            prediction.append(str(height))\n        res=\"\"\n        for p in prediction:\n            res+=p\n            res+=\" \"\n        output={\"image_id\":name[:-4],\"PredictionString\":res}\n        predictions.append(output) \n    df=pd.DataFrame(predictions, columns=['image_id', 'PredictionString'])\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions=submit()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"predictions.to_csv('submission.csv', index=False)","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}