{"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":"# ❗️ Inputs needed\n- `libcuda.so` imported from [here](https://www.kaggle.com/denispotapov/libcuda)\n- Turn on GPU","metadata":{}},{"cell_type":"markdown","source":"<a id=\"section-one\"></a>\n## Importing libraries","metadata":{}},{"cell_type":"code","source":"import os, stat\nimport cv2\nfrom PIL import Image\ntrain_on_gpu = True\n\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n%matplotlib inline","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:14:07.248549Z","iopub.execute_input":"2022-03-21T01:14:07.248929Z","iopub.status.idle":"2022-03-21T01:14:07.65858Z","shell.execute_reply.started":"2022-03-21T01:14:07.248844Z","shell.execute_reply":"2022-03-21T01:14:07.657884Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Setting up Darknet","metadata":{}},{"cell_type":"code","source":"!git clone https://github.com/AlexeyAB/darknet","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:14:08.368558Z","iopub.execute_input":"2022-03-21T01:14:08.36924Z","iopub.status.idle":"2022-03-21T01:14:11.687173Z","shell.execute_reply.started":"2022-03-21T01:14:08.369204Z","shell.execute_reply":"2022-03-21T01:14:11.686245Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Build Darknet with GPU enable settings\n%cd darknet\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","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:14:11.689325Z","iopub.execute_input":"2022-03-21T01:14:11.689579Z","iopub.status.idle":"2022-03-21T01:14:16.704257Z","shell.execute_reply.started":"2022-03-21T01:14:11.689533Z","shell.execute_reply":"2022-03-21T01:14:16.703311Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# verify CUDA\n!/usr/local/cuda/bin/nvcc --version","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:14:16.707919Z","iopub.execute_input":"2022-03-21T01:14:16.708147Z","iopub.status.idle":"2022-03-21T01:14:17.368354Z","shell.execute_reply.started":"2022-03-21T01:14:16.708116Z","shell.execute_reply":"2022-03-21T01:14:17.367604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# make darknet (builds darknet so that you can then use the darknet executable file to run or train object detectors)\n!make","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-21T01:14:17.370816Z","iopub.execute_input":"2022-03-21T01:14:17.371085Z","iopub.status.idle":"2022-03-21T01:15:40.796834Z","shell.execute_reply.started":"2022-03-21T01:14:17.371046Z","shell.execute_reply":"2022-03-21T01:15:40.795889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#Verify build\n!./darknet detector train","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:40.800631Z","iopub.execute_input":"2022-03-21T01:15:40.800896Z","iopub.status.idle":"2022-03-21T01:15:44.011399Z","shell.execute_reply.started":"2022-03-21T01:15:40.800862Z","shell.execute_reply":"2022-03-21T01:15:44.010623Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Helper functions","metadata":{}},{"cell_type":"code","source":"def rle_decode(mask_rle: str = '', shape: tuple = (1400, 2100)):\n    '''\n    Decode rle encoded mask.\n    \n    :param mask_rle: run-length as string formatted (start length)\n    :param shape: (height, width) of array to return \n    Returns numpy array, 1 - mask, 0 - background\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n    starts -= 1\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    return img.reshape(shape, order='F')\n\ndef get_mask_info(mask_rle: str = '', shape: tuple = (1400, 2100)):\n    '''\n    Darknet wants a .txt file for each image with a line for each ground truth object in the image that looks like:\n    <object-class> <x> <y> <width> <height>\n    \n    So this method gets x, y, width, and height from the rle (run-length encoding) encoded mask.\n\n    :param mask_rle: run-length as string formatted (start length)\n    :param shape: (height, width) of array to return \n    Returns array of tuples (x, y, width, height)\n    '''\n    s = mask_rle.split()\n    starts, lengths = [np.asarray(x, dtype=int) for x in (s[0:][::2], s[1:][::2])]\n\n    starts -= 1 # array index starts with 0\n    ends = starts + lengths\n    img = np.zeros(shape[0] * shape[1], dtype=np.uint8)\n    for lo, hi in zip(starts, ends):\n        img[lo:hi] = 1\n    img = np.reshape(img, shape, order='F')\n\n    mask_indices = np.where(img == 1)\n    # np.where returns row_indices,col_indices so y corresponds to row and x corresponds to col\n\n    # find max x & y and min x & y - this will give us our bounding box\n    min_x = np.amin(mask_indices[1]) + 1\n    min_y = np.amin(mask_indices[0]) + 1\n    max_x = np.amax(mask_indices[1]) + 1\n    max_y = np.amax(mask_indices[0]) + 1\n\n    mask_info = (min_x, min_y, max_x-min_x, max_y-min_y)\n\n    return mask_info\n\ndef imShow(path):\n    image = cv2.imread(path)\n    height, width = image.shape[:2]\n    resized_image = cv2.resize(image,(3*width, 3*height), interpolation = cv2.INTER_CUBIC)\n    \n    fig = plt.gcf()\n    fig.set_size_inches(18, 10)\n    plt.axis(\"off\")\n    plt.imshow(cv2.cvtColor(resized_image, cv2.COLOR_BGR2RGB))\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:44.012906Z","iopub.execute_input":"2022-03-21T01:15:44.013177Z","iopub.status.idle":"2022-03-21T01:15:44.031304Z","shell.execute_reply.started":"2022-03-21T01:15:44.013138Z","shell.execute_reply":"2022-03-21T01:15:44.030612Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Data overview\n\nLet's have a look at the data first.","metadata":{}},{"cell_type":"code","source":"path = '../../input/understanding_cloud_organization'\nos.listdir(path)","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:44.03565Z","iopub.execute_input":"2022-03-21T01:15:44.035847Z","iopub.status.idle":"2022-03-21T01:15:44.048351Z","shell.execute_reply.started":"2022-03-21T01:15:44.035824Z","shell.execute_reply":"2022-03-21T01:15:44.047519Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We have folders with train and test images, file with train image ids and masks and sample submission.","metadata":{}},{"cell_type":"code","source":"train = pd.read_csv(f'{path}/train.csv')\nsub = pd.read_csv(f'{path}/sample_submission.csv')","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:44.049466Z","iopub.execute_input":"2022-03-21T01:15:44.049716Z","iopub.status.idle":"2022-03-21T01:15:47.348335Z","shell.execute_reply.started":"2022-03-21T01:15:44.049684Z","shell.execute_reply":"2022-03-21T01:15:47.347603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.head()","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.349665Z","iopub.execute_input":"2022-03-21T01:15:47.349904Z","iopub.status.idle":"2022-03-21T01:15:47.366682Z","shell.execute_reply.started":"2022-03-21T01:15:47.349873Z","shell.execute_reply":"2022-03-21T01:15:47.366025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_train = len(os.listdir(f'{path}/train_images'))\nn_test = len(os.listdir(f'{path}/test_images'))\nprint(f'There are {n_train} images in train dataset')\nprint(f'There are {n_test} images in test dataset')","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.367791Z","iopub.execute_input":"2022-03-21T01:15:47.368128Z","iopub.status.idle":"2022-03-21T01:15:47.858486Z","shell.execute_reply.started":"2022-03-21T01:15:47.368066Z","shell.execute_reply":"2022-03-21T01:15:47.857749Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train['Image_Label'].apply(lambda x: x.split('_')[1]).value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.859977Z","iopub.execute_input":"2022-03-21T01:15:47.860266Z","iopub.status.idle":"2022-03-21T01:15:47.890444Z","shell.execute_reply.started":"2022-03-21T01:15:47.860229Z","shell.execute_reply":"2022-03-21T01:15:47.888328Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"So we have ~5.5k images in train dataset and they can have up to 4 masks: Fish, Flower, Gravel and Sugar.","metadata":{}},{"cell_type":"code","source":"train.loc[train['EncodedPixels'].isnull() == False, 'Image_Label'].apply(lambda x: x.split('_')[1]).value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.893517Z","iopub.execute_input":"2022-03-21T01:15:47.894075Z","iopub.status.idle":"2022-03-21T01:15:47.927091Z","shell.execute_reply.started":"2022-03-21T01:15:47.894031Z","shell.execute_reply":"2022-03-21T01:15:47.926421Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train.loc[train['EncodedPixels'].isnull() == False, 'Image_Label'].apply(lambda x: x.split('_')[0]).value_counts().value_counts()","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.928424Z","iopub.execute_input":"2022-03-21T01:15:47.928681Z","iopub.status.idle":"2022-03-21T01:15:47.975804Z","shell.execute_reply.started":"2022-03-21T01:15:47.928648Z","shell.execute_reply":"2022-03-21T01:15:47.975017Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"But there are a lot of empty masks. In fact only 266 images have all four masks. It is important to remember this.","metadata":{}},{"cell_type":"code","source":"train['label'] = train['Image_Label'].apply(lambda x: x.split('_')[1])\ntrain['im_id'] = train['Image_Label'].apply(lambda x: x.split('_')[0])\n\n\nsub['label'] = sub['Image_Label'].apply(lambda x: x.split('_')[1])\nsub['im_id'] = sub['Image_Label'].apply(lambda x: x.split('_')[0])","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:47.979802Z","iopub.execute_input":"2022-03-21T01:15:47.980493Z","iopub.status.idle":"2022-03-21T01:15:48.060059Z","shell.execute_reply.started":"2022-03-21T01:15:47.980449Z","shell.execute_reply":"2022-03-21T01:15:48.0585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Let's have a look at the images and the masks.","metadata":{}},{"cell_type":"code","source":"fig = plt.figure(figsize=(25, 16))\nfor j, im_id in enumerate(np.random.choice(train['im_id'].unique(), 4)):\n    for i, (idx, row) in enumerate(train.loc[train['im_id'] == im_id].iterrows()):\n        ax = fig.add_subplot(5, 4, j * 4 + i + 1, xticks=[], yticks=[])\n        im = Image.open(f\"{path}/train_images/{row['Image_Label'].split('_')[0]}\")\n        plt.imshow(im)\n        mask_rle = row['EncodedPixels']\n        try: # label might not be there!\n            mask = rle_decode(mask_rle)\n        except:\n            mask = np.zeros((1400, 2100))\n        plt.imshow(mask, alpha=0.5, cmap='gray')\n        ax.set_title(f\"Image: {row['Image_Label'].split('_')[0]}. Label: {row['label']}\")","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:15:48.065081Z","iopub.execute_input":"2022-03-21T01:15:48.065553Z","iopub.status.idle":"2022-03-21T01:16:02.785244Z","shell.execute_reply.started":"2022-03-21T01:15:48.06551Z","shell.execute_reply":"2022-03-21T01:16:02.784611Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"We can see that masks can overlap. Also we can see that clouds are really similar to fish, flower and so on. Another important point: masks are often quite big and can have seemingly empty areas.","metadata":{}},{"cell_type":"markdown","source":"## Preparing data for modelling\n\nWe want to prepare the data for use with YOLOv4.   \nDarknet wants a .txt file for each image with a line for each ground truth object in the image that looks like:\n```\n<object-class> <x> <y> <width> <height>\n```\nWhere x, y, width, and height are relative to the image's width and height.\nOur train.csv file has an image label and EncodedPixels: we are given pairs of a starting pixel and the length of pixels after it that are under the label.\n\nEnd goal: Have images and label files for each image in an obj folder, which we will then put in /darknet/data/.","metadata":{}},{"cell_type":"markdown","source":"First, create **obj** folder which we'll put all of our images and their respective label files in. Copy the image files from **train_images** to this folder.","metadata":{}},{"cell_type":"code","source":"src = path + '/train_images'\n!cp -R \"$src\"* \"../obj\"\n!ls\n\n# below copies all files from train_images into existing 'obj' directory\n# src = path + '/train_images/'\n# !cp \"$src\"* \"../obj\"","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:16:02.786151Z","iopub.execute_input":"2022-03-21T01:16:02.786361Z","iopub.status.idle":"2022-03-21T01:17:10.511636Z","shell.execute_reply.started":"2022-03-21T01:16:02.786333Z","shell.execute_reply":"2022-03-21T01:17:10.510777Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now, iterate through all of the data from train.csv. This gives us the labels and their encodings for each image, which we store in txt files.","metadata":{}},{"cell_type":"code","source":"for index, row in train.iterrows():\n    mask_rle = row['EncodedPixels']\n    try: # label might not be there!\n        mask = get_mask_info(mask_rle)\n    except:\n        mask = ()\n        \n    image_id = row['Image_Label'].split('.jpg_')[0]\n    label = row['Image_Label'].split('.jpg_')[1]\n    with open(\"../obj/\" + image_id + \".txt\", \"a\") as f:\n        if mask:\n            f.write(label + \" %d %d %d %d\\n\" % mask)","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-21T01:17:10.514062Z","iopub.execute_input":"2022-03-21T01:17:10.514343Z","iopub.status.idle":"2022-03-21T01:20:50.057267Z","shell.execute_reply.started":"2022-03-21T01:17:10.514302Z","shell.execute_reply":"2022-03-21T01:20:50.056488Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Make sure we have the right number of files.","metadata":{}},{"cell_type":"code","source":"label_count = 0\nim_count = 0\nfor file in os.listdir(\"../obj\"):\n    if file.endswith(\".txt\"):\n        label_count += 1\n    elif file.endswith(\".jpg\"):\n        im_count += 1\n        \nprint(f'Number of label files {label_count}')\nprint(f'Number of image files {im_count}')","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:20:50.058632Z","iopub.execute_input":"2022-03-21T01:20:50.058874Z","iopub.status.idle":"2022-03-21T01:20:50.075868Z","shell.execute_reply.started":"2022-03-21T01:20:50.058843Z","shell.execute_reply":"2022-03-21T01:20:50.075066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Check contents from one file to see if it looks correct.","metadata":{}},{"cell_type":"code","source":"with open('../obj/0011165.txt', 'r') as f:\n    content = f.read()\n    print(content)","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:20:50.077159Z","iopub.execute_input":"2022-03-21T01:20:50.077651Z","iopub.status.idle":"2022-03-21T01:20:50.084253Z","shell.execute_reply.started":"2022-03-21T01:20:50.077614Z","shell.execute_reply":"2022-03-21T01:20:50.083111Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Copy obj folder and test images into /darknet/data/ folder","metadata":{}},{"cell_type":"code","source":"!cp -R \"../obj\" \"data\"\nsrc = path + '/test_images'\n!cp -R \"$src\" \"data/test\"","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:20:50.087246Z","iopub.execute_input":"2022-03-21T01:20:50.087641Z","iopub.status.idle":"2022-03-21T01:21:40.262147Z","shell.execute_reply.started":"2022-03-21T01:20:50.087614Z","shell.execute_reply":"2022-03-21T01:21:40.261114Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Verify that we have everything in our darknet/data folder","metadata":{}},{"cell_type":"code","source":"os.listdir(\"data\")","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:21:40.267049Z","iopub.execute_input":"2022-03-21T01:21:40.26896Z","iopub.status.idle":"2022-03-21T01:21:40.281Z","shell.execute_reply.started":"2022-03-21T01:21:40.268914Z","shell.execute_reply":"2022-03-21T01:21:40.279912Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create train.txt and test.txt","metadata":{}},{"cell_type":"code","source":"# Generate train.txt and test.txt\nimage_files = []\nos.chdir(os.path.join(\"data\", \"obj\"))\nfor filename in os.listdir(os.getcwd()):\n    if filename.endswith(\".jpg\"):\n        image_files.append(\"data/obj/\" + filename)\nos.chdir(\"..\")\n# split train into 80% for train and 20% for validation\n# 80% of 5546 total train images is ~4436\nwith open(\"train.txt\", \"w\") as outfile:\n    for image in image_files[:4436]: \n        outfile.write(image)\n        outfile.write(\"\\n\")\n    outfile.close()\nwith open(\"test.txt\", \"w\") as outfile:\n    for image in image_files[4436:]: # 20% for validation\n        outfile.write(image)\n        outfile.write(\"\\n\")\n    outfile.close()\nos.chdir(\"..\")","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:21:40.283889Z","iopub.execute_input":"2022-03-21T01:21:40.286501Z","iopub.status.idle":"2022-03-21T01:21:40.316889Z","shell.execute_reply.started":"2022-03-21T01:21:40.286463Z","shell.execute_reply":"2022-03-21T01:21:40.316129Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"!ls data/","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:21:40.322034Z","iopub.execute_input":"2022-03-21T01:21:40.324123Z","iopub.status.idle":"2022-03-21T01:21:41.031081Z","shell.execute_reply.started":"2022-03-21T01:21:40.324085Z","shell.execute_reply":"2022-03-21T01:21:41.030201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Verify we have the right number in each file\nwith open(r\"data/train.txt\", 'r') as fp:\n    num_lines = sum(1 for line in fp)\n    print('Total lines:', num_lines)\nwith open(r\"data/test.txt\", 'r') as fp:\n    num_lines = sum(1 for line in fp)\n    print('Total lines:', num_lines)","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:21:41.034835Z","iopub.execute_input":"2022-03-21T01:21:41.03506Z","iopub.status.idle":"2022-03-21T01:21:41.043307Z","shell.execute_reply.started":"2022-03-21T01:21:41.03503Z","shell.execute_reply":"2022-03-21T01:21:41.042545Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Configure files for training\nWe must properly configure our custom .cfg, obj.data, obj.names, train.txt and test.txt files.","metadata":{}},{"cell_type":"markdown","source":"Let's look at what's currently in our custom cfg file.","metadata":{}},{"cell_type":"code","source":"'''\nwith open('darknet/cfg/yolov4-custom.cfg', 'r') as f:\n    content = f.read()\n    print(content)\n'''","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-19T21:16:53.859435Z","iopub.execute_input":"2022-03-19T21:16:53.859726Z","iopub.status.idle":"2022-03-19T21:16:55.028791Z","shell.execute_reply.started":"2022-03-19T21:16:53.859686Z","shell.execute_reply":"2022-03-19T21:16:55.028089Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Now we need to edit the .cfg to fit our needs based on our object detector. The following code generates a link to the .cfg file. Click on it to download the file to your computer.","metadata":{}},{"cell_type":"code","source":"from IPython.display import FileLink\nFileLink(r'darknet/cfg/yolov4-custom.cfg')\n# FileLink(r'darknet/cfg/yolov4-tiny.cfg')","metadata":{"execution":{"iopub.status.busy":"2022-03-19T21:27:18.413548Z","iopub.execute_input":"2022-03-19T21:27:18.413822Z","iopub.status.idle":"2022-03-19T21:27:18.419199Z","shell.execute_reply.started":"2022-03-19T21:27:18.413789Z","shell.execute_reply":"2022-03-19T21:27:18.418527Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Editing the .cfg file\nbatch = 64 and subdivisions = 16 for should give the best results. If you run into any issues then up subdivisions to 32.\n\nWe have 4 classes, so make the rest of the changes to the cfg based on this.\n\nHow to Configure Your Variables:\n\nwidth = 416\n\nheight = 416 (these can be any multiple of 32, 416 is standard, you can sometimes improve results by making value larger like 608 but will slow down training)\n\nNormally we'd want:\nmax_batches = (# of classes) * 2000 = 8000\n\nBut start with max_batches = 160 for now because it's taking too long\n\nsteps = (80% of max_batches), (90% of max_batches) = 6400, 7200\n\nfilters = (# of classes + 5) * 3 = (4 + 5) * 3 = 27 (change in every convolutional layer)\n\nOptional: If you run into memory issues or find the training taking a super long time. In each of the three yolo layers in the cfg, change one line from random = 1 to random = 0 to speed up training but slightly reduce accuracy of model. Will also help save memory if you run into any memory issues.\n\nAlso, change mosaic=1 to mosaic=0","metadata":{}},{"cell_type":"markdown","source":"### Add the .cfg file to kaggle\nRename the file to 'yolov4-obj.cfg'. Click 'Add data', then 'Upload' and upload custom config file under the title customconfig. This places your 'yolov4-obj.cfg' file in kaggle/input/custom-config. Then we can put this in darknet/cfg.","metadata":{}},{"cell_type":"code","source":"!ls ../../input","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:21:41.046064Z","iopub.execute_input":"2022-03-21T01:21:41.046458Z","iopub.status.idle":"2022-03-21T01:21:42.137585Z","shell.execute_reply.started":"2022-03-21T01:21:41.046421Z","shell.execute_reply":"2022-03-21T01:21:42.136662Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# !cp ../input/customconfig/yolov4-obj.cfg darknet/cfg/yolov4-obj.cfg\n# !cp ../input/customconfigtiny/yolov4-tiny.cfg darknet/cfg/yolov4-tiny-obj.cfg\n!cp ../../input/customconfigtinier/yolov4-tiny.cfg cfg/yolov4-tiny-obj.cfg","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-21T01:24:23.076246Z","iopub.execute_input":"2022-03-21T01:24:23.07664Z","iopub.status.idle":"2022-03-21T01:24:23.956169Z","shell.execute_reply.started":"2022-03-21T01:24:23.076544Z","shell.execute_reply":"2022-03-21T01:24:23.955183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Verify that your file looks right","metadata":{}},{"cell_type":"code","source":"'''\nwith open('darknet/cfg/yolov4-obj.cfg', 'r') as f:\n    content = f.read()\n    print(content)\n'''","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-19T21:31:09.226144Z","iopub.execute_input":"2022-03-19T21:31:09.22652Z","iopub.status.idle":"2022-03-19T21:31:09.237095Z","shell.execute_reply.started":"2022-03-19T21:31:09.226477Z","shell.execute_reply":"2022-03-19T21:31:09.236432Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Create obj.names and obj.data\nobj.names should have all of our classes, and obj.data contains the info our detector needs to know which images to train and test on.","metadata":{"execution":{"iopub.status.busy":"2022-03-13T23:54:39.699442Z","iopub.execute_input":"2022-03-13T23:54:39.699712Z","iopub.status.idle":"2022-03-13T23:54:39.703127Z","shell.execute_reply.started":"2022-03-13T23:54:39.699663Z","shell.execute_reply":"2022-03-13T23:54:39.702316Z"}}},{"cell_type":"code","source":"!mkdir ../backup","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:23:02.289831Z","iopub.execute_input":"2022-03-21T01:23:02.290115Z","iopub.status.idle":"2022-03-21T01:23:02.970439Z","shell.execute_reply.started":"2022-03-21T01:23:02.290081Z","shell.execute_reply":"2022-03-21T01:23:02.969485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"with open('data/obj.names', 'w') as f:\n    f.write('Fish\\n')\n    f.write('Flower\\n')\n    f.write('Gravel\\n')\n    f.write('Sugar\\n')\n    \nwith open('data/obj.data', 'w') as f:\n    f.write('classes = 4\\n')\n    f.write('train = data/train.txt\\n')\n    f.write('valid = data/test.txt\\n')\n    f.write('names = data/obj.names\\n')\n    f.write('backup = ../backup\\n')    # where we will save the weights to of our model throughout training","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:23:02.977933Z","iopub.execute_input":"2022-03-21T01:23:02.978728Z","iopub.status.idle":"2022-03-21T01:23:02.985263Z","shell.execute_reply.started":"2022-03-21T01:23:02.978682Z","shell.execute_reply":"2022-03-21T01:23:02.984485Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Download pre-trained weights for convolutional layers","metadata":{"execution":{"iopub.status.busy":"2022-03-14T00:15:33.583687Z","iopub.execute_input":"2022-03-14T00:15:33.584435Z","iopub.status.idle":"2022-03-14T00:15:34.248032Z","shell.execute_reply.started":"2022-03-14T00:15:33.584395Z","shell.execute_reply":"2022-03-14T00:15:34.247254Z"}}},{"cell_type":"code","source":"!wget https://github.com/AlexeyAB/darknet/releases/download/darknet_yolo_v3_optimal/yolov4.conv.137","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-21T01:23:04.919465Z","iopub.execute_input":"2022-03-21T01:23:04.920061Z","iopub.status.idle":"2022-03-21T01:23:14.396608Z","shell.execute_reply.started":"2022-03-21T01:23:04.920023Z","shell.execute_reply":"2022-03-21T01:23:14.395746Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"### Train the detector!","metadata":{"execution":{"iopub.status.busy":"2022-03-14T00:20:26.393516Z","iopub.execute_input":"2022-03-14T00:20:26.394296Z","iopub.status.idle":"2022-03-14T00:20:26.39857Z","shell.execute_reply.started":"2022-03-14T00:20:26.394254Z","shell.execute_reply":"2022-03-14T00:20:26.397737Z"}}},{"cell_type":"code","source":"# !./darknet detector train data/obj.data cfg/yolov4-obj.cfg yolov4.conv.137 -dont_show -map -gpus 0\n!./darknet detector train data/obj.data cfg/yolov4-tiny-obj.cfg -dont_show -map -gpus 0","metadata":{"scrolled":true,"execution":{"iopub.status.busy":"2022-03-21T01:24:47.187849Z","iopub.execute_input":"2022-03-21T01:24:47.188211Z","iopub.status.idle":"2022-03-21T01:47:15.183451Z","shell.execute_reply.started":"2022-03-21T01:24:47.188168Z","shell.execute_reply":"2022-03-21T01:47:15.182634Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.listdir(\"../backup\")","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:47:52.148708Z","iopub.execute_input":"2022-03-21T01:47:52.148991Z","iopub.status.idle":"2022-03-21T01:47:52.155941Z","shell.execute_reply.started":"2022-03-21T01:47:52.148956Z","shell.execute_reply":"2022-03-21T01:47:52.154934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Save last weights to your computer so we don't have to retrain if we lose it","metadata":{}},{"cell_type":"markdown","source":"### Run our custom detector","metadata":{}},{"cell_type":"code","source":"# set custom cfg to test mode \n%cd cfg\n!sed -i 's/batch=64/batch=1/' yolov4-tiny-obj.cfg\n!sed -i 's/subdivisions=16/subdivisions=1/' yolov4-tiny-obj.cfg\n%cd ..","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:57:47.561277Z","iopub.execute_input":"2022-03-21T01:57:47.561559Z","iopub.status.idle":"2022-03-21T01:57:48.981132Z","shell.execute_reply.started":"2022-03-21T01:57:47.561525Z","shell.execute_reply":"2022-03-21T01:57:48.980086Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# run your custom detector on one image with this command\n# (use one of the test images, thresh flag sets accuracy that detection must be in order to show it)\n!./darknet detector test data/obj.data cfg/yolov4-tiny-obj.cfg ../backup/yolov4-tiny-obj_last.weights data/test/002f507.jpg -thresh 0.3\nimShow('predictions.jpg')","metadata":{"execution":{"iopub.status.busy":"2022-03-21T01:58:47.980929Z","iopub.execute_input":"2022-03-21T01:58:47.981229Z","iopub.status.idle":"2022-03-21T01:58:54.119776Z","shell.execute_reply.started":"2022-03-21T01:58:47.981194Z","shell.execute_reply":"2022-03-21T01:58:54.117575Z"},"scrolled":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"imShow('data/test/002f507.jpg')","metadata":{"execution":{"iopub.status.busy":"2022-03-21T02:00:40.491777Z","iopub.execute_input":"2022-03-21T02:00:40.49215Z","iopub.status.idle":"2022-03-21T02:00:43.612782Z","shell.execute_reply.started":"2022-03-21T02:00:40.492094Z","shell.execute_reply":"2022-03-21T02:00:43.612107Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"os.remove('predictions.jpg')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# run custom detector on a train image we know to see how it does (hopefully we see mostly flower and fish labels)\n!./darknet detector test data/obj.data cfg/yolov4-tiny-obj.cfg ../backup/yolov4-tiny-obj_last.weights data/train/0011165.jpg -thresh 0.3\nimShow('predictions.jpg')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# run custom detector on a train image we know to see and save output label in yolo format\n!./darknet detector test data/obj.data cfg/yolov4-tiny-obj.cfg ../backup/yolov4-tiny-obj_last.weights data/train/0011165.jpg -thresh 0.3 -dont_show -save_labels < data/new_train.txt\nimShow('predictions.jpg')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Calculate mean average precision\n!./darknet detector map data/obj.data cfg/yolov4-tiny-obj.cfg ../backup/yolov4-tiny-obj_last.weights","metadata":{"execution":{"iopub.status.busy":"2022-03-21T02:16:54.505893Z","iopub.execute_input":"2022-03-21T02:16:54.506193Z","iopub.status.idle":"2022-03-21T02:20:20.139903Z","shell.execute_reply.started":"2022-03-21T02:16:54.506163Z","shell.execute_reply":"2022-03-21T02:20:20.139071Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# run detector on all test images, and save results of detection to result.txt  \n# !./darknet detector test data/obj.data cfg/yolov4-obj.cfg ../backup/yolov4-obj_last.weights -dont_show -ext_output < data/test.txt > result.txt","metadata":{"scrolled":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Pseudo-labelling - to process a list of images data/test.txt and save results of detection in Yolo training format for each image as label <image_name>.txt\n# ./darknet detector test data/obj.data cfg/yolov4-obj.cfg ../backup/yolov4-obj_last.weights -thresh 0.25 -dont_show -save_labels < data/test.txt","metadata":{},"execution_count":null,"outputs":[]}]}