{"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":"# 💻 You Only Look Once (YOLO) Implementation \n### Group: 4NN\n#### Dharani Palanisamy (z5260276)\n#### Faiyam Islam (z5258151) \n#### Pooja Saianand (z5312416)\n#### Priya Nandyal (z5312288) \n\nThis notebook implements EDA on the x-ray images that has not been covered in the EDA notebook then we use the YOLO algorithm to the predicted and actual distribution of each abnormality. We will also analyse the evaluation metrics such as mAP and IoU and instigate a conclusion on the accuracy of this object detection method. \n\nThis notebook implements some initial data exploration of the x-ray images then the YOLO algorithm. \n\nWe've used the following sources which assisted our approach for YOLO: \n\nhttps://www.kaggle.com/code/kimse0ha/vinbigdata-eda-infer-analysis-with-yolov5\n\nhttps://www.kaggle.com/code/awsaf49/vinbigdata-cxr-ad-yolov5-14-class-infer/notebook\n\nhttps://www.kaggle.com/code/mrutyunjaybiswal/vbd-chest-x-ray-abnormalities-detection-eda/notebook","metadata":{}},{"cell_type":"markdown","source":"# Importing Packages","metadata":{}},{"cell_type":"code","source":"import numpy as np # working with arrays in our images\nimport pandas as pd # machine learning tasks \nfrom sklearn.model_selection import GroupKFold # classification \nfrom tqdm.notebook import tqdm # creating Progress Metres and Progress Bars\nfrom glob import glob # used to return all file paths that match a specific pattern \nimport shutil # used for file collection, including copying\nimport os # creating and removing directories and folders\nimport random # generate random numbers\nimport cv2 # imports name for opencv in Python\nimport matplotlib # create 2D graphs and plotting\nimport matplotlib.pyplot as plt # for plotting\nfrom mpl_toolkits.axes_grid1 import ImageGrid # For creating heatmaps\nimport plotly.express as px # for aesthetics of figures and plots\nimport seaborn as sns # uses matplotlib to plot graphs\nimport torch # deep learning\nfrom IPython.display import Image, clear_output # Makes plots interactive","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:14:37.951821Z","iopub.execute_input":"2022-07-26T06:14:37.952318Z","iopub.status.idle":"2022-07-26T06:14:39.580647Z","shell.execute_reply.started":"2022-07-26T06:14:37.95225Z","shell.execute_reply":"2022-07-26T06:14:39.579863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Importing Datasets and assigning directories","metadata":{}},{"cell_type":"code","source":"train_dir = f'/kaggle/input/vinbigdata-512-image-dataset/vinbigdata/train'\nweights_dir = '/kaggle/input/vinbigdata-cxr-ad-yolov5-14-class-train/yolov5/runs/train/exp/weights/best.pt'\ntrain_df = pd.read_csv('../input/vinbigdata-512-image-dataset/vinbigdata/train.csv')\ntrain_df.head()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:14:41.745553Z","iopub.execute_input":"2022-07-26T06:14:41.745907Z","iopub.status.idle":"2022-07-26T06:14:41.862654Z","shell.execute_reply.started":"2022-07-26T06:14:41.745875Z","shell.execute_reply":"2022-07-26T06:14:41.861837Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Background information of the train dataset","metadata":{}},{"cell_type":"code","source":"len(train_df) # Total length of train dataset","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:44.646608Z","iopub.execute_input":"2022-07-26T06:14:44.646988Z","iopub.status.idle":"2022-07-26T06:14:44.654475Z","shell.execute_reply.started":"2022-07-26T06:14:44.646958Z","shell.execute_reply":"2022-07-26T06:14:44.65315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_df.image_id.unique()) # unique values in train dataset","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:45.275476Z","iopub.execute_input":"2022-07-26T06:14:45.275863Z","iopub.status.idle":"2022-07-26T06:14:45.294439Z","shell.execute_reply.started":"2022-07-26T06:14:45.275824Z","shell.execute_reply":"2022-07-26T06:14:45.293709Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_df) / len(train_df.image_id.unique()) # Average number of chest disease per person","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:45.850604Z","iopub.execute_input":"2022-07-26T06:14:45.850968Z","iopub.status.idle":"2022-07-26T06:14:45.867717Z","shell.execute_reply.started":"2022-07-26T06:14:45.850936Z","shell.execute_reply":"2022-07-26T06:14:45.866992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"len(train_df[train_df.class_id != 14]) / len(train_df[train_df.class_id != 14].image_id.unique())","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:47.183539Z","iopub.execute_input":"2022-07-26T06:14:47.183901Z","iopub.status.idle":"2022-07-26T06:14:47.208081Z","shell.execute_reply.started":"2022-07-26T06:14:47.183869Z","shell.execute_reply":"2022-07-26T06:14:47.207133Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Distribution of each class chest abnormality","metadata":{}},{"cell_type":"markdown","source":"Let's re-explore the plot label distribution of each disease from the patiences with and without the class name 'No finding'.","metadata":{}},{"cell_type":"code","source":"# Before plotting our distributions, let's set a colour palette\ncolor_palette = [px.colors.label_rgb(px.colors.convert_to_RGB_255(x)) \n                for x in sns.color_palette(\"plasma\", 15)]","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:48.924578Z","iopub.execute_input":"2022-07-26T06:14:48.924944Z","iopub.status.idle":"2022-07-26T06:14:48.933429Z","shell.execute_reply.started":"2022-07-26T06:14:48.924911Z","shell.execute_reply":"2022-07-26T06:14:48.931969Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Distribution of chest abnormalities","metadata":{}},{"cell_type":"code","source":"fig = px.bar(train_df.class_name.value_counts().sort_index(), \n             color = train_df.class_name.value_counts().sort_index().index,\n             color_discrete_sequence = color_palette,\n             title = \"Distribution of chest abnormalities\")\nfig.update_layout(legend_title = \"Disease names\",\n                  xaxis_title =\"Diseases\",\n                  yaxis_title = \"Count\")\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:14:50.952488Z","iopub.execute_input":"2022-07-26T06:14:50.952836Z","iopub.status.idle":"2022-07-26T06:14:51.403435Z","shell.execute_reply.started":"2022-07-26T06:14:50.952802Z","shell.execute_reply":"2022-07-26T06:14:51.402061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Distribution of chest abnormalities (without 'No finding') ","metadata":{}},{"cell_type":"code","source":"fig = px.bar(train_df[train_df.class_id != 14].class_name.value_counts().sort_index(), \n             color = train_df[train_df.class_id!=14].class_name.value_counts().sort_index().index,\n             color_discrete_sequence = color_palette,\n             title = \"Distribution of chest abnormalities (without 'No finding')\")\nfig.update_layout(legend_title = \"Disease names\",\n                  xaxis_title = \"Diseases\",\n                  yaxis_title = \"Count\")\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:14:53.89952Z","iopub.execute_input":"2022-07-26T06:14:53.899973Z","iopub.status.idle":"2022-07-26T06:14:54.24377Z","shell.execute_reply.started":"2022-07-26T06:14:53.899932Z","shell.execute_reply":"2022-07-26T06:14:54.242846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Bounding box placement in Heatmap ","metadata":{}},{"cell_type":"markdown","source":"In our EDA, we constructed various distribution of area of the bounding boxes for each category, however the issue was we were unable to visualise the relative sizes of each abnormality, we were simply observing the coordinates of the bounding boxes. Here, we have implemented code that will generate Heatmaps to properly visualise on the actual x-ray images. This gives us a good initial idea of bounding box sizes. ","metadata":{}},{"cell_type":"code","source":"boundingbox_df = train_df[train_df.class_id != 14].reset_index(drop = True) \n\nboundingbox_df['frac_x_min'] = boundingbox_df.apply(lambda x: (x.x_min) / x.width, axis = 1)\nboundingbox_df['frac_y_min'] = boundingbox_df.apply(lambda x: (x.y_min) / x.height, axis = 1) \nboundingbox_df['frac_x_max'] = boundingbox_df.apply(lambda x: (x.x_max) / x.width, axis = 1) \nboundingbox_df['frac_y_max'] = boundingbox_df.apply(lambda x: (x.y_max) / x.height, axis = 1) \nboundingbox_df.head()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:14:56.527131Z","iopub.execute_input":"2022-07-26T06:14:56.52747Z","iopub.status.idle":"2022-07-26T06:14:59.80789Z","shell.execute_reply.started":"2022-07-26T06:14:56.52744Z","shell.execute_reply":"2022-07-26T06:14:59.806868Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"avg_width  = int(np.mean(boundingbox_df.width))\navg_height = int(np.mean(boundingbox_df.height))\n\nheatmap_size = (avg_width, avg_height, 14)\nheatmap = np.zeros((heatmap_size), dtype=np.int16)\n\nbbox_np = boundingbox_df[[\"class_id\", \"frac_x_min\", \"frac_x_max\", \"frac_y_min\", \"frac_y_max\"]].to_numpy()\nbbox_np[:, 1:3] *= avg_width; bbox_np[:, 3:5] *= avg_height\nbbox_np = np.floor(bbox_np).astype(np.int16)\n\nlabel_dic = {i:train_df[train_df[\"class_id\"] == i].iloc[0][\"class_name\"] for i in range(15)}\n\ncustom_cmaps = [matplotlib.colors.LinearSegmentedColormap.from_list(colors = [(0.,0.,0.), c, (0.95,0.95,0.95)], \n        name = f\"custom_{i}\") for i,c in enumerate(sns.color_palette(\"Spectral\", 15))]\ncustom_cmaps.pop(8) # This removes the class 'No finding'\n\nfor row in tqdm(bbox_np, total=bbox_np.shape[0]):\n    heatmap[row[3]:row[4] + 1, row[1]:row[2] + 1, row[0]] += 1\n    \nfig = plt.figure(figsize = (20,25))\nplt.suptitle(\"Heatmaps of Bounding Box Placement \", fontsize = 20)\nfor i in range(15):\n    plt.subplot(4, 4, i + 1)\n    if i == 0:\n        plt.imshow(heatmap.mean(axis =- 1), cmap = \"bone\")\n        plt.title(f\"Average of All Classes\", fontweight = \"bold\")\n    else:\n        plt.imshow(heatmap[:, :, i-1], cmap=custom_cmaps[i - 1])\n        plt.title(f\"{label_dic[i - 1]} – id : {i}\", fontweight = \"bold\")\n        \n    plt.axis(False)\nfig.tight_layout(rect = [0, 0.03, 1, 0.97])\nplt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:15:01.269843Z","iopub.execute_input":"2022-07-26T06:15:01.270193Z","iopub.status.idle":"2022-07-26T06:15:36.421386Z","shell.execute_reply.started":"2022-07-26T06:15:01.270162Z","shell.execute_reply":"2022-07-26T06:15:36.420225Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Percentage of area of Bounding boxes in each image","metadata":{}},{"cell_type":"markdown","source":"We are able to quantify each class disease now in a range, this is more accurate and effective than estimating by scrutinising the dicom images. ","metadata":{}},{"cell_type":"code","source":"boundingbox_df[\"frac_bbox_area\"] = (boundingbox_df[\"frac_x_max\"] - boundingbox_df[\"frac_x_min\"]) * (boundingbox_df[\"frac_y_max\"] - boundingbox_df[\"frac_y_min\"])\nfig = px.box(boundingbox_df.sort_values(by = \"class_name\"), x = \"class_name\", y = \"frac_bbox_area\", color = \"class_name\", notched = True,\n             color_discrete_sequence = color_palette, \n             labels = {\"class_id_as_str\": \"Class Name\", \"frac_bbox_area\" : \"BBox Area (%)\"},\n             title = \"Percentage of bounding box on each image\")\n\nfig.update_layout(showlegend = True,\n                  yaxis_range = [-0.025,0.40],\n                  legend_title_text = None,\n                  xaxis_title = \"\",\n                  yaxis_title = \"\")\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:15:41.974258Z","iopub.execute_input":"2022-07-26T06:15:41.974642Z","iopub.status.idle":"2022-07-26T06:15:42.466285Z","shell.execute_reply.started":"2022-07-26T06:15:41.974606Z","shell.execute_reply":"2022-07-26T06:15:42.465313Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Validation Set with K = 4 folds \nCreating a validation set will assist in selecting and tuning the YOLO model. Using GroupKFold() command ensures that the same group is not represented in both testing/validation and training sets. In this case for all the features we will have k = 4 folds. \nSource: https://www.kaggle.com/code/reighns/groupkfold-and-stratified-groupkfold-efficientnet/notebook","metadata":{}},{"cell_type":"code","source":"dimension = 512\n# Justification of using 512 \n# Essentially this is the size of the images. We believed this was the best one to use because there is a good balance between \n# the quality of the images and the time it takes to import the datasets.\n# Here is a useful source we looked into deciding which one was more effective for YOLO: \n# https://www.kaggle.com/code/seokhyunseo/256-vs-512-vs-1024-which-dataset-is-useful \ntrain_df['image_path'] = f'/kaggle/input/vinbigdata-{dimension}-image-dataset/vinbigdata/train/' + train_df.image_id + ('.png' if dimension != 'original' else '.jpg')\ntrain_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:15:46.858381Z","iopub.execute_input":"2022-07-26T06:15:46.858712Z","iopub.status.idle":"2022-07-26T06:15:46.905245Z","shell.execute_reply.started":"2022-07-26T06:15:46.85868Z","shell.execute_reply":"2022-07-26T06:15:46.904307Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Essentially, adding an image path helps alleviate the confusion between the features of the chest abnormalities, such as x_min, y_min, x_max and y_max as well as the class_name of each image. ","metadata":{}},{"cell_type":"code","source":"# Drop all the x-rays that do not contain any abnormality.\ntrain_df = train_df[train_df.class_id != 14].reset_index(drop = True)\n\nfold = 4\ngkf  = GroupKFold(n_splits = 5)\ntrain_df['fold'] = -1 # adds folds to the end of the dataframe\n\nfor fold, (train_idx, val_idx) in enumerate(gkf.split(train_df, groups = train_df.image_id.tolist())):\n    train_df.loc[val_idx, 'fold'] = fold\n    \nval_df = train_df[train_df['fold'] == 4]\nval_df.head()","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:15:48.597194Z","iopub.execute_input":"2022-07-26T06:15:48.597539Z","iopub.status.idle":"2022-07-26T06:15:48.683284Z","shell.execute_reply.started":"2022-07-26T06:15:48.597505Z","shell.execute_reply":"2022-07-26T06:15:48.681934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_files = []\nval_files   = [] \nval_files += list(train_df[train_df.fold == fold].image_path.unique())\ntrain_files += list(train_df[train_df.fold != fold].image_path.unique())\nprint(len(train_files)) # size of train dataset\nprint(len(val_files)) # size of validation dataset (which includes the folds) ","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:15:50.121998Z","iopub.execute_input":"2022-07-26T06:15:50.122333Z","iopub.status.idle":"2022-07-26T06:15:50.147135Z","shell.execute_reply.started":"2022-07-26T06:15:50.122301Z","shell.execute_reply":"2022-07-26T06:15:50.146153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"In our training dataset we do not include the folds, but we do for the validation files, hence we get a smaller number of files for the validation set at 879. ","metadata":{}},{"cell_type":"code","source":"os.makedirs('/kaggle/working/vinbigdata/labels/train', exist_ok = True)\nos.makedirs('/kaggle/working/vinbigdata/labels/val', exist_ok = True)\nos.makedirs('/kaggle/working/vinbigdata/images/train', exist_ok = True)\nos.makedirs('/kaggle/working/vinbigdata/images/val', exist_ok = True)\nlabel_dir = '/kaggle/input/vinbigdata-yolo-labels-dataset/labels'\n\nfor file in train_files:\n    shutil.copy(file, '/kaggle/working/vinbigdata/images/train')\n    filename = file.split('/')[-1].split('.')[0]\n    shutil.copy(os.path.join(label_dir, filename+'.txt'), '/kaggle/working/vinbigdata/labels/train')\n    \nfor file in val_files:\n    shutil.copy(file, '/kaggle/working/vinbigdata/images/val')\n    filename = file.split('/')[-1].split('.')[0]\n    shutil.copy(os.path.join(label_dir, filename+'.txt'), '/kaggle/working/vinbigdata/labels/val')\n    \nval_dir = f'/kaggle/working/vinbigdata/images/val'","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:15:51.303211Z","iopub.execute_input":"2022-07-26T06:15:51.303544Z","iopub.status.idle":"2022-07-26T06:16:09.702967Z","shell.execute_reply.started":"2022-07-26T06:15:51.303515Z","shell.execute_reply":"2022-07-26T06:16:09.702011Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Setting up YOLOv5","metadata":{}},{"cell_type":"code","source":"shutil.copytree('/kaggle/input/yolov5-official-v31-dataset/yolov5', '/kaggle/working/yolov5')\nos.chdir('/kaggle/working/yolov5') \nclear_output()\nprint('Setup complete. Using torch %s %s' % (torch.__version__, torch.cuda.get_device_properties(0) if torch.cuda.is_available() else 'CPU'))","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:17:05.55325Z","iopub.execute_input":"2022-07-26T06:17:05.553584Z","iopub.status.idle":"2022-07-26T06:17:05.810919Z","shell.execute_reply.started":"2022-07-26T06:17:05.553552Z","shell.execute_reply":"2022-07-26T06:17:05.809856Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Below we import the validation set containing 879 images, the image resolution is 640x640, the confidence threshold being 0.15, the IoU or \nIntersection Over Union is set to 0.4 and the source is from the validation directoy. The justification of setting IoU to 0.4 instead of 0.5\nor over is because we are trying to retrieve all the images that are the classified correctly and then using the algorithm we can not only\nclassify the chest abnormalities correctly but also showcase them through data visualisation in charts. \n\nIt is also important to notice that unlike the code executed in the EDA section which converts the DICOM x-ray files to np array, the validation set of the 512 image dataset from VingBigData automatically converted the images to png. This is confirmed from the output we get below with 879 images all in png showcasing the resolutions and the different class names of diseases. ","metadata":{}},{"cell_type":"code","source":"!python detect.py --weights $weights_dir\\\n--img 640\\ # image resolution: 640 x 640\n--conf 0.15\\ # confidence threshold \n--iou 0.4\\ # Intersection Over Union, more information on this can be found in the methdology of report.pdf\n--source $val_dir\\ # set source to the validation directory \n--save-txt --save-conf --exist-ok","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:18:07.803272Z","iopub.execute_input":"2022-07-26T06:18:07.803604Z","iopub.status.idle":"2022-07-26T06:19:14.199311Z","shell.execute_reply.started":"2022-07-26T06:18:07.803572Z","shell.execute_reply":"2022-07-26T06:19:14.198355Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference plots of objection detection using YOLO\n\nIt is important to note that the output is randomised, meaning if we were to run the below again we will observe different outputs. The output does not guarantee a correct prediction, because there are instances where we produce an IoU value of less than 0.5, further inference\nand explanation of the output we achieved is explained in the results section of report.pdf\n","metadata":{}},{"cell_type":"code","source":"files = glob('runs/detect/exp/*png')\nfor _ in range(1):\n    row = 3; col = 5 # we get 15 images here\n    grid_files = random.sample(files, row*col)\n    images     = []\n    for image_path in tqdm(grid_files):\n        img          = cv2.cvtColor(cv2.imread(image_path), cv2.COLOR_BGR2RGB)\n        images.append(img)\n\n    fig = plt.figure(figsize=(col*5, row*5))\n    grid = ImageGrid(fig, 111,  # similar to subplot(111)\n                     nrows_ncols=(row, col),  # creates 2x2 grid of axes\n                     axes_pad=0.10,  # pad between axes in inch.\n                     )\n\n    for ax, im in zip(grid, images):\n        # Iterating over the grid returns the Axes.\n        ax.imshow(im)\n        ax.set_xticks([])\n        ax.set_yticks([])\n    plt.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:19:19.176655Z","iopub.execute_input":"2022-07-26T06:19:19.177038Z","iopub.status.idle":"2022-07-26T06:19:21.19768Z","shell.execute_reply.started":"2022-07-26T06:19:19.177006Z","shell.execute_reply":"2022-07-26T06:19:21.196863Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def yolo2voc(image_height, image_width, bboxes):\n    bboxes = bboxes.copy().astype(float)\n    bboxes[..., [0, 2]] = bboxes[..., [0, 2]] * image_width\n    bboxes[..., [1, 3]] = bboxes[..., [1, 3]] * image_height\n    bboxes[..., [0, 1]] = bboxes[..., [0, 1]] - bboxes[..., [2, 3]] / 2\n    bboxes[..., [2, 3]] = bboxes[..., [0, 1]] + bboxes[..., [2, 3]]\n    return bboxes","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:19:25.803459Z","iopub.execute_input":"2022-07-26T06:19:25.803829Z","iopub.status.idle":"2022-07-26T06:19:25.81046Z","shell.execute_reply.started":"2022-07-26T06:19:25.803795Z","shell.execute_reply":"2022-07-26T06:19:25.80928Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image_ids = []; PredictionStrings = []; classes = []; scores = []\nx_min = []; y_min = []; x_max = []; y_max = []\n\nfor file_path in glob('runs/detect/exp/labels/*txt'):\n    image_id = file_path.split('/')[-1].split('.')[0]\n    w, h = val_df[val_df.image_id == image_id][['width', 'height']].values[0]\n    f = open(file_path, 'r')\n    data = np.array(f.read().replace('\\n', ' ').strip().split(' ')).astype(np.float32).reshape(-1, 6)\n    data = data[:, [0, 5, 1, 2, 3, 4]]\n    bboxes = list(np.concatenate((data[:, :2], np.round(yolo2voc(h, w, data[:, 2:]))), axis = 1).reshape(-1))#.astype(str))\n    for i in range(len(bboxes) // 6):\n        image_ids.append(image_id)\n        classes.append(int(bboxes[i * 6]))\n        scores.append(int(bboxes[i * 6 + 1]))\n        x_min.append(int(bboxes[i * 6 + 2]))\n        y_min.append(int(bboxes[i * 6 + 3]))\n        x_max.append(int(bboxes[i * 6 + 4]))\n        y_max.append(int(bboxes[i * 6 + 5]))\n        \npred_df = pd.DataFrame({'image_id' : image_ids,'classes' : classes,'scores' : scores,'x_min' : x_min,'y_min' : y_min,'x_max' : x_max,'y_max' : y_max})\npred_df['class_name'] = pred_df.classes.apply(lambda x : label_dic[x])","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:19:27.256271Z","iopub.execute_input":"2022-07-26T06:19:27.256604Z","iopub.status.idle":"2022-07-26T06:19:29.475116Z","shell.execute_reply.started":"2022-07-26T06:19:27.256575Z","shell.execute_reply":"2022-07-26T06:19:29.474256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Distribution of actual vs predicted","metadata":{}},{"cell_type":"code","source":"fig = px.bar(val_df.class_name.value_counts().sort_index(), \n             color = val_df.class_name.value_counts().sort_index().index,\n             color_discrete_sequence = color_palette,\n             title = \"Actual Distribution of Validation Dataset\")\nfig.update_layout(legend_title = \"Disease names\",\n                  xaxis_title = \"Diseases\",\n                  yaxis_title = \"Count\")\nfig.show()","metadata":{"_kg_hide-input":true,"execution":{"iopub.status.busy":"2022-07-26T06:19:32.008128Z","iopub.execute_input":"2022-07-26T06:19:32.008454Z","iopub.status.idle":"2022-07-26T06:19:32.118361Z","shell.execute_reply.started":"2022-07-26T06:19:32.008424Z","shell.execute_reply":"2022-07-26T06:19:32.117437Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Distribution of predicted validation dataset","metadata":{}},{"cell_type":"code","source":"fig = px.bar(pred_df.class_name.value_counts().sort_index(), \n             color = pred_df.class_name.value_counts().sort_index().index,\n             color_discrete_sequence = color_palette,\n             title = \"Predicted Distribution of Validation Dataset\")\nfig.update_layout(legend_title = \"Disease names\",\n                  xaxis_title = \"Diseases\",\n                  yaxis_title = \"Count\")\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:19:35.076665Z","iopub.execute_input":"2022-07-26T06:19:35.077053Z","iopub.status.idle":"2022-07-26T06:19:35.186462Z","shell.execute_reply.started":"2022-07-26T06:19:35.077023Z","shell.execute_reply":"2022-07-26T06:19:35.18562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Distribution of difference in the actual and predicted dataset","metadata":{}},{"cell_type":"code","source":"difference = val_df.class_name.value_counts().sort_index() - pred_df.class_name.value_counts().sort_index()\nfig = px.bar(difference, \n             color = difference.index,\n             color_discrete_sequence = color_palette,\n             title = \"The Difference between Actual Distribution and Predicted Distribution\")\nfig.update_layout(legend_title = \"Disease names\",\n                  xaxis_title = \"Diseases\",\n                  yaxis_title = \"Count\")\nfig.show()","metadata":{"execution":{"iopub.status.busy":"2022-07-26T06:19:37.732156Z","iopub.execute_input":"2022-07-26T06:19:37.732487Z","iopub.status.idle":"2022-07-26T06:19:37.845434Z","shell.execute_reply.started":"2022-07-26T06:19:37.732459Z","shell.execute_reply":"2022-07-26T06:19:37.844685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"This is the end of the notebook, the next process is to calculate mAP (mean average precision) on the dataset, then analyse the PR curves that will involve understanding the difference between precision and recall values for different thresholds. ","metadata":{}}]}