{"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.execute_input":"2021-11-29T13:34:31.033449Z","iopub.status.busy":"2021-11-29T13:34:31.033138Z","iopub.status.idle":"2021-11-29T13:34:33.455468Z","shell.execute_reply":"2021-11-29T13:34:33.454141Z","shell.execute_reply.started":"2021-11-29T13:34:31.033368Z"},"papermill":{"duration":0.032599,"end_time":"2021-12-02T11:42:48.314913","exception":false,"start_time":"2021-12-02T11:42:48.282314","status":"completed"},"tags":[]}},{"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":{"papermill":{"duration":0.030049,"end_time":"2021-12-02T11:42:48.377825","exception":false,"start_time":"2021-12-02T11:42:48.347776","status":"completed"},"tags":[]}},{"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 = './cots_dataset'","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:42:48.444494Z","iopub.status.busy":"2021-12-02T11:42:48.442996Z","iopub.status.idle":"2021-12-02T11:42:50.802189Z","shell.execute_reply":"2021-12-02T11:42:50.801548Z","shell.execute_reply.started":"2021-11-30T20:30:28.751184Z"},"papermill":{"duration":2.394121,"end_time":"2021-12-02T11:42:50.802342","exception":false,"start_time":"2021-12-02T11:42:48.408221","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.environ[\"CUDA_DEVICE_ORDER\"]=\"PCI_BUS_ID\"\nos.environ[\"CUDA_VISIBLE_DEVICES\"] = \"4\"\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\nprint('Device:', device)\nprint('Current cuda device:', torch.cuda.current_device())\nprint('Count of using GPUs:', torch.cuda.device_count())","metadata":{"collapsed":false,"pycharm":{"name":"#%%\n","is_executing":true},"jupyter":{"outputs_hidden":false}},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# check Torch and CUDA version\nprint(f\"Torch: {torch.__version__}\")\n!nvcc --version","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:42:50.872567Z","iopub.status.busy":"2021-12-02T11:42:50.872033Z","iopub.status.idle":"2021-12-02T11:42:51.553071Z","shell.execute_reply":"2021-12-02T11:42:51.552251Z","shell.execute_reply.started":"2021-11-30T16:04:52.408171Z"},"papermill":{"duration":0.716484,"end_time":"2021-12-02T11:42:51.553204","exception":false,"start_time":"2021-12-02T11:42:50.83672","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 1. INSTALL YOLOX","metadata":{"papermill":{"duration":0.032014,"end_time":"2021-12-02T11:42:51.617844","exception":false,"start_time":"2021-12-02T11:42:51.58583","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:42:51.696898Z","iopub.status.busy":"2021-12-02T11:42:51.690299Z","iopub.status.idle":"2021-12-02T11:43:57.991814Z","shell.execute_reply":"2021-12-02T11:43:57.990635Z","shell.execute_reply.started":"2021-11-30T16:04:53.103871Z"},"papermill":{"duration":66.34162,"end_time":"2021-12-02T11:43:57.992011","exception":false,"start_time":"2021-12-02T11:42:51.650391","status":"completed"},"scrolled":true,"tags":[]},"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.execute_input":"2021-12-02T11:43:58.237781Z","iopub.status.busy":"2021-12-02T11:43:58.237Z","iopub.status.idle":"2021-12-02T11:44:17.007934Z","shell.execute_reply":"2021-12-02T11:44:17.008436Z","shell.execute_reply.started":"2021-11-30T16:05:51.067774Z"},"papermill":{"duration":18.893385,"end_time":"2021-12-02T11:44:17.008615","exception":false,"start_time":"2021-12-02T11:43:58.11523","status":"completed"},"scrolled":true,"tags":[]},"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":{"papermill":{"duration":0.066832,"end_time":"2021-12-02T11:44:17.145795","exception":false,"start_time":"2021-12-02T11:44:17.078963","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:44:17.285099Z","iopub.status.busy":"2021-12-02T11:44:17.284288Z","iopub.status.idle":"2021-12-02T11:44:17.28669Z","shell.execute_reply":"2021-12-02T11:44:17.286258Z","shell.execute_reply.started":"2021-11-30T20:30:36.704412Z"},"papermill":{"duration":0.074378,"end_time":"2021-12-02T11:44:17.286794","exception":false,"start_time":"2021-12-02T11:44:17.212416","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%pwd","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%cd ..","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"./cots_dataset/train.csv\")\n\ndf.head(5)","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:44:17.423879Z","iopub.status.busy":"2021-12-02T11:44:17.423398Z","iopub.status.idle":"2021-12-02T11:44:17.492542Z","shell.execute_reply":"2021-12-02T11:44:17.492937Z","shell.execute_reply.started":"2021-11-30T20:30:38.341899Z"},"papermill":{"duration":0.140442,"end_time":"2021-12-02T11:44:17.4931","exception":false,"start_time":"2021-12-02T11:44:17.352658","status":"completed"},"scrolled":true,"tags":[]},"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.execute_input":"2021-12-02T11:44:17.654651Z","iopub.status.busy":"2021-12-02T11:44:17.652315Z","iopub.status.idle":"2021-12-02T11:44:21.364408Z","shell.execute_reply":"2021-12-02T11:44:21.363937Z","shell.execute_reply.started":"2021-11-30T20:30:40.699897Z"},"papermill":{"duration":3.802933,"end_time":"2021-12-02T11:44:21.364534","exception":false,"start_time":"2021-12-02T11:44:17.561601","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T11:44:21.508577Z","iopub.status.busy":"2021-12-02T11:44:21.507647Z","iopub.status.idle":"2021-12-02T11:44:21.530632Z","shell.execute_reply":"2021-12-02T11:44:21.531035Z","shell.execute_reply.started":"2021-11-30T20:30:46.419544Z"},"papermill":{"duration":0.097233,"end_time":"2021-12-02T11:44:21.531185","exception":false,"start_time":"2021-12-02T11:44:21.433952","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"HOME_DIR = './' \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.execute_input":"2021-12-02T11:44:21.678904Z","iopub.status.busy":"2021-12-02T11:44:21.678195Z","iopub.status.idle":"2021-12-02T11:44:24.960228Z","shell.execute_reply":"2021-12-02T11:44:24.959388Z","shell.execute_reply.started":"2021-11-30T16:06:11.318103Z"},"papermill":{"duration":3.359936,"end_time":"2021-12-02T11:44:24.960379","exception":false,"start_time":"2021-12-02T11:44:21.600443","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T11:44:25.126177Z","iopub.status.busy":"2021-12-02T11:44:25.125042Z","iopub.status.idle":"2021-12-02T11:45:23.433942Z","shell.execute_reply":"2021-12-02T11:45:23.434474Z","shell.execute_reply.started":"2021-11-30T16:06:14.838064Z"},"papermill":{"duration":58.405347,"end_time":"2021-12-02T11:45:23.434687","exception":false,"start_time":"2021-12-02T11:44:25.02934","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T11:45:24.814547Z","iopub.status.busy":"2021-12-02T11:45:24.813943Z","iopub.status.idle":"2021-12-02T11:45:24.822047Z","shell.execute_reply":"2021-12-02T11:45:24.822604Z","shell.execute_reply.started":"2021-11-30T16:07:20.416221Z"},"papermill":{"duration":1.314583,"end_time":"2021-12-02T11:45:24.822784","exception":false,"start_time":"2021-12-02T11:45:23.508201","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## B. CREATE COCO ANNOTATION FILES","metadata":{"papermill":{"duration":0.070015,"end_time":"2021-12-02T11:45:24.964365","exception":false,"start_time":"2021-12-02T11:45:24.89435","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:45:25.110171Z","iopub.status.busy":"2021-12-02T11:45:25.108574Z","iopub.status.idle":"2021-12-02T11:45:25.11074Z","shell.execute_reply":"2021-12-02T11:45:25.111189Z","shell.execute_reply.started":"2021-11-30T16:07:20.427277Z"},"papermill":{"duration":0.076656,"end_time":"2021-12-02T11:45:25.11133","exception":false,"start_time":"2021-12-02T11:45:25.034674","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annotion_id = 0","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:45:25.255045Z","iopub.status.busy":"2021-12-02T11:45:25.253294Z","iopub.status.idle":"2021-12-02T11:45:25.255685Z","shell.execute_reply":"2021-12-02T11:45:25.256124Z","shell.execute_reply.started":"2021-11-30T16:07:20.435087Z"},"papermill":{"duration":0.075147,"end_time":"2021-12-02T11:45:25.256257","exception":false,"start_time":"2021-12-02T11:45:25.18111","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T11:45:25.405946Z","iopub.status.busy":"2021-12-02T11:45:25.402772Z","iopub.status.idle":"2021-12-02T11:45:25.409049Z","shell.execute_reply":"2021-12-02T11:45:25.40861Z","shell.execute_reply.started":"2021-11-30T16:35:10.711945Z"},"papermill":{"duration":0.084498,"end_time":"2021-12-02T11:45:25.409161","exception":false,"start_time":"2021-12-02T11:45:25.324663","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T11:45:25.554678Z","iopub.status.busy":"2021-12-02T11:45:25.553776Z","iopub.status.idle":"2021-12-02T11:45:25.776077Z","shell.execute_reply":"2021-12-02T11:45:25.776526Z","shell.execute_reply.started":"2021-11-30T16:35:15.110977Z"},"papermill":{"duration":0.298102,"end_time":"2021-12-02T11:45:25.776674","exception":false,"start_time":"2021-12-02T11:45:25.478572","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.126672,"end_time":"2021-12-02T11:45:26.006043","exception":false,"start_time":"2021-12-02T11:45:25.879371","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:45:26.241244Z","iopub.status.busy":"2021-12-02T11:45:26.239017Z","iopub.status.idle":"2021-12-02T11:45:26.242104Z","shell.execute_reply":"2021-12-02T11:45:26.242747Z","shell.execute_reply.started":"2021-11-30T16:23:24.135506Z"},"papermill":{"duration":0.122145,"end_time":"2021-12-02T11:45:26.242924","exception":false,"start_time":"2021-12-02T11:45:26.120779","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.089575,"end_time":"2021-12-02T11:45:26.447038","exception":false,"start_time":"2021-12-02T11:45:26.357463","status":"completed"},"tags":[]}},{"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":{"papermill":{"duration":0.068893,"end_time":"2021-12-02T11:45:26.585284","exception":false,"start_time":"2021-12-02T11:45:26.516391","status":"completed"},"tags":[]}},{"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        \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'''","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:45:26.730435Z","iopub.status.busy":"2021-12-02T11:45:26.728686Z","iopub.status.idle":"2021-12-02T11:45:26.731104Z","shell.execute_reply":"2021-12-02T11:45:26.73154Z","shell.execute_reply.started":"2021-11-30T16:58:48.094747Z"},"papermill":{"duration":0.077486,"end_time":"2021-12-02T11:45:26.731674","exception":false,"start_time":"2021-12-02T11:45:26.654188","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.06907,"end_time":"2021-12-02T11:45:26.871356","exception":false,"start_time":"2021-12-02T11:45:26.802286","status":"completed"},"tags":[]}},{"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\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":{"execution":{"iopub.execute_input":"2021-12-02T11:45:27.018222Z","iopub.status.busy":"2021-12-02T11:45:27.016619Z","iopub.status.idle":"2021-12-02T11:45:27.018803Z","shell.execute_reply":"2021-12-02T11:45:27.019243Z","shell.execute_reply.started":"2021-11-30T16:18:13.561722Z"},"papermill":{"duration":0.077479,"end_time":"2021-12-02T11:45:27.019377","exception":false,"start_time":"2021-12-02T11:45:26.941898","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.069635,"end_time":"2021-12-02T11:45:27.160037","exception":false,"start_time":"2021-12-02T11:45:27.090402","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:45:27.303649Z","iopub.status.busy":"2021-12-02T11:45:27.302834Z","iopub.status.idle":"2021-12-02T11:45:27.304805Z","shell.execute_reply":"2021-12-02T11:45:27.305197Z","shell.execute_reply.started":"2021-11-30T16:58:53.180488Z"},"papermill":{"duration":0.076537,"end_time":"2021-12-02T11:45:27.305328","exception":false,"start_time":"2021-12-02T11:45:27.228791","status":"completed"},"tags":[]},"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/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/yolox/data/datasets/coco_classes.py', 'w') as f:\n    f.write(coco_cls)\n\n# check if everything is ok    \n!more ./YOLOX/yolox/data/datasets/coco_classes.py","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:45:27.45012Z","iopub.status.busy":"2021-12-02T11:45:27.449531Z","iopub.status.idle":"2021-12-02T11:45:28.121547Z","shell.execute_reply":"2021-12-02T11:45:28.121083Z","shell.execute_reply.started":"2021-11-30T16:35:30.284543Z"},"papermill":{"duration":0.747771,"end_time":"2021-12-02T11:45:28.121683","exception":false,"start_time":"2021-12-02T11:45:27.373912","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 4. DOWNLOAD PRETRAINED WEIGHTS","metadata":{"papermill":{"duration":0.07208,"end_time":"2021-12-02T11:45:28.271235","exception":false,"start_time":"2021-12-02T11:45:28.199155","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"List of pretrained models:\n* YOLOX-s\n* YOLOX-m\n* YOLOX-nano for inference speed (!)\n* etc.","metadata":{"papermill":{"duration":0.069745,"end_time":"2021-12-02T11:45:28.410162","exception":false,"start_time":"2021-12-02T11:45:28.340417","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T11:45:28.558065Z","iopub.status.busy":"2021-12-02T11:45:28.557244Z","iopub.status.idle":"2021-12-02T11:45:34.123496Z","shell.execute_reply":"2021-12-02T11:45:34.123042Z","shell.execute_reply.started":"2021-11-30T16:24:16.591028Z"},"papermill":{"duration":5.643821,"end_time":"2021-12-02T11:45:34.123622","exception":false,"start_time":"2021-12-02T11:45:28.479801","status":"completed"},"scrolled":true,"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 5. TRAIN MODEL","metadata":{"papermill":{"duration":0.07624,"end_time":"2021-12-02T11:45:34.27709","exception":false,"start_time":"2021-12-02T11:45:34.20085","status":"completed"},"tags":[]}},{"cell_type":"code","source":"!cp ./YOLOX/tools/train.py ./","metadata":{"execution":{"iopub.execute_input":"2021-12-02T11:45:34.442822Z","iopub.status.busy":"2021-12-02T11:45:34.43783Z","iopub.status.idle":"2021-12-02T11:45:35.102825Z","shell.execute_reply":"2021-12-02T11:45:35.101896Z","shell.execute_reply.started":"2021-11-30T16:35:38.863551Z"},"papermill":{"duration":0.750633,"end_time":"2021-12-02T11:45:35.102993","exception":false,"start_time":"2021-12-02T11:45:34.35236","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!python train.py \\\n    -f cots_config.py \\\n    -d 1 \\\n    -b 40 \\\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.execute_input":"2021-12-02T11:45:35.264333Z","iopub.status.busy":"2021-12-02T11:45:35.263577Z","iopub.status.idle":"2021-12-02T14:52:03.208559Z","shell.execute_reply":"2021-12-02T14:52:03.209069Z","shell.execute_reply.started":"2021-11-30T16:58:59.338486Z"},"papermill":{"duration":11188.029825,"end_time":"2021-12-02T14:52:03.209243","exception":false,"start_time":"2021-12-02T11:45:35.179418","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 6. RUN INFERENCE\n\n## 6A. INFERENCE USING YOLOX TOOL","metadata":{"papermill":{"duration":0.509103,"end_time":"2021-12-02T14:52:04.061196","exception":false,"start_time":"2021-12-02T14:52:03.552093","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T14:52:04.927622Z","iopub.status.busy":"2021-12-02T14:52:04.926842Z","iopub.status.idle":"2021-12-02T14:52:05.677087Z","shell.execute_reply":"2021-12-02T14:52:05.676559Z","shell.execute_reply.started":"2021-11-30T17:40:23.530309Z"},"papermill":{"duration":1.104025,"end_time":"2021-12-02T14:52:05.677218","exception":false,"start_time":"2021-12-02T14:52:04.573193","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T14:52:06.38001Z","iopub.status.busy":"2021-12-02T14:52:06.374279Z","iopub.status.idle":"2021-12-02T14:52:13.814332Z","shell.execute_reply":"2021-12-02T14:52:13.813508Z","shell.execute_reply.started":"2021-11-30T17:40:25.955415Z"},"papermill":{"duration":7.788164,"end_time":"2021-12-02T14:52:13.814488","exception":false,"start_time":"2021-12-02T14:52:06.026324","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T14:52:14.507984Z","iopub.status.busy":"2021-12-02T14:52:14.507434Z","iopub.status.idle":"2021-12-02T14:52:14.913779Z","shell.execute_reply":"2021-12-02T14:52:14.9161Z","shell.execute_reply.started":"2021-11-30T17:40:33.95912Z"},"papermill":{"duration":0.757835,"end_time":"2021-12-02T14:52:14.917871","exception":false,"start_time":"2021-12-02T14:52:14.160036","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.38768,"end_time":"2021-12-02T14:52:15.903134","exception":false,"start_time":"2021-12-02T14:52:15.515454","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T14:52:16.685684Z","iopub.status.busy":"2021-12-02T14:52:16.6851Z","iopub.status.idle":"2021-12-02T14:52:18.762554Z","shell.execute_reply":"2021-12-02T14:52:18.762107Z","shell.execute_reply.started":"2021-11-30T17:40:47.582427Z"},"papermill":{"duration":2.471735,"end_time":"2021-12-02T14:52:18.762678","exception":false,"start_time":"2021-12-02T14:52:16.290943","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.2 INFERENCE BBOXES","metadata":{"papermill":{"duration":0.388003,"end_time":"2021-12-02T14:52:19.541364","exception":false,"start_time":"2021-12-02T14:52:19.153361","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T14:52:20.343251Z","iopub.status.busy":"2021-12-02T14:52:20.342511Z","iopub.status.idle":"2021-12-02T14:52:20.345414Z","shell.execute_reply":"2021-12-02T14:52:20.344939Z","shell.execute_reply.started":"2021-11-30T17:44:42.017256Z"},"papermill":{"duration":0.409989,"end_time":"2021-12-02T14:52:20.345553","exception":false,"start_time":"2021-12-02T14:52:19.935564","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.3 DRAW RESULT","metadata":{"papermill":{"duration":0.386904,"end_time":"2021-12-02T14:52:21.122467","exception":false,"start_time":"2021-12-02T14:52:20.735563","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T14:52:21.91707Z","iopub.status.busy":"2021-12-02T14:52:21.915413Z","iopub.status.idle":"2021-12-02T14:52:21.917637Z","shell.execute_reply":"2021-12-02T14:52:21.918063Z","shell.execute_reply.started":"2021-11-30T17:40:55.800179Z"},"papermill":{"duration":0.409076,"end_time":"2021-12-02T14:52:21.918211","exception":false,"start_time":"2021-12-02T14:52:21.509135","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### 6B.4 ALL PUZZLES TOGETHER","metadata":{"papermill":{"duration":0.384862,"end_time":"2021-12-02T14:52:22.69198","exception":false,"start_time":"2021-12-02T14:52:22.307118","status":"completed"},"tags":[]}},{"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.execute_input":"2021-12-02T14:52:23.475501Z","iopub.status.busy":"2021-12-02T14:52:23.474738Z","iopub.status.idle":"2021-12-02T14:52:24.531926Z","shell.execute_reply":"2021-12-02T14:52:24.532371Z","shell.execute_reply.started":"2021-11-30T17:44:46.826943Z"},"papermill":{"duration":1.45195,"end_time":"2021-12-02T14:52:24.53252","exception":false,"start_time":"2021-12-02T14:52:23.08057","status":"completed"},"tags":[]},"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":{"papermill":{"duration":0.450911,"end_time":"2021-12-02T14:52:25.429263","exception":false,"start_time":"2021-12-02T14:52:24.978352","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"# 7. SUBMIT TO COTS COMPETITION AND EVALUATE","metadata":{"papermill":{"duration":0.670298,"end_time":"2021-12-02T14:52:26.579061","exception":false,"start_time":"2021-12-02T14:52:25.908763","status":"completed"},"tags":[]}},{"cell_type":"code","source":"import greatbarrierreef\n\nenv = greatbarrierreef.make_env()   # initialize the environment\niter_test = env.iter_test()  ","metadata":{"execution":{"iopub.execute_input":"2021-12-02T14:52:27.465244Z","iopub.status.busy":"2021-12-02T14:52:27.464617Z","iopub.status.idle":"2021-12-02T14:52:27.50299Z","shell.execute_reply":"2021-12-02T14:52:27.502558Z","shell.execute_reply.started":"2021-11-30T17:41:53.605068Z"},"papermill":{"duration":0.482595,"end_time":"2021-12-02T14:52:27.503127","exception":false,"start_time":"2021-12-02T14:52:27.020532","status":"completed"},"tags":[]},"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.execute_input":"2021-12-02T14:52:28.3971Z","iopub.status.busy":"2021-12-02T14:52:28.396539Z","iopub.status.idle":"2021-12-02T14:52:28.847839Z","shell.execute_reply":"2021-12-02T14:52:28.847374Z","shell.execute_reply.started":"2021-11-30T17:44:53.458871Z"},"papermill":{"duration":0.903362,"end_time":"2021-12-02T14:52:28.847979","exception":false,"start_time":"2021-12-02T14:52:27.944617","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_df = pd.read_csv('submission.csv')\nsub_df.head()","metadata":{"execution":{"iopub.execute_input":"2021-12-02T14:52:29.73083Z","iopub.status.busy":"2021-12-02T14:52:29.72995Z","iopub.status.idle":"2021-12-02T14:52:29.740892Z","shell.execute_reply":"2021-12-02T14:52:29.740342Z","shell.execute_reply.started":"2021-11-30T17:46:07.265368Z"},"papermill":{"duration":0.454318,"end_time":"2021-12-02T14:52:29.741041","exception":false,"start_time":"2021-12-02T14:52:29.286723","status":"completed"},"tags":[]},"execution_count":null,"outputs":[]}]}