{"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":"markdown","source":"# Train YOLOX on COTS dataset (PART 1 - TRAINING)\n\nThis notebook shows how to train custom object detection model (COTS dataset) on Kaggle. It could be good starting point for build own custom model based on YOLOX detector. Full github repository you can find here - [YOLOX](https://github.com/Megvii-BaseDetection/YOLOX)\n\n<div align = 'center'><img src='https://github.com/Megvii-BaseDetection/YOLOX/raw/main/assets/logo.png'/></div>\n\n**Steps covered in this notebook:**\n* Install YOLOX \n* Prepare COTS dataset for YOLOX object detection training\n* Download Pre-Trained Weights for YOLOX\n* Prepare configuration files\n* YOLOX training\n* Run YOLOX inference on test images\n* Export YOLOX weights for Tensorflow inference (soon)\n\nNow I created notebook for learning and prototyping in YOLOX. Next step is too create better model (play with YOLOX experimentation parameters).","metadata":{"execution":{"iopub.status.busy":"2021-11-29T13:34:31.033138Z","iopub.execute_input":"2021-11-29T13:34:31.033449Z","iopub.status.idle":"2021-11-29T13:34:33.455468Z","shell.execute_reply.started":"2021-11-29T13:34:31.033368Z","shell.execute_reply":"2021-11-29T13:34:33.454141Z"}}},{"cell_type":"markdown","source":"<div class=\"alert alert-warning\">\n<strong>I found that there is no reference custom model training YOLOX notebook on Kaggle (or I am bad in searching ... ). Since we have such an opportunity this is my contribution to this competition. Feel free to use it and enjoy!\n    I really appreciate if you upvote this notebook. Thank you! </strong>\n</div>\n\n\n<div class=\"alert alert-success\" role=\"alert\">\nThis work consists of two parts:     \n    <ul>\n        <li> PART 1 - TRAIN CUSTOM MODEL (for COTS dataset) - > YoloX full training pipeline for COTS dataset -> this notebook</li>\n        <li> PART 2 - INFERENCE PART - YOLOX on Kaggle for COTS is available -> <a href=\"https://www.kaggle.com/remekkinas/yolox-inference-on-kaggle-for-cots\">YOLOX detections submission made on COTS dataset (PART 2 - DETECTION)</a></li>\n    </ul>\n    \n</div>","metadata":{}},{"cell_type":"code","source":"import warnings\nwarnings.filterwarnings(\"ignore\")\n\nimport ast\nimport os\nimport json\nimport pandas as pd\nimport torch\nimport importlib\nimport cv2 \n\nfrom shutil import copyfile\nfrom tqdm.notebook import tqdm\ntqdm.pandas()\nfrom sklearn.model_selection import GroupKFold\nfrom PIL import Image\nfrom string import Template\nfrom IPython.display import display\n\nTRAIN_PATH = '/kaggle/input/tensorflow-great-barrier-reef'","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:38:18.718463Z","iopub.execute_input":"2023-07-05T16:38:18.718836Z","iopub.status.idle":"2023-07-05T16:38:20.963665Z","shell.execute_reply.started":"2023-07-05T16:38:18.718724Z","shell.execute_reply":"2023-07-05T16:38:20.962884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check Torch and CUDA version\nprint(f\"Torch: {torch.__version__}\")\n!nvcc --version","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:38:20.966283Z","iopub.execute_input":"2023-07-05T16:38:20.966768Z","iopub.status.idle":"2023-07-05T16:38:21.929597Z","shell.execute_reply.started":"2023-07-05T16:38:20.966702Z","shell.execute_reply":"2023-07-05T16:38:21.928707Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. INSTALL YOLOX","metadata":{}},{"cell_type":"code","source":"!git clone https://github.com/Megvii-BaseDetection/YOLOX -q\n\n%cd YOLOX\n!pip install -U pip && pip install -r requirements.txt\n!pip install -v -e . ","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-07-05T16:38:21.931344Z","iopub.execute_input":"2023-07-05T16:38:21.931974Z","iopub.status.idle":"2023-07-05T16:39:58.065051Z","shell.execute_reply.started":"2023-07-05T16:38:21.931927Z","shell.execute_reply":"2023-07-05T16:39:58.064040Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2023-07-05T16:39:58.068281Z","iopub.execute_input":"2023-07-05T16:39:58.068878Z","iopub.status.idle":"2023-07-05T16:40:16.438011Z","shell.execute_reply.started":"2023-07-05T16:39:58.068827Z","shell.execute_reply":"2023-07-05T16:40:16.436993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 2. PREPARE COTS DATASET FOR YOLOX\nThis section is taken from  notebook created by Awsaf [Great-Barrier-Reef: YOLOv5 train](https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-train)\n\n## A. PREPARE DATASET AND ANNOTATIONS","metadata":{}},{"cell_type":"code","source":"def get_bbox(annots):\n    bboxes = [list(annot.values()) for annot in annots]\n    return bboxes\n\ndef get_path(row):\n    row['image_path'] = f'{TRAIN_PATH}/train_images/video_{row.video_id}/{row.video_frame}.jpg'\n    return row","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:16.439976Z","iopub.execute_input":"2023-07-05T16:40:16.440614Z","iopub.status.idle":"2023-07-05T16:40:16.447273Z","shell.execute_reply.started":"2023-07-05T16:40:16.440566Z","shell.execute_reply":"2023-07-05T16:40:16.446530Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"/kaggle/input/tensorflow-great-barrier-reef/train.csv\")\ndf.head(5)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:16.448837Z","iopub.execute_input":"2023-07-05T16:40:16.449393Z","iopub.status.idle":"2023-07-05T16:40:16.529358Z","shell.execute_reply.started":"2023-07-05T16:40:16.449355Z","shell.execute_reply":"2023-07-05T16:40:16.528601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Taken only annotated photos\ndf[\"num_bbox\"] = df['annotations'].apply(lambda x: str.count(x, 'x'))\ndf_train = df[df[\"num_bbox\"]>0]\n\n#Annotations \ndf_train['annotations'] = df_train['annotations'].progress_apply(lambda x: ast.literal_eval(x))\ndf_train['bboxes'] = df_train.annotations.progress_apply(get_bbox)\n\n#Images resolution\ndf_train[\"width\"] = 1280\ndf_train[\"height\"] = 720\n\n#Path of images\ndf_train = df_train.progress_apply(get_path, axis=1)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:16.530874Z","iopub.execute_input":"2023-07-05T16:40:16.531137Z","iopub.status.idle":"2023-07-05T16:40:20.668515Z","shell.execute_reply.started":"2023-07-05T16:40:16.531101Z","shell.execute_reply":"2023-07-05T16:40:20.667687Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"kf = GroupKFold(n_splits = 5) \ndf_train = df_train.reset_index(drop=True)\ndf_train['fold'] = -1\nfor fold, (train_idx, val_idx) in enumerate(kf.split(df_train, y = df_train.video_id.tolist(), groups=df_train.sequence)):\n    df_train.loc[val_idx, 'fold'] = fold\n\ndf_train.head(5)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:20.669797Z","iopub.execute_input":"2023-07-05T16:40:20.670087Z","iopub.status.idle":"2023-07-05T16:40:20.704336Z","shell.execute_reply.started":"2023-07-05T16:40:20.670044Z","shell.execute_reply":"2023-07-05T16:40:20.703624Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"HOME_DIR = '/kaggle/working/' \nDATASET_PATH = 'dataset/images'\n\n!mkdir {HOME_DIR}dataset\n!mkdir {HOME_DIR}{DATASET_PATH}\n!mkdir {HOME_DIR}{DATASET_PATH}/train2017\n!mkdir {HOME_DIR}{DATASET_PATH}/val2017\n!mkdir {HOME_DIR}{DATASET_PATH}/annotations","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:20.705539Z","iopub.execute_input":"2023-07-05T16:40:20.705841Z","iopub.status.idle":"2023-07-05T16:40:25.467422Z","shell.execute_reply.started":"2023-07-05T16:40:20.705800Z","shell.execute_reply":"2023-07-05T16:40:25.466296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SELECTED_FOLD = 4\n\nfor i in tqdm(range(len(df_train))):\n    row = df_train.loc[i]\n    if row.fold != SELECTED_FOLD:\n        copyfile(f'{row.image_path}', f'{HOME_DIR}{DATASET_PATH}/train2017/{row.image_id}.jpg')\n    else:\n        copyfile(f'{row.image_path}', f'{HOME_DIR}{DATASET_PATH}/val2017/{row.image_id}.jpg') ","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:40:25.475053Z","iopub.execute_input":"2023-07-05T16:40:25.477231Z","iopub.status.idle":"2023-07-05T16:41:50.318173Z","shell.execute_reply.started":"2023-07-05T16:40:25.477168Z","shell.execute_reply":"2023-07-05T16:41:50.317261Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'Number of training files: {len(os.listdir(f\"{HOME_DIR}{DATASET_PATH}/train2017/\"))}')\nprint(f'Number of validation files: {len(os.listdir(f\"{HOME_DIR}{DATASET_PATH}/val2017/\"))}')","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.319554Z","iopub.execute_input":"2023-07-05T16:41:50.320404Z","iopub.status.idle":"2023-07-05T16:41:50.334596Z","shell.execute_reply.started":"2023-07-05T16:41:50.320362Z","shell.execute_reply":"2023-07-05T16:41:50.333723Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## B. CREATE COCO ANNOTATION FILES","metadata":{}},{"cell_type":"code","source":"def save_annot_json(json_annotation, filename):\n    with open(filename, 'w') as f:\n        output_json = json.dumps(json_annotation)\n        f.write(output_json)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.338553Z","iopub.execute_input":"2023-07-05T16:41:50.339163Z","iopub.status.idle":"2023-07-05T16:41:50.349920Z","shell.execute_reply.started":"2023-07-05T16:41:50.339120Z","shell.execute_reply":"2023-07-05T16:41:50.348774Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annotion_id = 0","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.351781Z","iopub.execute_input":"2023-07-05T16:41:50.352337Z","iopub.status.idle":"2023-07-05T16:41:50.360462Z","shell.execute_reply.started":"2023-07-05T16:41:50.352298Z","shell.execute_reply":"2023-07-05T16:41:50.359411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def dataset2coco(df, dest_path):\n    \n    global annotion_id\n    \n    annotations_json = {\n        \"info\": [],\n        \"licenses\": [],\n        \"categories\": [],\n        \"images\": [],\n        \"annotations\": []\n    }\n    \n    info = {\n        \"year\": \"2021\",\n        \"version\": \"1\",\n        \"description\": \"COTS dataset - COCO format\",\n        \"contributor\": \"\",\n        \"url\": \"https://kaggle.com\",\n        \"date_created\": \"2021-11-30T15:01:26+00:00\"\n    }\n    annotations_json[\"info\"].append(info)\n    \n    lic = {\n            \"id\": 1,\n            \"url\": \"\",\n            \"name\": \"Unknown\"\n        }\n    annotations_json[\"licenses\"].append(lic)\n\n    classes = {\"id\": 0, \"name\": \"starfish\", \"supercategory\": \"none\"}\n\n    annotations_json[\"categories\"].append(classes)\n\n    \n    for ann_row in df.itertuples():\n            \n        images = {\n            \"id\": ann_row[0],\n            \"license\": 1,\n            \"file_name\": ann_row.image_id + '.jpg',\n            \"height\": ann_row.height,\n            \"width\": ann_row.width,\n            \"date_captured\": \"2021-11-30T15:01:26+00:00\"\n        }\n        \n        annotations_json[\"images\"].append(images)\n        \n        bbox_list = ann_row.bboxes\n        \n        for bbox in bbox_list:\n            b_width = bbox[2]\n            b_height = bbox[3]\n            \n            # some boxes in COTS are outside the image height and width\n            if (bbox[0] + bbox[2] > 1280):\n                b_width = bbox[0] - 1280 \n            if (bbox[1] + bbox[3] > 720):\n                b_height = bbox[1] - 720 \n                \n            image_annotations = {\n                \"id\": annotion_id,\n                \"image_id\": ann_row[0],\n                \"category_id\": 0,\n                \"bbox\": [bbox[0], bbox[1], b_width, b_height],\n                \"area\": bbox[2] * bbox[3],\n                \"segmentation\": [],\n                \"iscrowd\": 0\n            }\n            \n            annotion_id += 1\n            annotations_json[\"annotations\"].append(image_annotations)\n        \n        \n    print(f\"Dataset COTS annotation to COCO json format completed! Files: {len(df)}\")\n    return annotations_json","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.362376Z","iopub.execute_input":"2023-07-05T16:41:50.362975Z","iopub.status.idle":"2023-07-05T16:41:50.385455Z","shell.execute_reply.started":"2023-07-05T16:41:50.362937Z","shell.execute_reply":"2023-07-05T16:41:50.384517Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Convert COTS dataset to JSON COCO\ntrain_annot_json = dataset2coco(df_train[df_train.fold != SELECTED_FOLD], f\"{HOME_DIR}{DATASET_PATH}/train2017/\")\nval_annot_json = dataset2coco(df_train[df_train.fold == SELECTED_FOLD], f\"{HOME_DIR}{DATASET_PATH}/val2017/\")\n\n# Save converted annotations\nsave_annot_json(train_annot_json, f\"{HOME_DIR}{DATASET_PATH}/annotations/train.json\")\nsave_annot_json(val_annot_json, f\"{HOME_DIR}{DATASET_PATH}/annotations/valid.json\")","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.386692Z","iopub.execute_input":"2023-07-05T16:41:50.386974Z","iopub.status.idle":"2023-07-05T16:41:50.793293Z","shell.execute_reply.started":"2023-07-05T16:41:50.386936Z","shell.execute_reply":"2023-07-05T16:41:50.792461Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 3. PREPARE CONFIGURATION FILE\n\nConfiguration files for Yolox:\n- [YOLOX-nano](https://github.com/Megvii-BaseDetection/YOLOX/blob/main/exps/default/nano.py)\n- [YOLOX-s](https://github.com/Megvii-BaseDetection/YOLOX/blob/main/exps/default/yolox_s.py)\n- [YOLOX-m](https://github.com/Megvii-BaseDetection/YOLOX/blob/main/exps/default/yolox_m.py)\n\nBelow you can find two (yolox-s and yolox-nano) configuration files for our COTS dataset training.\n\n<div align=\"center\"><img  width=\"800\" src=\"https://github.com/Megvii-BaseDetection/YOLOX/raw/main/assets/git_fig.png\"/></div>","metadata":{}},{"cell_type":"code","source":"# Choose model for your experiments NANO or YOLOX-S (you can adapt for other model type)\n\nNANO = False","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.794750Z","iopub.execute_input":"2023-07-05T16:41:50.795265Z","iopub.status.idle":"2023-07-05T16:41:50.799562Z","shell.execute_reply.started":"2023-07-05T16:41:50.795222Z","shell.execute_reply":"2023-07-05T16:41:50.798773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3A. YOLOX-S EXPERIMENT CONFIGURATION FILE\nTraining parameters could be set up in experiment config files. I created custom files for YOLOX-s and nano. You can create your own using files from oryginal github repo.","metadata":{}},{"cell_type":"markdown","source":"<div class=\"alert alert-warning\">\n<strong> For YOLOX_s I use input size 960x960 but you can change it for your experiments.</strong> \n</div>","metadata":{}},{"cell_type":"code","source":"config_file_template = '''\n\n#!/usr/bin/env python3\n# -*- coding:utf-8 -*-\n# Copyright (c) Megvii, Inc. and its affiliates.\n\nimport os\n\nfrom yolox.exp import Exp as MyExp\n\n\nclass Exp(MyExp):\n    def __init__(self):\n        super(Exp, self).__init__()\n        self.depth = 0.33\n        self.width = 0.50\n        self.exp_name = os.path.split(os.path.realpath(__file__))[1].split(\".\")[0]\n        \n        # Define yourself dataset path\n        self.data_dir = \"/kaggle/working/dataset/images\"\n        self.train_ann = \"train.json\"\n        self.val_ann = \"valid.json\"\n\n        self.num_classes = 1\n\n        self.max_epoch = $max_epoch\n        self.data_num_workers = 2\n        self.eval_interval = 1\n        \n        self.mosaic_prob = 1.0\n        self.mixup_prob = 1.0\n        self.hsv_prob = 1.0\n        self.flip_prob = 0.5\n        self.no_aug_epochs = 2\n        self.albu=True\n        \n        self.input_size = (960, 960)\n        self.mosaic_scale = (0.5, 1.5)\n        self.random_size = (10, 20)\n        self.test_size = (960, 960)\n    def get_dataset(self, cache: bool = False, cache_type: str = \"ram\"):\n        \"\"\"\n        Get dataset according to cache and cache_type parameters.\n        Args:\n            cache (bool): Whether to cache imgs to ram or disk.\n            cache_type (str, optional): Defaults to \"ram\".\n                \"ram\" : Caching imgs to ram for fast training.\n                \"disk\": Caching imgs to disk for fast training.\n        \"\"\"\n        from yolox.data import COCODataset, TrainTransform\n        print('Cocodataset called with albu as ',self.albu)\n\n        return COCODataset(\n            data_dir=self.data_dir,\n            json_file=self.train_ann,\n            img_size=self.input_size,\n            preproc=TrainTransform(\n                max_labels=50,\n                flip_prob=self.flip_prob,\n                hsv_prob=self.hsv_prob,\n                albu=self.albu\n            ),\n            cache=cache,\n            cache_type=cache_type,\n        )\n    def get_data_loader(self, batch_size, is_distributed, no_aug=False, \n    cache_img: str = None):\n        \"\"\"\n        Get dataloader according to cache_img parameter.\n        Args:\n            no_aug (bool, optional): Whether to turn off mosaic data enhancement. Defaults to False.\n            cache_img (str, optional): cache_img is equivalent to cache_type. Defaults to None.\n                \"ram\" : Caching imgs to ram for fast training.\n                \"disk\": Caching imgs to disk for fast training.\n                None: Do not use cache, in this case cache_data is also None.\n        \"\"\"\n        from yolox.data import (\n            TrainTransform,\n            YoloBatchSampler,\n            DataLoader,\n            InfiniteSampler,\n            MosaicDetection,\n            worker_init_reset_seed,\n        )\n        from yolox.utils import wait_for_the_master\n\n        # if cache is True, we will create self.dataset before launch\n        # else we will create self.dataset after launch\n        if self.dataset is None:\n            print('build dataset')\n            with wait_for_the_master():\n                assert cache_img is None, \\\n                    \"cache_img must be None if you didn't create self.dataset before launch\"\n                self.dataset = self.get_dataset(cache=False, cache_type=cache_img)\n        print('new data loader')\n        self.dataset = MosaicDetection(\n            dataset=self.dataset,\n            mosaic=not no_aug,\n            img_size=self.input_size,\n            preproc=TrainTransform(\n                max_labels=120,\n                flip_prob=self.flip_prob,\n                hsv_prob=self.hsv_prob,\n                albu=self.albu),\n            degrees=self.degrees,\n            translate=self.translate,\n            mosaic_scale=self.mosaic_scale,\n            mixup_scale=self.mixup_scale,\n            shear=self.shear,\n            enable_mixup=self.enable_mixup,\n            mosaic_prob=self.mosaic_prob,\n            mixup_prob=self.mixup_prob,\n        )\n\n        if is_distributed:\n            batch_size = batch_size // dist.get_world_size()\n\n        sampler = InfiniteSampler(len(self.dataset), seed=self.seed if self.seed else 0)\n\n        batch_sampler = YoloBatchSampler(\n            sampler=sampler,\n            batch_size=batch_size,\n            drop_last=False,\n            mosaic=not no_aug,\n        )\n\n        dataloader_kwargs = {\"num_workers\": self.data_num_workers, \"pin_memory\": True}\n        dataloader_kwargs[\"batch_sampler\"] = batch_sampler\n\n        # Make sure each process has different random seed, especially for 'fork' method.\n        # Check https://github.com/pytorch/pytorch/issues/63311 for more details.\n        dataloader_kwargs[\"worker_init_fn\"] = worker_init_reset_seed\n\n        train_loader = DataLoader(self.dataset, **dataloader_kwargs)\n\n        return train_loader\n\n'''","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.801415Z","iopub.execute_input":"2023-07-05T16:41:50.802005Z","iopub.status.idle":"2023-07-05T16:41:50.811964Z","shell.execute_reply.started":"2023-07-05T16:41:50.801966Z","shell.execute_reply":"2023-07-05T16:41:50.811259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Data augment.y","metadata":{}},{"cell_type":"code","source":"%%writefile /kaggle/working/YOLOX/yolox/data/data_augment.py\nimport albumentations as A\nclass Albumentations:\n    # YOLOv5 Albumentations class (optional, only used if package is installed)\n    def __init__(self, size=640):\n        self.transform = None\n        print('initi Albu')\n        #prefix = colorstr('albumentations: ')\n        try:\n            import albumentations as A\n            #check_version(A.__version__, '1.0.3', hard=True)  # version requirement\n\n            T = [\n                \n                A.OneOf([\n                #A.HueSaturationValue(hue_shift_limit=(0.1,0.2), sat_shift_limit= (0.1,0.2), \n                #                     val_shift_limit=(0.1,0.2), p=0.8), #0.9\n                A.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2, p=1),\n                A.RandomBrightnessContrast(brightness_limit=(0.1,0.2), \n                                           contrast_limit=(0.1,0.3), p=0.8), #0.9\n                A.RandomGamma(gamma_limit=(30, 150),p=0.2)  ],p=0.6),\n                A.Cutout(max_h_size=int(25), max_w_size=int(50), num_holes=2, p=0.5,fill_value=256) ]  # transforms\n            #self.transform = A.Compose(T, \n            #                           bbox_params=A.BboxParams(format='coco', \n            #                                                    label_fields=['class_labels']))\n            self.transform = A.Compose(T)\n            #LOGGER.info(prefix + ', '.join(f'{x}'.replace('always_apply=False, ', '') for x in T if x.p))\n        except ImportError:  # package not installed, skip\n            pass\n        except Exception as e:\n            print('Error message in Albu ',e)\n            #LOGGER.info(f'{prefix}{e}')\n\n    def __call__(self, im, boxes=None,label=None, p=1.0):\n        if self.transform and random.random() < p:\n            #print('im shape',im.shape, boxes)\n            #new = self.transform(image=im, bboxes=boxes, \n            #                     class_labels=label)  # transformed\n            new = self.transform(image=im)\n            #im, labels = new['image'], np.array([[c, *b] for c, b in zip(new['class_labels'], new['bboxes'])])\n            im=new['image']\n        return im#, labels\n    \n    #!/usr/bin/env python3\n# -*- coding:utf-8 -*-\n# Copyright (c) Megvii, Inc. and its affiliates.\n\"\"\"\nData augmentation functionality. Passed as callable transformations to\nDataset classes.\n\nThe data augmentation procedures were interpreted from @weiliu89's SSD paper\nhttp://arxiv.org/abs/1512.02325\n\"\"\"\n\nimport math\nimport random\n\nimport cv2\nimport numpy as np\n\nfrom yolox.utils import xyxy2cxcywh\n\n\ndef augment_hsv(img, hgain=5, sgain=30, vgain=30):\n    hsv_augs = np.random.uniform(-1, 1, 3) * [hgain, sgain, vgain]  # random gains\n    hsv_augs *= np.random.randint(0, 2, 3)  # random selection of h, s, v\n    hsv_augs = hsv_augs.astype(np.int16)\n    img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV).astype(np.int16)\n\n    img_hsv[..., 0] = (img_hsv[..., 0] + hsv_augs[0]) % 180\n    img_hsv[..., 1] = np.clip(img_hsv[..., 1] + hsv_augs[1], 0, 255)\n    img_hsv[..., 2] = np.clip(img_hsv[..., 2] + hsv_augs[2], 0, 255)\n\n    cv2.cvtColor(img_hsv.astype(img.dtype), cv2.COLOR_HSV2BGR, dst=img)  # no return needed\n\n\ndef get_aug_params(value, center=0):\n    if isinstance(value, float):\n        return random.uniform(center - value, center + value)\n    elif len(value) == 2:\n        return random.uniform(value[0], value[1])\n    else:\n        raise ValueError(\n            \"Affine params should be either a sequence containing two values\\\n             or single float values. Got {}\".format(value)\n        )\n\n\ndef get_affine_matrix(\n    target_size,\n    degrees=10,\n    translate=0.1,\n    scales=0.1,\n    shear=10,\n):\n    twidth, theight = target_size\n\n    # Rotation and Scale\n    angle = get_aug_params(degrees)\n    scale = get_aug_params(scales, center=1.0)\n\n    if scale <= 0.0:\n        raise ValueError(\"Argument scale should be positive\")\n\n    R = cv2.getRotationMatrix2D(angle=angle, center=(0, 0), scale=scale)\n\n    M = np.ones([2, 3])\n    # Shear\n    shear_x = math.tan(get_aug_params(shear) * math.pi / 180)\n    shear_y = math.tan(get_aug_params(shear) * math.pi / 180)\n\n    M[0] = R[0] + shear_y * R[1]\n    M[1] = R[1] + shear_x * R[0]\n\n    # Translation\n    translation_x = get_aug_params(translate) * twidth  # x translation (pixels)\n    translation_y = get_aug_params(translate) * theight  # y translation (pixels)\n\n    M[0, 2] = translation_x\n    M[1, 2] = translation_y\n\n    return M, scale\n\n\ndef apply_affine_to_bboxes(targets, target_size, M, scale):\n    num_gts = len(targets)\n\n    # warp corner points\n    twidth, theight = target_size\n    corner_points = np.ones((4 * num_gts, 3))\n    corner_points[:, :2] = targets[:, [0, 1, 2, 3, 0, 3, 2, 1]].reshape(\n        4 * num_gts, 2\n    )  # x1y1, x2y2, x1y2, x2y1\n    corner_points = corner_points @ M.T  # apply affine transform\n    corner_points = corner_points.reshape(num_gts, 8)\n\n    # create new boxes\n    corner_xs = corner_points[:, 0::2]\n    corner_ys = corner_points[:, 1::2]\n    new_bboxes = (\n        np.concatenate(\n            (corner_xs.min(1), corner_ys.min(1), corner_xs.max(1), corner_ys.max(1))\n        )\n        .reshape(4, num_gts)\n        .T\n    )\n\n    # clip boxes\n    new_bboxes[:, 0::2] = new_bboxes[:, 0::2].clip(0, twidth)\n    new_bboxes[:, 1::2] = new_bboxes[:, 1::2].clip(0, theight)\n\n    targets[:, :4] = new_bboxes\n\n    return targets\n\n\ndef random_affine(\n    img,\n    targets=(),\n    target_size=(640, 640),\n    degrees=10,\n    translate=0.1,\n    scales=0.1,\n    shear=10,\n):\n    M, scale = get_affine_matrix(target_size, degrees, translate, scales, shear)\n\n    img = cv2.warpAffine(img, M, dsize=target_size, borderValue=(114, 114, 114))\n\n    # Transform label coordinates\n    if len(targets) > 0:\n        targets = apply_affine_to_bboxes(targets, target_size, M, scale)\n\n    return img, targets\n\n\ndef _mirror(image, boxes, prob=0.5):\n    _, width, _ = image.shape\n    if random.random() < prob:\n        image = image[:, ::-1]\n        boxes[:, 0::2] = width - boxes[:, 2::-2]\n    return image, boxes\n\n\ndef preproc(img, input_size, swap=(2, 0, 1)):\n    if len(img.shape) == 3:\n        padded_img = np.ones((input_size[0], input_size[1], 3), dtype=np.uint8) * 114\n    else:\n        padded_img = np.ones(input_size, dtype=np.uint8) * 114\n\n    r = min(input_size[0] / img.shape[0], input_size[1] / img.shape[1])\n    resized_img = cv2.resize(\n        img,\n        (int(img.shape[1] * r), int(img.shape[0] * r)),\n        interpolation=cv2.INTER_LINEAR,\n    ).astype(np.uint8)\n    padded_img[: int(img.shape[0] * r), : int(img.shape[1] * r)] = resized_img\n\n    padded_img = padded_img.transpose(swap)\n    padded_img = np.ascontiguousarray(padded_img, dtype=np.float32)\n    return padded_img, r\n\n\nclass TrainTransform:\n    def __init__(self, max_labels=50, flip_prob=0.5, hsv_prob=1.0,albu=False):\n        self.max_labels = max_labels\n        self.flip_prob = flip_prob\n        self.hsv_prob = hsv_prob\n        self.albu=albu\n         \n        self.albumentations = Albumentations() if albu else None\n        print('self_albumentations',self.albumentations)\n\n    def __call__(self, image, targets, input_dim):\n        boxes = targets[:, :4].copy()\n        labels = targets[:, 4].copy()\n        if len(boxes) == 0:\n            targets = np.zeros((self.max_labels, 5), dtype=np.float32)\n            image, r_o = preproc(image, input_dim)\n            return image, targets\n        \n        image_o = image.copy()\n        targets_o = targets.copy()\n        height_o, width_o, _ = image_o.shape\n        boxes_o = targets_o[:, :4]\n        labels_o = targets_o[:, 4]\n        # bbox_o: [xyxy] to [c_x,c_y,w,h]\n        boxes_o = xyxy2cxcywh(boxes_o)\n\n        if random.random() < self.hsv_prob:\n            augment_hsv(image)\n        #print('self.albu',self.albu)\n        if self.albu:\n            #print('albu called',image.shape)\n            #print('boxes',boxes)\n            #boxes=[int(b) for b in box for box in boxes] \n            box_int=[]\n            '''\n            for b in boxes:\n                b[0]=int(b[0])\n                b[1]=int(b[1])\n                b[2]=min(int(b[2]),image.shape[1])\n                b[3]=min(int(b[3]),image.shape[0])\n                box_int.append(b)\n            '''    \n            #image, boxes = self.albumentations(image, boxes,labels)\n            image  = self.albumentations(image )\n        image_t, boxes = _mirror(image, boxes, self.flip_prob)\n        height, width, _ = image_t.shape\n        image_t, r_ = preproc(image_t, input_dim)\n        # boxes [xyxy] 2 [cx,cy,w,h]\n        boxes = xyxy2cxcywh(boxes)\n        boxes *= r_\n\n        mask_b = np.minimum(boxes[:, 2], boxes[:, 3]) > 1\n        boxes_t = boxes[mask_b]\n        labels_t = labels[mask_b]\n\n        if len(boxes_t) == 0:\n            image_t, r_o = preproc(image_o, input_dim)\n            boxes_o *= r_o\n            boxes_t = boxes_o\n            labels_t = labels_o\n\n        labels_t = np.expand_dims(labels_t, 1)\n\n        targets_t = np.hstack((labels_t, boxes_t))\n        padded_labels = np.zeros((self.max_labels, 5))\n        padded_labels[range(len(targets_t))[: self.max_labels]] = targets_t[\n            : self.max_labels\n        ]\n        padded_labels = np.ascontiguousarray(padded_labels, dtype=np.float32)\n        return image_t, padded_labels\n\n\nclass ValTransform:\n    \"\"\"\n    Defines the transformations that should be applied to test PIL image\n    for input into the network\n\n    dimension -> tensorize -> color adj\n\n    Arguments:\n        resize (int): input dimension to SSD\n        rgb_means ((int,int,int)): average RGB of the dataset\n            (104,117,123)\n        swap ((int,int,int)): final order of channels\n\n    Returns:\n        transform (transform) : callable transform to be applied to test/val\n        data\n    \"\"\"\n\n    def __init__(self, swap=(2, 0, 1), legacy=False):\n        self.swap = swap\n        self.legacy = legacy\n\n    # assume input is cv2 img for now\n    def __call__(self, img, res, input_size):\n        img, _ = preproc(img, input_size, self.swap)\n        if self.legacy:\n            img = img[::-1, :, :].copy()\n            img /= 255.0\n            img -= np.array([0.485, 0.456, 0.406]).reshape(3, 1, 1)\n            img /= np.array([0.229, 0.224, 0.225]).reshape(3, 1, 1)\n        return img, np.zeros((1, 5))","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:51:06.343525Z","iopub.execute_input":"2023-07-05T16:51:06.343847Z","iopub.status.idle":"2023-07-05T16:51:06.358537Z","shell.execute_reply.started":"2023-07-05T16:51:06.343806Z","shell.execute_reply":"2023-07-05T16:51:06.357766Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 3B. YOLOX-NANO CONFIG FILE\n<div class=\"alert alert-warning\">\n<strong> For YOLOX_nano I use input size 460x460 but you can change it for your experiments.</strong> \n</div","metadata":{}},{"cell_type":"code","source":"if NANO:\n    config_file_template = '''\n\n#!/usr/bin/env python3\n# -*- coding:utf-8 -*-\n# Copyright (c) Megvii, Inc. and its affiliates.\n\nimport os\n\nimport torch.nn as nn\n\nfrom yolox.exp import Exp as MyExp\n\n\nclass Exp(MyExp):\n    def __init__(self):\n        super(Exp, self).__init__()\n        self.depth = 0.33\n        self.width = 0.25\n        self.input_size = (416, 416)\n        self.mosaic_scale = (0.5, 1.5)\n        self.random_size = (10, 20)\n        self.test_size = (416, 416)\n        self.exp_name = os.path.split(\n            os.path.realpath(__file__))[1].split(\".\")[0]\n        self.enable_mixup = False\n\n        # Define yourself dataset path\n        self.data_dir = \"/kaggle/working/dataset/images\"\n        self.train_ann = \"train.json\"\n        self.val_ann = \"valid.json\"\n\n        self.num_classes = 1\n\n        self.max_epoch = $max_epoch\n        self.data_num_workers = 2\n        self.eval_interval = 1\n        self.albu=True\n\n    def get_model(self, sublinear=False):\n        def init_yolo(M):\n            for m in M.modules():\n                if isinstance(m, nn.BatchNorm2d):\n                    m.eps = 1e-3\n                    m.momentum = 0.03\n\n        if \"model\" not in self.__dict__:\n            from yolox.models import YOLOX, YOLOPAFPN, YOLOXHead\n            in_channels = [256, 512, 1024]\n            # NANO model use depthwise = True, which is main difference.\n            backbone = YOLOPAFPN(self.depth,\n                                 self.width,\n                                 in_channels=in_channels,\n                                 depthwise=True)\n            head = YOLOXHead(self.num_classes,\n                             self.width,\n                             in_channels=in_channels,\n                             depthwise=True)\n            self.model = YOLOX(backbone, head)\n\n        self.model.apply(init_yolo)\n        self.model.head.initialize_biases(1e-2)\n        return self.model\n\n'''","metadata":{"jupyter":{"source_hidden":true},"execution":{"iopub.status.busy":"2023-07-05T16:41:50.833086Z","iopub.execute_input":"2023-07-05T16:41:50.833702Z","iopub.status.idle":"2023-07-05T16:41:50.843617Z","shell.execute_reply.started":"2023-07-05T16:41:50.833655Z","shell.execute_reply":"2023-07-05T16:41:50.842836Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-warning\">\n<strong> I trained model for 20 EPOCHS only .... This is for DEMO purposes only.</strong> \n</div>","metadata":{}},{"cell_type":"code","source":"PIPELINE_CONFIG_PATH='cots_config.py'\n\npipeline = Template(config_file_template).substitute(max_epoch = 20)\n\nwith open(PIPELINE_CONFIG_PATH, 'w') as f:\n    f.write(pipeline)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:51:15.504121Z","iopub.execute_input":"2023-07-05T16:51:15.504789Z","iopub.status.idle":"2023-07-05T16:51:15.510394Z","shell.execute_reply.started":"2023-07-05T16:51:15.504719Z","shell.execute_reply":"2023-07-05T16:51:15.509210Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ./yolox/data/datasets/voc_classes.py\n\nvoc_cls = '''\nVOC_CLASSES = (\n  \"starfish\",\n)\n'''\nwith open('./yolox/data/datasets/voc_classes.py', 'w') as f:\n    f.write(voc_cls)\n\n# ./yolox/data/datasets/coco_classes.py\n\ncoco_cls = '''\nCOCO_CLASSES = (\n  \"starfish\",\n)\n'''\nwith open('./yolox/data/datasets/coco_classes.py', 'w') as f:\n    f.write(coco_cls)\n\n# check if everything is ok    \n!more ./yolox/data/datasets/coco_classes.py","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:50.858063Z","iopub.execute_input":"2023-07-05T16:41:50.858281Z","iopub.status.idle":"2023-07-05T16:41:51.814895Z","shell.execute_reply.started":"2023-07-05T16:41:50.858255Z","shell.execute_reply":"2023-07-05T16:41:51.813962Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. DOWNLOAD PRETRAINED WEIGHTS","metadata":{}},{"cell_type":"markdown","source":"List of pretrained models:\n* YOLOX-s\n* YOLOX-m\n* YOLOX-nano for inference speed (!)\n* etc.","metadata":{}},{"cell_type":"code","source":"sh = 'wget https://github.com/Megvii-BaseDetection/storage/releases/download/0.0.1/yolox_s.pth'\nMODEL_FILE = 'yolox_s.pth'\n\nif NANO:\n    sh = '''\n    wget https://github.com/Megvii-BaseDetection/storage/releases/download/0.0.1/yolox_nano.pth\n    '''\n    MODEL_FILE = 'yolox_nano.pth'\n\nwith open('script.sh', 'w') as file:\n  file.write(sh)\n\n!bash script.sh","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:51.818643Z","iopub.execute_input":"2023-07-05T16:41:51.818921Z","iopub.status.idle":"2023-07-05T16:41:57.926161Z","shell.execute_reply.started":"2023-07-05T16:41:51.818888Z","shell.execute_reply":"2023-07-05T16:41:57.925142Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. TRAIN MODEL","metadata":{}},{"cell_type":"code","source":"!cp ./tools/train.py ./","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:41:57.928981Z","iopub.execute_input":"2023-07-05T16:41:57.929929Z","iopub.status.idle":"2023-07-05T16:41:58.933510Z","shell.execute_reply.started":"2023-07-05T16:41:57.929883Z","shell.execute_reply":"2023-07-05T16:41:58.932474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!pip install --upgrade \"protobuf<=3.20.1\"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python train.py \\\n    -f cots_config.py \\\n    -d 1 \\\n    -b 32 \\\n    --fp16 \\\n    -o \\\n    -c {MODEL_FILE}   # Remember to chenge this line if you take different model eg. yolo_nano.pth, yolox_s.pth or yolox_m.pth","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:51:18.747300Z","iopub.execute_input":"2023-07-05T16:51:18.747591Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cat #/opt/conda/lib/python3.7/site-packages/albumentations/augmentations/bbox_utils.py","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:02.287321Z","iopub.execute_input":"2023-07-05T16:42:02.287621Z","iopub.status.idle":"2023-07-05T16:42:03.244451Z","shell.execute_reply.started":"2023-07-05T16:42:02.287578Z","shell.execute_reply":"2023-07-05T16:42:03.243307Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:44:57.178988Z","iopub.execute_input":"2023-07-05T16:44:57.179317Z","iopub.status.idle":"2023-07-05T16:45:07.428277Z","shell.execute_reply.started":"2023-07-05T16:44:57.179283Z","shell.execute_reply":"2023-07-05T16:45:07.427320Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6. RUN INFERENCE\n\n## 6A. INFERENCE USING YOLOX TOOL","metadata":{}},{"cell_type":"code","source":"# I have to fix demo.py file because it:\n# - raises error in Kaggle (cvWaitKey does not work) \n# - saves result files in time named directory eg. /2021_11_29_22_51_08/ which is difficult then to automatically show results\n\n%cp ../../input/yolox-kaggle-fix-for-demo-inference/demo.py tools/demo.py","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:13.822354Z","iopub.execute_input":"2023-07-05T16:42:13.822675Z","iopub.status.idle":"2023-07-05T16:42:14.781338Z","shell.execute_reply.started":"2023-07-05T16:42:13.822631Z","shell.execute_reply":"2023-07-05T16:42:14.780274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_IMAGE_PATH = \"/kaggle/working/dataset/images/val2017/0-4614.jpg\"\nMODEL_PATH = \"./YOLOX_outputs/cots_config/best_ckpt.pth\"\n\n!python tools/demo.py image \\\n    -f cots_config.py \\\n    -c {MODEL_PATH} \\\n    --path {TEST_IMAGE_PATH} \\\n    --conf 0.1 \\\n    --nms 0.45 \\\n    --tsize 960 \\\n    --save_result \\\n    --device gpu","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:14.787393Z","iopub.execute_input":"2023-07-05T16:42:14.787651Z","iopub.status.idle":"2023-07-05T16:42:23.157231Z","shell.execute_reply.started":"2023-07-05T16:42:14.787617Z","shell.execute_reply":"2023-07-05T16:42:23.156281Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"OUTPUT_IMAGE_PATH = \"./YOLOX_outputs/cots_config/vis_res/0-4614.jpg\" \nImage.open(OUTPUT_IMAGE_PATH)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.160026Z","iopub.execute_input":"2023-07-05T16:42:23.161950Z","iopub.status.idle":"2023-07-05T16:42:23.321764Z","shell.execute_reply.started":"2023-07-05T16:42:23.161900Z","shell.execute_reply":"2023-07-05T16:42:23.320583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 6B. INFERENCE USING CUSTOM SCRIPT (IT WOULD BE USED FOR COTS INFERENCE PART)\n\n### 6B.1 SETUP MODEL","metadata":{}},{"cell_type":"code","source":"from yolox.utils import postprocess\nfrom yolox.data.data_augment import ValTransform\n\nCOCO_CLASSES = (\n  \"starfish\",\n)\n\n# get YOLOX experiment\ncurrent_exp = importlib.import_module('cots_config')\nexp = current_exp.Exp()\n\n# set inference parameters\ntest_size = (960, 960)\nnum_classes = 1\nconfthre = 0.1\nnmsthre = 0.45\n\n\n# get YOLOX model\nmodel = exp.get_model()\nmodel.cuda()\nmodel.eval()\n\n# get custom trained checkpoint\nckpt_file = \"./YOLOX_outputs/cots_config/best_ckpt.pth\"\nckpt = torch.load(ckpt_file, map_location=\"cpu\")\nmodel.load_state_dict(ckpt[\"model\"])","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.323414Z","iopub.status.idle":"2023-07-05T16:42:23.324155Z","shell.execute_reply.started":"2023-07-05T16:42:23.323878Z","shell.execute_reply":"2023-07-05T16:42:23.323906Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.2 INFERENCE BBOXES","metadata":{}},{"cell_type":"code","source":"def yolox_inference(img, model, test_size): \n    bboxes = []\n    bbclasses = []\n    scores = []\n    \n    preproc = ValTransform(legacy = False)\n\n    tensor_img, _ = preproc(img, None, test_size)\n    tensor_img = torch.from_numpy(tensor_img).unsqueeze(0)\n    tensor_img = tensor_img.float()\n    tensor_img = tensor_img.cuda()\n\n    with torch.no_grad():\n        outputs = model(tensor_img)\n        outputs = postprocess(\n                    outputs, num_classes, confthre,\n                    nmsthre, class_agnostic=True\n                )\n\n    if outputs[0] is None:\n        return [], [], []\n    \n    outputs = outputs[0].cpu()\n    bboxes = outputs[:, 0:4]\n\n    bboxes /= min(test_size[0] / img.shape[0], test_size[1] / img.shape[1])\n    bbclasses = outputs[:, 6]\n    scores = outputs[:, 4] * outputs[:, 5]\n    \n    return bboxes, bbclasses, scores","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.325612Z","iopub.status.idle":"2023-07-05T16:42:23.326348Z","shell.execute_reply.started":"2023-07-05T16:42:23.326065Z","shell.execute_reply":"2023-07-05T16:42:23.326092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.3 DRAW RESULT","metadata":{}},{"cell_type":"code","source":"def draw_yolox_predictions(img, bboxes, scores, bbclasses, confthre, classes_dict):\n    for i in range(len(bboxes)):\n            box = bboxes[i]\n            cls_id = int(bbclasses[i])\n            score = scores[i]\n            if score < confthre:\n                continue\n            x0 = int(box[0])\n            y0 = int(box[1])\n            x1 = int(box[2])\n            y1 = int(box[3])\n\n            cv2.rectangle(img, (x0, y0), (x1, y1), (0, 255, 0), 2)\n            cv2.putText(img, '{}:{:.1f}%'.format(classes_dict[cls_id], score * 100), (x0, y0 - 3), cv2.FONT_HERSHEY_PLAIN, 0.8, (0,255,0), thickness = 1)\n    return img","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.327710Z","iopub.status.idle":"2023-07-05T16:42:23.328408Z","shell.execute_reply.started":"2023-07-05T16:42:23.328148Z","shell.execute_reply":"2023-07-05T16:42:23.328175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.4 ALL PUZZLES TOGETHER","metadata":{}},{"cell_type":"code","source":"TEST_IMAGE_PATH = \"/kaggle/working/dataset/images/val2017/0-4614.jpg\"\nimg = cv2.imread(TEST_IMAGE_PATH)\n\n# Get predictions\nbboxes, bbclasses, scores = yolox_inference(img, model, test_size)\n\n# Draw predictions\nout_image = draw_yolox_predictions(img, bboxes, scores, bbclasses, confthre, COCO_CLASSES)\n\n# Since we load image using OpenCV we have to convert it \nout_image = cv2.cvtColor(out_image, cv2.COLOR_BGR2RGB)\ndisplay(Image.fromarray(out_image))","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.329776Z","iopub.status.idle":"2023-07-05T16:42:23.330459Z","shell.execute_reply.started":"2023-07-05T16:42:23.330203Z","shell.execute_reply":"2023-07-05T16:42:23.330230Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"<div class=\"alert alert-success\" role=\"alert\">\n    Find this notebook helpful? :) Please give me a vote ;) Thank you\n </div>","metadata":{}},{"cell_type":"markdown","source":"# 7. SUBMIT TO COTS COMPETITION AND EVALUATE","metadata":{}},{"cell_type":"code","source":"import greatbarrierreef\n\nenv = greatbarrierreef.make_env()   # initialize the environment\niter_test = env.iter_test()  ","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.331814Z","iopub.status.idle":"2023-07-05T16:42:23.332489Z","shell.execute_reply.started":"2023-07-05T16:42:23.332231Z","shell.execute_reply":"2023-07-05T16:42:23.332257Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission_dict = {\n    'id': [],\n    'prediction_string': [],\n}\n\nfor (image_np, sample_prediction_df) in iter_test:\n \n    bboxes, bbclasses, scores = yolox_inference(image_np, model, test_size)\n    \n    predictions = []\n    for i in range(len(bboxes)):\n        box = bboxes[i]\n        cls_id = int(bbclasses[i])\n        score = scores[i]\n        if score < confthre:\n            continue\n        x_min = int(box[0])\n        y_min = int(box[1])\n        x_max = int(box[2])\n        y_max = int(box[3])\n        \n        bbox_width = x_max - x_min\n        bbox_height = y_max - y_min\n        \n        predictions.append('{:.2f} {} {} {} {}'.format(score, x_min, y_min, bbox_width, bbox_height))\n    \n    prediction_str = ' '.join(predictions)\n    sample_prediction_df['annotations'] = prediction_str\n    env.predict(sample_prediction_df)\n\n    print('Prediction:', prediction_str)","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.333858Z","iopub.status.idle":"2023-07-05T16:42:23.334544Z","shell.execute_reply.started":"2023-07-05T16:42:23.334281Z","shell.execute_reply":"2023-07-05T16:42:23.334308Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('submission.csv')\nsub_df.head()","metadata":{"execution":{"iopub.status.busy":"2023-07-05T16:42:23.335880Z","iopub.status.idle":"2023-07-05T16:42:23.336557Z","shell.execute_reply.started":"2023-07-05T16:42:23.336300Z","shell.execute_reply":"2023-07-05T16:42:23.336326Z"},"trusted":true},"execution_count":null,"outputs":[]}]}