{"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":"## 📒 inferecne Notebooks:\n* Train: [Great-Barrier-Reef: YOLOv5 [train] 🌊](https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-train)\n* Infer: [Great-Barrier-Reef: YOLOv5 [infer] 🌊](https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-infer)\n* F2 score : [competition metric implementation](https://www.kaggle.com/bamps53/competition-metric-implementation)","metadata":{}},{"cell_type":"markdown","source":"## Import Library","metadata":{}},{"cell_type":"code","source":"from itertools import groupby\nimport numpy as np\nfrom tqdm.notebook import tqdm\ntqdm.pandas()\nimport pandas as pd\nimport os\nimport pickle\nimport cv2\nfrom multiprocessing import Pool\nimport matplotlib.pyplot as plt\n# import cupy as cp\nimport ast\nimport glob\n\nimport shutil\nimport sys\nsys.path.append('../input/tensorflow-great-barrier-reef')\n\nfrom joblib import Parallel, delayed\n\nfrom IPython.display import display, HTML\n\nfrom matplotlib import animation, rc\nrc('animation', html='jshtml')\n\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:25:00.030545Z","iopub.execute_input":"2022-01-04T08:25:00.03099Z","iopub.status.idle":"2022-01-04T08:25:00.430376Z","shell.execute_reply.started":"2022-01-04T08:25:00.030876Z","shell.execute_reply":"2022-01-04T08:25:00.429661Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Define model weight, validation images, labels","metadata":{}},{"cell_type":"code","source":"os.listdir('/kaggle/input/great-barrier-reef-yolov5-train/')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:25:00.432109Z","iopub.execute_input":"2022-01-04T08:25:00.43236Z","iopub.status.idle":"2022-01-04T08:25:00.446003Z","shell.execute_reply.started":"2022-01-04T08:25:00.432326Z","shell.execute_reply":"2022-01-04T08:25:00.445307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"VAL_TXT = '/kaggle/input/great-barrier-reef-yolov5-train/val.txt'\nTRAIN_TXT = '/kaggle/input/great-barrier-reef-yolov5-train/train.txt'\nBEST_PT = '/kaggle/input/great-barrier-reef-yolov5-train/yolov5/runs/train/exp/weights/best.pt' # best wegith of yolov5 model trained in great-barrier-reef\n","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:25:00.447184Z","iopub.execute_input":"2022-01-04T08:25:00.447576Z","iopub.status.idle":"2022-01-04T08:25:00.451419Z","shell.execute_reply.started":"2022-01-04T08:25:00.447541Z","shell.execute_reply":"2022-01-04T08:25:00.450721Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Make images, labels directory on /kaggle\nrefer to https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-train","metadata":{}},{"cell_type":"code","source":"ROOT_DIR  = '/kaggle/input/tensorflow-great-barrier-reef/'\nIMAGE_DIR = '/kaggle/images/' # directory to save images\nLABEL_DIR = '/kaggle/labels/' # directory to save labels\n!mkdir -p {IMAGE_DIR}\n!mkdir -p {LABEL_DIR}","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:00.453522Z","iopub.execute_input":"2022-01-04T08:25:00.453943Z","iopub.status.idle":"2022-01-04T08:25:01.811647Z","shell.execute_reply.started":"2022-01-04T08:25:00.453907Z","shell.execute_reply":"2022-01-04T08:25:01.810728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_path(row):\n    row['old_image_path'] = f'{ROOT_DIR}/train_images/video_{row.video_id}/{row.video_frame}.jpg'\n    row['image_path'] = f'{IMAGE_DIR}/video_{row.video_id}_{row.video_frame}.jpg'\n    row['label_path'] = f'{LABEL_DIR}/video_{row.video_id}_{row.video_frame}.txt'\n    return row","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:01.813496Z","iopub.execute_input":"2022-01-04T08:25:01.813763Z","iopub.status.idle":"2022-01-04T08:25:01.820714Z","shell.execute_reply.started":"2022-01-04T08:25:01.813719Z","shell.execute_reply":"2022-01-04T08:25:01.819509Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train Data\ndf = pd.read_csv(f'{ROOT_DIR}/train.csv')\ndf = df.progress_apply(get_path, axis=1)\ndf['annotations'] = df['annotations'].progress_apply(lambda x: ast.literal_eval(x))\ndisplay(df.head(2))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:01.822233Z","iopub.execute_input":"2022-01-04T08:25:01.822855Z","iopub.status.idle":"2022-01-04T08:25:41.595933Z","shell.execute_reply.started":"2022-01-04T08:25:01.822674Z","shell.execute_reply":"2022-01-04T08:25:41.595144Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['num_bbox'] = df['annotations'].progress_apply(lambda x: len(x))\ndata = (df.num_bbox>0).value_counts(normalize=True)*100\nprint(f\"No BBox: {data[0]:0.2f}% | With BBox: {data[1]:0.2f}%\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:41.59733Z","iopub.execute_input":"2022-01-04T08:25:41.597596Z","iopub.status.idle":"2022-01-04T08:25:41.693821Z","shell.execute_reply.started":"2022-01-04T08:25:41.597561Z","shell.execute_reply":"2022-01-04T08:25:41.693123Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"REMOVE_NOBBOX=True\nif REMOVE_NOBBOX:\n    df = df.query(\"num_bbox>0\")","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:41.694923Z","iopub.execute_input":"2022-01-04T08:25:41.695672Z","iopub.status.idle":"2022-01-04T08:25:41.720467Z","shell.execute_reply.started":"2022-01-04T08:25:41.695634Z","shell.execute_reply":"2022-01-04T08:25:41.719777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def make_copy(path):\n    data = path.split('/')\n    filename = data[-1]\n    video_id = data[-2]\n    new_path = os.path.join(IMAGE_DIR,f'{video_id}_{filename}')\n    shutil.copy(path, new_path)\n    return","metadata":{"_kg_hide-input":false,"execution":{"iopub.status.busy":"2022-01-04T08:25:41.721576Z","iopub.execute_input":"2022-01-04T08:25:41.721895Z","iopub.status.idle":"2022-01-04T08:25:41.72706Z","shell.execute_reply.started":"2022-01-04T08:25:41.721858Z","shell.execute_reply":"2022-01-04T08:25:41.726407Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_paths = df.old_image_path.tolist()\n_ = Parallel(n_jobs=-1, backend='threading')(delayed(make_copy)(path) for path in tqdm(image_paths))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:25:41.730902Z","iopub.execute_input":"2022-01-04T08:25:41.731572Z","iopub.status.idle":"2022-01-04T08:26:11.149868Z","shell.execute_reply.started":"2022-01-04T08:25:41.731536Z","shell.execute_reply":"2022-01-04T08:26:11.149067Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def voc2yolo(image_height, image_width, bboxes):\n    \"\"\"\n    voc  => [x1, y1, x2, y1]\n    yolo => [xmid, ymid, w, h] (normalized)\n    \"\"\"\n    \n    bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n    \n    bboxes[..., [0, 2]] = bboxes[..., [0, 2]]/ image_width\n    bboxes[..., [1, 3]] = bboxes[..., [1, 3]]/ image_height\n    \n    w = bboxes[..., 2] - bboxes[..., 0]\n    h = bboxes[..., 3] - bboxes[..., 1]\n    \n    print(img_name)\n    bboxes[..., 0] = bboxes[..., 0] + w/2\n    bboxes[..., 1] = bboxes[..., 1] + h/2\n    bboxes[..., 2] = w\n    bboxes[..., 3] = h\n    \n    return bboxes\n\ndef yolo2voc(image_height, image_width, bboxes):\n    \"\"\"\n    yolo => [xmid, ymid, w, h] (normalized)\n    voc  => [x1, y1, x2, y1]\n    \n    \"\"\" \n    bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n    \n    bboxes[..., [0, 2]] = bboxes[..., [0, 2]]* image_width\n    bboxes[..., [1, 3]] = bboxes[..., [1, 3]]* image_height\n    \n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] - bboxes[..., [2, 3]]/2\n    bboxes[..., [2, 3]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]\n    \n    return bboxes\n\ndef coco2yolo(image_height, image_width, bboxes):\n    \"\"\"\n    coco => [xmin, ymin, w, h]\n    yolo => [xmid, ymid, w, h] (normalized)\n    \"\"\"\n    \n    bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n    \n    # normolizinig\n    bboxes[..., [0, 2]]= bboxes[..., [0, 2]]/ image_width\n    bboxes[..., [1, 3]]= bboxes[..., [1, 3]]/ image_height\n    \n    # converstion (xmin, ymin) => (xmid, ymid)\n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]/2\n    \n    return bboxes\n\ndef yolo2coco(image_height, image_width, bboxes):\n    \"\"\"\n    yolo => [xmid, ymid, w, h] (normalized)\n    coco => [xmin, ymin, w, h]\n    \n    \"\"\" \n    bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n    \n    # denormalizing\n    bboxes[..., [0, 2]]= bboxes[..., [0, 2]]* image_width\n    bboxes[..., [1, 3]]= bboxes[..., [1, 3]]* image_height\n    \n    # converstion (xmid, ymid) => (xmin, ymin) \n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] - bboxes[..., [2, 3]]/2\n    \n    return bboxes\n\n\ndef load_image(image_path):\n    return cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)\n\n\ndef plot_one_box(x, img, color=None, label=None, line_thickness=None):\n    # Plots one bounding box on image img\n    tl = line_thickness or round(0.002 * (img.shape[0] + img.shape[1]) / 2) + 1  # line/font thickness\n    color = color or [random.randint(0, 255) for _ in range(3)]\n    c1, c2 = (int(x[0]), int(x[1])), (int(x[2]), int(x[3]))\n    cv2.rectangle(img, c1, c2, color, thickness=tl, lineType=cv2.LINE_AA)\n    if label:\n        tf = max(tl - 1, 1)  # font thickness\n        t_size = cv2.getTextSize(label, 0, fontScale=tl / 3, thickness=tf)[0]\n        c2 = c1[0] + t_size[0], c1[1] - t_size[1] - 3\n        cv2.rectangle(img, c1, c2, color, -1, cv2.LINE_AA)  # filled\n        cv2.putText(img, label, (c1[0], c1[1] - 2), 0, tl / 3, [225, 255, 255], thickness=tf, lineType=cv2.LINE_AA)\n\ndef draw_bboxes(img, bboxes, classes, class_ids, colors = None, show_classes = None, bbox_format = 'yolo', class_name = False, line_thickness = 2):  \n     \n    image = img.copy()\n    show_classes = classes if show_classes is None else show_classes\n    colors = (0, 255 ,0) if colors is None else colors\n    \n    if bbox_format == 'yolo':\n        \n        for idx in range(len(bboxes)):  \n            \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors\n            \n            if cls in show_classes:\n            \n                x1 = round(float(bbox[0])*image.shape[1])\n                y1 = round(float(bbox[1])*image.shape[0])\n                w  = round(float(bbox[2])*image.shape[1]/2) #w/2 \n                h  = round(float(bbox[3])*image.shape[0]/2)\n\n                voc_bbox = (x1-w, y1-h, x1+w, y1+h)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(get_label(cls)),\n                             line_thickness = line_thickness)\n            \n    elif bbox_format == 'coco':\n        \n        for idx in range(len(bboxes)):  \n            \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors\n            \n            if cls in show_classes:            \n                x1 = int(round(bbox[0]))\n                y1 = int(round(bbox[1]))\n                w  = int(round(bbox[2]))\n                h  = int(round(bbox[3]))\n\n                voc_bbox = (x1, y1, x1+w, y1+h)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(cls_id),\n                             line_thickness = line_thickness)\n\n    elif bbox_format == 'voc_pascal':\n        \n        for idx in range(len(bboxes)):  \n            \n            bbox  = bboxes[idx]\n            cls   = classes[idx]\n            cls_id = class_ids[idx]\n            color = colors[cls_id] if type(colors) is list else colors\n            \n            if cls in show_classes: \n                x1 = int(round(bbox[0]))\n                y1 = int(round(bbox[1]))\n                x2 = int(round(bbox[2]))\n                y2 = int(round(bbox[3]))\n                voc_bbox = (x1, y1, x2, y2)\n                plot_one_box(voc_bbox, \n                             image,\n                             color = color,\n                             label = cls if class_name else str(cls_id),\n                             line_thickness = line_thickness)\n    else:\n        raise ValueError('wrong bbox format')\n\n    return image\n\ndef get_bbox(annots):\n    bboxes = [list(annot.values()) for annot in annots]\n    return bboxes\n\ndef get_imgsize(row):\n    row['width'], row['height'] = imagesize.get(row['image_path'])\n    return row\n\n\n# https://www.kaggle.com/diegoalejogm/great-barrier-reefs-eda-with-animations\ndef create_animation(ims):\n    fig = plt.figure(figsize=(16, 12))\n    plt.axis('off')\n    im = plt.imshow(ims[0])\n\n    def animate_func(i):\n        im.set_array(ims[i])\n        return [im]\n\n    return animation.FuncAnimation(fig, animate_func, frames = len(ims), interval = 1000//12)\n\nnp.random.seed(32)\ncolors = [(np.random.randint(255), np.random.randint(255), np.random.randint(255))\\\n          for idx in range(1)]","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:26:11.152116Z","iopub.execute_input":"2022-01-04T08:26:11.156376Z","iopub.status.idle":"2022-01-04T08:26:11.223034Z","shell.execute_reply.started":"2022-01-04T08:26:11.15634Z","shell.execute_reply":"2022-01-04T08:26:11.222435Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['bboxes'] = df.annotations.progress_apply(get_bbox)\ndf.head(2)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:26:11.226954Z","iopub.execute_input":"2022-01-04T08:26:11.228969Z","iopub.status.idle":"2022-01-04T08:26:13.045557Z","shell.execute_reply.started":"2022-01-04T08:26:11.228927Z","shell.execute_reply":"2022-01-04T08:26:13.044889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['width']  = 1280\ndf['height'] = 720\ndisplay(df.head(2))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:26:13.046983Z","iopub.execute_input":"2022-01-04T08:26:13.047689Z","iopub.status.idle":"2022-01-04T08:26:13.066132Z","shell.execute_reply.started":"2022-01-04T08:26:13.047653Z","shell.execute_reply":"2022-01-04T08:26:13.065498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"cnt = 0\nall_bboxes = []\nfor row_idx in tqdm(range(df.shape[0])):\n    row = df.iloc[row_idx]\n    image_height = row.height\n    image_width  = row.width\n    bboxes_coco  = np.array(row.bboxes).astype(np.float32).copy()\n    num_bbox     = len(bboxes_coco)\n    names        = ['cots']*num_bbox\n    labels       = [0]*num_bbox\n    ## Create Annotation(YOLO)\n    with open(row.label_path, 'w') as f:\n        if num_bbox<1:\n            annot = ''\n            f.write(annot)\n            cnt+=1\n            continue\n        bboxes_yolo  = coco2yolo(image_height, image_width, bboxes_coco)\n        bboxes_yolo  = np.clip(bboxes_yolo, 0, 1)\n        all_bboxes.extend(bboxes_yolo)\n        for bbox_idx in range(len(bboxes_yolo)):\n            annot = [str(labels[bbox_idx])]+ list(bboxes_yolo[bbox_idx].astype(str))+(['\\n'] if num_bbox!=(bbox_idx+1) else [''])\n            annot = ' '.join(annot)\n            annot = annot.strip(' ')\n            f.write(annot)\nprint('Missing:',cnt)","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-01-04T08:26:13.067275Z","iopub.execute_input":"2022-01-04T08:26:13.06798Z","iopub.status.idle":"2022-01-04T08:26:15.434512Z","shell.execute_reply.started":"2022-01-04T08:26:13.067944Z","shell.execute_reply":"2022-01-04T08:26:15.433726Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# images, labels folder check\nassert os.path.exists(IMAGE_DIR)\nassert os.path.exists(LABEL_DIR)","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:15.43602Z","iopub.execute_input":"2022-01-04T08:26:15.436291Z","iopub.status.idle":"2022-01-04T08:26:15.443532Z","shell.execute_reply.started":"2022-01-04T08:26:15.436255Z","shell.execute_reply":"2022-01-04T08:26:15.441809Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## YOLOV5 install","metadata":{}},{"cell_type":"code","source":"%cd /kaggle/working\n!rm -r /kaggle/working/yolov5\n!git clone https://github.com/ultralytics/yolov5 # clone\n%cd yolov5\n%pip install -qr requirements.txt  # install\n\nfrom yolov5 import utils\ndisplay = utils.notebook_init()  # check","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:15.446167Z","iopub.execute_input":"2022-01-04T08:26:15.446639Z","iopub.status.idle":"2022-01-04T08:26:32.662301Z","shell.execute_reply.started":"2022-01-04T08:26:15.446604Z","shell.execute_reply":"2022-01-04T08:26:32.661396Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Run YOLOV5 model in validation images ","metadata":{}},{"cell_type":"code","source":"!cd yolov5","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:32.664367Z","iopub.execute_input":"2022-01-04T08:26:32.664849Z","iopub.status.idle":"2022-01-04T08:26:33.456691Z","shell.execute_reply.started":"2022-01-04T08:26:32.664796Z","shell.execute_reply":"2022-01-04T08:26:33.45581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir('/kaggle/input/great-barrier-reef-yolov5-train/yolov5/runs/train/exp/weights/')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:33.461255Z","iopub.execute_input":"2022-01-04T08:26:33.461526Z","iopub.status.idle":"2022-01-04T08:26:33.487358Z","shell.execute_reply.started":"2022-01-04T08:26:33.461492Z","shell.execute_reply":"2022-01-04T08:26:33.486652Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# move files to /kaggle/working\n!cp /kaggle/input/great-barrier-reef-yolov5-train/yolov5/runs/train/exp/weights/best.pt /kaggle/working/\n!cp /kaggle/input/great-barrier-reef-yolov5-train/train.txt /kaggle/working/\n!cp /kaggle/input/great-barrier-reef-yolov5-train/val.txt /kaggle/working/\n!cp /kaggle/input/great-barrier-reef-yolov5-train/bgr.yaml /kaggle/working/","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:33.488735Z","iopub.execute_input":"2022-01-04T08:26:33.488997Z","iopub.status.idle":"2022-01-04T08:26:36.703483Z","shell.execute_reply.started":"2022-01-04T08:26:33.488964Z","shell.execute_reply":"2022-01-04T08:26:36.70254Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir('/kaggle/working')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:36.705212Z","iopub.execute_input":"2022-01-04T08:26:36.705487Z","iopub.status.idle":"2022-01-04T08:26:36.714419Z","shell.execute_reply.started":"2022-01-04T08:26:36.705436Z","shell.execute_reply":"2022-01-04T08:26:36.713696Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import val\n!python val.py --data ../bgr.yaml\\\n    --weights ../best.pt\\\n    --imgsz 1280\\\n    --conf-thres 0.01\\\n    --iou-thres 0.3\\\n    --save-txt\\\n    --save-conf\\\n    --exist-ok","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:26:36.717559Z","iopub.execute_input":"2022-01-04T08:26:36.718142Z","iopub.status.idle":"2022-01-04T08:27:28.496801Z","shell.execute_reply.started":"2022-01-04T08:26:36.718116Z","shell.execute_reply":"2022-01-04T08:27:28.495929Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Check how predicted bounding box is created","metadata":{}},{"cell_type":"code","source":"# val bbox result directory\nPRD_BBOX_DIR = '/kaggle/working/yolov5/runs/val/exp/labels/'\nprint(f'made bounding box of {len(os.listdir(PRD_BBOX_DIR))} images in validation set ')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:27:28.498408Z","iopub.execute_input":"2022-01-04T08:27:28.498696Z","iopub.status.idle":"2022-01-04T08:27:28.505223Z","shell.execute_reply.started":"2022-01-04T08:27:28.498658Z","shell.execute_reply":"2022-01-04T08:27:28.504495Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### why predicted bounding box txt file for some images doesn't exist?","metadata":{}},{"cell_type":"code","source":"val_images = []\nwith open('/kaggle/working/val.txt', 'r') as f:\n    while True:\n        r = f.readline().rstrip()\n        if not r:\n            break\n        val_images.append(os.path.basename(r))\nprint(f'{len(val_images)} image in validation set')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:27:28.506335Z","iopub.execute_input":"2022-01-04T08:27:28.506941Z","iopub.status.idle":"2022-01-04T08:27:28.520632Z","shell.execute_reply.started":"2022-01-04T08:27:28.5069Z","shell.execute_reply":"2022-01-04T08:27:28.519826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"not_processed_images = val_images.copy()\nfor file in os.listdir(PRD_BBOX_DIR):\n    img_name = file[:-4]+'.jpg'\n    if img_name in val_images:\n        not_processed_images.remove(img_name)\nprint(f\"yolov5 model doesn't create bounding box for {len(not_processed_images)} images\")","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:27:28.522106Z","iopub.execute_input":"2022-01-04T08:27:28.522587Z","iopub.status.idle":"2022-01-04T08:27:28.541345Z","shell.execute_reply.started":"2022-01-04T08:27:28.52255Z","shell.execute_reply":"2022-01-04T08:27:28.540599Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"model didn't detect starfish in \"not_processed_images\" - it will be calculated as False Negative(FN)\n\nrun code to know that there exist ground truth bounding boxs in \"not_processed_images\"","metadata":{}},{"cell_type":"code","source":"# model didn't detect starfish in \"not_processed_images\" - it will be calculated as False Negative(FN)\n# run code to know that there exist ground truth bounding boxs in \"not_processed_images\"\n# in fact, /kaggle/images/ only include images which have bounding boxs\nfor image_name in not_processed_images[:20]:\n    img = cv2.imread('/kaggle/images/'+image_name)\n    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    plt.imshow(img)\n    plt.title(image_name)\n    plt.show()\n    txt_name = image_name[:-4]+'.txt'\n    with open('/kaggle/labels/'+txt_name, 'r') as f:\n        r = f.read()\n        count = r.count('\\n')+1\n        print(f\"{count} ground truth bounding box exits\")","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-01-04T08:27:28.542587Z","iopub.execute_input":"2022-01-04T08:27:28.543056Z","iopub.status.idle":"2022-01-04T08:27:30.122256Z","shell.execute_reply.started":"2022-01-04T08:27:28.543021Z","shell.execute_reply":"2022-01-04T08:27:30.121492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Calculate F2 score on validation set\nreference : [competition metric implementation](https://www.kaggle.com/bamps53/competition-metric-implementation)","metadata":{}},{"cell_type":"code","source":"def calc_iou(bboxes1, bboxes2, bbox_mode='xywh'):\n    assert len(bboxes1.shape) == 2 and bboxes1.shape[1] == 4\n    assert len(bboxes2.shape) == 2 and bboxes2.shape[1] == 4\n    \n    bboxes1 = bboxes1.copy()\n    bboxes2 = bboxes2.copy()\n    \n    if bbox_mode == 'xywh':\n        bboxes1[:, 2:] += bboxes1[:, :2]\n        bboxes2[:, 2:] += bboxes2[:, :2]\n\n    x11, y11, x12, y12 = np.split(bboxes1, 4, axis=1)\n    x21, y21, x22, y22 = np.split(bboxes2, 4, axis=1)\n    xA = np.maximum(x11, np.transpose(x21))\n    yA = np.maximum(y11, np.transpose(y21))\n    xB = np.minimum(x12, np.transpose(x22))\n    yB = np.minimum(y12, np.transpose(y22))\n    interArea = np.maximum((xB - xA + 1), 0) * np.maximum((yB - yA + 1), 0)\n    boxAArea = (x12 - x11 + 1) * (y12 - y11 + 1)\n    boxBArea = (x22 - x21 + 1) * (y22 - y21 + 1)\n    iou = interArea / (boxAArea + np.transpose(boxBArea) - interArea)\n    return iou\n\ndef f_beta(tp, fp, fn, beta=2):\n    return (1+beta**2)*tp / ((1+beta**2)*tp + beta**2*fn+fp)\n\ndef calc_is_correct_at_iou_th(gt_bboxes, pred_bboxes, iou_th, verbose=False):\n    gt_bboxes = gt_bboxes.copy()\n    pred_bboxes = pred_bboxes.copy()\n    \n    tp = 0\n    fp = 0\n    for k, pred_bbox in enumerate(pred_bboxes): # fixed in ver.7\n        ious = calc_iou(gt_bboxes, pred_bbox[None, 1:])\n        max_iou = ious.max()\n        if max_iou > iou_th:\n            tp += 1\n            gt_bboxes = np.delete(gt_bboxes, ious.argmax(), axis=0)\n        else:\n            fp += 1\n        if len(gt_bboxes) == 0:\n            fp += len(pred_bboxes) - (k + 1) # fix in ver.7\n            break\n\n    fn = len(gt_bboxes)\n    return tp, fp, fn\n\ndef calc_is_correct(gt_bboxes, pred_bboxes, iou_th=0.5):\n    \"\"\"\n    gt_bboxes: (N, 4) np.array in xywh format\n    pred_bboxes: (N, 5) np.array in conf+xywh format\n    \"\"\"\n    if len(gt_bboxes) == 0 and len(pred_bboxes) == 0:\n        tps, fps, fns = 0, 0, 0\n        return tps, fps, fns\n\n    elif len(gt_bboxes) == 0:\n        tps, fps, fns = 0, len(pred_bboxes), 0\n        return tps, fps, fns\n\n    elif len(pred_bboxes) == 0:\n        tps, fps, fns = 0, 0, len(gt_bboxes)\n        return tps, fps, fns\n\n    pred_bboxes = pred_bboxes[pred_bboxes[:,0].argsort()[::-1]] # sort by conf\n\n    tps, fps, fns = 0, 0, 0\n    tp, fp, fn = calc_is_correct_at_iou_th(gt_bboxes, pred_bboxes, iou_th)\n    tps += tp\n    fps += fp\n    fns += fn\n    return tps, fps, fns\n\ndef calc_f2_score(gt_bboxes_list, pred_bboxes_list, verbose=False):\n    \"\"\"\n    gt_bboxes_list: list of (N, 4) np.array in xywh format\n    pred_bboxes_list: list of (N, 5) np.array in conf+xywh format\n    \"\"\"\n    f2s = []\n    for iou_th in np.arange(0.3, 0.85, 0.05):\n        tps, fps, fns = 0, 0, 0\n        for gt_bboxes, pred_bboxes in zip(gt_bboxes_list, pred_bboxes_list):\n            tp, fp, fn = calc_is_correct(gt_bboxes, pred_bboxes, iou_th)\n            tps += tp\n            fps += fp\n            fns += fn\n            if verbose:\n                num_gt = len(gt_bboxes)\n                num_pred = len(pred_bboxes)\n                print(f'num_gt:{num_gt:<3} num_pred:{num_pred:<3} tp:{tp:<3} fp:{fp:<3} fn:{fn:<3}')\n        f2 = f_beta(tps, fps, fns, beta=2)    \n        print(f'f2@{iou_th}:{f2}')\n        f2s.append(f2)\n    return np.mean(f2s)","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:29:25.867328Z","iopub.execute_input":"2022-01-04T08:29:25.867692Z","iopub.status.idle":"2022-01-04T08:29:25.891086Z","shell.execute_reply.started":"2022-01-04T08:29:25.867661Z","shell.execute_reply":"2022-01-04T08:29:25.88993Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"gt_bboxs_list, prd_bboxs_list = [], []\ncount = 0\nfor image_file in val_images:\n    txt_name = image_file[:-4]+'.txt'\n    gt_bboxs = []\n    prd_bboxs = []\n    with open(LABEL_DIR+txt_name, 'r') as f:\n        while True:\n            r = f.readline().rstrip()\n            if not r:\n                break\n            r = r.split()[1:]\n            bbox = np.array(list(map(float, r)))\n            gt_bboxs.append(bbox)\n    if os.path.exists(PRD_BBOX_DIR+txt_name):\n        with open(PRD_BBOX_DIR+txt_name, 'r') as f:\n            while True:\n                r = f.readline().rstrip()\n                if not r:\n                    break\n                r = r.split()[1:]\n                r = [r[4], *r[:4]]\n                bbox = np.array(list(map(float, r)))\n                prd_bboxs.append(bbox)\n    gt_bboxs, prd_bboxs = np.array(gt_bboxs), np.array(prd_bboxs)\n    gt_bboxs_list.append(gt_bboxs)\n    prd_bboxs_list.append(prd_bboxs)\n    count += 1\nprint(f'{count} bound boxs appended to list')","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-01-04T08:29:28.586406Z","iopub.execute_input":"2022-01-04T08:29:28.587134Z","iopub.status.idle":"2022-01-04T08:29:28.680344Z","shell.execute_reply.started":"2022-01-04T08:29:28.587095Z","shell.execute_reply":"2022-01-04T08:29:28.679601Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"score = calc_f2_score(gt_bboxs_list, prd_bboxs_list, verbose=False)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-01-04T08:29:29.787946Z","iopub.execute_input":"2022-01-04T08:29:29.788294Z","iopub.status.idle":"2022-01-04T08:29:31.68189Z","shell.execute_reply.started":"2022-01-04T08:29:29.788257Z","shell.execute_reply":"2022-01-04T08:29:31.681116Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'f2 score for validation set is {score}')","metadata":{"execution":{"iopub.status.busy":"2022-01-04T08:29:32.099942Z","iopub.execute_input":"2022-01-04T08:29:32.100199Z","iopub.status.idle":"2022-01-04T08:29:32.105895Z","shell.execute_reply.started":"2022-01-04T08:29:32.100172Z","shell.execute_reply":"2022-01-04T08:29:32.105141Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}