{"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> Wykrywanie Koron cierniowych (rozgwiazd) na rafie koralowej\n\n<img src=\"https://storage.googleapis.com/kaggle-competitions/kaggle/31703/logos/header.png?t=2021-10-29-00-30-04\">","metadata":{"execution":{"iopub.status.busy":"2022-02-08T13:11:44.770075Z","iopub.execute_input":"2022-02-08T13:11:44.770547Z","iopub.status.idle":"2022-02-08T13:11:44.803418Z","shell.execute_reply.started":"2022-02-08T13:11:44.770457Z","shell.execute_reply":"2022-02-08T13:11:44.802216Z"}}},{"cell_type":"markdown","source":"# 🐣 Wstęp oraz inne informacje\n* Wyniki trzba zgłaszać przy pomocy dostarczonego **python time-series API**\n* Każdy wiersz zgłoszenia powinien zawierać wszystkie bbox-y (bounding box-y) na danej klatce filmu. Zgłoszenia powinny być w formacie **COCO** co oznacza: `[x_min, y_min, width, height]`\n* Oficjalną metryką zawadów jest: `F2`. Toleruje ona  wyniki false positives(FP), aby zapewnić, że mała ilość rozgwiazd zostanie pominięta. Oznacza to, że eliminacja wyników **false negatives(FN)** jest znacznie ważniejsza niż eliminacja wyników false positives(FP). \n$$F2 = 5 \\cdot \\frac{precision \\cdot recall}{4\\cdot precision + recall}$$\n\n* Notatniki, które pomogły wykonać ten notatnik:\n1. https://www.kaggle.com/ihorin/great-barrier-reef-yolov5-train-only\n2. https://www.kaggle.com/jillanisofttech/great-barrier-reef-yolov5\n3. https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-infer\n4. https://www.kaggle.com/awsaf49/great-barrier-reef-yolov5-train","metadata":{"execution":{"iopub.status.busy":"2022-02-08T13:20:13.067329Z","iopub.execute_input":"2022-02-08T13:20:13.067628Z","iopub.status.idle":"2022-02-08T13:20:13.072106Z","shell.execute_reply.started":"2022-02-08T13:20:13.06759Z","shell.execute_reply":"2022-02-08T13:20:13.07124Z"}}},{"cell_type":"markdown","source":"# 🛠 Instalacja bibliotek (wandb i bbox-utility)","metadata":{}},{"cell_type":"code","source":"!pip install -qU wandb # check https://github.com/wandb/client for more info\n!pip install -qU bbox-utility # check https://github.com/awsaf49/bbox for source code","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2022-02-11T00:10:57.263724Z","iopub.execute_input":"2022-02-11T00:10:57.264431Z","iopub.status.idle":"2022-02-11T00:11:18.059974Z","shell.execute_reply.started":"2022-02-11T00:10:57.264345Z","shell.execute_reply":"2022-02-11T00:11:18.059095Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📚 Importowanie bibliotek","metadata":{}},{"cell_type":"code","source":"import numpy as np\nfrom tqdm.notebook import tqdm\ntqdm.pandas()\nimport pandas as pd\nimport os\nimport cv2\nimport matplotlib.pyplot as plt\nimport glob\n\nfrom shutil import copyfile\nimport shutil\nimport sys\nsys.path.append('../input/tensorflow-great-barrier-reef')\n\nfrom joblib import Parallel, delayed\n\nfrom IPython.display import display","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:18.064085Z","iopub.execute_input":"2022-02-11T00:11:18.064707Z","iopub.status.idle":"2022-02-11T00:11:18.480475Z","shell.execute_reply.started":"2022-02-11T00:11:18.064672Z","shell.execute_reply":"2022-02-11T00:11:18.479773Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📜 WandB\n<img src=\"https://camo.githubusercontent.com/dd842f7b0be57140e68b2ab9cb007992acd131c48284eaf6b1aca758bfea358b/68747470733a2f2f692e696d6775722e636f6d2f52557469567a482e706e67\" width=600>\n\nW naszym projekcie wykorzystujemy W&B do śledzenia wyników uczenia oraz samego procesu. Przydaje się również on do zapisywania hiperparametrów i zapisywania wyników eksperymentów. Wszystkie najważniesze funkcje W&B to:\n\n* Przechowywanie hiperparametrów użytych w badaniu treningowym\n* Wyszukiwanie, porównywanie i wizualizacja przebiegów treningowych\n* Analizuj metryki użycia systemu wraz z przebiegami\n* Współpracuj z członkami zespołu\n* Replikuj wyniki historyczne\n* Wykonuj przeszukiwanie parametrów\n* Zachowaj zapisy eksperymentów z dostępem na zawsze\n","metadata":{}},{"cell_type":"code","source":"import wandb\n\ntry:\n    from kaggle_secrets import UserSecretsClient\n    user_secrets = UserSecretsClient()\n    api_key = user_secrets.get_secret(\"WANDB\")\n    wandb.login(key=api_key)\n    anonymous = None\nexcept:\n    wandb.login(anonymous='must')\n    print('To use your W&B account,\\nGo to Add-ons -> Secrets and provide your W&B access token. Use the Label name as WANDB. \\nGet your W&B access token from here: https://wandb.ai/authorize')","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:18.481927Z","iopub.execute_input":"2022-02-11T00:11:18.482197Z","iopub.status.idle":"2022-02-11T00:11:19.662878Z","shell.execute_reply.started":"2022-02-11T00:11:18.48216Z","shell.execute_reply":"2022-02-11T00:11:19.661821Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📖 Meta Data","metadata":{"execution":{"iopub.status.busy":"2022-02-08T14:09:27.279972Z","iopub.execute_input":"2022-02-08T14:09:27.280477Z","iopub.status.idle":"2022-02-08T14:09:27.283851Z","shell.execute_reply.started":"2022-02-08T14:09:27.280441Z","shell.execute_reply":"2022-02-08T14:09:27.283186Z"}}},{"cell_type":"code","source":"FOLD      = 1 # which fold to train\nDIM       = 4000\nMODEL     = 'yolov5s6'\nBATCH     = 2\nEPOCHS    = 5\nOPTMIZER  = 'Adam'\n\nPROJECT   = 'great-barrier-reef-public' # w&b in yolov5\nNAME      = f'{MODEL}-dim{DIM}-fold{FOLD}-bat{BATCH}-opt{OPTMIZER}-epch{EPOCHS}' # w&b for yolov5\n\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":"2022-02-11T00:11:19.665197Z","iopub.execute_input":"2022-02-11T00:11:19.665475Z","iopub.status.idle":"2022-02-11T00:11:19.671462Z","shell.execute_reply.started":"2022-02-11T00:11:19.665434Z","shell.execute_reply":"2022-02-11T00:11:19.670817Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📁 Stworzenie folderów pod YOLOv5","metadata":{}},{"cell_type":"code","source":"!mkdir -p {IMAGE_DIR}\n!mkdir -p {LABEL_DIR}","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:19.672595Z","iopub.execute_input":"2022-02-11T00:11:19.673199Z","iopub.status.idle":"2022-02-11T00:11:21.00073Z","shell.execute_reply.started":"2022-02-11T00:11:19.673158Z","shell.execute_reply":"2022-02-11T00:11:20.999813Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📎 Get Paths","metadata":{}},{"cell_type":"code","source":"# Train Data\ndf = pd.read_csv(f'{ROOT_DIR}/train.csv')\ndf['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'].progress_apply(eval)\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:21.002631Z","iopub.execute_input":"2022-02-11T00:11:21.002938Z","iopub.status.idle":"2022-02-11T00:11:21.54711Z","shell.execute_reply.started":"2022-02-11T00:11:21.002899Z","shell.execute_reply":"2022-02-11T00:11:21.546473Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## 📦 Liczba bounding box-ów\n* Sprawdzamy ile klatek z filmu posiada bounding box-y","metadata":{"execution":{"iopub.status.busy":"2022-02-08T14:14:21.901591Z","iopub.execute_input":"2022-02-08T14:14:21.901898Z","iopub.status.idle":"2022-02-08T14:14:21.905692Z","shell.execute_reply.started":"2022-02-08T14:14:21.901865Z","shell.execute_reply":"2022-02-08T14:14:21.904977Z"}}},{"cell_type":"code","source":"df['num_bbox'] = df['annotations'].progress_apply(lambda x: len(x))\ndata = (df.num_bbox>0).value_counts(normalize=True)*100\nprint(f\"No BBox: {data[0]:0.2f}% | With BBox: {data[1]:0.2f}%\")","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:21.550774Z","iopub.execute_input":"2022-02-11T00:11:21.552753Z","iopub.status.idle":"2022-02-11T00:11:21.721259Z","shell.execute_reply.started":"2022-02-11T00:11:21.552714Z","shell.execute_reply":"2022-02-11T00:11:21.720608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🧹 Czyszczenie zbioru [TEST] trzeba potem przetrenowac model na braku boxów\n* uzyjemy tylko **bboxed-images** (`~5k`), z powodu bardzo dużego zbioru (`~23k`), a jednocześnie braku zasobów obliczeniowych do obliczania wag w bardzo dużych modelach (GPU time na kagglu).","metadata":{}},{"cell_type":"code","source":"if REMOVE_NOBBOX:\n    df = df.query(\"num_bbox>0\")","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:21.725104Z","iopub.execute_input":"2022-02-11T00:11:21.727022Z","iopub.status.idle":"2022-02-11T00:11:21.74925Z","shell.execute_reply.started":"2022-02-11T00:11:21.726985Z","shell.execute_reply":"2022-02-11T00:11:21.748489Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ✏️ Zmiana folderu klatek filmu\n* Potrzebne są nam wszystkie prawa do obrazka, dlatego zmieniamy ich folder\n* możemy ten proces uczynić szybszy przy pomocy **Joblib**, który używa obliczania równoległego.","metadata":{}},{"cell_type":"code","source":"def make_copy(row):\n    shutil.copyfile(row.old_image_path, row.image_path)\n    return","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:21.753476Z","iopub.execute_input":"2022-02-11T00:11:21.755553Z","iopub.status.idle":"2022-02-11T00:11:21.761572Z","shell.execute_reply.started":"2022-02-11T00:11:21.755488Z","shell.execute_reply":"2022-02-11T00:11:21.760663Z"},"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)(row) for _, row in tqdm(df.iterrows(), total=len(df)))","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:21.767694Z","iopub.execute_input":"2022-02-11T00:11:21.769909Z","iopub.status.idle":"2022-02-11T00:11:52.221464Z","shell.execute_reply.started":"2022-02-11T00:11:21.769871Z","shell.execute_reply":"2022-02-11T00:11:52.220722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🔨 Funkcje pomocnicze (?)","metadata":{}},{"cell_type":"code","source":"# check https://github.com/awsaf49/bbox for source code of following utility functions\nfrom bbox.utils import coco2yolo, coco2voc, voc2yolo\nfrom bbox.utils import draw_bboxes, load_image\nfrom bbox.utils import clip_bbox, str2annot, annot2str\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":{"execution":{"iopub.status.busy":"2022-02-11T00:11:52.222465Z","iopub.execute_input":"2022-02-11T00:11:52.222699Z","iopub.status.idle":"2022-02-11T00:11:53.117559Z","shell.execute_reply.started":"2022-02-11T00:11:52.222669Z","shell.execute_reply":"2022-02-11T00:11:53.116853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Stworzenie kolumny BBox-ów w data frame-ie","metadata":{}},{"cell_type":"code","source":"df['bboxes'] = df.annotations.progress_apply(get_bbox)\ndf.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:53.118811Z","iopub.execute_input":"2022-02-11T00:11:53.1193Z","iopub.status.idle":"2022-02-11T00:11:53.364102Z","shell.execute_reply.started":"2022-02-11T00:11:53.119262Z","shell.execute_reply":"2022-02-11T00:11:53.363296Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Stowrzenie kolumny wielkości obrazów w data frame-ie\n> All Images have same dimension, [Width, Height] =  `[1280, 720]`","metadata":{}},{"cell_type":"code","source":"df['width']  = 1280\ndf['height'] = 720\ndisplay(df.head(2))","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:53.36543Z","iopub.execute_input":"2022-02-11T00:11:53.365751Z","iopub.status.idle":"2022-02-11T00:11:53.387636Z","shell.execute_reply.started":"2022-02-11T00:11:53.365713Z","shell.execute_reply":"2022-02-11T00:11:53.387004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🏷️ Tworzenie etykiet w formie plików `*.txt`\nTrzeba przeeksportować etykiety do formatu **YOLO**, z jednym plikiem `*.txt` na każdą klatkę video (jeżeli nie ma bbox-a na klatce, to plik `*.txt` nie jest wymagany). wymagania pliku `*.txt`  wyglądają następująco:\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.","metadata":{}},{"cell_type":"code","source":"cnt = 0\nall_bboxes = []\nbboxes_info = []\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       = np.array([0]*num_bbox)[..., None].astype(str)\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_voc  = coco2voc(bboxes_coco, image_height, image_width)\n        bboxes_voc  = clip_bbox(bboxes_voc, image_height, image_width)\n        bboxes_yolo = voc2yolo(bboxes_voc, image_height, image_width).astype(str)\n        all_bboxes.extend(bboxes_yolo.astype(float))\n        bboxes_info.extend([[row.image_id, row.video_id, row.sequence]]*len(bboxes_yolo))\n        annots = np.concatenate([labels, bboxes_yolo], axis=1)\n        string = annot2str(annots)\n        f.write(string)\nprint('Missing:',cnt)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:53.39018Z","iopub.execute_input":"2022-02-11T00:11:53.390374Z","iopub.status.idle":"2022-02-11T00:11:58.184853Z","shell.execute_reply.started":"2022-02-11T00:11:53.390351Z","shell.execute_reply":"2022-02-11T00:11:58.183852Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🦾 Data Augmentation \n* Z każdej klatki wideo tworzymy nową klatkę z drobnymi zmianami. zmiemy kontrast, ostrość, saturacje, szum lub dodajemy wszystko naraz (AKA. Fancy Rhea).","metadata":{}},{"cell_type":"code","source":"#df = df.reset_index(drop=True)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:13:08.751593Z","iopub.execute_input":"2022-02-11T00:13:08.751888Z","iopub.status.idle":"2022-02-11T00:13:08.757439Z","shell.execute_reply.started":"2022-02-11T00:13:08.751858Z","shell.execute_reply":"2022-02-11T00:13:08.756668Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import random\n\ndef fancy_rhea_augumentation(path):\n    img = cv2.imread(path, cv2.IMREAD_COLOR)\n    i =  random.randint(0, 4)\n    if(i == 0 or i == 4):\n        #contrast\n        rand = random.uniform(0.3, 1.2)\n        alpha = rand\n        img = cv2.convertScaleAbs(img, alpha=alpha)\n    if (i == 1 or i == 4):\n        #sharpness\n        kernel = np.array([[0,-1,0], [-1,5,-1], [0,-1,0]])\n        img = cv2.filter2D(img, -1, kernel)\n    if (i == 2 or i == 4):\n        #saturation\n        img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)\n        (h, s, v) = cv2.split(img_hsv)\n        rand = random.choice([2,3,0.5])\n        if(rand == 0.5):\n            s = s * 2\n        else:\n            s = s // rand \n        s = np.clip(s,0,255)\n        imghsv = cv2.merge([h,s,v])\n        img = cv2.cvtColor(imghsv.astype(\"uint8\"), cv2.COLOR_HSV2BGR)\n    if (i == 3 or i == 4):\n        #noise\n        gauss = np.random.normal(0,1,img.size)\n        gauss = gauss.reshape(img.shape[0],img.shape[1],img.shape[2]).astype('uint8')\n        img = img * gauss + img\n    return img","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:11:58.187645Z","iopub.execute_input":"2022-02-11T00:11:58.187969Z","iopub.status.idle":"2022-02-11T00:11:58.206205Z","shell.execute_reply.started":"2022-02-11T00:11:58.187928Z","shell.execute_reply":"2022-02-11T00:11:58.204436Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for i in range(len(df)):\n#     row = df.loc[i]\n#     img = fancy_rhea_augumentation(f'{IMAGE_DIR}/{row.image_id}.jpg')\n#     cv2.imwrite(f'{IMAGE_DIR}/{row.image_id}_2.jpg', img)\n    \n#     #Adding to df\n#     row.image_path = f'{IMAGE_DIR}/{row.image_id}_2.jpg'\n#     df = df.append(row,ignore_index=True)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:13:31.887004Z","iopub.execute_input":"2022-02-11T00:13:31.887709Z","iopub.status.idle":"2022-02-11T00:20:16.3689Z","shell.execute_reply.started":"2022-02-11T00:13:31.887663Z","shell.execute_reply":"2022-02-11T00:20:16.368237Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# for file_name in os.listdir(LABEL_DIR):\n#     if (\"_2.txt\" in file_name):\n#         continue\n#     source = LABEL_DIR + \"/\" + file_name\n#     copyfile(source, source.replace(\".txt\", \"_2.txt\"))","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:07.573158Z","iopub.execute_input":"2022-02-11T00:21:07.573522Z","iopub.status.idle":"2022-02-11T00:21:08.263403Z","shell.execute_reply.started":"2022-02-11T00:21:07.573484Z","shell.execute_reply":"2022-02-11T00:21:08.262352Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📁 Tworzenie foldów\n>  **Cross-Validation**.","metadata":{}},{"cell_type":"code","source":"from sklearn.model_selection import GroupKFold\nkf = GroupKFold(n_splits = 3)\ndf = df.reset_index(drop=True)\ndf['fold'] = -1\nfor fold, (train_idx, val_idx) in enumerate(kf.split(df, groups=df.video_id.tolist())):\n    df.loc[val_idx, 'fold'] = fold\ndisplay(df.fold.value_counts())","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:09.829259Z","iopub.execute_input":"2022-02-11T00:21:09.829507Z","iopub.status.idle":"2022-02-11T00:21:10.573463Z","shell.execute_reply.started":"2022-02-11T00:21:09.829477Z","shell.execute_reply":"2022-02-11T00:21:10.572728Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ⭕ `[Data Science]` BBox Distribution","metadata":{"execution":{"iopub.status.busy":"2022-02-08T14:28:55.35642Z","iopub.execute_input":"2022-02-08T14:28:55.356794Z","iopub.status.idle":"2022-02-08T14:28:55.362043Z","shell.execute_reply.started":"2022-02-08T14:28:55.356748Z","shell.execute_reply":"2022-02-08T14:28:55.360989Z"}}},{"cell_type":"code","source":"bbox_df = pd.DataFrame(np.concatenate([bboxes_info, all_bboxes], axis=1),\n             columns=['image_id','video_id','sequence',\n                     'xmid','ymid','w','h'])\nbbox_df[['xmid','ymid','w','h']] = bbox_df[['xmid','ymid','w','h']].astype(float)\nbbox_df['area'] = bbox_df.w * bbox_df.h * 1280 * 720\nbbox_df = bbox_df.merge(df[['image_id','fold']], on='image_id', how='left')\nbbox_df.head(2)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:12.61369Z","iopub.execute_input":"2022-02-11T00:21:12.614376Z","iopub.status.idle":"2022-02-11T00:21:12.752305Z","shell.execute_reply.started":"2022-02-11T00:21:12.614336Z","shell.execute_reply":"2022-02-11T00:21:12.751653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## `x_center` Vs `y_center`","metadata":{}},{"cell_type":"code","source":"from scipy.stats import gaussian_kde\n\nall_bboxes = np.array(all_bboxes)\n\nx_val = all_bboxes[...,0]\ny_val = all_bboxes[...,1]\n\n# Calculate the point density\nxy = np.vstack([x_val,y_val])\nz = gaussian_kde(xy)(xy)\n\nfig, ax = plt.subplots(figsize = (12.8, 7.2))\n# ax.axis('off')\nax.scatter(x_val, y_val, c=z, s=100, cmap='viridis')\n# ax.set_xlabel('x_mid')\n# ax.set_ylabel('y_mid')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:18.180482Z","iopub.execute_input":"2022-02-11T00:21:18.180736Z","iopub.status.idle":"2022-02-11T00:21:20.389177Z","shell.execute_reply.started":"2022-02-11T00:21:18.180709Z","shell.execute_reply":"2022-02-11T00:21:20.386946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## `width` Vs `height`","metadata":{}},{"cell_type":"code","source":"x_val = all_bboxes[...,2]\ny_val = all_bboxes[...,3]\n\n# Calculate the point density\nxy = np.vstack([x_val,y_val])\nz = gaussian_kde(xy)(xy)\n\nfig, ax = plt.subplots(figsize = (10, 10))\n# ax.axis('off')\nax.scatter(x_val, y_val, c=z, s=100, cmap='viridis')\n# ax.set_xlabel('bbox_width')\n# ax.set_ylabel('bbox_height')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:23.038713Z","iopub.execute_input":"2022-02-11T00:21:23.039389Z","iopub.status.idle":"2022-02-11T00:21:25.160102Z","shell.execute_reply.started":"2022-02-11T00:21:23.039355Z","shell.execute_reply":"2022-02-11T00:21:25.159446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Area","metadata":{}},{"cell_type":"code","source":"import matplotlib as mpl\nimport seaborn as sns\n\nf, ax = plt.subplots(figsize=(12, 6))\nsns.despine(f)\n\nsns.histplot(\n    bbox_df,\n    x=\"area\", hue=\"fold\",\n    multiple=\"stack\",\n    palette=\"viridis\",\n    edgecolor=\".3\",\n    linewidth=.5,\n    log_scale=True,\n)\nax.xaxis.set_major_formatter(mpl.ticker.ScalarFormatter())\nax.set_xticks([500, 1000, 2000, 5000, 10000]);","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:25.161544Z","iopub.execute_input":"2022-02-11T00:21:25.161884Z","iopub.status.idle":"2022-02-11T00:21:26.283536Z","shell.execute_reply.started":"2022-02-11T00:21:25.161842Z","shell.execute_reply":"2022-02-11T00:21:26.282853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🌈 `[Data Science]` Wizualizacja klatek z BBox-ami","metadata":{}},{"cell_type":"code","source":"df2 = df[(df.num_bbox>0)].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           = load_image(row.image_path)\n    image_height  = row.height\n    image_width   = row.width\n    with open(row.label_path) as f:\n        annot = str2annot(f.read())\n    bboxes_yolo = annot[...,1:]\n    labels      = annot[..., 0].astype(int).tolist()\n    names         = ['cots']*len(bboxes_yolo)\n    plt.subplot(y, x, idx+1)\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')\nplt.tight_layout()\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:32.455183Z","iopub.execute_input":"2022-02-11T00:21:32.455709Z","iopub.status.idle":"2022-02-11T00:21:35.272059Z","shell.execute_reply.started":"2022-02-11T00:21:32.455675Z","shell.execute_reply":"2022-02-11T00:21:35.269886Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🍚 Dataset do uczenia modelu YOLOv5","metadata":{}},{"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":"2022-02-11T00:21:39.438726Z","iopub.execute_input":"2022-02-11T00:21:39.439416Z","iopub.status.idle":"2022-02-11T00:21:39.458352Z","shell.execute_reply.started":"2022-02-11T00:21:39.439381Z","shell.execute_reply":"2022-02-11T00:21:39.45768Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ⚙️ Configuration\nPotrzeba stworzyć pliki yaml\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 , 'gbr.yaml'), 'w') as outfile:\n    yaml.dump(data, outfile, default_flow_style=False)\n\nf = open(os.path.join( cwd , 'gbr.yaml'), 'r')\nprint('\\nyaml:')\nprint(f.read())","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:52.162603Z","iopub.execute_input":"2022-02-11T00:21:52.162916Z","iopub.status.idle":"2022-02-11T00:21:52.181578Z","shell.execute_reply.started":"2022-02-11T00:21:52.162884Z","shell.execute_reply":"2022-02-11T00:21:52.180529Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%writefile /kaggle/working/hyp.yaml\nlr0: 0.001  # initial learning rate (SGD=1E-2, Adam=1E-3)\nlrf: 0.1  # final OneCycleLR learning rate (lr0 * lrf)\nmomentum: 0.937  # SGD momentum/Adam beta1\nweight_decay: 0.0005  # optimizer weight decay 5e-4\nwarmup_epochs: 4.0  # warmup epochs (fractions ok)\nwarmup_momentum: 0.8  # warmup initial momentum\nwarmup_bias_lr: 0.1  # warmup initial bias lr\nbox: 0.05  # box loss gain\ncls: 0.5  # cls loss gain\ncls_pw: 1.0  # cls BCELoss positive_weight\nobj: 1.0  # obj loss gain (scale with pixels)\nobj_pw: 1.0  # obj BCELoss positive_weight\niou_t: 0.20  # IoU training threshold\nanchor_t: 4.0  # anchor-multiple threshold\n# anchors: 3  # anchors per output layer (0 to ignore)\nfl_gamma: 0.0  # focal loss gamma (efficientDet default gamma=1.5)\nhsv_h: 0.015  # image HSV-Hue augmentation (fraction)\nhsv_s: 0.7  # image HSV-Saturation augmentation (fraction)\nhsv_v: 0.4  # image HSV-Value augmentation (fraction)\ndegrees: 0.0  # image rotation (+/- deg)\ntranslate: 0.10  # image translation (+/- fraction)\nscale: 0.5  # image scale (+/- gain)\nshear: 0.0  # image shear (+/- deg)\nperspective: 0.0  # image perspective (+/- fraction), range 0-0.001\nflipud: 0.5  # image flip up-down (probability)\nfliplr: 0.5  # image flip left-right (probability)\nmosaic: 0.5  # image mosaic (probability)\nmixup: 0.5 # image mixup (probability)\ncopy_paste: 0.0  # segment copy-paste (probability)","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:53.726315Z","iopub.execute_input":"2022-02-11T00:21:53.726707Z","iopub.status.idle":"2022-02-11T00:21:53.734055Z","shell.execute_reply.started":"2022-02-11T00:21:53.726672Z","shell.execute_reply":"2022-02-11T00:21:53.733071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 📦 [YOLOv5](https://github.com/ultralytics/yolov5/)\n","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()  # check","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:21:55.923962Z","iopub.execute_input":"2022-02-11T00:21:55.92445Z","iopub.status.idle":"2022-02-11T00:22:09.536564Z","shell.execute_reply.started":"2022-02-11T00:21:55.924418Z","shell.execute_reply":"2022-02-11T00:22:09.53571Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 🚅 Training","metadata":{}},{"cell_type":"code","source":"!python train.py --img {DIM}\\\n--batch {BATCH}\\\n--epochs {EPOCHS}\\\n--data /kaggle/working/gbr.yaml\\\n--hyp /kaggle/working/hyp.yaml\\\n--weights {MODEL}.pt\\\n--optimizer {OPTMIZER}\\\n--project {PROJECT} --name {NAME}\\\n--exist-ok","metadata":{"execution":{"iopub.status.busy":"2022-02-11T00:22:25.841373Z","iopub.execute_input":"2022-02-11T00:22:25.841693Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# ✂️ Usuwanie zbędnych plików (przekazujemy output do INFER)","metadata":{}},{"cell_type":"code","source":"!rm -r {IMAGE_DIR}\n!rm -r {LABEL_DIR}","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}