{"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":"# [Tensorflow - Help Protect the Great Barrier Reef](https://www.kaggle.com/c/tensorflow-great-barrier-reef)\n> Detect crown-of-thorns starfish in underwater image data","metadata":{}},{"cell_type":"markdown","source":"# Install Libraries","metadata":{}},{"cell_type":"code","source":"!pip install -q imagesize\n!pip install -qU wandb\n!add-apt-repository ppa:ubuntu-toolchain-r/test -y\n!apt-get update\n!apt-get upgrade libstdc++6 -y","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T10:40:24.651659Z","iopub.execute_input":"2021-12-15T10:40:24.652004Z","iopub.status.idle":"2021-12-15T10:44:53.877215Z","shell.execute_reply.started":"2021-12-15T10:40:24.65192Z","shell.execute_reply":"2021-12-15T10:44:53.876329Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Import Libraries","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\nimport matplotlib.image as mpimg\nimport plotly.express as px\nimport plotly.graph_objects as go\nimport seaborn as sns\nfrom PIL import Image, ImageDraw\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\nimport imagesize","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-15T10:44:53.87911Z","iopub.execute_input":"2021-12-15T10:44:53.879389Z","iopub.status.idle":"2021-12-15T10:44:57.683368Z","shell.execute_reply.started":"2021-12-15T10:44:53.879343Z","shell.execute_reply":"2021-12-15T10:44:57.682647Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Key-Points\n* One have to submit prediction using the provided **python time-series API**, which makes this competition different from previous Object Detection Competitions.\n* Each prediction row needs to include all bounding boxes for the image. Submission is format seems also **COCO** which means `[x_min, y_min, width, height]`\n* Copmetition metric `F2` tolerates some false positives(FP) in order to ensure very few starfish are missed. Which means tackling **false negatives(FN)** is more important than false positives(FP). \n$$F2 = 5 \\cdot \\frac{precision \\cdot recall}{4\\cdot precision + recall}$$","metadata":{}},{"cell_type":"markdown","source":"#  Meta Data\n* `train_images/` - Folder containing training set photos of the form `video_{video_id}/{video_frame}.jpg`.\n\n* `[train/test].csv` - Metadata for the images. As with other test files, most of the test metadata data is only available to your notebook upon submission. Just the first few rows available for download.\n\n* `video_id` - ID number of the video the image was part of. The video ids are not meaningfully ordered.\n* `video_frame` - The frame number of the image within the video. Expect to see occasional gaps in the frame number from when the diver surfaced.\n* `sequence` - ID of a gap-free subset of a given video. The sequence ids are not meaningfully ordered.\n* `sequence_frame` - The frame number within a given sequence.\n* `image_id` - ID code for the image, in the format `{video_id}-{video_frame}`\n* `annotations` - The bounding boxes of any starfish detections in a string format that can be evaluated directly with Python. Does not use the same format as the predictions you will submit. Not available in test.csv. A bounding box is described by the pixel coordinate `(x_min, y_min)` of its lower left corner within the image together with its `width` and `height` in pixels --> (COCO format).","metadata":{}},{"cell_type":"code","source":"FOLD      = 6 # which fold to train\nREMOVE_NOBBOX = True # remove images with no bbox\nROOT_DIR  = '/kaggle/input/tensorflow-great-barrier-reef/'\nIMAGE_DIR = '/kaggle/images' # directory to save images\nLABEL_DIR = '/kaggle/labels' # directory to save labels","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:44:57.684645Z","iopub.execute_input":"2021-12-15T10:44:57.684936Z","iopub.status.idle":"2021-12-15T10:44:57.689542Z","shell.execute_reply.started":"2021-12-15T10:44:57.6849Z","shell.execute_reply":"2021-12-15T10:44:57.68874Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Get Paths","metadata":{}},{"cell_type":"code","source":"#create directories \n!mkdir -p {IMAGE_DIR}\n!mkdir -p {LABEL_DIR}\n\ndef 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":{"execution":{"iopub.status.busy":"2021-12-15T10:44:57.691983Z","iopub.execute_input":"2021-12-15T10:44:57.692486Z","iopub.status.idle":"2021-12-15T10:44:59.195624Z","shell.execute_reply.started":"2021-12-15T10:44:57.692451Z","shell.execute_reply":"2021-12-15T10:44:59.194708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Train Dataset\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":{"execution":{"iopub.status.busy":"2021-12-15T10:44:59.198912Z","iopub.execute_input":"2021-12-15T10:44:59.199118Z","iopub.status.idle":"2021-12-15T10:45:39.691658Z","shell.execute_reply.started":"2021-12-15T10:44:59.199093Z","shell.execute_reply":"2021-12-15T10:45:39.690889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data Exploration","metadata":{}},{"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","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:45:39.69295Z","iopub.execute_input":"2021-12-15T10:45:39.693266Z","iopub.status.idle":"2021-12-15T10:45:39.793429Z","shell.execute_reply.started":"2021-12-15T10:45:39.693229Z","shell.execute_reply":"2021-12-15T10:45:39.792749Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# How many image with starfish ?\nlabels = ['Without Bounding Box', 'With Bounding Box']\n\nfig = go.Figure([go.Bar(x=labels, \n                        y=[data[0], data[1]], width=0.6)])\nfig.update_layout(title=\"Image with Starfish\", autosize=False, width=500, height=350, margin=dict(l=60, r=60, b=50, t=50, pad=4))\nfig.show()\nprint(f\"Without Bounding Box: {data[0]:0.2f}% | With Bounding Box: {data[1]:0.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:45:39.794686Z","iopub.execute_input":"2021-12-15T10:45:39.79508Z","iopub.status.idle":"2021-12-15T10:45:39.916674Z","shell.execute_reply.started":"2021-12-15T10:45:39.795043Z","shell.execute_reply":"2021-12-15T10:45:39.915965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# How many image per video?\nplt.figure(figsize=(8,5))\nsns.countplot(df['video_id'], color='#49A9DB').set_title('Nb of image per video')","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:45:39.918036Z","iopub.execute_input":"2021-12-15T10:45:39.918289Z","iopub.status.idle":"2021-12-15T10:45:40.157718Z","shell.execute_reply.started":"2021-12-15T10:45:39.918254Z","shell.execute_reply":"2021-12-15T10:45:40.157031Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# How many starfish detected per image ? \nfig = px.bar(df['num_bbox'].value_counts().drop(0), title='Count of Bounding Boxes per image')\nfig.update_layout(autosize=False, width=700, height=400, margin=dict(l=60, r=60, b=50, t=50, pad=4))\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:45:40.159244Z","iopub.execute_input":"2021-12-15T10:45:40.159707Z","iopub.status.idle":"2021-12-15T10:45:41.026378Z","shell.execute_reply.started":"2021-12-15T10:45:40.159668Z","shell.execute_reply":"2021-12-15T10:45:41.02569Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Filter\n* In this notebook, we use only **bboxed-images** (`~5k`). We can use all `~23K` images for train but most of them don't have any labels. So it would be easier to carry out experiments using only **bboxed images**.","metadata":{}},{"cell_type":"code","source":"if REMOVE_NOBBOX:\n    df = df.query(\"num_bbox>0\")","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:45:41.029532Z","iopub.execute_input":"2021-12-15T10:45:41.029738Z","iopub.status.idle":"2021-12-15T10:45:41.05248Z","shell.execute_reply.started":"2021-12-15T10:45:41.029713Z","shell.execute_reply":"2021-12-15T10:45:41.051778Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Write Images\n* We need to copy the Images to Current Directory(`/kaggle/working`) as `/kaggle/input` doesn't have **write access** which is needed for **YOLOv5**.\n* We can make this process faster using **Joblib** which uses **Parallel** computing.","metadata":{}},{"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":{"execution":{"iopub.status.busy":"2021-12-15T10:45:41.053854Z","iopub.execute_input":"2021-12-15T10:45:41.054116Z","iopub.status.idle":"2021-12-15T10:45:41.059096Z","shell.execute_reply.started":"2021-12-15T10:45:41.05408Z","shell.execute_reply":"2021-12-15T10:45:41.058273Z"},"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":{"execution":{"iopub.status.busy":"2021-12-15T10:45:41.060541Z","iopub.execute_input":"2021-12-15T10:45:41.060993Z","iopub.status.idle":"2021-12-15T10:46:11.869126Z","shell.execute_reply.started":"2021-12-15T10:45:41.060952Z","shell.execute_reply":"2021-12-15T10:46:11.868379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Functions","metadata":{}},{"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    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\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":"2021-12-15T10:46:11.870601Z","iopub.execute_input":"2021-12-15T10:46:11.87095Z","iopub.status.idle":"2021-12-15T10:46:11.913295Z","shell.execute_reply.started":"2021-12-15T10:46:11.870912Z","shell.execute_reply":"2021-12-15T10:46:11.912524Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Create BBox","metadata":{}},{"cell_type":"code","source":"df.annotations[20]","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:11.916563Z","iopub.execute_input":"2021-12-15T10:46:11.916825Z","iopub.status.idle":"2021-12-15T10:46:11.928441Z","shell.execute_reply.started":"2021-12-15T10:46:11.91679Z","shell.execute_reply":"2021-12-15T10:46:11.927025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['bboxes'] = df.annotations.progress_apply(get_bbox)\ndf.head()","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:11.930454Z","iopub.execute_input":"2021-12-15T10:46:11.931156Z","iopub.status.idle":"2021-12-15T10:46:12.006495Z","shell.execute_reply.started":"2021-12-15T10:46:11.931119Z","shell.execute_reply":"2021-12-15T10:46:12.005693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Check the Image-Size\n> All Images have same dimension, [Width, Height] =  `[1280, 720]`","metadata":{}},{"cell_type":"code","source":"df = df.progress_apply(get_imgsize,axis=1)\ndisplay(df.width.unique(), df.height.unique())\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:12.007878Z","iopub.execute_input":"2021-12-15T10:46:12.008194Z","iopub.status.idle":"2021-12-15T10:46:18.243597Z","shell.execute_reply.started":"2021-12-15T10:46:12.008156Z","shell.execute_reply":"2021-12-15T10:46:18.242808Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🏷️ Create Labels\nWe need to export our labels to **YOLO** format, with one `*.txt` file per image (if no objects in image, no `*.txt` file is required). The *.txt file specifications are:\n\n* One row per object\n* Each row is class `[x_center, y_center, width, height]` format.\n* Box coordinates must be in **normalized** `xywh` format (from `0 - 1`). If your boxes are in pixels, divide `x_center` and `width` by `image width`, and `y_center` and `height` by `image height`.\n* Class numbers are **zero-indexed** (start from `0`).\n\n> Competition bbox format is **COCO** hence `[x_min, y_min, width, height]`. So, we need to convert form **COCO** to **YOLO** format.\n","metadata":{}},{"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":"2021-12-15T10:46:18.244758Z","iopub.execute_input":"2021-12-15T10:46:18.24642Z","iopub.status.idle":"2021-12-15T10:46:21.510994Z","shell.execute_reply.started":"2021-12-15T10:46:18.246383Z","shell.execute_reply":"2021-12-15T10:46:21.510278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🌈 Visualization","metadata":{}},{"cell_type":"code","source":"df2 = df[(df.num_bbox>0)].sample(100) # takes samples with bbox\nfor idx in range(10):\n    row = df2.iloc[idx]\n    img           = load_image(row.image_path)\n    image_height  = row.height\n    image_width   = row.width\n    bboxes_coco   = np.array(row.bboxes)\n    bboxes_yolo   = coco2yolo(image_height, image_width, bboxes_coco)\n    names         = ['cots']*len(bboxes_coco)\n    labels        = [0]*len(bboxes_coco)\n\n    plt.figure(figsize = (12, 8))\n    plt.imshow(draw_bboxes(img = img,\n                           bboxes = bboxes_yolo, \n                           classes = names,\n                           class_ids = labels,\n                           class_name = True, \n                           colors = colors, \n                           bbox_format = 'yolo',\n                           line_thickness = 2))\n    plt.axis('OFF')\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T10:46:21.512437Z","iopub.execute_input":"2021-12-15T10:46:21.512924Z","iopub.status.idle":"2021-12-15T10:46:26.075547Z","shell.execute_reply.started":"2021-12-15T10:46:21.512885Z","shell.execute_reply":"2021-12-15T10:46:26.074801Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📁 Create Folds and datasets\n> Number of samples aren't same in each fold which can create large variance in **Cross-Validation**.","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\nkf = GroupKFold(n_splits = 10) # num_folds=3 as there are total 3 videos\ndf = df.reset_index(drop=True)\ndf['fold'] = -1\nfor fold, (train_idx, val_idx) in enumerate(kf.split(df, y = df.video_id.tolist(), groups=df.sequence)):\n    df.loc[val_idx, 'fold'] = fold\ndisplay(df.fold.value_counts())","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:26.076539Z","iopub.execute_input":"2021-12-15T10:46:26.076763Z","iopub.status.idle":"2021-12-15T10:46:27.130181Z","shell.execute_reply.started":"2021-12-15T10:46:26.076732Z","shell.execute_reply":"2021-12-15T10:46:27.129494Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_files = []\nval_files   = []\ntrain_df = df.query(\"fold!=@FOLD\")\nvalid_df = df.query(\"fold==@FOLD\")\ntrain_files += list(train_df.image_path.unique())\nval_files += list(valid_df.image_path.unique())\nlen(train_files), len(val_files)","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:27.134178Z","iopub.execute_input":"2021-12-15T10:46:27.136569Z","iopub.status.idle":"2021-12-15T10:46:27.16455Z","shell.execute_reply.started":"2021-12-15T10:46:27.136526Z","shell.execute_reply":"2021-12-15T10:46:27.1639Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ⚙️ Configuration\nThe dataset config file requires\n1. The dataset root directory path and relative paths to `train / val / test` image directories (or *.txt files with image paths)\n2. The number of classes `nc` and \n3. A list of class `names`:`['cots']`","metadata":{}},{"cell_type":"code","source":"import yaml\n\ncwd = '/kaggle/working/'\n\nwith open(os.path.join( cwd , 'train.txt'), 'w') as f:\n    for path in train_df.image_path.tolist():\n        f.write(path+'\\n')\n            \nwith open(os.path.join(cwd , 'val.txt'), 'w') as f:\n    for path in valid_df.image_path.tolist():\n        f.write(path+'\\n')\n\ndata = dict(\n    path  = '/kaggle/working',\n    train =  os.path.join( cwd , 'train.txt') ,\n    val   =  os.path.join( cwd , 'val.txt' ),\n    nc    = 1,\n    names = ['cots'],\n    )\n\nwith open(os.path.join( cwd , 'tgbr.yaml'), 'w') as outfile:\n    yaml.dump(data, outfile, default_flow_style=False)\n\nf = open(os.path.join( cwd , 'tgbr.yaml'), 'r')\nprint('\\nyaml:')\nprint(f.read())","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:27.168378Z","iopub.execute_input":"2021-12-15T10:46:27.170378Z","iopub.status.idle":"2021-12-15T10:46:27.189406Z","shell.execute_reply.started":"2021-12-15T10:46:27.170339Z","shell.execute_reply":"2021-12-15T10:46:27.188708Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# [YOLOv5 Model](https://github.com/ultralytics/yolov5/)","metadata":{}},{"cell_type":"code","source":"%cd /kaggle/working\n!rm -r /kaggle/working/yolov5\n!git clone https://github.com/ultralytics/yolov5 # clone\n!cp -r /kaggle/input/yolov5-lib-ds /kaggle/working/yolov5\n%cd yolov5\n%pip install -qr requirements.txt  # install\n\nfrom yolov5 import utils\ndisplay = utils.notebook_init()  # checks","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:46:27.193207Z","iopub.execute_input":"2021-12-15T10:46:27.195093Z","iopub.status.idle":"2021-12-15T10:46:40.729394Z","shell.execute_reply.started":"2021-12-15T10:46:27.195018Z","shell.execute_reply":"2021-12-15T10:46:40.728554Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Training","metadata":{}},{"cell_type":"code","source":"# Train YOLOv5s on COCO128 for 10 epochs\n!python train.py --img 1280\\\n--batch 10\\\n--epochs 15\\\n--data /kaggle/working/tgbr.yaml\\\n--weights yolov5s.pt\\\n--workers 0","metadata":{"execution":{"iopub.status.busy":"2021-12-15T10:54:32.915911Z","iopub.execute_input":"2021-12-15T10:54:32.916162Z","iopub.status.idle":"2021-12-15T14:59:05.61073Z","shell.execute_reply.started":"2021-12-15T10:54:32.916134Z","shell.execute_reply":"2021-12-15T14:59:05.609892Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Output Files","metadata":{}},{"cell_type":"code","source":"!ls runs/train/exp","metadata":{"execution":{"iopub.status.busy":"2021-12-15T14:59:05.612741Z","iopub.execute_input":"2021-12-15T14:59:05.613033Z","iopub.status.idle":"2021-12-15T14:59:06.377732Z","shell.execute_reply.started":"2021-12-15T14:59:05.612997Z","shell.execute_reply":"2021-12-15T14:59:06.376899Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📈 Class Distribution","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nplt.axis('off')\nplt.imshow(plt.imread('runs/train/exp/labels_correlogram.jpg'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:06.380849Z","iopub.execute_input":"2021-12-15T14:59:06.381091Z","iopub.status.idle":"2021-12-15T14:59:07.165109Z","shell.execute_reply.started":"2021-12-15T14:59:06.381062Z","shell.execute_reply":"2021-12-15T14:59:07.164411Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize = (10,10))\nplt.axis('off')\nplt.imshow(plt.imread('runs/train/exp/labels.jpg'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:07.166934Z","iopub.execute_input":"2021-12-15T14:59:07.167309Z","iopub.status.idle":"2021-12-15T14:59:07.717407Z","shell.execute_reply.started":"2021-12-15T14:59:07.167272Z","shell.execute_reply":"2021-12-15T14:59:07.716688Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔭 Batch Image","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread('runs/train/exp/train_batch0.jpg'))\n\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread('runs/train/exp/train_batch1.jpg'))\n\nplt.figure(figsize = (10, 10))\nplt.imshow(plt.imread('runs/train/exp/train_batch2.jpg'))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:07.718746Z","iopub.execute_input":"2021-12-15T14:59:07.719038Z","iopub.status.idle":"2021-12-15T14:59:10.122472Z","shell.execute_reply.started":"2021-12-15T14:59:07.719001Z","shell.execute_reply":"2021-12-15T14:59:10.121864Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## GT Vs Pred","metadata":{}},{"cell_type":"code","source":"fig, ax = plt.subplots(3, 2, figsize = (2*9,3*5), constrained_layout = True)\nfor row in range(3):\n    ax[row][0].imshow(plt.imread(f'runs/train/exp/val_batch{row}_labels.jpg'))\n    ax[row][0].set_xticks([])\n    ax[row][0].set_yticks([])\n    ax[row][0].set_title(f'runs/train/exp/val_batch{row}_labels.jpg', fontsize = 12)\n    \n    ax[row][1].imshow(plt.imread(f'runs/train/exp/val_batch{row}_pred.jpg'))\n    ax[row][1].set_xticks([])\n    ax[row][1].set_yticks([])\n    ax[row][1].set_title(f'runs/train/exp/val_batch{row}_pred.jpg', fontsize = 12)\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:10.123866Z","iopub.execute_input":"2021-12-15T14:59:10.124351Z","iopub.status.idle":"2021-12-15T14:59:12.267227Z","shell.execute_reply.started":"2021-12-15T14:59:10.124315Z","shell.execute_reply":"2021-12-15T14:59:12.264917Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔍 Result","metadata":{}},{"cell_type":"markdown","source":"## Score Vs Epoch","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(30,15))\nplt.axis('off')\nplt.imshow(plt.imread('runs/train/exp/results.png'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:29.851286Z","iopub.execute_input":"2021-12-15T14:59:29.851576Z","iopub.status.idle":"2021-12-15T14:59:30.974321Z","shell.execute_reply.started":"2021-12-15T14:59:29.851547Z","shell.execute_reply":"2021-12-15T14:59:30.973659Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Confusion Matrix","metadata":{}},{"cell_type":"code","source":"plt.figure(figsize=(12,10))\nplt.axis('off')\nplt.imshow(plt.imread('runs/train/exp/confusion_matrix.png'));","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:30.97599Z","iopub.execute_input":"2021-12-15T14:59:30.976406Z","iopub.status.idle":"2021-12-15T14:59:32.705284Z","shell.execute_reply.started":"2021-12-15T14:59:30.976373Z","shell.execute_reply":"2021-12-15T14:59:32.704528Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Metrics","metadata":{}},{"cell_type":"code","source":"for metric in ['F1', 'PR', 'P', 'R']:\n    print(f'Metric: {metric}')\n    plt.figure(figsize=(12,10))\n    plt.axis('off')\n    plt.imshow(plt.imread(f'runs/train/exp/{metric}_curve.png'));\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2021-12-15T14:59:32.706746Z","iopub.execute_input":"2021-12-15T14:59:32.707086Z","iopub.status.idle":"2021-12-15T14:59:35.515356Z","shell.execute_reply.started":"2021-12-15T14:59:32.707048Z","shell.execute_reply":"2021-12-15T14:59:35.514664Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}