{"cells":[{"metadata":{},"cell_type":"markdown","source":"Hi,everyone! Good news!  \nMMdetection V2 has supported SOTA model DetectoRS, I integrated mosaic data augmentation into mmdetv2. For details, please check [my repo](https://github.com/WangLibo1995/mmdetection-v2-with-mosaic-data-augmentation). If you find it help, don't forget add stars:)  \nI also recommend you to try more models in mmdetv2(DetectoRS LB 68.4 with default settings). My training notebook is in my github repo too.","execution_count":null},{"metadata":{"id":"QXo7TY3g_9Mk","outputId":"c8f0389c-7846-4558-bf06-d6ea43b05ccc","trusted":true},"cell_type":"code","source":"! nvidia-smi","execution_count":null,"outputs":[]},{"metadata":{"id":"aJkxuyB-KNkH"},"cell_type":"markdown","source":"#prepare data and env\n","execution_count":null},{"metadata":{"id":"05LassAoTfA8","trusted":false},"cell_type":"code","source":"! pip install --upgrade --force-reinstall --no-deps albumentations","execution_count":null,"outputs":[]},{"metadata":{"id":"fsyZ7Vx9REcz","trusted":false},"cell_type":"code","source":"! git clone https://github.com/open-mmlab/mmcv.git /content/mmcv/\n%cd /content/mmcv\n! pip install -e .","execution_count":null,"outputs":[]},{"metadata":{"id":"LSU0zXynQayL","trusted":false},"cell_type":"code","source":"! git clone https://github.com/WangLibo1995/mmdetection-v2-with-mosaic-data-augmentation.git /content/mmdetection/  \n%cd /content/mmdetection\n! pip install -r requirements/build.txt\n! pip install \"git+https://github.com/open-mmlab/cocoapi.git#subdirectory=pycocotools\"\n! python setup.py develop","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"AFF52_md_6s-"},"cell_type":"code","source":"#!wget -c https://www.cs.jhu.edu/~syqiao/DetectoRS/DetectoRS_X101-ed983634.pth -O /content/DetectoRS_x101.pth","execution_count":null,"outputs":[]},{"metadata":{"id":"8J51HtdPBaY9","trusted":false},"cell_type":"code","source":"# !wget -c http://cs.jhu.edu/~syqiao/DetectoRS/DetectoRS_R50-0f1c8080.pth -O /content/DetectoRS_50.pth","execution_count":null,"outputs":[]},{"metadata":{"id":"QWP4A8VWnlpm","outputId":"cf676667-2614-4b92-8ee5-639c3b509efe","trusted":false},"cell_type":"code","source":"!wget -c https://open-mmlab.s3.ap-northeast-2.amazonaws.com/mmdetection/v2.0/detectors/detectors_cascade_rcnn_r50_1x_coco/detectors_cascade_rcnn_r50_1x_coco-0db1ab6a.pth -O /content/DetectoRS_box_50.pth","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"NMuonVCB_6s7"},"cell_type":"code","source":"from mmdet.apis import init_detector, inference_detector, show_result_pyplot\nimport mmcv\nfrom mmcv import Config\nfrom mmdet.models import build_detector\nfrom mmcv.runner import load_checkpoint\nfrom mmcv.parallel import MMDataParallel\nfrom mmdet.apis import single_gpu_test\nfrom mmdet.datasets import build_dataloader, build_dataset\nimport cv2\nimport pandas as pd\nimport numpy as np\nimport os\nimport re\nimport json\n\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nimport torch","execution_count":null,"outputs":[]},{"metadata":{"id":"jkcjnb4M_6tF"},"cell_type":"markdown","source":"# csv2coco and 5-flod","execution_count":null},{"metadata":{"trusted":true,"id":"De_bjP6w_6tH"},"cell_type":"code","source":"def expand_bbox(x):\n    r = np.array(re.findall(\"([0-9]+[.]?[0-9]*)\", x))\n    if len(r) == 0:\n        r = [-1, -1, -1, -1]\n    return r\n\ndef marking_pre(csv_file, debug=False):\n    df = pd.read_csv(csv_file)\n    df['x'] = -1\n    df['y'] = -1\n    df['w'] = -1\n    df['h'] = -1\n    \n    df[['x', 'y', 'w', 'h']] = np.stack(df['bbox'].apply(lambda x: expand_bbox(x)))\n    df.drop(columns=['bbox'], inplace=True)\n    df['xmin'] = df['x'].astype(np.float)\n    df['ymin'] = df['y'].astype(np.float)\n    df['w'] = df['w'].astype(np.float)\n    df['h'] = df['h'].astype(np.float)\n    df['area'] = df['w']*df['h']\n    error_bbox = [100648.0, 145360.0, 149744.0, 119790.0, 106743.0]\n    df = df[df['area']<154200.0]\n    df = df[~df['area'].isin(error_bbox)]\n    df = df[df['w']>=10.0]\n    df = df[df['h']>=10.0]\n    df['xmax'] = df.apply(lambda x: x['xmin'] + x['w'], axis=1)\n    df['ymax'] = df.apply(lambda x: x['ymin'] + x['h'], axis=1)\n    df['category'] = 'wheat'\n    df['image_id'] = df.apply(lambda x: x['image_id'] + '.jpg', axis=1)\n    df.drop(columns=['x', 'y', 'w', 'h','width','height','area'], inplace=True)\n    print(df.head())\n    if debug:\n      df =df[:1500]\n    return df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"W42UqdSi_6tJ"},"cell_type":"code","source":"import glob\nimport os\nimport shutil\nfrom IPython import embed\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.model_selection import StratifiedKFold\nnp.random.seed(42)\n\n# reference https://github.com/spytensor/prepare_detection_dataset\nclassname_to_id = {\"wheat\": 0}\n\nclass Csv2CoCo:\n\n    def __init__(self,image_dir,total_annos):\n        self.images = []\n        self.annotations = []\n        self.categories = []\n        self.img_id = 0\n        self.ann_id = 0\n        self.image_dir = image_dir\n        self.total_annos = total_annos\n\n    def save_coco_json(self, instance, save_path):\n        json.dump(instance, open(save_path, 'w'), ensure_ascii=False, indent=2)  # indent=2 更加美观显示\n\n    # 由txt文件构建COCO\n    def to_coco(self, keys):\n        self._init_categories()\n        for key in keys:\n            self.images.append(self._image(key))\n            shapes = self.total_annos[key]\n            for shape in shapes:\n                bboxi = []\n                for cor in shape[:-1]:\n                    bboxi.append(int(float(cor)))\n                label = shape[-1]\n                annotation = self._annotation(bboxi,label)\n                self.annotations.append(annotation)\n                self.ann_id += 1\n            self.img_id += 1\n        instance = {}\n        instance['info'] = 'Libo Wang created'\n        instance['license'] = ['license']\n        instance['images'] = self.images\n        instance['annotations'] = self.annotations\n        instance['categories'] = self.categories\n        return instance\n\n    # 构建类别\n    def _init_categories(self):\n        for k, v in classname_to_id.items():\n            category = {}\n            category['id'] = v\n            category['name'] = k\n            self.categories.append(category)\n\n    # 构建COCO的image字段\n    def _image(self, path):\n        image = {}\n        img_path = self.image_dir + path\n        print(img_path)\n        img = cv2.imread(img_path)\n        image['height'] = img.shape[0]\n        image['width'] = img.shape[1]\n        image['id'] = self.img_id\n        image['file_name'] = path\n        return image\n\n    # 构建COCO的annotation字段\n    def _annotation(self, shape, label):\n        # label = shape[-1]\n        points = shape[:4]\n        annotation = {}\n        annotation['id'] = self.ann_id\n        annotation['image_id'] = self.img_id\n        annotation['category_id'] = int(classname_to_id[label])\n        annotation['segmentation'] = self._get_seg(points)\n        annotation['bbox'] = self._get_box(points)\n        annotation['iscrowd'] = 0\n        annotation['area'] = self._get_area(points)\n        return annotation\n\n    # COCO的格式： [x1,y1,w,h] 对应COCO的bbox格式\n    def _get_box(self, points):\n        min_x = points[0]\n        min_y = points[1]\n        max_x = points[2]\n        max_y = points[3]\n        return [min_x, min_y, max_x - min_x, max_y - min_y]\n    # 计算面积\n    def _get_area(self, points):\n        min_x = points[0]\n        min_y = points[1]\n        max_x = points[2]\n        max_y = points[3]\n        return (max_x - min_x+1) * (max_y - min_y+1)\n    # segmentation\n    def _get_seg(self, points):\n        min_x = points[0]\n        min_y = points[1]\n        max_x = points[2]\n        max_y = points[3]\n        h = max_y - min_y\n        w = max_x - min_x\n        a = []\n        a.append([min_x,min_y, min_x,min_y+0.5*h, min_x,max_y, min_x+0.5*w,max_y, max_x,max_y, max_x,max_y-0.5*h, max_x,min_y, max_x-0.5*w,min_y])\n        return a\n\n# Alex Shonenkov‘s data split: https://www.kaggle.com/shonenkov/training-efficientdet\ndef sk_5fold(marking,fold_number):\n    skf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\n    df_folds = marking[['image_id']].copy()\n    df_folds.loc[:, 'bbox_count'] = 1\n    df_folds = df_folds.groupby('image_id').count()\n    df_folds.loc[:, 'source'] = marking[['image_id', 'source']].groupby('image_id').min()['source']\n    df_folds.loc[:, 'stratify_group'] = np.char.add(\n        df_folds['source'].values.astype(str),\n        df_folds['bbox_count'].apply(lambda x: f'_{x // 15}').values.astype(str)\n    )\n    df_folds.loc[:, 'fold'] = 0\n\n    for fold_number, (train_index, val_index) in enumerate(skf.split(X=df_folds.index, y=df_folds['stratify_group'])):\n        df_folds.loc[df_folds.iloc[val_index].index, 'fold'] = fold_number\n    \n    return df_folds\n    \n    \n    \ndef with_5fold_to_coco(csv_file,image_dir,saved_coco_path,fold_number,debug):\n#     csv_file = \"train_df.csv\"\n#     image_dir = \"/content/global-wheat-detection/train/\"\n#     saved_coco_path = \"/content/wheat\"\n    # 整合csv格式标注文件\n    total_csv_annotations = {}\n    marking = marking_pre(csv_file, debug)\n    \n    df_folds = sk_5fold(marking,fold_number)\n    train_keys = df_folds[df_folds['fold'] != fold_number].index.values\n    val_keys = df_folds[df_folds['fold'] == fold_number].index.values\n    \n    marking = marking.drop(columns=['source'], axis=1)\n    print(marking.head())\n    annotations = marking.values\n    for annotation in annotations:\n        key = annotation[0].split(os.sep)[-1]\n        value = np.array([annotation[1:]])\n        if key in total_csv_annotations.keys():\n            total_csv_annotations[key] = np.concatenate((total_csv_annotations[key],value),axis=0)\n        else:\n            total_csv_annotations[key] = value\n    # 按照键值划分数据\n    total_keys = list(total_csv_annotations.keys())\n    print(\"train_n:\", len(train_keys), 'val_n:', len(val_keys), 'total_n:', len(total_keys))\n    # 创建必须的文件夹      \n    annotations_path = f'{saved_coco_path}/annotations/'\n    train_path = f'{saved_coco_path}/train2017'\n    val_path = f'{saved_coco_path}/val2017'\n    if not os.path.exists(annotations_path):\n        os.makedirs(annotations_path)\n    if not os.path.exists(train_path):\n        os.makedirs(train_path)\n    if not os.path.exists(val_path):\n        os.makedirs(val_path)\n    # 把训练集转化为COCO的json格式\n    l2c_train = Csv2CoCo(image_dir=image_dir,total_annos=total_csv_annotations)\n    train_instance = l2c_train.to_coco(train_keys)\n    l2c_train.save_coco_json(train_instance, f'{annotations_path}instances_train2017.json')\n    for file in train_keys:\n        shutil.copy(image_dir+file,train_path)\n    for file in val_keys:\n        shutil.copy(image_dir+file,val_path)\n    # 把验证集转化为COCO的json格式\n    l2c_val = Csv2CoCo(image_dir=image_dir,total_annos=total_csv_annotations)\n    val_instance = l2c_val.to_coco(val_keys)\n    l2c_val.save_coco_json(val_instance, f'{annotations_path}instances_val2017.json')","execution_count":null,"outputs":[]},{"metadata":{"id":"4LpR9nL5dPl0"},"cell_type":"markdown","source":"# File Path","execution_count":null},{"metadata":{"id":"v-u_XYbbdJfA","trusted":false},"cell_type":"code","source":"csv_file = '/content/global-wheat-detection/train.csv'\nimage_dir = '/content/global-wheat-detection/train/'\nsaved_coco_path = '/content/mmdetection/data/coco'\nfold_number = 0\ndebug = False","execution_count":null,"outputs":[]},{"metadata":{"id":"u4yi3n-tfaw0"},"cell_type":"markdown","source":"# Run Data Format Conversion","execution_count":null},{"metadata":{"trusted":true,"id":"ZTBK9kcq_6tM"},"cell_type":"code","source":"with_5fold_to_coco(csv_file,image_dir,saved_coco_path,fold_number,debug)","execution_count":null,"outputs":[]},{"metadata":{"id":"5mFyX8RJay5N"},"cell_type":"markdown","source":"# Show Dataset","execution_count":null},{"metadata":{"id":"wLEvPJWfa7qq","outputId":"8d9f3b12-1486-4f87-8abb-4eb2bda7efad","trusted":false},"cell_type":"code","source":"%cd '/content/mmdetection'\n!python tools/browse_dataset.py /content/mmdetection/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py \\\n--output-dir /content/fig \\\n--not-show","execution_count":null,"outputs":[]},{"metadata":{"id":"C83u89OfpJ9U","outputId":"e97fc643-d711-4866-eeb3-da7805346e37","trusted":false},"cell_type":"code","source":"import os\nimport mmcv\nimport matplotlib.pyplot as plt\n\nimage_list = os.listdir('/content/fig')\nprint(len(image_list))\nfor image_id in image_list[:5]:\n  fig, ax = plt.subplots(1, 1, figsize=(16, 8))\n  img = mmcv.imread(f'/content/fig/{image_id}')\n  ax.imshow(img)","execution_count":null,"outputs":[]},{"metadata":{"id":"hy4A1u9if5-E"},"cell_type":"markdown","source":"# Training","execution_count":null},{"metadata":{"id":"aRFmtMuXVV-K","outputId":"1255433c-dd0d-4e12-ed96-1d65f6cd945a","trusted":false},"cell_type":"code","source":"%cd '/content/mmdetection'\n!python tools/train.py /content/mmdetection/configs/detectors/detectors_cascade_rcnn_r50_1x_coco.py \\\n--work-dir \"/content/drive/My Drive/Global_Wheat_Detection/mmdetv2-resnet50_ft\" \\\n--gpus 1 \\\n--seed 42 \\\n--load-from /content/DetectoRS_box_50.pth ","execution_count":null,"outputs":[]},{"metadata":{"id":"eDTF1lAH4w3w"},"cell_type":"markdown","source":"# Testing","execution_count":null},{"metadata":{"id":"89u9-R_C4vm_","trusted":false},"cell_type":"code","source":"# %cd /content/mmdetection\n# !python tools/test.py \\\n# --config /content/mmdetection/configs/DetectoRS/My_DetectoRS_resnet101_from_x.py \\\n# --checkpoint \"/content/drive/My Drive/Global_Wheat_Detection/mmdet-resnet101/epoch_2.pth\" \\\n# --eval 'bbox' \\\n# --out \"/content/drive/My Drive/Global_Wheat_Detection/mmdet-resnet101/result.pkl\" ","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"JYBFaDogepA6"},"cell_type":"code","source":"# cfg_path = '/content/mmdetection/configs/DetectoRS/My_DetectoRS_resnet101_from_x.py'\n# cp_path = '/content/drive/My Drive/Global_Wheat_Detection/mmdet-resnet101/epoch_2.pth'\n\n# # build the model from a config file and a checkpoint file\n# model = init_detector(cfg_path, cp_path, device='cuda:0')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"id":"el87h9m_etu8"},"cell_type":"code","source":"# img = '/content/mmdetection/data/coco/train2017/00333207f.jpg'\n# img = mmcv.imread(img)# or img = mmcv.imread(img), which will only load it once\n# result = inference_detector(model, img)\n# #print(result)\n# show_result_pyplot(img, result, model.CLASSES)\n# torch.cuda.empty_cache()","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}