{"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":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nimport shutil\nfrom IPython.display import display\n# shutil.copytree(f'/kaggle/input/tfgbr-ipynb', f'/kaggle/working/model')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","scrolled":true,"execution":{"iopub.status.busy":"2022-04-11T05:13:39.341639Z","iopub.execute_input":"2022-04-11T05:13:39.341894Z","iopub.status.idle":"2022-04-11T05:13:39.346269Z","shell.execute_reply.started":"2022-04-11T05:13:39.341865Z","shell.execute_reply":"2022-04-11T05:13:39.345588Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Grab training data and copy files to a path where the data can be modified","metadata":{}},{"cell_type":"code","source":"ROOT_DIR = '/kaggle/input/tensorflow-great-barrier-reef'","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:39.395667Z","iopub.execute_input":"2022-04-11T05:13:39.396218Z","iopub.status.idle":"2022-04-11T05:13:39.400574Z","shell.execute_reply.started":"2022-04-11T05:13:39.396179Z","shell.execute_reply":"2022-04-11T05:13:39.399849Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# these directories will allow us to make changes to the data\nIMAGE_DIR = '/kaggle/working/images'\nLABEL_DIR = '/kaggle/working/labels'\n\n!mkdir -p {IMAGE_DIR}\n!mkdir -p {LABEL_DIR}","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:39.445918Z","iopub.execute_input":"2022-04-11T05:13:39.446240Z","iopub.status.idle":"2022-04-11T05:13:40.776609Z","shell.execute_reply.started":"2022-04-11T05:13:39.446208Z","shell.execute_reply":"2022-04-11T05:13:40.775691Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(f'{ROOT_DIR}/train.csv')\ndisplay(df)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:40.778807Z","iopub.execute_input":"2022-04-11T05:13:40.779086Z","iopub.status.idle":"2022-04-11T05:13:40.856679Z","shell.execute_reply.started":"2022-04-11T05:13:40.779044Z","shell.execute_reply":"2022-04-11T05:13:40.855980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df['old_image_path'] = f'{ROOT_DIR}/train_images/video_' + df.video_id.astype(str) + '/' + df.video_frame.astype(str) + '.jpg'\ndf['image_path']  = f'{IMAGE_DIR}/' + df.image_id + '.jpg'\ndf['label_path']  = f'{LABEL_DIR}/' + df.image_id + '.txt'\ndf['annotations'] = df['annotations'].apply(eval)\n\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:40.858119Z","iopub.execute_input":"2022-04-11T05:13:40.858398Z","iopub.status.idle":"2022-04-11T05:13:41.372723Z","shell.execute_reply.started":"2022-04-11T05:13:40.858360Z","shell.execute_reply":"2022-04-11T05:13:41.370373Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Yolo models are only trained with data containing a starfish, get rid of the other rows when training","metadata":{}},{"cell_type":"code","source":"df['contains_bounding_boxes'] = df.annotations.apply(lambda x: len(x) > 0)\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:41.378125Z","iopub.execute_input":"2022-04-11T05:13:41.380232Z","iopub.status.idle":"2022-04-11T05:13:41.413702Z","shell.execute_reply.started":"2022-04-11T05:13:41.380188Z","shell.execute_reply":"2022-04-11T05:13:41.412804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# YOLOV5 does not need data where no bounding box exists\ndf = df[df['contains_bounding_boxes'] == True]\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:41.418564Z","iopub.execute_input":"2022-04-11T05:13:41.420716Z","iopub.status.idle":"2022-04-11T05:13:41.453714Z","shell.execute_reply.started":"2022-04-11T05:13:41.420677Z","shell.execute_reply":"2022-04-11T05:13:41.452984Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import shutil\nfor row in df.itertuples():\n    shutil.copyfile(row.old_image_path, row.image_path)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:13:41.457715Z","iopub.execute_input":"2022-04-11T05:13:41.459690Z","iopub.status.idle":"2022-04-11T05:14:52.890312Z","shell.execute_reply.started":"2022-04-11T05:13:41.459653Z","shell.execute_reply":"2022-04-11T05:14:52.889498Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# pillow\nfrom PIL import Image, ImageDraw, ImageFont","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:52.891492Z","iopub.execute_input":"2022-04-11T05:14:52.891756Z","iopub.status.idle":"2022-04-11T05:14:52.921177Z","shell.execute_reply.started":"2022-04-11T05:14:52.891721Z","shell.execute_reply":"2022-04-11T05:14:52.920540Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_bounding_boxes(annotations):\n    cots_locations = []\n    for annotation in annotations:\n        cots_locations.append(list(annotation.values()))\n    return cots_locations","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:52.924030Z","iopub.execute_input":"2022-04-11T05:14:52.924224Z","iopub.status.idle":"2022-04-11T05:14:52.928865Z","shell.execute_reply.started":"2022-04-11T05:14:52.924201Z","shell.execute_reply":"2022-04-11T05:14:52.928190Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Convert \"annotations\" column to \"bounding boxes\" column.. then normalize those values so the yolo model can read them","metadata":{}},{"cell_type":"code","source":"df['bounding_boxes'] = df.annotations.apply(get_bounding_boxes)\ndf['width'] = 1280\ndf['height'] = 720\n\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:52.930098Z","iopub.execute_input":"2022-04-11T05:14:52.930893Z","iopub.status.idle":"2022-04-11T05:14:52.963704Z","shell.execute_reply.started":"2022-04-11T05:14:52.930856Z","shell.execute_reply":"2022-04-11T05:14:52.962980Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def to_yolo(bounding_boxes):\n    yolo_boxes = []\n    for box in bounding_boxes:\n        # [label, normalized_x_center, n_y_center, n_width, n_height]\n        yolo_box = [0,0,0,0,0]\n        yolo_box[1] = box[0] / 1280\n        yolo_box[2] = box[1] / 720\n        yolo_box[3] = box[2] / 1280\n        yolo_box[4] = box[3] / 720\n        yolo_boxes.append(yolo_box)\n    return yolo_boxes\n\ndf['yolo_bounding_boxes'] = df.bounding_boxes.apply(to_yolo)\n\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:52.967079Z","iopub.execute_input":"2022-04-11T05:14:52.967284Z","iopub.status.idle":"2022-04-11T05:14:53.000224Z","shell.execute_reply.started":"2022-04-11T05:14:52.967259Z","shell.execute_reply":"2022-04-11T05:14:52.999383Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def annot_to_string(yolo_annotation):\n    annot_str = ''\n    for annot in yolo_annotation:\n        if annot_str != '':\n            annot_str += '\\n'\n        annot_str += str(annot).replace(',', '').replace('[', '').replace(']', '')\n    return annot_str\n\nfor row in df.itertuples():\n    annotated_string = annot_to_string(row.yolo_bounding_boxes)\n    with open(row.label_path, 'w') as label_file:\n        label_file.write(annotated_string)\n        label_file.close()","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:53.001906Z","iopub.execute_input":"2022-04-11T05:14:53.002397Z","iopub.status.idle":"2022-04-11T05:14:53.295090Z","shell.execute_reply.started":"2022-04-11T05:14:53.002356Z","shell.execute_reply":"2022-04-11T05:14:53.294344Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Display some of the training data","metadata":{}},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport cv2\ndf2 = df[df['contains_bounding_boxes'] == True].sample(100) # takes samples with bbox\ny = 3; x = 2\nplt.figure(figsize=(12.8*x, 7.2*y))\nfor idx in range(x*y):\n    row = df2.iloc[idx]\n    img           = plt.imread(row.image_path)\n    image_height  = row.height\n    image_width   = row.width\n    \n    bboxes = row.bounding_boxes\n    plt.subplot(y, x, idx+1)\n    \n    for box in bboxes:\n        # 0   x1,y1 ------ 1280\n        #     |          |\n        #     |          |\n        #     |          |\n        # 720 --------x2,y2\n        \n        x1 = box[0]\n        y1 = box[1]\n        \n        width = box[2]\n        height = box[3]\n        \n        x2 = x1 + width\n        y2 = y1 + height\n        \n        top_left = (x1,y1)\n        bottom_right = (x2,y2)\n        cv2.rectangle(img, top_left, bottom_right, (255,0,0), 2)\n\n        label = 'cots'\n        t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2 , 2)[0]\n        cv2.rectangle(img,(x1, y1),(x1+t_size[0],y1-t_size[1]), (255,0,0),-1)\n        cv2.putText(img,label,(x1,y1), cv2.FONT_HERSHEY_PLAIN, 2, [255,255,255], 2)\n\n    plt.axis('OFF')\n    plt.tight_layout()\n    plt.imshow(img)\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:53.296509Z","iopub.execute_input":"2022-04-11T05:14:53.296757Z","iopub.status.idle":"2022-04-11T05:14:56.592160Z","shell.execute_reply.started":"2022-04-11T05:14:53.296725Z","shell.execute_reply":"2022-04-11T05:14:56.591362Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Now we want to split the data we have into a test set and a training set\nNormally we could do this by taking ~20% of the dataframe and calling it the training set, leaving the rest for testing. The problem with that is we are training on videos. Luckily we know there are 3 videos in the dataset, so we can make the training dataframe the first video (video 0) and the test dataframe the second two videos (video 1 and video 2).\n\n```\ntrain_data = (subset of your main dataframe, where each row is part of video 0)\ntest_data = (subset of your main dataframe, where each row is part of video 1 and 2)\n```","metadata":{}},{"cell_type":"code","source":"df.video_id.unique()","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.593281Z","iopub.execute_input":"2022-04-11T05:14:56.593578Z","iopub.status.idle":"2022-04-11T05:14:56.606621Z","shell.execute_reply.started":"2022-04-11T05:14:56.593540Z","shell.execute_reply":"2022-04-11T05:14:56.602350Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_data = df[df[\"video_id\"] == 1]\ntest_data = df[df[\"video_id\"].isin([0, 2])]\n\nprint(\"Train Length:\", len(train_data))\nprint(\"Test Length:\", len(test_data))","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.608126Z","iopub.execute_input":"2022-04-11T05:14:56.609026Z","iopub.status.idle":"2022-04-11T05:14:56.621163Z","shell.execute_reply.started":"2022-04-11T05:14:56.608981Z","shell.execute_reply":"2022-04-11T05:14:56.620326Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create train and test path data\ntrain_images = list(train_data[\"image_path\"])\nwith open(\"/kaggle/working/train_images.txt\", \"w\") as file:\n    for path in train_images:\n        file.write(path + \"\\n\")\n        \ntest_images = list(test_data[\"image_path\"])\nwith open(\"/kaggle/working/test_images.txt\", \"w\") as file:\n    for path in test_images:\n        file.write(path + \"\\n\")","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.622331Z","iopub.execute_input":"2022-04-11T05:14:56.623033Z","iopub.status.idle":"2022-04-11T05:14:56.633394Z","shell.execute_reply.started":"2022-04-11T05:14:56.623000Z","shell.execute_reply":"2022-04-11T05:14:56.632645Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Configure the model","metadata":{}},{"cell_type":"code","source":"import yaml","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.634711Z","iopub.execute_input":"2022-04-11T05:14:56.635553Z","iopub.status.idle":"2022-04-11T05:14:56.667994Z","shell.execute_reply.started":"2022-04-11T05:14:56.635520Z","shell.execute_reply":"2022-04-11T05:14:56.667420Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"config = {\n    'path': '/kaggle/working',\n    'train': '/kaggle/working/train_images.txt',\n    'val': '/kaggle/working/test_images.txt',\n    'nc': 1,\n    'names': ['cots']\n }","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.669359Z","iopub.execute_input":"2022-04-11T05:14:56.669969Z","iopub.status.idle":"2022-04-11T05:14:56.674212Z","shell.execute_reply.started":"2022-04-11T05:14:56.669929Z","shell.execute_reply":"2022-04-11T05:14:56.673474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open(\"/kaggle/working/cots.yaml\", \"w\") as file:\n    yaml.dump(config, file, default_flow_style=False)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.675434Z","iopub.execute_input":"2022-04-11T05:14:56.676423Z","iopub.status.idle":"2022-04-11T05:14:56.688677Z","shell.execute_reply.started":"2022-04-11T05:14:56.676388Z","shell.execute_reply":"2022-04-11T05:14:56.687697Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"To use the model we need to have the following:\n\n    Yolov5 Repository (available in this dataset by Awsaf)\n    Python 3\n    PyTorch\n    CUDA","metadata":{}},{"cell_type":"code","source":"# installing Yolov5\n%cd /kaggle/working     \n!cp -r /kaggle/input/yolov5-lib-ds /kaggle/working/yolov5     \n%cd yolov5     \n%pip install -qr requirements.txt\n\nfrom yolov5 import utils\ndisplay = utils.notebook_init()","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:14:56.690197Z","iopub.execute_input":"2022-04-11T05:14:56.690424Z","iopub.status.idle":"2022-04-11T05:15:09.158113Z","shell.execute_reply.started":"2022-04-11T05:14:56.690398Z","shell.execute_reply":"2022-04-11T05:15:09.157266Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SIZE = 3000\nBATCH_SIZE = 4\nEPOCHS = 8\nMODEL = \"yolov5s\"\nOPTIMIZER = 'Adam'\nWORKERS = 1\nPROJECT = \"GreatBarrierReef\"\nRUN_NAME = f\"{MODEL}_size{SIZE}_epochs{EPOCHS}_batch{BATCH_SIZE}_simple\"","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:15:09.160155Z","iopub.execute_input":"2022-04-11T05:15:09.160459Z","iopub.status.idle":"2022-04-11T05:15:09.165985Z","shell.execute_reply.started":"2022-04-11T05:15:09.160417Z","shell.execute_reply":"2022-04-11T05:15:09.165206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train the model","metadata":{}},{"cell_type":"code","source":"# # We call the train.py file which is part of the yolov5 directory.\n# # This file will take parameters that we set up in the above config\n# ## Training - train.py can be found in yolov5 directory\n# !python train.py --img {SIZE}\\\n#                 --batch {BATCH_SIZE}\\\n#                 --epochs {EPOCHS}\\\n#                 --data /kaggle/working/cots.yaml\\\n#                 --weights {MODEL}.pt\\\n#                 --workers {WORKERS}\\\n#                 --project {PROJECT}\\\n#                 --name {RUN_NAME}\\\n#                 --exist-ok","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-04-11T05:15:11.878744Z","iopub.execute_input":"2022-04-11T05:15:11.878997Z","iopub.status.idle":"2022-04-11T05:15:11.885700Z","shell.execute_reply.started":"2022-04-11T05:15:11.878966Z","shell.execute_reply":"2022-04-11T05:15:11.884925Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load the trained model from the previous run","metadata":{}},{"cell_type":"code","source":"os.listdir('/kaggle/')","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:15:11.914699Z","iopub.execute_input":"2022-04-11T05:15:11.915335Z","iopub.status.idle":"2022-04-11T05:15:11.924041Z","shell.execute_reply.started":"2022-04-11T05:15:11.915281Z","shell.execute_reply":"2022-04-11T05:15:11.923059Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nmodel = torch.hub.load(\"/kaggle/input/yolov5-lib-ds\", \"custom\",\n                       path='/kaggle/input/yolov5300084/yolov5/GreatBarrierReef/yolov5s_size3000_epochs8_batch4_simple/weights/best.pt',\n                       source='local', force_reload=True)","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:15:11.925350Z","iopub.execute_input":"2022-04-11T05:15:11.925876Z","iopub.status.idle":"2022-04-11T05:15:22.349005Z","shell.execute_reply.started":"2022-04-11T05:15:11.925837Z","shell.execute_reply":"2022-04-11T05:15:22.348346Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# BoundingBox Confidence\nmodel.conf = 0.01\n# Intersection Over Union\nmodel.iou = 0.5","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:15:22.355023Z","iopub.execute_input":"2022-04-11T05:15:22.356930Z","iopub.status.idle":"2022-04-11T05:15:22.362872Z","shell.execute_reply.started":"2022-04-11T05:15:22.356887Z","shell.execute_reply":"2022-04-11T05:15:22.361747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport cv2\nfrom IPython.display import display","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:15:22.367987Z","iopub.execute_input":"2022-04-11T05:15:22.368793Z","iopub.status.idle":"2022-04-11T05:15:22.374130Z","shell.execute_reply.started":"2022-04-11T05:15:22.368753Z","shell.execute_reply":"2022-04-11T05:15:22.372782Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images_displayed = 0\n\nwhile images_displayed < 20:\n    image_path = test_data.sample(1).image_path.item()\n    prediction = model(image_path, size=3600, augment=True)\n\n    prediction_df = prediction.pandas().xyxy[0]\n    prediction_df = prediction_df[prediction_df.confidence >= 0.20]\n    starfish_found = prediction_df.shape[0]\n    if starfish_found < 1:\n        continue\n\n    print(f'Found {starfish_found} starfish within {image_path}')\n    display(prediction_df)\n\n    image = plt.imread(image_path)\n    for row in prediction_df.itertuples():\n        x1 = round(row.xmin)\n        y1 = round(row.ymin)\n\n        x2 = round(row.xmax)\n        y2 = round(row.ymax)\n\n        color = (0,255,0)\n\n        if row.confidence < 0.40:\n            color = (255,150,0)\n        elif row.confidence < 0.20:\n            color = (255,0,0)\n\n        cv2.rectangle(image, (x1,y1), (x2,y2), color, 2)\n\n        label = f'cots: {round(row.confidence * 100, 2)}%'\n        t_size = cv2.getTextSize(label, cv2.FONT_HERSHEY_PLAIN, 2 , 2)[0]\n        cv2.rectangle(image,(x1, y1),(x1+t_size[0],y1-t_size[1]), color,-1)\n        cv2.putText(image,label,(x1,y1), cv2.FONT_HERSHEY_PLAIN, 2, [255,255,255], 2)\n\n    plt.figure(figsize=(12.8*2, 7.2*2))\n    plt.imshow(image)\n    images_displayed = images_displayed + 1","metadata":{"execution":{"iopub.status.busy":"2022-04-11T05:18:11.075522Z","iopub.execute_input":"2022-04-11T05:18:11.075793Z","iopub.status.idle":"2022-04-11T05:18:44.247668Z","shell.execute_reply.started":"2022-04-11T05:18:11.075762Z","shell.execute_reply":"2022-04-11T05:18:44.245403Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}