{"cells":[{"metadata":{},"cell_type":"markdown","source":"# VinBigData detectron2 prediction\n\n\n\n\n## Version history\n\n[Update 24/01/2021] : 512, R50, 10000 iterations doing learning rate and batch size expermients lr = 1e-5, bs = 256, PS v22\n\n[Update 20/01/2021] : 1024, R101 18000 iterations v13 run train model is used here check out [this output model details](https://www.kaggle.com/sourabhchauhan/vinbigdata1024r101e18000)"},{"metadata":{},"cell_type":"markdown","source":"# Table of Contents\n\n** [Prediction method implementations](#pred_method)** <br/>\n** [Prediction scripts](#pred_scripts)** <br/>\n** [Apply 2 class filter](#2class)** <br/>\n** [Other kernels](#ref)** <br/>\n\nSince first setup part is same with the training kernel, I skipped listing on ToC."},{"metadata":{},"cell_type":"markdown","source":"# Dataset preparation\n\nPreprocessing x-ray image format (dicom) into normal png image format is already done by @xhlulu in the below discussion:\n - [Multiple preprocessed datasets: 256/512/1024px, PNG and JPG, modified and original ratio](https://www.kaggle.com/c/vinbigdata-chest-xray-abnormalities-detection/discussion/207955).\n\nHere I will just use the dataset [VinBigData Chest X-ray Resized PNG (256x256)](https://www.kaggle.com/xhlulu/vinbigdata-chest-xray-resized-png-256x256) to skip the preprocessing and focus on modeling part. Please upvote the dataset as well!"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import gc\nimport os\nfrom pathlib import Path\nimport random\nimport sys\n\nfrom tqdm.notebook import tqdm\nimport numpy as np\nimport pandas as pd\nimport scipy as sp\n\n\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nfrom IPython.core.display import display, HTML\n\n# --- plotly ---\nfrom plotly import tools, subplots\nimport plotly.offline as py\npy.init_notebook_mode(connected=True)\nimport plotly.graph_objs as go\nimport plotly.express as px\nimport plotly.figure_factory as ff\nimport plotly.io as pio\npio.templates.default = \"plotly_dark\"\n\n# --- models ---\nfrom sklearn import preprocessing\nfrom sklearn.model_selection import KFold\nimport lightgbm as lgb\nimport xgboost as xgb\nimport catboost as cb\n\n# --- setup ---\npd.set_option('max_columns', 50)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Installation\n\ndetectron2 is not pre-installed in this kaggle docker, so let's install it. \nWe can follow [installation instruction](https://github.com/facebookresearch/detectron2/blob/master/INSTALL.md), we need to know CUDA and pytorch version to install correct `detectron2`."},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!nvcc --version","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"import torch\n\ntorch.__version__","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"It seems CUDA=10.2 and torch==1.7.0 is used in this kaggle docker image.\n\nSee [installation](https://detectron2.readthedocs.io/tutorials/install.html) for details."},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"!pip install detectron2 -f \\\n  https://dl.fbaipublicfiles.com/detectron2/wheels/cu102/torch1.7/index.html","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"pred_method\"></a>\n# Prediction method implementations\n\nBasically we don't need to implement neural network part, `detectron2` already implements famous architectures and provides its pre-trained weights. We can finetune these pre-trained architectures.\n\nThese models are summarized in [MODEL_ZOO.md](https://github.com/facebookresearch/detectron2/blob/master/MODEL_ZOO.md).\n\nIn this competition, we need object detection model, I will choose [R50-FPN](https://github.com/facebookresearch/detectron2/blob/master/configs/COCO-Detection/faster_rcnn_R_50_FPN_3x.yaml) for this kernel."},{"metadata":{},"cell_type":"markdown","source":"## Data preparation\n\n`detectron2` provides high-level API for training custom dataset.\n\nTo define custom dataset, we need to create **list of dict** where each dict contains following:\n\n - file_name: file name of the image.\n - image_id: id of the image, index is used here.\n - height: height of the image.\n - width: width of the image.\n - annotation: This is the ground truth annotation data for object detection, which contains following\n     - bbox: bounding box pixel location with shape (n_boxes, 4)\n     - bbox_mode: `BoxMode.XYXY_ABS` is used here, meaning that absolute value of (xmin, ymin, xmax, ymax) annotation is used in the `bbox`.\n     - category_id: class label id for each bounding box, with shape (n_boxes,)\n\n`get_vinbigdata_dicts` is for train dataset preparation and `get_vinbigdata_dicts_test` is for test dataset preparation."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"import pickle\nfrom pathlib import Path\nfrom typing import Optional\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom detectron2.structures import BoxMode\nfrom tqdm import tqdm\n\n\ndef get_vinbigdata_dicts(\n    imgdir: Path,\n    train_df: pd.DataFrame,\n    train_data_type: str = \"original\",\n    use_cache: bool = True,\n    debug: bool = True,\n    target_indices: Optional[np.ndarray] = None,\n    use_class14: bool = False,\n):\n    debug_str = f\"_debug{int(debug)}\"\n    train_data_type_str = f\"_{train_data_type}\"\n    class14_str = f\"_14class{int(use_class14)}\"\n    cache_path = Path(\".\") / f\"dataset_dicts_cache{train_data_type_str}{class14_str}{debug_str}.pkl\"\n    if not use_cache or not cache_path.exists():\n        print(\"Creating data...\")\n        train_meta = pd.read_csv(imgdir / \"train_meta.csv\")\n        if debug:\n            train_meta = train_meta.iloc[:500]  # For debug....\n\n        # Load 1 image to get image size.\n        image_id = train_meta.loc[0, \"image_id\"]\n        image_path = str(imgdir / \"train\" / f\"{image_id}.png\")\n        image = cv2.imread(image_path)\n        resized_height, resized_width, ch = image.shape\n        print(f\"image shape: {image.shape}\")\n\n        dataset_dicts = []\n        for index, train_meta_row in tqdm(train_meta.iterrows(), total=len(train_meta)):\n            record = {}\n\n            image_id, height, width = train_meta_row.values\n            filename = str(imgdir / \"train\" / f\"{image_id}.png\")\n            record[\"file_name\"] = filename\n            record[\"image_id\"] = image_id\n            record[\"height\"] = resized_height\n            record[\"width\"] = resized_width\n            objs = []\n            for index2, row in train_df.query(\"image_id == @image_id\").iterrows():\n                # print(row)\n                # print(row[\"class_name\"])\n                # class_name = row[\"class_name\"]\n                class_id = row[\"class_id\"]\n                if class_id == 14:\n                    # It is \"No finding\"\n                    if use_class14:\n                        # Use this No finding class with the bbox covering all image area.\n                        bbox_resized = [0, 0, resized_width, resized_height]\n                        obj = {\n                            \"bbox\": bbox_resized,\n                            \"bbox_mode\": BoxMode.XYXY_ABS,\n                            \"category_id\": class_id,\n                        }\n                        objs.append(obj)\n                    else:\n                        # This annotator does not find anything, skip.\n                        pass\n                else:\n                    # bbox_original = [int(row[\"x_min\"]), int(row[\"y_min\"]), int(row[\"x_max\"]), int(row[\"y_max\"])]\n                    h_ratio = resized_height / height\n                    w_ratio = resized_width / width\n                    bbox_resized = [\n                        float(row[\"x_min\"]) * w_ratio,\n                        float(row[\"y_min\"]) * h_ratio,\n                        float(row[\"x_max\"]) * w_ratio,\n                        float(row[\"y_max\"]) * h_ratio,\n                    ]\n                    obj = {\n                        \"bbox\": bbox_resized,\n                        \"bbox_mode\": BoxMode.XYXY_ABS,\n                        \"category_id\": class_id,\n                    }\n                    objs.append(obj)\n            record[\"annotations\"] = objs\n            dataset_dicts.append(record)\n        with open(cache_path, mode=\"wb\") as f:\n            pickle.dump(dataset_dicts, f)\n\n    print(f\"Load from cache {cache_path}\")\n    with open(cache_path, mode=\"rb\") as f:\n        dataset_dicts = pickle.load(f)\n    if target_indices is not None:\n        dataset_dicts = [dataset_dicts[i] for i in target_indices]\n    return dataset_dicts\n\n\ndef get_vinbigdata_dicts_test(\n    imgdir: Path, test_meta: pd.DataFrame, use_cache: bool = True, debug: bool = True,\n):\n    debug_str = f\"_debug{int(debug)}\"\n    cache_path = Path(\".\") / f\"dataset_dicts_cache_test{debug_str}.pkl\"\n    if not use_cache or not cache_path.exists():\n        print(\"Creating data...\")\n        # test_meta = pd.read_csv(imgdir / \"test_meta.csv\")\n        if debug:\n            test_meta = test_meta.iloc[:500]  # For debug....\n\n        # Load 1 image to get image size.\n        image_id = test_meta.loc[0, \"image_id\"]\n        image_path = str(imgdir / \"test\" / f\"{image_id}.png\")\n        image = cv2.imread(image_path)\n        resized_height, resized_width, ch = image.shape\n        print(f\"image shape: {image.shape}\")\n\n        dataset_dicts = []\n        for index, test_meta_row in tqdm(test_meta.iterrows(), total=len(test_meta)):\n            record = {}\n\n            image_id, height, width = test_meta_row.values\n            filename = str(imgdir / \"test\" / f\"{image_id}.png\")\n            record[\"file_name\"] = filename\n            # record[\"image_id\"] = index\n            record[\"image_id\"] = image_id\n            record[\"height\"] = resized_height\n            record[\"width\"] = resized_width\n            # objs = []\n            # record[\"annotations\"] = objs\n            dataset_dicts.append(record)\n        with open(cache_path, mode=\"wb\") as f:\n            pickle.dump(dataset_dicts, f)\n\n    print(f\"Load from cache {cache_path}\")\n    with open(cache_path, mode=\"rb\") as f:\n        dataset_dicts = pickle.load(f)\n    return dataset_dicts","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"Methods for prediction for this competition"},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# Methods for prediction for this competition\nfrom math import ceil\nfrom typing import Any, Dict, List\n\nimport cv2\nimport detectron2\nimport numpy as np\nfrom numpy import ndarray\nimport pandas as pd\nimport torch\nfrom detectron2 import model_zoo\nfrom detectron2.config import get_cfg\nfrom detectron2.data import DatasetCatalog, MetadataCatalog, build_detection_test_loader\nfrom detectron2.engine import DefaultPredictor\nfrom detectron2.evaluation import COCOEvaluator, inference_on_dataset\nfrom detectron2.structures import BoxMode\nfrom detectron2.utils.logger import setup_logger\nfrom detectron2.utils.visualizer import ColorMode, Visualizer\nfrom tqdm import tqdm\n\n\ndef format_pred(labels: ndarray, boxes: ndarray, scores: ndarray) -> str:\n    pred_strings = []\n    for label, score, bbox in zip(labels, scores, boxes):\n        xmin, ymin, xmax, ymax = bbox.astype(np.int64)\n        pred_strings.append(f\"{label} {score} {xmin} {ymin} {xmax} {ymax}\")\n    return \" \".join(pred_strings)\n\n\ndef predict_batch(predictor: DefaultPredictor, im_list: List[ndarray]) -> List:\n    with torch.no_grad():  # https://github.com/sphinx-doc/sphinx/issues/4258\n        inputs_list = []\n        for original_image in im_list:\n            # Apply pre-processing to image.\n            if predictor.input_format == \"RGB\":\n                # whether the model expects BGR inputs or RGB\n                original_image = original_image[:, :, ::-1]\n            height, width = original_image.shape[:2]\n            # Do not apply original augmentation, which is resize.\n            # image = predictor.aug.get_transform(original_image).apply_image(original_image)\n            image = original_image\n            image = torch.as_tensor(image.astype(\"float32\").transpose(2, 0, 1))\n            inputs = {\"image\": image, \"height\": height, \"width\": width}\n            inputs_list.append(inputs)\n        predictions = predictor.model(inputs_list)\n        return predictions","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"# --- utils ---\nfrom pathlib import Path\nfrom typing import Any, Union\n\nimport yaml\n\n\ndef save_yaml(filepath: Union[str, Path], content: Any, width: int = 120):\n    with open(filepath, \"w\") as f:\n        yaml.dump(content, f, width=width)\n\n\ndef load_yaml(filepath: Union[str, Path]) -> Any:\n    with open(filepath, \"r\") as f:\n        content = yaml.full_load(f)\n    return content\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# --- configs ---\nthing_classes = [\n    \"Aortic enlargement\",\n    \"Atelectasis\",\n    \"Calcification\",\n    \"Cardiomegaly\",\n    \"Consolidation\",\n    \"ILD\",\n    \"Infiltration\",\n    \"Lung Opacity\",\n    \"Nodule/Mass\",\n    \"Other lesion\",\n    \"Pleural effusion\",\n    \"Pleural thickening\",\n    \"Pneumothorax\",\n    \"Pulmonary fibrosis\"\n]\ncategory_name_to_id = {class_name: index for index, class_name in enumerate(thing_classes)}\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"This `Flags` class is to manage experiments. I will tune these parameters through the competition to improve model's performance."},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"# --- flags ---\nfrom dataclasses import dataclass, field\nfrom typing import Dict\n\n\n@dataclass\nclass Flags:\n    # General\n    debug: bool = True\n    outdir: str = \"results/det\"\n\n    # Data config\n    imgdir_name: str = \"../input/vinbigdata-512-image-dataset/vinbigdata/\"\n    split_mode: str = \"all_train\"  # all_train or valid20\n    seed: int = 111\n    train_data_type: str = \"original\"  # original or wbf\n    use_class14: bool = False\n    # Training config\n    iter: int = 10000\n    ims_per_batch: int = 2  # images per batch, this corresponds to \"total batch size\"\n    num_workers: int = 4\n    lr_scheduler_name: str = \"WarmupMultiStepLR\"  # WarmupMultiStepLR (default) or WarmupCosineLR\n    base_lr: float = 0.00025\n    roi_batch_size_per_image: int = 512\n    eval_period: int = 10000\n    aug_kwargs: Dict = field(default_factory=lambda: {})\n\n    def update(self, param_dict: Dict) -> \"Flags\":\n        # Overwrite by `param_dict`\n        for key, value in param_dict.items():\n            if not hasattr(self, key):\n                raise ValueError(f\"[ERROR] Unexpected key for flag = {key}\")\n            setattr(self, key, value)\n        return self","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"pred_scripts\"></a>\n# Prediction scripts\n\nNow the methods are ready. Main training scripts starts from here."},{"metadata":{"trusted":true},"cell_type":"code","source":"inputdir = Path(\"/kaggle/input\")\ntraineddir = inputdir / \"vbd-v28-sc-kaggle-v16-anchor-box-play\" # ## PS kaggle v4, v24 overall, same confused on R50 in laptop \n\n# flags = Flags()\nflags: Flags = Flags().update(load_yaml(str(traineddir/\"flags.yaml\")))\nprint(\"flags\", flags)\ndebug = flags.debug\n# flags_dict = dataclasses.asdict(flags)\noutdir = Path(flags.outdir)\nos.makedirs(str(outdir), exist_ok=True)\n\n# --- Read data ---\ndatadir = inputdir / \"vinbigdata-chest-xray-abnormalities-detection\"\nif flags.imgdir_name == \"vinbigdata-chest-xray-resized-png-512x512\":\n    imgdir = inputdir/ \"vinbigdata\"\nelse:\n    imgdir = inputdir / flags.imgdir_name\n\n# Read in the data CSV files\n# train = pd.read_csv(datadir / \"train.csv\")\ntest_meta = pd.read_csv(inputdir / \"vinbigdata-testmeta\" / \"test_meta.csv\")\nsample_submission = pd.read_csv(datadir / \"sample_submission.csv\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"cfg = get_cfg()\noriginal_output_dir = cfg.OUTPUT_DIR\ncfg.OUTPUT_DIR = str(outdir)\nprint(f\"cfg.OUTPUT_DIR {original_output_dir} -> {cfg.OUTPUT_DIR}\")\n\ncfg.merge_from_file(model_zoo.get_config_file(\"COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml\"))\ncfg.DATASETS.TRAIN = (\"vinbigdata_train\",)\ncfg.DATASETS.TEST = ()\n# cfg.DATASETS.TEST = (\"vinbigdata_train\",)\n# cfg.TEST.EVAL_PERIOD = 50\ncfg.DATALOADER.NUM_WORKERS = 2\n# Let training initialize from model zoo\ncfg.MODEL.WEIGHTS = model_zoo.get_checkpoint_url(\"COCO-Detection/faster_rcnn_R_101_FPN_3x.yaml\")\ncfg.SOLVER.IMS_PER_BATCH = 2\ncfg.SOLVER.BASE_LR = flags.base_lr  # pick a good LR\ncfg.SOLVER.MAX_ITER = flags.iter\ncfg.MODEL.ROI_HEADS.BATCH_SIZE_PER_IMAGE = flags.roi_batch_size_per_image\ncfg.MODEL.ROI_HEADS.NUM_CLASSES = len(thing_classes)\n\n\n#cfg.MODEL.ANCHOR_GENERATOR.SIZES = [[16], [32], [64], [128], [256], [512], [1024]]\n#cfg.MODEL.RPN.IN_FEATURES = ['p2', 'p2', 'p3', 'p4', 'p5', 'p6', 'p6']\n\n#cfg.MODEL.ANCHOR_GENERATOR.ASPECT_RATIOS = [[0.33, 0.5, 1.0, 2.0, 3.0]]\n\n# NOTE: this config means the number of classes, but a few popular unofficial tutorials incorrect uses num_classes+1 here.\n\n### --- Inference & Evaluation ---\n# Inference should use the config with parameters that are used in training\n# cfg now already contains everything we've set previously. We changed it a little bit for inference:\n# path to the model we just trained\ncfg.MODEL.WEIGHTS = str(traineddir/\"model_final.pth\")\nprint(\"Original thresh\", cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST)  # 0.05\ncfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.0  # set a custom testing threshold\nprint(\"Changed  thresh\", cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST)\npredictor = DefaultPredictor(cfg)\n\nDatasetCatalog.register(\n    \"vinbigdata_test\", lambda: get_vinbigdata_dicts_test(imgdir, test_meta, debug=debug)\n)\nMetadataCatalog.get(\"vinbigdata_test\").set(thing_classes=thing_classes)\nmetadata = MetadataCatalog.get(\"vinbigdata_test\")\ndataset_dicts = get_vinbigdata_dicts_test(imgdir, test_meta, debug=debug)\n\nif debug:\n    dataset_dicts = dataset_dicts[:100]\n\nresults_list = []\nindex = 0\nbatch_size = 4\n\nfor i in tqdm(range(ceil(len(dataset_dicts) / batch_size))):\n    inds = list(range(batch_size * i, min(batch_size * (i + 1), len(dataset_dicts))))\n    dataset_dicts_batch = [dataset_dicts[i] for i in inds]\n    im_list = [cv2.imread(d[\"file_name\"]) for d in dataset_dicts_batch]\n    outputs_list = predict_batch(predictor, im_list)\n\n    for im, outputs, d in zip(im_list, outputs_list, dataset_dicts_batch):\n        resized_height, resized_width, ch = im.shape\n        # outputs = predictor(im)\n        if index < 5:\n            # format is documented at https://detectron2.readthedocs.io/tutorials/models.html#model-output-format\n            v = Visualizer(\n                im[:, :, ::-1],\n                metadata=metadata,\n                scale=0.5,\n                instance_mode=ColorMode.IMAGE_BW\n                # remove the colors of unsegmented pixels. This option is only available for segmentation models\n            )\n            out = v.draw_instance_predictions(outputs[\"instances\"].to(\"cpu\"))\n            # cv2_imshow(out.get_image()[:, :, ::-1])\n            cv2.imwrite(str(outdir / f\"pred_{index}.jpg\"), out.get_image()[:, :, ::-1])\n\n        image_id, dim0, dim1 = test_meta.iloc[index].values\n\n        instances = outputs[\"instances\"]\n        if len(instances) == 0:\n            # No finding, let's set 14 1 0 0 1 1x.\n            result = {\"image_id\": image_id, \"PredictionString\": \"14 1.0 0 0 1 1\"}\n        else:\n            # Find some bbox...\n            # print(f\"index={index}, find {len(instances)} bbox.\")\n            fields: Dict[str, Any] = instances.get_fields()\n            pred_classes = fields[\"pred_classes\"]  # (n_boxes,)\n            pred_scores = fields[\"scores\"]\n            # shape (n_boxes, 4). (xmin, ymin, xmax, ymax)\n            pred_boxes = fields[\"pred_boxes\"].tensor\n\n            h_ratio = dim0 / resized_height\n            w_ratio = dim1 / resized_width\n            pred_boxes[:, [0, 2]] *= w_ratio\n            pred_boxes[:, [1, 3]] *= h_ratio\n\n            pred_classes_array = pred_classes.cpu().numpy()\n            pred_boxes_array = pred_boxes.cpu().numpy()\n            pred_scores_array = pred_scores.cpu().numpy()\n\n            result = {\n                \"image_id\": image_id,\n                \"PredictionString\": format_pred(\n                    pred_classes_array, pred_boxes_array, pred_scores_array\n                ),\n            }\n        results_list.append(result)\n        index += 1","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"* Here I set `cfg.MODEL.ROI_HEADS.SCORE_THRESH_TEST = 0.0` to produce **all the detection box prediction even if confidence score is very low**.<br/>\nActually it affects a lot to score, since competition metric is AP (Average-Precision) which is calculated using the boxes with confidence score = 0~100%."},{"metadata":{"trusted":true},"cell_type":"code","source":"# This submission includes only detection model's predictions\nsubmission_det = pd.DataFrame(results_list, columns=['image_id', 'PredictionString'])\nsubmission_det.to_csv(\"./results/submission_v28_SC_kaggle_nbv16.csv\", index=False)\nprint (outdir)\nsubmission_det","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"2class\"></a>\n# Apply 2 class filter\n\nI moved this section to [📸VinBigData 2-class classifier complete pipeline](https://www.kaggle.com/corochann/vinbigdata-2-class-classifier-complete-pipeline).<br/>\nPlease refer the kernel, **it improves LB score significantly from 0.141 -> 0.221**."},{"metadata":{},"cell_type":"markdown","source":"**Discussion: How to improve more?**\n\nI'm now thinking that it's better to include normal images for training to learn where there is **no** abnormality.<br/>\nAlso, I think it's nice to try **including \"No finding\" class during detection training** (by adding virtual \"No finding\" boxes, or by adding global classifier together with the detection).\n\n\nThat's all!\nObject deteaction is rather complicated task among deep learning tasks, but it's easy to train SoTA models & predict using `detectron2`!!!\n\n<h3 style=\"color:red\">If this kernel helps you, please upvote to keep me motivated 😁<br>Thanks!</h3>"},{"metadata":{},"cell_type":"markdown","source":"<a id=\"ref\"></a>\n# Other kernels\n\n[VinBigData detectron2 train](https://www.kaggle.com/sourabhchauhan/train-vinbigdata-detectron2-weights-and-biases/) kernel explains how to run object detection training, using `detectron2` library.\n"},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}