{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.9","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":23823,"databundleVersionId":1920183,"sourceType":"competition"},{"sourceId":1895197,"sourceType":"datasetVersion","datasetId":1129329},{"sourceId":1911681,"sourceType":"datasetVersion","datasetId":1128406},{"sourceId":8066897,"sourceType":"datasetVersion","datasetId":4759370}],"dockerImageVersionId":30056,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# install packages\n!rsync -a ../input/mmdetection-v280/mmdetection ../\n!pip install ../input/mmdetection-v280/src/mmdet-2.8.0/mmdet-2.8.0/\n!pip install ../input/mmdetection-v280/src/mmpycocotools-12.0.3/mmpycocotools-12.0.3/\n!pip install ../input/mmdetection-v280/src/addict-2.4.0-py3-none-any.whl\n!pip install ../input/mmdetection-v280/src/yapf-0.30.0-py2.py3-none-any.whl\n!pip install ../input/mmdetection-v280/src/mmcv_full-1.2.6-cp37-cp37m-manylinux1_x86_64.whl","metadata":{"_kg_hide-output":true,"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !pip install mmcv==1.3.8","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from itertools import groupby\nfrom pycocotools import mask as mutils\nimport numpy as np\nfrom tqdm import tqdm\nimport pandas as pd\nimport os\nimport pickle\nimport cv2\nfrom multiprocessing import Pool\nimport matplotlib.pyplot as plt","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:52:54.83308Z","iopub.execute_input":"2024-04-09T03:52:54.833517Z","iopub.status.idle":"2024-04-09T03:52:54.857188Z","shell.execute_reply.started":"2024-04-09T03:52:54.833431Z","shell.execute_reply":"2024-04-09T03:52:54.856424Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\nexp_name = \"v3\"\nconf_name = \"mask_rcnn_s101_fpn_syncbn-backbone+head_mstrain_1x_coco\"\ncell_mask_dir = '../input/hpa-mask/hpa_cell_mask'    \nROOT = '../input/hpa-single-cell-image-classification/'\ntrain_or_test = 'train'\nimg_dir = f'../work/mmdet_{exp_name}_{train_or_test}'\n!mkdir -p {img_dir}\ndf = pd.read_csv(os.path.join(ROOT, 'train.csv'))\n\n# this script takes more than 9hours for full data.\ndebug = True\nif debug:\n    df = df[:4]","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:52:54.859659Z","iopub.execute_input":"2024-04-09T03:52:54.860087Z","iopub.status.idle":"2024-04-09T03:52:55.913426Z","shell.execute_reply.started":"2024-04-09T03:52:54.860045Z","shell.execute_reply":"2024-04-09T03:52:55.911851Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# helper funcs","metadata":{}},{"cell_type":"code","source":"# convert segmentation mask image to run length encoding\nMAX_GREEN = 64 # filter out dark green cells\ndef get_rles_from_mask(image_id, class_id):\n    mask = np.load(f'{cell_mask_dir}/{image_id}.npz')['arr_0']\n    if class_id != '18':\n        green_img = read_img(image_id, 'green')\n    rle_list = []\n    mask_ids = np.unique(mask)\n    for val in mask_ids:\n        if val == 0:\n            continue\n        binary_mask = np.where(mask == val, 1, 0).astype(bool)\n        if class_id != '18':\n            masked_img = green_img * binary_mask\n            #print(val, green_img.max(),masked_img.max())\n            if masked_img.max() < MAX_GREEN:\n                continue\n        rle = coco_rle_encode(binary_mask)\n        rle_list.append(rle)\n    return rle_list, mask.shape[0], mask.shape[1]\n\ndef coco_rle_encode(mask):\n    rle = {'counts': [], 'size': list(mask.shape)}\n    counts = rle.get('counts')\n    for i, (value, elements) in enumerate(groupby(mask.ravel(order='F'))):\n        if i == 0 and value == 1:\n            counts.append(0)\n        counts.append(len(list(elements)))\n    return rle\n\n# mmdet custom dataset generator\ndef mk_mmdet_custom_data(image_id, class_id):\n    rles, height, width = get_rles_from_mask(image_id, class_id)\n    if len(rles) == 0:\n        return {\n            'filename': image_id+'.jpg',\n            'width': width,\n            'height': height,\n            'ann': {}\n        }\n    rles = mutils.frPyObjects(rles, height, width)\n    bboxes = mutils.toBbox(rles)\n    bboxes[:, 2] += bboxes[:, 0]\n    bboxes[:, 3] += bboxes[:, 1]\n    return {\n        'filename': image_id+'.jpg',\n        'width': width,\n        'height': height,\n        'ann':\n            {\n                'bboxes': np.array(bboxes, dtype=np.float32),\n                'labels': np.zeros(len(bboxes)), # dummy data.(will be replaced later)\n                'masks': rles\n            }\n    }\n\n# print utility from public notebook\ndef print_masked_img(image_id, mask):\n    img = load_RGBY_image(image_id, train_or_test)\n    \n    plt.figure(figsize=(15, 15))\n    plt.subplot(1, 3, 1)\n    plt.imshow(img)\n    plt.title('Image')\n    plt.axis('off')\n    \n    plt.subplot(1, 3, 2)\n    plt.imshow(mask)\n    plt.title('Mask')\n    plt.axis('off')\n    \n    plt.subplot(1, 3, 3)\n    plt.imshow(img)\n    plt.imshow(mask, alpha=0.6)\n    plt.title('Image + Mask')\n    plt.axis('off')\n    plt.show()\n    \n# image loader, using rgb only here\ndef load_RGBY_image(image_id, train_or_test='train', image_size=None):\n    red = read_img(image_id, \"red\", train_or_test, image_size)\n    green = read_img(image_id, \"green\", train_or_test, image_size)\n    blue = read_img(image_id, \"blue\", train_or_test, image_size)\n    #yellow = read_img(image_id, \"yellow\", train_or_test, image_size)\n    stacked_images = np.transpose(np.array([red, green, blue]), (1,2,0))\n    return stacked_images\n\n# \ndef read_img(image_id, color, train_or_test='train', image_size=None):\n    filename = f'{ROOT}/{train_or_test}/{image_id}_{color}.png'\n    assert os.path.exists(filename), f'not found {filename}'\n    img = cv2.imread(filename, cv2.IMREAD_UNCHANGED)\n    if image_size is not None:\n        img = cv2.resize(img, (image_size, image_size))\n    if img.max() > 255:\n        img_max = img.max()\n        img = (img/255).astype('uint8')\n    return img\n\n# make annotation helper called multi processes\ndef mk_ann(idx):\n    image_id = df.iloc[idx].ID\n    class_id = df.iloc[idx].Label\n    anno = mk_mmdet_custom_data(image_id, class_id)\n    img = load_RGBY_image(image_id, train_or_test)\n    cv2.imwrite(f'{img_dir}/{image_id}.jpg', img)\n    return anno, idx, image_id","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:52:55.915314Z","iopub.execute_input":"2024-04-09T03:52:55.915674Z","iopub.status.idle":"2024-04-09T03:52:55.941775Z","shell.execute_reply.started":"2024-04-09T03:52:55.915638Z","shell.execute_reply":"2024-04-09T03:52:55.940667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cell_mask_dir = '../input/hpa-mask/hpa_cell_mask'    \nfor idx in range(3):\n    image_id = df.iloc[idx].ID\n    cell_mask = np.load(f'{cell_mask_dir}/{image_id}.npz')['arr_0']\n    print_masked_img(image_id, cell_mask)","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:52:55.943358Z","iopub.execute_input":"2024-04-09T03:52:55.943786Z","iopub.status.idle":"2024-04-09T03:53:03.11393Z","shell.execute_reply.started":"2024-04-09T03:52:55.943753Z","shell.execute_reply":"2024-04-09T03:53:03.113089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# generate data for mmdetection training","metadata":{}},{"cell_type":"code","source":"# this part would take several hours, depends on your CPU power.\nMAX_THRE = 4 # set your avarable CPU count.\np = Pool(processes=MAX_THRE)\nannos = []\nlen_df = len(df)\nfor anno, idx, image_id in p.imap(mk_ann, range(len(df))):\n    if len(anno['ann']) > 0:\n        annos.append(anno)\n    print(f'{idx+1}/{len_df}, {image_id}')","metadata":{"lines_to_next_cell":2,"_kg_hide-output":true,"_kg_hide-input":false,"execution":{"iopub.status.busy":"2024-04-09T03:53:03.116829Z","iopub.execute_input":"2024-04-09T03:53:03.117135Z","iopub.status.idle":"2024-04-09T03:53:16.244262Z","shell.execute_reply.started":"2024-04-09T03:53:03.117104Z","shell.execute_reply":"2024-04-09T03:53:16.242664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"lbl_cnt_dict = df.set_index('ID').to_dict()['Label']\ntrn_annos = []\nval_annos = []\nval_len = int(len(annos)*0.01)\nfor idx in range(len(annos)):\n    ann = annos[idx]\n    filename = ann['filename'].replace('.jpg','').replace('.png','')\n    label_ids = lbl_cnt_dict[filename]\n    len_ann = len(ann['ann']['bboxes'])\n    bboxes = ann['ann']['bboxes']\n    masks = ann['ann']['masks']\n    # asign image level labels to each cells\n    for cnt, label_id in enumerate(label_ids.split('|')):\n        label_id = int(label_id)\n        if cnt == 0:\n            ann['ann']['labels'] = np.full(len_ann, label_id)\n        else:\n            ann['ann']['bboxes'] = np.concatenate([ann['ann']['bboxes'],bboxes])\n            ann['ann']['labels'] = np.concatenate([ann['ann']['labels'],np.full(len_ann, label_id)])\n            ann['ann']['masks'] = ann['ann']['masks'] + masks    \n    if idx < val_len:\n        val_annos.append(ann)\n    else:\n        trn_annos.append(ann)","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:53:16.247319Z","iopub.execute_input":"2024-04-09T03:53:16.247793Z","iopub.status.idle":"2024-04-09T03:53:16.263178Z","shell.execute_reply.started":"2024-04-09T03:53:16.247742Z","shell.execute_reply":"2024-04-09T03:53:16.262327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(f'../work/mmdet_{exp_name}_full.pkl', 'wb') as f:\n    pickle.dump(annos, f)\nwith open(f'../work/mmdet_{exp_name}_trn.pkl', 'wb') as f:\n    pickle.dump(trn_annos, f)\nwith open(f'../work/mmdet_{exp_name}_val.pkl', 'wb') as f:\n    pickle.dump(val_annos, f)","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:53:16.264604Z","iopub.execute_input":"2024-04-09T03:53:16.264932Z","iopub.status.idle":"2024-04-09T03:53:16.281811Z","shell.execute_reply.started":"2024-04-09T03:53:16.264901Z","shell.execute_reply":"2024-04-09T03:53:16.281025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# training","metadata":{}},{"cell_type":"code","source":"# I just made following config files based on default mask_rcnn.\n# The main changes are CustomDataset, num_classes, data path, etc.\n# Other than that, I used it as is for mmdetection.\n!ls -l ../mmdetection/configs/hpa_{exp_name}/","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:53:16.283366Z","iopub.execute_input":"2024-04-09T03:53:16.283681Z","iopub.status.idle":"2024-04-09T03:53:17.326059Z","shell.execute_reply.started":"2024-04-09T03:53:16.28365Z","shell.execute_reply":"2024-04-09T03:53:17.324846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = f'configs/hpa_{exp_name}/{conf_name}.py'\n# using --no-validate to avoid some errors for custom dataset metrics\nadditional_conf = '--no-validate --cfg-options'\nadditional_conf += f' work_dir=../working/work_dir'\nadditional_conf += f' optimizer.lr=0.0025'\ncmd = f'bash -x tools/dist_train.sh {config} 1 {additional_conf}'\n!cd ../mmdetection; {cmd}\n\n# !cd /kaggle/input/vdigpku/CBNetV2; {cmd}","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls -Rl .","metadata":{"execution":{"iopub.status.busy":"2024-04-09T03:53:21.644252Z","iopub.execute_input":"2024-04-09T03:53:21.644634Z","iopub.status.idle":"2024-04-09T03:53:22.663586Z","shell.execute_reply.started":"2024-04-09T03:53:21.644593Z","shell.execute_reply":"2024-04-09T03:53:22.662527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}