{"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":"##  Notebooks: Yolov4 pour prédire les COTS\n","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"markdown","source":"#### Ce notebook a pour objectif de présenter une application de Yolov4 avec Darknet (voir https://www.kaggle.com/gimarcecaml/build-darknet-yolo4 ) à la compétition Great Barrier Reef. \n#### Utilisation de yolov4-tiny.conv.29\n","metadata":{}},{"cell_type":"markdown","source":"#### Kernel de référence:\nhttps://www.kaggle.com/gimarcecaml/cots-det-yolov4-darknet-install-train-infer","metadata":{}},{"cell_type":"code","source":"!apt update\n!apt install --yes python-opencv\n!apt install --yes libopencv-dev\n!/bin/bash -c 'echo \"/opt/conda/lib/\" > /etc/ld.so.conf.d/opencv.conf'\n!ldconfig\n!pip install imagesize","metadata":{"_kg_hide-output":true,"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-02-26T04:42:33.183749Z","iopub.execute_input":"2022-02-26T04:42:33.184120Z","iopub.status.idle":"2022-02-26T04:43:33.691726Z","shell.execute_reply.started":"2022-02-26T04:42:33.184019Z","shell.execute_reply":"2022-02-26T04:43:33.690529Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pandas as pd\nimport os\nimport pickle\nimport matplotlib.pyplot as plt\nimport ast\nimport glob\nimport shutil\nimport sys\nimport numpy as np\nimport imagesize\nimport cv2\nfrom tqdm.notebook import tqdm\nfrom typing import List\nimport torch\nfrom torchvision.ops import box_iou\nfrom typing import List\nimport torch\nfrom torchvision.ops import box_iou\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:43:33.694552Z","iopub.execute_input":"2022-02-26T04:43:33.694945Z","iopub.status.idle":"2022-02-26T04:43:35.839858Z","shell.execute_reply.started":"2022-02-26T04:43:33.694896Z","shell.execute_reply":"2022-02-26T04:43:35.838905Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Installation de darknet","metadata":{}},{"cell_type":"code","source":"!git clone https://github.com/AlexeyAB/darknet.git\n\n%cd darknet\n\n!cp '../../input/libcuda/libcuda.so' .\n\n!sed -i 's/OPENCV=0/OPENCV=1/g' Makefile\n!sed -i 's/GPU=0/GPU=1/g' Makefile\n!sed -i 's/CUDNN=0/CUDNN=1/g' Makefile\n!sed -i 's/CUDNN_HALF=0/CUDNN_HALF=1/g' Makefile\n!sed -i 's/LIBSO=0/LIBSO=1/' Makefile\n!sed -i \"s/ARCH= -gencode arch=compute_60,code=sm_60/ARCH= ${ARCH_VALUE}/g\" Makefile\n\n!sed -i 's/LDFLAGS+= -L\\/usr\\/local\\/cuda\\/lib64 -lcuda -lcudart -lcublas -lcurand/LDFLAGS+= -L\\/usr\\/local\\/cuda\\/lib64 -lcudart -lcublas -lcurand -L\\/kaggle\\/working\\/darknet -lcuda/' Makefile\n!make &> compile.log","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:43:48.910477Z","iopub.execute_input":"2022-02-26T04:43:48.911114Z","iopub.status.idle":"2022-02-26T04:45:55.462679Z","shell.execute_reply.started":"2022-02-26T04:43:48.911081Z","shell.execute_reply":"2022-02-26T04:45:55.461163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Voir si aucune erreur n'a été détecté \n!tail compile.log","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-02-26T04:45:55.471425Z","iopub.execute_input":"2022-02-26T04:45:55.471976Z","iopub.status.idle":"2022-02-26T04:45:56.450368Z","shell.execute_reply.started":"2022-02-26T04:45:55.471906Z","shell.execute_reply":"2022-02-26T04:45:56.449243Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Voir si  on peut effectivement utiliser les commandes Darknet\n!./darknet detector train","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:45:56.452741Z","iopub.execute_input":"2022-02-26T04:45:56.453142Z","iopub.status.idle":"2022-02-26T04:46:00.830137Z","shell.execute_reply.started":"2022-02-26T04:45:56.453092Z","shell.execute_reply":"2022-02-26T04:46:00.828881Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Préparation des données ","metadata":{}},{"cell_type":"code","source":"ROOT_DIR  = '/kaggle/input'\nWORKING_DIR  = '/kaggle/working'\ndef get_path(row):\n    row['image_path'] = f'{ROOT_DIR}/tensorflow-great-barrier-reef/train_images/video_{row.video_id}/{row.video_frame}.jpg'\n    row['label_path'] = f'{WORKING_DIR}/darknet/data/obj/video_{row.video_id}_{row.video_frame}.txt'\n    return row","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:09.855396Z","iopub.execute_input":"2022-02-26T04:46:09.855754Z","iopub.status.idle":"2022-02-26T04:46:09.863401Z","shell.execute_reply.started":"2022-02-26T04:46:09.855718Z","shell.execute_reply":"2022-02-26T04:46:09.862216Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(f'{ROOT_DIR}/tensorflow-great-barrier-reef/train.csv')\ndf = df.apply(get_path, axis=1)\ndf['annotations'] = df['annotations'].apply(lambda x: ast.literal_eval(x))\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:10.081881Z","iopub.execute_input":"2022-02-26T04:46:10.082429Z","iopub.status.idle":"2022-02-26T04:46:46.998310Z","shell.execute_reply.started":"2022-02-26T04:46:10.082385Z","shell.execute_reply":"2022-02-26T04:46:46.997126Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['num_bbox'] = df['annotations'].apply(lambda x: len(x))\ndata = (df.num_bbox>0).value_counts()/len(df)*100\nprint('% images without annotations: {}'.format(data[0]))\nprint('% images with  annotations: {} '.format(data[1]))","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.000903Z","iopub.execute_input":"2022-02-26T04:46:47.001251Z","iopub.status.idle":"2022-02-26T04:46:47.031367Z","shell.execute_reply.started":"2022-02-26T04:46:47.001204Z","shell.execute_reply":"2022-02-26T04:46:47.030286Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.033292Z","iopub.execute_input":"2022-02-26T04:46:47.033981Z","iopub.status.idle":"2022-02-26T04:46:47.060695Z","shell.execute_reply.started":"2022-02-26T04:46:47.033934Z","shell.execute_reply":"2022-02-26T04:46:47.059535Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Remove data without boxes\ndf = df.query(\"num_bbox>0\")","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.063612Z","iopub.execute_input":"2022-02-26T04:46:47.064034Z","iopub.status.idle":"2022-02-26T04:46:47.087192Z","shell.execute_reply.started":"2022-02-26T04:46:47.063988Z","shell.execute_reply":"2022-02-26T04:46:47.086025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.shape","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.089623Z","iopub.execute_input":"2022-02-26T04:46:47.090689Z","iopub.status.idle":"2022-02-26T04:46:47.099176Z","shell.execute_reply.started":"2022-02-26T04:46:47.090639Z","shell.execute_reply":"2022-02-26T04:46:47.097739Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Conversion des annotations entre coco et yolo\ndef coco2yolo(image_height, image_width, bboxes):\n    \"\"\"\n    coco => [xmin, ymin, w, h]\n    yolo => [xmid, ymid, w, h] (normalized)\n    \"\"\"\n    bboxes = bboxes.copy().astype(float) # otherwise all value will be 0 as voc_pascal dtype is np.int\n    \n    # normalizinig\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\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    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","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.102249Z","iopub.execute_input":"2022-02-26T04:46:47.102985Z","iopub.status.idle":"2022-02-26T04:46:47.129133Z","shell.execute_reply.started":"2022-02-26T04:46:47.102941Z","shell.execute_reply":"2022-02-26T04:46:47.127978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['bboxes'] = df.annotations.apply(get_bbox)\ndf = df.apply(get_imgsize,axis=1)\ndisplay(df.width.unique(), df.height.unique())\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:46:47.131164Z","iopub.execute_input":"2022-02-26T04:46:47.131869Z","iopub.status.idle":"2022-02-26T04:47:52.766932Z","shell.execute_reply.started":"2022-02-26T04:46:47.131826Z","shell.execute_reply":"2022-02-26T04:47:52.765631Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#df=df.sample(frac=0.05)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:52.768756Z","iopub.execute_input":"2022-02-26T04:47:52.769295Z","iopub.status.idle":"2022-02-26T04:47:52.774683Z","shell.execute_reply.started":"2022-02-26T04:47:52.769249Z","shell.execute_reply":"2022-02-26T04:47:52.773348Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.shape","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:52.776656Z","iopub.execute_input":"2022-02-26T04:47:52.777650Z","iopub.status.idle":"2022-02-26T04:47:52.789725Z","shell.execute_reply.started":"2022-02-26T04:47:52.777583Z","shell.execute_reply":"2022-02-26T04:47:52.788310Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Structure du working ","metadata":{}},{"cell_type":"markdown","source":"We need to have the following dir structure according to [YOLOv4 tutorial](https://colab.research.google.com/drive/1_GdoqCJWXsChrOiY8sZMr_zbr_fH-0Fg#scrollTo=POozxsvFdXTu)\n```\n/Kaggle/working/darknet\n    /data\n         /obj\n             /video_X_XXX.jpg\n             /video_X_XXX.txt\n         /test\n             /video_X_XXX.jpg\n             /video_X_XXX.txt\n         /train.txt\n         /test.txt\n        /obj.data\n        /obj.names\n    /cfg\n        /yolov4-custom.cfg\n```\n- `video_X_XXX.txt`: contains the YOLO normalized annotations (one per line)\n- `train(test).txt`: contains the filenames of the images `data/obj(test)/video_X_XXX.jpg`\n- `yolov4-custom.cfg`: YOLO config provided by darknet. We updated some values accordingly for this challenge.","metadata":{}},{"cell_type":"code","source":"%cd data/\n!mkdir obj test\n\ncnt = 0\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.asarray(row.bboxes).astype(np.float32).copy()\n    num_bbox = len(bboxes_coco)\n    labels = [0]*num_bbox\n  \n    f = open(row.label_path, 'w')\n\n    if num_bbox < 1:\n        annot = ''\n        f.write(annot)\n        f.close()\n        cnt += 1\n        continue\n  \n    bboxes_yolo  = coco2yolo(image_height, image_width, bboxes_coco)\n\n    for i in range(len(bboxes_yolo)):\n        annot = [str(labels[i])] + list(bboxes_yolo[i].astype(str)) + (['\\n'] if num_bbox!=(i+1) else [''])\n        annot = ' '.join(annot)\n        annot = annot.strip(' ')\n        f.write(annot)\n    f.close()\n\nprint('Missing boxes ', cnt)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:52.794638Z","iopub.execute_input":"2022-02-26T04:47:52.795234Z","iopub.status.idle":"2022-02-26T04:47:56.423329Z","shell.execute_reply.started":"2022-02-26T04:47:52.795189Z","shell.execute_reply":"2022-02-26T04:47:56.422008Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df.head()","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:56.425490Z","iopub.execute_input":"2022-02-26T04:47:56.426166Z","iopub.status.idle":"2022-02-26T04:47:56.457665Z","shell.execute_reply.started":"2022-02-26T04:47:56.426114Z","shell.execute_reply":"2022-02-26T04:47:56.456503Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cat obj/video_0_9828.txt","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:56.459661Z","iopub.execute_input":"2022-02-26T04:47:56.460214Z","iopub.status.idle":"2022-02-26T04:47:57.225450Z","shell.execute_reply.started":"2022-02-26T04:47:56.460155Z","shell.execute_reply":"2022-02-26T04:47:57.224293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split dataset","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\nkf = GroupKFold(n_splits = 5) \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":"2022-02-26T04:47:57.228018Z","iopub.execute_input":"2022-02-26T04:47:57.229892Z","iopub.status.idle":"2022-02-26T04:47:58.143554Z","shell.execute_reply.started":"2022-02-26T04:47:57.229849Z","shell.execute_reply":"2022-02-26T04:47:58.142608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df = df[df['fold']==2]\ntrain_df = df[df['fold']!=2]\nprint(train_df.shape)\nprint(val_df.shape)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:58.145150Z","iopub.execute_input":"2022-02-26T04:47:58.146227Z","iopub.status.idle":"2022-02-26T04:47:58.157221Z","shell.execute_reply.started":"2022-02-26T04:47:58.146181Z","shell.execute_reply":"2022-02-26T04:47:58.156095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# # Move labels from obj/ to test/ directory\ndef mv_labels (row):\n    old_path = row.label_path\n    filename = row.label_path.split('/')[-1]\n    new_path = '/'.join(row.label_path.split('/')[:-2]) + '/test/' + filename\n    row['label_path'] = new_path\n    shutil.move(old_path, new_path)\n    return row\n\nval_df= val_df.apply(lambda x: mv_labels(x), axis=1)\nval_df.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:58.159173Z","iopub.execute_input":"2022-02-26T04:47:58.160249Z","iopub.status.idle":"2022-02-26T04:47:58.371819Z","shell.execute_reply.started":"2022-02-26T04:47:58.160204Z","shell.execute_reply":"2022-02-26T04:47:58.370670Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Copy images to working dir\n'''\nLabels and images must have the same name:\nImages: obj/image_XX.jpg\nLabels: obj/image_XX.txt\n'''\ndef copy_images (row):\n    old_path = row.image_path\n    filename = row.label_path.split('/')[-1][:-4] + '.jpg'\n    new_path = '/'.join(row.label_path.split('/')[:-1]) + '/' + filename\n    shutil.copy(old_path, new_path)\nval_df.apply(lambda x: copy_images(x), axis=1)\ntrain_df.apply(lambda x: copy_images(x), axis=1)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:47:58.373176Z","iopub.execute_input":"2022-02-26T04:47:58.374110Z","iopub.status.idle":"2022-02-26T04:48:10.748415Z","shell.execute_reply.started":"2022-02-26T04:47:58.374049Z","shell.execute_reply":"2022-02-26T04:48:10.747019Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls obj/*.jpg | wc -l\n!ls obj/*.txt | wc -l\n!ls test/*.jpg | wc -l\n!ls test/*.txt | wc -l","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:48:10.750033Z","iopub.execute_input":"2022-02-26T04:48:10.750307Z","iopub.status.idle":"2022-02-26T04:48:13.985931Z","shell.execute_reply.started":"2022-02-26T04:48:10.750268Z","shell.execute_reply":"2022-02-26T04:48:13.984835Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Generate train.txt and test.txt\n%cd ../\ntrain_images = glob.glob('data/obj/*.jpg')\nf = open('./data/train.txt', 'w')\nannot = [os.path.join(os.getcwd(),t) + ('\\n' if i<len(train_images)-1 else '') for i, t in enumerate(train_images)]\nannot = ''.join(annot)\nannot = annot.strip()\nf.write(annot)\n\nval_images = glob.glob('data/test/*.jpg')\nf = open('./data/test.txt', 'w')  \nannot = [os.path.join(os.getcwd(),t) + ('\\n' if i<len(val_images)-1 else '') for i, t in enumerate(val_images)]\nannot = ''.join(annot)\nannot = annot.strip()\nf.write(annot)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:48:13.988979Z","iopub.execute_input":"2022-02-26T04:48:13.989763Z","iopub.status.idle":"2022-02-26T04:48:14.059922Z","shell.execute_reply.started":"2022-02-26T04:48:13.989709Z","shell.execute_reply":"2022-02-26T04:48:14.058877Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!cat data/train.txt | wc -l\n!cat data/test.txt | wc -l","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:48:14.061644Z","iopub.execute_input":"2022-02-26T04:48:14.062198Z","iopub.status.idle":"2022-02-26T04:48:15.650740Z","shell.execute_reply.started":"2022-02-26T04:48:14.062151Z","shell.execute_reply":"2022-02-26T04:48:15.649657Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df.shape","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:48:15.653377Z","iopub.execute_input":"2022-02-26T04:48:15.653978Z","iopub.status.idle":"2022-02-26T04:48:15.662414Z","shell.execute_reply.started":"2022-02-26T04:48:15.653919Z","shell.execute_reply":"2022-02-26T04:48:15.661328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Visualization","metadata":{}},{"cell_type":"code","source":"np.random.seed(32)\ncolors = [(np.random.randint(255), np.random.randint(255), np.random.randint(255))\\\n          for idx in range(1)]\n\ndf2 = train_df[(train_df.num_bbox>0)].sample(100) # takes samples with bbox\n\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    f = open(row.label_path)\n    bboxes_yolo = np.asarray([[float(a) for a in l[1:].strip().split(' ')] for l in f.readlines()])\n\n    names         = ['starfish']*len(bboxes_yolo)\n    labels        = [0]*len(bboxes_yolo)\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":{"execution":{"iopub.status.busy":"2022-02-26T04:48:15.664080Z","iopub.execute_input":"2022-02-26T04:48:15.664424Z","iopub.status.idle":"2022-02-26T04:48:21.578227Z","shell.execute_reply.started":"2022-02-26T04:48:15.664380Z","shell.execute_reply":"2022-02-26T04:48:21.575705Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# configuration des fichiers","metadata":{}},{"cell_type":"markdown","source":"On modifie `yolov4-custom.cfg` de darknet pour prédire une seule classe d'éléments (les étoiles de mer)","metadata":{}},{"cell_type":"code","source":"# Adapt yolov4-custom.cfg to one-class model\n# If subdivisions=16 runs into memory issues use 32, otherwise 16 is the optimal\n!sed -i 's/subdivisions=16/subdivisions=4/g' ./cfg/yolov4-custom.cfg\n# To avoid memory issues with downsized image size from 608 to 416. \n!sed -i 's/width=608/width=160/g' ./cfg/yolov4-custom.cfg\n!sed -i 's/height=608/height=160/g' ./cfg/yolov4-custom.cfg\n\n# Make the rest of the changes to the cfg based on how many classes you are training your detector on.\n'''\nheight = 416 (these can be any multiple of 32, 416 is standard, you can sometimes \nimprove results by making value larger like 608 but will slow down training)\n\nmax_batches = (# of classes) * 2000 (but no less than 6000 so if you are training \nfor 1, 2, or 3 classes it will be 6000, however detector for 5 classes would have max_batches=10000)\n\nsteps = (80% of max_batches), (90% of max_batches) \n(so if your max_batches = 10000, then steps = 8000, 9000)\n\nfilters = (# of classes + 5) * 3 (so if you are training for one class then your \nfilters = 18, but if you are training for 4 classes then your filters = 27)\n'''\n!sed -i 's/max_batches = 500500/max_batches = 1000/g' ./cfg/yolov4-custom.cfg\n!sed -i 's/steps=400000,450000/steps=800,900/g' ./cfg/yolov4-custom.cfg\n!sed -i 's/classes=80/classes=1/g' ./cfg/yolov4-custom.cfg\n!sed -i 's/filters=255/filters=18/g' ./cfg/yolov4-custom.cfg\n\n# Let's build obj.data and obj.names needed by darknet\nf = open('./data/obj.data', 'w')\nf.write('classes = 1\\ntrain = data/train.txt\\nvalid = data/test.txt\\nnames = data/obj.names\\nbackup = backup\\n')\nf.close()\nf = open('./data/obj.names', 'w')\nf.write('starfish')\nf.close()","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:55:21.569857Z","iopub.execute_input":"2022-02-26T04:55:21.570186Z","iopub.status.idle":"2022-02-26T04:55:26.959799Z","shell.execute_reply.started":"2022-02-26T04:55:21.570151Z","shell.execute_reply":"2022-02-26T04:55:26.958570Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  Train à partir d'un modèle pré-entraîné ","metadata":{}},{"cell_type":"code","source":"# On utilise le modèle pré-entrainé yolod-tiny.con.29 qui possède 29 couches\n!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v4_pre/yolov4-tiny.conv.29\n","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:49:13.833743Z","iopub.execute_input":"2022-02-26T04:49:13.834095Z","iopub.status.idle":"2022-02-26T04:49:16.212514Z","shell.execute_reply.started":"2022-02-26T04:49:13.834047Z","shell.execute_reply":"2022-02-26T04:49:16.211298Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Entraînemet avec la commande train \n#%cd darknet\n!./darknet detector train data/obj.data cfg/yolov4-custom.cfg yolov4-tiny.conv.29 -dont_show -map | tee output.log\n","metadata":{"execution":{"iopub.status.busy":"2022-02-26T04:55:30.777685Z","iopub.execute_input":"2022-02-26T04:55:30.778057Z","iopub.status.idle":"2022-02-26T05:15:00.954065Z","shell.execute_reply.started":"2022-02-26T04:55:30.778022Z","shell.execute_reply":"2022-02-26T05:15:00.952920Z"},"collapsed":true,"jupyter":{"outputs_hidden":true},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# on vérifie que les entraînements ont bien été enregistré \n!ls backup","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:15:06.272028Z","iopub.execute_input":"2022-02-26T05:15:06.272316Z","iopub.status.idle":"2022-02-26T05:15:07.101342Z","shell.execute_reply.started":"2022-02-26T05:15:06.272284Z","shell.execute_reply":"2022-02-26T05:15:07.100259Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#  Inference","metadata":{}},{"cell_type":"code","source":"# need to set our custom cfg to test mode \n%cd cfg\n!sed -i 's/batch=64/batch=1/' yolov4-custom.cfg\n!sed -i 's/subdivisions=16/subdivisions=1/' yolov4-custom.cfg\n%cd ..","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_image = './data/obj/video_0_9670.jpg'\n# ext_output \n!./darknet detector test data/obj.data cfg/yolov4-custom.cfg backup/yolov4-custom_last.weights {test_image} -thresh 0.1 -ext_output -dont_show","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:15:28.312034Z","iopub.execute_input":"2022-02-26T05:15:28.312352Z","iopub.status.idle":"2022-02-26T05:15:33.320472Z","shell.execute_reply.started":"2022-02-26T05:15:28.312310Z","shell.execute_reply":"2022-02-26T05:15:33.319239Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\n\nnp.random.seed(32)\ncolors = [(np.random.randint(255), np.random.randint(255), np.random.randint(255))\\\n          for idx in range(1)]\n\nIMAGEPATH = test_image\n\ndef change_path(row):\n    filename = row.image_path.split('/')[-1]\n    videoname = row.image_path.split('/')[-2]\n    return os.path.join('./data/obj', videoname + '_' + filename)\n\ntmp_df = train_df.copy()\ntmp_df['image_path'] = tmp_df.apply(lambda x: change_path(x), 1)\n\ndf2 = tmp_df[(tmp_df.image_path==IMAGEPATH)]\nrow = df2.iloc[0]\nimg           = load_image(row.image_path)\nimage_height  = row.height\nimage_width   = row.width\nf = open(row.image_path[:-4] + '.txt')\nbboxes_yolo = np.asarray([[float(a) for a in l[1:].strip().split(' ')] for l in f.readlines()])\n\nnames         = ['starfish']*len(bboxes_yolo)\nlabels        = [0]*len(bboxes_yolo)\n\n\n# 2. Plot in same line, on two rows\nplt.figure(figsize = (19, 8))\nplt.subplot(1, 2, 1)\n\nplt.imshow(draw_bboxes(img = img,\n                      bboxes = bboxes_yolo, \n                      classes = names,\n                      class_ids = labels,\n                      class_name = True, \n                      bbox_format = 'yolo',\n                       colors = colors,\n                      line_thickness = 2))\n\nplt.axis('OFF')\nplt.title('Ground truth test set')\n\nplt.subplot(1, 2, 2)\n#plt.figure(figsize = (12, 8))\nplt.axis('OFF')\nplt.title('Prediction test set')\nimg = Image.open('predictions.jpg')\nplt.imshow(img)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:15:38.232170Z","iopub.execute_input":"2022-02-26T05:15:38.232679Z","iopub.status.idle":"2022-02-26T05:15:39.037248Z","shell.execute_reply.started":"2022-02-26T05:15:38.232638Z","shell.execute_reply":"2022-02-26T05:15:39.036225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### Modèle avec les poids donné par tiny29 avec aucun préprocessing des images","metadata":{}},{"cell_type":"code","source":"def load_model(conf=0.25, iou=0.50):\n    net = cv2.dnn.readNet(f'/kaggle/working/darknet/cfg/yolov4-custom.cfg',\n                            f'/kaggle/working/darknet/backup/yolov4-custom_last.weights')\n    net = cv2.dnn_DetectionModel(net)\n    net.setInputParams(size=(608, 608), scale=1/255, swapRB=True)\n    return net","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:16.668317Z","iopub.execute_input":"2022-02-26T05:17:16.668653Z","iopub.status.idle":"2022-02-26T05:17:16.675249Z","shell.execute_reply.started":"2022-02-26T05:17:16.668616Z","shell.execute_reply":"2022-02-26T05:17:16.673829Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"confThreshold = 0.1\nconfthre = 0.1\nIMG_SIZE=416\nwith open('/kaggle/working/darknet/data/obj.names', 'rt') as f:\n    names = f.read().rstrip('\\n').split('\\n')\n\ndef predict(net, img, size=IMG_SIZE):\n    confs = []\n    bboxes = []\n    height, width = img.shape[:2]\n    bbclasses, scores, bboxes = net.detect(img, confThreshold=confThreshold, nmsThreshold=0.4)\n   \n    if len(bboxes):\n        confs=[]\n        for i in scores:\n            confs.append('{:.2f}'.format(i))\n        score=np.array(confs,dtype=float)  \n        return bboxes, score\n    else:\n        return [],[]\ndef format_prediction(bboxes, confs):\n    annot = ''\n    if len(bboxes)>0:\n        for idx in range(len(bboxes)):\n            xmin, ymin, w, h = bboxes[idx]\n            conf             = confs[idx]\n            annot += f'{conf} {xmin} {ymin} {w} {h}'\n            annot +=' '\n        annot = annot.strip(' ')\n    return annot    ","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:17.015714Z","iopub.execute_input":"2022-02-26T05:17:17.015999Z","iopub.status.idle":"2022-02-26T05:17:17.027162Z","shell.execute_reply.started":"2022-02-26T05:17:17.015970Z","shell.execute_reply":"2022-02-26T05:17:17.025763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img = Image.open('/kaggle/input/tensorflow-great-barrier-reef/train_images/video_0/1010.jpg')\nnumpydata = np.asarray(img)\nnet = load_model(conf=0.1, iou=0.1)\nbboxes, confs  = predict(net, numpydata, size=IMG_SIZE)\nbboxes","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:17.304064Z","iopub.execute_input":"2022-02-26T05:17:17.304804Z","iopub.status.idle":"2022-02-26T05:17:21.775498Z","shell.execute_reply.started":"2022-02-26T05:17:17.304755Z","shell.execute_reply":"2022-02-26T05:17:21.774485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df_1=val_df.sample(100)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:24.619411Z","iopub.execute_input":"2022-02-26T05:17:24.621786Z","iopub.status.idle":"2022-02-26T05:17:24.627969Z","shell.execute_reply.started":"2022-02-26T05:17:24.621735Z","shell.execute_reply":"2022-02-26T05:17:24.626613Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"'''\nOn calcule pour chaque image, les bboxes issues de notre algorithme entrainé \n'''\n\ndef annoter_pred(df):\n    df['preds'] = df['bboxes']\n    net = load_model(conf=0.1, iou=0.40)\n    for idx in df.index:\n        img= Image.open(df[\"image_path\"][idx])\n        numpydata = np.asarray(img)\n        bboxes, confs  = predict(net, numpydata, size=IMG_SIZE)\n        if bboxes==[]:\n            df['preds'][idx]=[]\n        else:    \n            df['preds'][idx]= bboxes.tolist()","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:24.913267Z","iopub.execute_input":"2022-02-26T05:17:24.913610Z","iopub.status.idle":"2022-02-26T05:17:24.924041Z","shell.execute_reply.started":"2022-02-26T05:17:24.913551Z","shell.execute_reply":"2022-02-26T05:17:24.922974Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"annoter_pred(val_df_1)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:17:25.531044Z","iopub.execute_input":"2022-02-26T05:17:25.531310Z","iopub.status.idle":"2022-02-26T05:23:19.010792Z","shell.execute_reply.started":"2022-02-26T05:17:25.531282Z","shell.execute_reply":"2022-02-26T05:23:19.009691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Evualuation","metadata":{}},{"cell_type":"code","source":"def calculate_score(\n    preds: List[torch.Tensor],\n    gts: List[torch.Tensor],\n    iou_th: float\n) -> float:\n    num_tp = 0\n    num_fp = 0\n    num_fn = 0\n    for p, GT in zip(preds, gts):\n        if len(p) and len(GT):\n            gt = GT.clone()\n            gt[:, 2] = gt[:, 0] + gt[:, 2]\n            gt[:, 3] = gt[:, 1] + gt[:, 3]\n            pp = p.clone()\n            pp[:, 2] = pp[:, 0] + pp[:, 2]\n            pp[:, 3] = pp[:, 1] + pp[:, 3]\n            iou_matrix = box_iou(pp, gt)\n            tp = len(torch.where(iou_matrix.max(0)[0] >= iou_th)[0])\n            fp = len(p) - tp\n            fn = len(torch.where(iou_matrix.max(0)[0] < iou_th)[0])\n            num_tp += tp\n            num_fp += fp\n            num_fn += fn\n        elif len(p) == 0 and len(GT):\n            num_fn += len(GT)\n        elif len(p) and len(GT) == 0:\n            num_fp += len(p)\n    score = 5 * num_tp / (5 * num_tp + 4 * num_fn + num_fp)\n    return score","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:23:19.012965Z","iopub.execute_input":"2022-02-26T05:23:19.013503Z","iopub.status.idle":"2022-02-26T05:23:19.031522Z","shell.execute_reply.started":"2022-02-26T05:23:19.013443Z","shell.execute_reply":"2022-02-26T05:23:19.030658Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculer_f2(df):\n    predictions = []\n    gts = []\n    for i, row in (df.iterrows()):\n        if type(row.preds) != float and len(row.preds) > 0:\n            preds = torch.tensor(row.preds)\n            predictions.append(preds)\n        else:\n            predictions.append([])\n        if type(row.bboxes) != float and len(row.bboxes) > 0:\n            gts.append(torch.tensor(row.bboxes))\n        else:\n            gts.append([])\n    iou_ths = np.arange(0.3, 0.85, 0.05)\n    scores = [calculate_score(predictions, gts, iou_th) for iou_th in iou_ths]\n    return np.mean(scores)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:23:19.032838Z","iopub.execute_input":"2022-02-26T05:23:19.033326Z","iopub.status.idle":"2022-02-26T05:23:19.052308Z","shell.execute_reply.started":"2022-02-26T05:23:19.033288Z","shell.execute_reply":"2022-02-26T05:23:19.051095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"calculer_f2(val_df_1)","metadata":{"execution":{"iopub.status.busy":"2022-02-26T05:23:19.060025Z","iopub.execute_input":"2022-02-26T05:23:19.061822Z","iopub.status.idle":"2022-02-26T05:23:19.130527Z","shell.execute_reply.started":"2022-02-26T05:23:19.061775Z","shell.execute_reply":"2022-02-26T05:23:19.129621Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}