{"cells":[{"metadata":{"_uuid":"416b6c78-a9e6-4145-894c-02f3629ea632","_cell_guid":"8d5bf3b4-99df-4853-a59b-35bf8d2db54b","trusted":true},"cell_type":"markdown","source":"## Thanks:\nMark Peng, for precompiling AlexeyAB's Darknet to work on the Kaggle enviornment: [Notebook](https://www.kaggle.com/markpeng/darknet-gpu-on-kaggle/?)\n\nAlex Shonenkov for his notebook detailing WBF over TTA for Efficientdet: [Notebook](https://www.kaggle.com/shonenkov/wbf-over-tta-single-model-efficientdet)\n\nTianxiaomo for a great library to convert and infer Darknet models in Pytorch, and for accepting my pull requests: [Github Repo](https://github.com/Tianxiaomo/pytorch-YOLOv4)\n\n## Info\nThis notebook is a complete inference for a single YOLOv4 model trained using Darknet. Inference is done with TTAx4 at 1024x1024 resolution, while training is done with randaug and 704x704 resolution.\n\nPlease see [Version 19](https://www.kaggle.com/stanleyjzheng/apache2-yolov4-pseudolabelling-oof?scriptVersionId=40172709) for a notebook that would have gotten 38th place in this competition.","execution_count":null},{"metadata":{"_uuid":"f502e52d-7a3f-4c58-acb6-59fdba5933a9","_cell_guid":"758ec00b-e9c7-4ee7-a657-50f0a4d203f2","trusted":true},"cell_type":"code","source":"!cp -r ../input/pytorchyolov4/* .\n#!cp ../input/yolov4weights/obj.names * \n#!cp ../input/yolov4weights/trainsubmit.data * \n#!cp ../input/yolov4weights/trainsubmit.cfg * \n!mkdir /kaggle/working/backup","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"8e8f3de1-f6cb-426a-9332-800099573b05","_cell_guid":"d0b28a2d-fa84-4acc-b0c6-071684a4f605","trusted":true},"cell_type":"code","source":"!cp -r \"../input/darknet/darknet\" .\n!cp -r \"../input/darknet/libdarknet.so\" .\n!cp -r \"../input/darknet/darknet.py\" .\n!chmod a+x darknet","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ba6254ea-0b7a-4fa1-a490-74c897376b3c","_cell_guid":"a7f6549d-d77d-4ace-981d-2bbeb0fe3424","trusted":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport os\nfrom tqdm.auto import tqdm\nimport shutil as sh\nimport sys\nimport glob\nimport cv2\n\nsys.path.insert(0, \"../input/weightedboxesfusion/\")\nfrom ensemble_boxes import *\nfrom tool.utils import *\nfrom tool.torch_utils import *\nfrom tool.darknet2pytorch import Darknet\n\nNMS_IOU_THR = 0.6\nNMS_CONF_THR = 0.5\n\n# WBF\nbest_iou_thr = 0.42\nbest_skip_box_thr = 0.41\n\n# Box conf threshold\nbest_final_score = 0\nbest_score_threshold = 0\n\ncfgfile = '../input/yolov4weights/submit.cfg'\nweightfile = '../input/yolov4weights/submit.weights'\n\nWEIGHTS = Darknet(cfgfile)\nWEIGHTS.load_weights(weightfile)\nimport torch\nWEIGHTS.cuda()\n\nis_TEST = len(os.listdir('../input/global-wheat-detection/test/'))>11\n\nis_AUG = True\nis_ROT = True\n\nVALIDATE = True\n\nPSEUDO = True\n\n# For OOF evaluation\nmarking = pd.read_csv('../input/global-wheat-detection/train.csv')\n\nbboxs = np.stack(marking['bbox'].apply(lambda x: np.fromstring(x[1:-1], sep=',')))\nfor i, column in enumerate(['x', 'y', 'w', 'h']):\n    marking[column] = bboxs[:,i]\nmarking.drop(columns=['bbox'], inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"728e897a-b4ab-4f94-8b51-17e55210e1b6","_cell_guid":"95fdbd66-2e9f-4e3e-9074-65b9dd8ddcf5","trusted":true},"cell_type":"code","source":"import ast\nimport random\ndef convert(size, box):\n    dw = 1. / size[0]\n    dh = 1. / size[1]\n    x = (box[0] + box[1]) / 2.0\n    y = (box[2] + box[3]) / 2.0\n    w = box[1] - box[0]\n    h = box[3] - box[2]\n    x = x * dw\n    w = w * dw\n    y = y * dh\n    h = h * dh\n    return [x, y, w, h]\n\ndef convert_to_yolo_label(coco_format_box, w = 1024, h = 1024):\n    bbox = ast.literal_eval(coco_format_box)\n    xmin = bbox[0]\n    xmax = bbox[0] + bbox[2]\n    ymin = bbox[1]\n    ymax = bbox[1] + bbox[3]\n    b = (float(xmin), float(xmax), float(ymin), float(ymax))\n    yolo_box = convert((w, h), b)\n    if np.max(yolo_box) > 1 or np.min(yolo_box) < 0:\n        print(\"BOX HAS AN ISSUE\")\n    return yolo_box\n\ndef convertTrainLabel():\n    df = pd.read_csv('../input/global-wheat-detection/train.csv')\n    from tqdm.auto import tqdm\n    import shutil as sh\n    index = list(set(df.image_id))\n    df['yolo_box'] = df.bbox.apply(convert_to_yolo_label)\n    unique_img_ids = df.image_id.unique()\n    for fold in [0]:\n        val_index = index[len(index)*fold//5:len(index)*(fold+1)//5]\n        source = 'train'\n        for img_id in unique_img_ids:\n            filt_df = df.query(\"image_id == @img_id\")\n            path2save = 'val2017/' if img_id in val_index else 'train2017/'\n            os.makedirs('convertor/fold{}/{}'.format(fold,path2save), exist_ok=True)\n            folder_location = 'convertor/fold0/'+path2save\n            all_boxes = filt_df.yolo_box.values\n            file_name = \"{}/{}.txt\".format(folder_location,img_id)\n            s = \"0 %s %s %s %s \\n\"\n            with open(file_name, 'a') as file:\n                for i in all_boxes:\n                    new_line = (s % tuple(i))\n                    file.write(new_line)\n            sh.copy(\"../input/global-wheat-detection/{}/{}.jpg\".format(source,img_id),'convertor/fold{}/{}/{}.jpg'.format(fold,path2save,img_id))\n        print(\"finished positive images\")\n        all_imgs = glob.glob(\"../input/global-wheat-detection/train/*.jpg\")\n        all_imgs = [i.split(\"/\")[-1].replace(\".jpg\", \"\") for i in all_imgs]\n        positive_imgs = df.image_id.unique()\n        negative_images = set(all_imgs) - set(positive_imgs)\n        folder_location = 'convertor/fold0/train2017/'\n        for i in list(negative_images):\n            file_name = folder_location+\"{}.txt\".format(i)\n            sh.copy(\"../input/global-wheat-detection/train/{}.jpg\".format(i),'convertor/fold0/train2017/{}.jpg'.format(i))\n            with open(file_name, 'w') as fp: \n                pass\n        print('finished negative images')\n\ndef run_wbf(boxes, scores, image_size=1024, iou_thr=0.5, skip_box_thr=0.7, weights=None):\n    labels = [np.zeros(score.shape[0]) for score in scores]\n    boxes = [box/(image_size) for box in boxes]\n    boxes, scores, labels = weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    boxes = boxes*(image_size)\n    return boxes, scores, labels\n\ndef TTAImage(image, index):\n    image1 = image.copy()\n    if index==0: \n        rotated_image = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image\n    elif index==1:\n        rotated_image2 = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image2 = cv2.rotate(rotated_image2, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image2\n    elif index==2:\n        rotated_image3 = cv2.rotate(image1, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image3 = cv2.rotate(rotated_image3, cv2.ROTATE_90_CLOCKWISE)\n        rotated_image3 = cv2.rotate(rotated_image3, cv2.ROTATE_90_CLOCKWISE)\n        return rotated_image3\n    elif index == 3:\n        return image1\n\ndef rotBoxes90(boxes, im_w, im_h):\n    ret_boxes =[]\n    for box in boxes:\n        x1, y1, x2, y2 = box\n        x1, y1, x2, y2 = x1-im_w//2, im_h//2 - y1, x2-im_w//2, im_h//2 - y2\n        x1, y1, x2, y2 = y1, -x1, y2, -x2\n        x1, y1, x2, y2 = int(x1+im_w//2), int(im_h//2 - y1), int(x2+im_w//2), int(im_h//2 - y2)\n        x1a, y1a, x2a, y2a = min(x1, x2), min(y1, y2), max(x1, x2), max(y1, y2)\n        ret_boxes.append([x1a, y1a, x2a, y2a])\n    return np.array(ret_boxes)\n\ndef process_det(index, det, imgsize=1024, score_threshold=0.35):\n    try :\n        scores = det[index][:, 5].copy()\n        det = det[index][:, :4].copy()\n        bboxes = np.zeros((det.shape))\n        bboxes[:, 0] = (det[:, 0] * imgsize).astype(int)\n        bboxes[:, 1] = (det[:, 1] * imgsize).astype(int)\n        bboxes[:, 2] = (det[:, 2] * imgsize).astype(int)\n        bboxes[:, 3] = (det[:, 3] * imgsize).astype(int)\n        bboxes = (bboxes).clip(min = 0, max = imgsize).astype(int)\n        indexes = np.where(scores>score_threshold)\n        bboxes = bboxes[indexes]\n        scores = scores[indexes]\n        return bboxes, scores\n    except IndexError:\n        print(det)\n\n\ndef detect1Image(img, img0, model, device, aug):\n    pred = do_detect(model, img, NMS_CONF_THR, NMS_IOU_THR, use_cuda=1)\n\n    prednp = np.array(pred)\n    if prednp is None or prednp.size==0:\n        return np.array([]), np.array([])\n    else:\n        boxes, scores = process_det(0, prednp)\n        return np.array(boxes), np.array(scores)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"fffdcb58-160e-464f-9b1f-21c160785460","_cell_guid":"e8ab34f1-a6cb-447f-800c-7a7931c88498","trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport numba\nimport re\nimport cv2\nimport matplotlib.pyplot as plt\n\nfrom numba import jit\nfrom typing import List, Union, Tuple\n\n\n@jit(nopython=True)\ndef calculate_iou(gt, pr, form='pascal_voc') -> float:\n    \"\"\"Calculates the Intersection over Union.\n\n    Args:\n        gt: (np.ndarray[Union[int, float]]) coordinates of the ground-truth box\n        pr: (np.ndarray[Union[int, float]]) coordinates of the prdected box\n        form: (str) gt/pred coordinates format\n            - pascal_voc: [xmin, ymin, xmax, ymax]\n            - coco: [xmin, ymin, w, h]\n    Returns:\n        (float) Intersection over union (0.0 <= iou <= 1.0)\n    \"\"\"\n    if form == 'coco':\n        gt = gt.copy()\n        pr = pr.copy()\n\n        gt[2] = gt[0] + gt[2]\n        gt[3] = gt[1] + gt[3]\n        pr[2] = pr[0] + pr[2]\n        pr[3] = pr[1] + pr[3]\n\n    # Calculate overlap area\n    dx = min(gt[2], pr[2]) - max(gt[0], pr[0]) + 1\n    \n    if dx < 0:\n        return 0.0\n    \n    dy = min(gt[3], pr[3]) - max(gt[1], pr[1]) + 1\n\n    if dy < 0:\n        return 0.0\n\n    overlap_area = dx * dy\n    \n    # Calculate union area\n    union_area = (\n            (gt[2] - gt[0] + 1) * (gt[3] - gt[1] + 1) +\n            (pr[2] - pr[0] + 1) * (pr[3] - pr[1] + 1) -\n            overlap_area\n    )\n\n    return overlap_area / union_area\n\n\n@jit(nopython=True)\ndef find_best_match(gts, pred, pred_idx, threshold = 0.5, form = 'pascal_voc', ious=None) -> int:\n    \"\"\"Returns the index of the 'best match' between the\n    ground-truth boxes and the prediction. The 'best match'\n    is the highest IoU. (0.0 IoUs are ignored).\n\n    Args:\n        gts: (List[List[Union[int, float]]]) Coordinates of the available ground-truth boxes\n        pred: (List[Union[int, float]]) Coordinates of the predicted box\n        pred_idx: (int) Index of the current predicted box\n        threshold: (float) Threshold\n        form: (str) Format of the coordinates\n        ious: (np.ndarray) len(gts) x len(preds) matrix for storing calculated ious.\n\n    Return:\n        (int) Index of the best match GT box (-1 if no match above threshold)\n    \"\"\"\n    best_match_iou = -np.inf\n    best_match_idx = -1\n\n    for gt_idx in range(len(gts)):\n        \n        if gts[gt_idx][0] < 0:\n            # Already matched GT-box\n            continue\n        \n        iou = -1 if ious is None else ious[gt_idx][pred_idx]\n\n        if iou < 0:\n            iou = calculate_iou(gts[gt_idx], pred, form=form)\n            \n            if ious is not None:\n                ious[gt_idx][pred_idx] = iou\n\n        if iou < threshold:\n            continue\n\n        if iou > best_match_iou:\n            best_match_iou = iou\n            best_match_idx = gt_idx\n\n    return best_match_idx\n\n@jit(nopython=True)\ndef calculate_precision(gts, preds, threshold = 0.5, form = 'coco', ious=None) -> float:\n    \"\"\"Calculates precision for GT - prediction pairs at one threshold.\n\n    Args:\n        gts: (List[List[Union[int, float]]]) Coordinates of the available ground-truth boxes\n        preds: (List[List[Union[int, float]]]) Coordinates of the predicted boxes,\n               sorted by confidence value (descending)\n        threshold: (float) Threshold\n        form: (str) Format of the coordinates\n        ious: (np.ndarray) len(gts) x len(preds) matrix for storing calculated ious.\n\n    Return:\n        (float) Precision\n    \"\"\"\n    n = len(preds)\n    tp = 0\n    fp = 0\n    \n    # for pred_idx, pred in enumerate(preds_sorted):\n    for pred_idx in range(n):\n\n        best_match_gt_idx = find_best_match(gts, preds[pred_idx], pred_idx,\n                                            threshold=threshold, form=form, ious=ious)\n\n        if best_match_gt_idx >= 0:\n            # True positive: The predicted box matches a gt box with an IoU above the threshold.\n            tp += 1\n            # Remove the matched GT box\n            gts[best_match_gt_idx] = -1\n\n        else:\n            # No match\n            # False positive: indicates a predicted box had no associated gt box.\n            fp += 1\n\n    # False negative: indicates a gt box had no associated predicted box.\n    fn = (gts.sum(axis=1) > 0).sum()\n\n    return tp / (tp + fp + fn)\n\n\n@jit(nopython=True)\ndef calculate_image_precision(gts, preds, thresholds = (0.5, ), form = 'coco') -> float:\n    \"\"\"Calculates image precision.\n\n    Args:\n        gts: (List[List[Union[int, float]]]) Coordinates of the available ground-truth boxes\n        preds: (List[List[Union[int, float]]]) Coordinates of the predicted boxes,\n               sorted by confidence value (descending)\n        thresholds: (float) Different thresholds\n        form: (str) Format of the coordinates\n\n    Return:\n        (float) Precision\n    \"\"\"\n    n_threshold = len(thresholds)\n    image_precision = 0.0\n    \n    ious = np.ones((len(gts), len(preds))) * -1\n    # ious = None\n\n    for threshold in thresholds:\n        precision_at_threshold = calculate_precision(gts.copy(), preds, threshold=threshold,\n                                                     form=form, ious=ious)\n        image_precision += precision_at_threshold / n_threshold\n\n    return image_precision\n\n    \n# Numba typed list!\niou_thresholds = numba.typed.List()\n\nfor x in [0.5, 0.55, 0.6, 0.65, 0.7, 0.75]:\n    iou_thresholds.append(x)\n    \ndef validate():\n    source = 'convertor/fold0/val2017'\n    \n    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\n    # Load model\n    model = WEIGHTS\n    model.to(device).eval()\n    \n    dataset = LoadImages(source, img_size=1024)\n\n    results = []\n    \n    for path, img, img0, vid_cap in dataset:\n            \n        image_id = os.path.basename(path).split('.')[0]\n        img = img.transpose(1,2,0) # [H, W, 3]\n        \n        enboxes = []\n        enscores = []\n        \n        # only rot, no flip\n        if is_ROT:    \n            for i in range(4):\n                img1 = TTAImage(img, i)\n                boxes, scores = detect1Image(img1, img0, model, device, aug=False)\n                for _ in range(3-i):\n                    boxes = rotBoxes90(boxes, *img.shape[:2])            \n                enboxes.append(boxes)\n                enscores.append(scores) \n        \n        # flip\n        boxes, scores = detect1Image(img, img0, model, device, aug=is_AUG)\n        enboxes.append(boxes)\n        enscores.append(scores) \n            \n        boxes, scores, labels = run_wbf(enboxes, enscores, image_size=1024, iou_thr=best_iou_thr, skip_box_thr=best_skip_box_thr)    \n        boxes = boxes.astype(np.int32).clip(min=0, max=1024)\n\n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n        \n        boxes = boxes[scores >= 0.05].astype(np.int32)\n        scores = scores[scores >= float(0.05)]\n        \n        records = marking[marking['image_id'] == image_id]\n        gtboxes = records[['x', 'y', 'w', 'h']].values\n        gtboxes = gtboxes.astype(np.int32).clip(min=0, max=1024)\n        gtboxes[:, 2] = gtboxes[:, 0] + gtboxes[:, 2]\n        gtboxes[:, 3] = gtboxes[:, 1] + gtboxes[:, 3]\n        \n            \n        result = {\n            'image_id': image_id,\n            'pred_enboxes': enboxes, # xyhw\n            'pred_enscores': enscores,\n            'gt_boxes': gtboxes, # xyhw\n        }\n\n        results.append(result)\n        \n    return results\n\ndef calculate_final_score(all_predictions, iou_thr, skip_box_thr, score_threshold):\n    final_scores = []\n    for i in range(len(all_predictions)):\n        gt_boxes = all_predictions[i]['gt_boxes'].copy()\n        enboxes = all_predictions[i]['pred_enboxes'].copy()\n        enscores = all_predictions[i]['pred_enscores'].copy()\n        image_id = all_predictions[i]['image_id']\n        \n        pred_boxes, scores, labels = run_wbf(enboxes, enscores, image_size=1024, iou_thr=iou_thr, skip_box_thr=skip_box_thr)    \n        pred_boxes = pred_boxes.astype(np.int32).clip(min=0, max=1024)\n\n        indexes = np.where(scores>score_threshold)\n        pred_boxes = pred_boxes[indexes]\n        scores = scores[indexes]\n\n        image_precision = calculate_image_precision(gt_boxes, pred_boxes,thresholds=iou_thresholds,form='pascal_voc')\n        final_scores.append(image_precision)\n\n    return np.mean(final_scores)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"7753ccfe-d5c1-4525-90e0-9ee59ef7a0f5","_cell_guid":"85245111-2aec-4fa7-b7ea-5238c9dd3e5e","trusted":true},"cell_type":"code","source":"!pip install scikit-optimize\nfrom skopt import gp_minimize, forest_minimize\nfrom skopt.utils import use_named_args\nfrom skopt.plots import plot_objective, plot_evaluations, plot_convergence, plot_regret\nfrom skopt.space import Categorical, Integer, Real\nfrom pathlib import Path\nfrom sys import exit\n\ndef log(text):\n    print(text)\n\ndef optimize(space, all_predictions, n_calls=10):\n    @use_named_args(space)\n    def score(**params):\n        log('-'*10)\n        log(params)\n        final_score = calculate_final_score(all_predictions, **params)\n        log(f'final_score = {final_score}')\n        log('-'*10)\n        return -final_score\n\n    return gp_minimize(func=score, dimensions=space, n_calls=n_calls) \n\ndef letterbox(img, new_shape=(416, 416), color=(114, 114, 114), auto=True, scaleFill=False, scaleup=True):\n    shape = img.shape[:2]  \n    if isinstance(new_shape, int):\n        new_shape = (new_shape, new_shape)\n\n    r = min(new_shape[0] / shape[0], new_shape[1] / shape[1])\n    if not scaleup:\n        r = min(r, 1.0)\n\n    ratio = r, r \n    new_unpad = int(round(shape[1] * r)), int(round(shape[0] * r))\n    dw, dh = new_shape[1] - new_unpad[0], new_shape[0] - new_unpad[1]  \n    if auto:\n        dw, dh = np.mod(dw, 64), np.mod(dh, 64)\n    elif scaleFill:\n        dw, dh = 0.0, 0.0\n        new_unpad = new_shape\n        ratio = new_shape[0] / shape[1], new_shape[1] / shape[0]\n\n    dw /= 2 \n    dh /= 2\n\n    if shape[::-1] != new_unpad:\n        img = cv2.resize(img, new_unpad, interpolation=cv2.INTER_LINEAR)\n    top, bottom = int(round(dh - 0.1)), int(round(dh + 0.1))\n    left, right = int(round(dw - 0.1)), int(round(dw + 0.1))\n    img = cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, value=color)  # add border\n    return img, ratio, (dw, dh)\n\nclass LoadImages:  \n    def __init__(self, path, img_size=416):\n        path = str(Path(path))\n        files = []\n        if os.path.isdir(path):\n            files = sorted(glob.glob(os.path.join(path, '*.*')))\n        elif os.path.isfile(path):\n            files = [path]\n\n        img_formats = ['.bmp', '.jpg', '.jpeg', '.png', '.tif', '.tiff', '.dng']\n        images = [x for x in files if os.path.splitext(x)[-1].lower() in img_formats]\n        videos = []\n        nI, nV = len(images), len(videos)\n\n        self.img_size = img_size\n        self.files = images + videos\n        self.nF = nI + nV  # number of files\n        self.video_flag = [False] * nI + [True] * nV\n        self.mode = 'images'\n        if any(videos):\n            self.new_video(videos[0])  \n        else:\n            self.cap = None\n        assert self.nF > 0, 'No images or found in %s. Supported formats are:\\nimages: %s\\nvideos: %s' % \\\n                            (path)\n\n    def __iter__(self):\n        self.count = 0\n        return self\n\n    def __next__(self):\n        if self.count == self.nF:\n            raise StopIteration\n        path = self.files[self.count]\n        self.count += 1\n        img0 = cv2.imread(path)\n        assert img0 is not None, 'Image Not Found ' + path\n        print('image %g/%g %s: ' % (self.count, self.nF, path), end='')\n\n        img = letterbox(img0, new_shape=self.img_size)[0]\n\n        img = img[:, :, ::-1].transpose(2, 0, 1) \n        img = np.ascontiguousarray(img)\n\n        return path, img, img0, self.cap\n\n    def __len__(self):\n        return self.nF","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"21d236c4-7489-41d3-a886-5c7607dea9f8","_cell_guid":"104fcb42-d5a3-4f3d-89ad-2df5dc40a8c0","trusted":true},"cell_type":"code","source":"def makePseudolabel():\n    source = '../input/global-wheat-detection/test/'\n    \n    imagenames =  os.listdir(source)\n    \n    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\n    model = WEIGHTS\n    model.to(device).eval()\n    \n    dataset = LoadImages(source, img_size=1024)\n\n    path2save = 'train2017/'\n    \n    if not os.path.exists('convertor/fold0/labels/'+path2save):\n        os.makedirs('convertor/fold0/labels/'+path2save)\n    if not os.path.exists('convertor/fold0/images/{}'.format(path2save)):\n        os.makedirs('convertor/fold0/images/{}'.format(path2save))\n    \n    for path, img, img0, vid_cap in dataset:\n        image_id = os.path.basename(path).split('.')[0]\n        img = img.transpose(1,2,0)\n        \n        enboxes = []\n        enscores = []\n        \n        if is_ROT:    \n            for i in range(4):\n                img1 = TTAImage(img, i)\n                boxes, scores = detect1Image(img1, img0, model, device, aug=False)\n                for _ in range(3-i):\n                    boxes = rotBoxes90(boxes, *img.shape[:2])            \n                enboxes.append(boxes)\n                enscores.append(scores) \n        \n        boxes, scores = detect1Image(img, img0, model, device, aug=is_AUG)\n        enboxes.append(boxes)\n        enscores.append(scores)\n        boxes, scores, labels = run_wbf(enboxes, enscores, image_size=1024, iou_thr=best_iou_thr, skip_box_thr=best_skip_box_thr)\n        boxes = boxes.astype(np.int32).clip(min=0, max=1024)\n\n        indices = scores >= best_score_threshold\n        boxes = boxes[indices]\n        scores = scores[indices] #Right now, x1, y1, x2, y2\n\n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0] #convert to x1, y1, w, h\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1] \n \n        yolo_box = []\n        for bbox in boxes:\n            xmin = bbox[0]\n            xmax = bbox[0] + bbox[2]\n            ymin = bbox[1]\n            ymax = bbox[1] + bbox[3]\n            b = (float(xmin), float(xmax), float(ymin), float(ymax))\n            yolo_box.append(convert((1024, 1024), b))\n        \n        folder_location = 'convertor/fold0/'+path2save\n        file_name = \"{}/{}.txt\".format(folder_location,image_id) \n        s = \"0 %s %s %s %s \\n\" \n        with open(file_name, 'w+') as file:\n            for i in yolo_box:\n                new_line = (s % tuple(i))\n                file.write(new_line)\n\n        sh.copy(\"../input/global-wheat-detection/test/{}.jpg\".format(image_id),'convertor/fold0/{}/{}.jpg'.format(path2save,image_id))\n\ndef generate_train():\n    image_files = []\n    os.chdir(os.path.join(\"convertor\", \"fold0\", \"train2017\"))\n    for filename in os.listdir(os.getcwd()):\n        if filename.endswith(\".jpg\"):\n            image_files.append(\"/kaggle/working/convertor/fold0/train2017/\" + filename)\n    os.chdir(\"..\")\n    with open(\"train.txt\", \"w+\") as outfile:\n        for image in image_files:\n            outfile.write(image)\n            outfile.write(\"\\n\")\n        outfile.close()\n    os.chdir(\"..\")\n    os.chdir(\"..\")","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"9585f695-6af0-4cd2-92c5-780abceffda9","_cell_guid":"e2019109-4cd6-41aa-8a79-dbfbf2547a4a","trusted":true},"cell_type":"code","source":"if PSEUDO or VALIDATE:\n    convertTrainLabel()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"From some testing, this training takes about 5.5 hours to run. It doesn't depend on the amount of input images, only on the number of max batches, so it shouldn't be affected by the increase in test data. ","execution_count":null},{"metadata":{"_uuid":"471ef2c4-881c-4868-b662-53afa62498e4","_cell_guid":"3b2f40a4-0142-47c2-bc67-36ef37687403","trusted":true},"cell_type":"code","source":"if PSEUDO:\n    makePseudolabel()\n\n    if is_TEST:\n        torch.cuda.empty_cache()\n        generate_train()\n        !mkdir backup # save in ../backup\n        !rm obj.names\n        !touch obj.names # data.names is the classes\n        !echo \"wheat\" >> obj.names\n        print('training')\n        !./darknet detector train ../input/yolov4weights/trainsubmit.data ../input/yolov4weights/trainsubmit.cfg ../input/yolov4weights/submit.weights -dont_show -clear 1\n        WEIGHTS = Darknet(cfgfile)\n        WEIGHTS.load_weights('backup/trainsubmit_final.weights')\n        WEIGHTS.cuda()\n    else:\n        pass","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"718f2900-7882-47b0-b71d-57980ce1d8c7","_cell_guid":"d80c5eac-f774-42e0-9272-6c00e136f48a","trusted":true},"cell_type":"code","source":"if VALIDATE and is_TEST:\n    all_predictions = validate()\n    \n    # Bayesian Optimization\n    '''\n    space = [\n        Real(0, 1, name='iou_thr'),\n        Real(0.25, 1, name='skip_box_thr'),\n        Real(0, 1, name='score_threshold'),\n    ]\n\n    opt_result = optimize(\n        space, \n        all_predictions,\n        n_calls=50,\n    )\n    '''\n    best_final_score = -opt_result.fun\n    best_iou_thr = opt_result.x[0]\n    best_skip_box_thr = opt_result.x[1]\n    best_score_threshold = opt_result.x[2]\n\n\n    print('-'*13 + 'WBF' + '-'*14)\n    print(\"[Baseline score]\", calculate_final_score(all_predictions, 0.6, 0.43, 0))\n    print(f'[Best Iou Thr]: {best_iou_thr:.3f}')\n    print(f'[Best Skip Box Thr]: {best_skip_box_thr:.3f}')\n    print(f'[Best Score Thr]: {best_score_threshold:.3f}')\n    print(f'[Best Score]: {best_final_score:.4f}')\n    print('-'*30)\n    \n    \n    for score_threshold in tqdm(np.arange(0, 1, 0.01), total=np.arange(0, 1, 0.01).shape[0]):\n        final_score = calculate_final_score(all_predictions, best_iou_thr, best_skip_box_thr, score_threshold)\n        if final_score > best_final_score:\n            best_final_score = final_score\n            best_score_threshold = score_threshold\n\n    print('-'*30)\n    print(f'[Best Score Threshold]: {best_score_threshold}')\n    print(f'[OOF Score]: {best_final_score:.4f}')\n    print('-'*30)","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ff2792a2-bf2b-4fb9-8610-a4689187db52","_cell_guid":"035fbe1f-89ab-442f-b9c4-d7df28eb8419","trusted":true},"cell_type":"code","source":"def format_prediction_string(boxes, scores):\n    pred_strings = []\n    for j in zip(scores, boxes):\n        pred_strings.append(\"{0:.4f} {1} {2} {3} {4}\".format(j[0], j[1][0], j[1][1], j[1][2], j[1][3]))\n\n    return \" \".join(pred_strings)\n\ndef detect():\n    source = '../input/global-wheat-detection/test/'\n    weights = WEIGHTS\n    \n    imagenames =  os.listdir(source)\n    \n    device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\n    # Load model\n    model = WEIGHTS  # load to FP32\n    model.to(device).eval()\n    \n    dataset = LoadImages(source, img_size=1024)\n\n    results = []\n    fig, ax = plt.subplots(5, 2, figsize=(30, 70))\n    count = 0\n    \n    for path, img, img0, vid_cap in dataset:\n        image_id = os.path.basename(path).split('.')[0]\n        img = img.transpose(1,2,0) # [H, W, 3]\n        \n        enboxes = []\n        enscores = []\n        \n        # only rot, no flip\n        if is_ROT:    \n            for i in range(4):\n                img1 = TTAImage(img, i)\n                boxes, scores = detect1Image(img1, img0, model, device, aug=False)\n                for _ in range(3-i):\n                    boxes = rotBoxes90(boxes, *img.shape[:2])            \n                enboxes.append(boxes)\n                enscores.append(scores) \n        \n        # flip\n        boxes, scores = detect1Image(img, img0, model, device, aug=is_AUG)\n        enboxes.append(boxes)\n        enscores.append(scores) \n            \n        boxes, scores, labels = run_wbf(enboxes, enscores, image_size=1024, iou_thr=best_iou_thr, skip_box_thr=best_skip_box_thr)    \n        boxes = boxes.astype(np.int32).clip(min=0, max=1023)\n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n        \n        indices = scores >= best_score_threshold\n        boxes = boxes[indices]\n        scores = scores[indices]\n        \n        if count<10:\n            img_ = cv2.imread(path)  # BGR\n            img_ = cv2.cvtColor(img_, cv2.COLOR_BGR2RGB)\n            for box, score in zip(boxes,scores):\n                cv2.rectangle(img_, (box[0], box[1]), (box[2]+box[0], box[3]+box[1]), (220, 0, 0), 2)\n                cv2.putText(img_, '%.2f'%(score), (box[0], box[1]), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255), 2, cv2.LINE_AA)\n            ax[count%5][count//5].imshow(img_)\n            count+=1\n            \n        result = {\n            'image_id': image_id,\n            'PredictionString': format_prediction_string(boxes, scores)\n        }\n\n        results.append(result)\n    return results","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"6954280c-1f60-4344-9c8a-520a58d1cd71","_cell_guid":"eb087c9c-1df1-4750-b98f-22845bebea7a","trusted":true},"cell_type":"code","source":"results = detect()\ntest_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\n!rm -rf ./*\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"053d646e-bd8d-4c6f-84f5-7ce7ee275c92","_cell_guid":"b28cdeee-81d2-4890-a733-c150358f1399","trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}