{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"cd /kaggle/working","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_kg_hide-input":true,"_kg_hide-output":true,"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true},"cell_type":"code","source":"!pip install --no-deps '../input/wheatdep/timm-0.1.26-py3-none-any.whl' > /dev/null\n!pip install --no-deps '../input/wheatdep/pycocotools-2.0-cp37-cp37m-linux_x86_64.whl' > /dev/null","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"import sys\nsys.path.insert(0, \"../input/wheatdep/efficientdet-kaggle/efficientdet-kaggle/\")\nsys.path.insert(0, \"../input/wheatdep/omegaconf\")\n\nimport torch\nimport numpy as np\nimport pandas as pd\nfrom glob import glob\nfrom torch.utils.data import Dataset,DataLoader\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport cv2\nimport gc\nfrom matplotlib import pyplot as plt\nfrom effdet import get_efficientdet_config, EfficientDet\nfrom effdet.efficientdet import HeadNet\nimport random\nimport os\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Eval Bench Definition (Hidden)","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"NMS_THRESHOLD = 0.94","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true},"cell_type":"code","source":"import collections\nimport numpy as np\nimport torch\nimport torch.nn as nn\nfrom torchvision.ops.boxes import batched_nms\n\nfrom effdet.object_detection import argmax_matcher\nfrom effdet.object_detection import box_list\nfrom effdet.object_detection import faster_rcnn_box_coder\nfrom effdet.object_detection import region_similarity_calculator\nfrom effdet.object_detection import target_assigner\n\n# The minimum score to consider a logit for identifying detections.\nMIN_CLASS_SCORE = -5.0\n\n# The score for a dummy detection\n_DUMMY_DETECTION_SCORE = -1e5\n\n# The maximum number of (anchor,class) pairs to keep for non-max suppression.\nMAX_DETECTION_POINTS = 5000\n\n# The maximum number of detections per image.\nMAX_DETECTIONS_PER_IMAGE = 100\n\n\ndef decode_box_outputs(rel_codes, anchors, output_xyxy=False):\n    \"\"\"Transforms relative regression coordinates to absolute positions.\n\n    Network predictions are normalized and relative to a given anchor; this\n    reverses the transformation and outputs absolute coordinates for the input image.\n\n    Args:\n        rel_codes: box regression targets.\n\n        anchors: anchors on all feature levels.\n\n    Returns:\n        outputs: bounding boxes.\n\n    \"\"\"\n    ycenter_a = (anchors[0] + anchors[2]) / 2\n    xcenter_a = (anchors[1] + anchors[3]) / 2\n    ha = anchors[2] - anchors[0]\n    wa = anchors[3] - anchors[1]\n    ty, tx, th, tw = rel_codes\n\n    w = torch.exp(tw) * wa\n    h = torch.exp(th) * ha\n    ycenter = ty * ha + ycenter_a\n    xcenter = tx * wa + xcenter_a\n    ymin = ycenter - h / 2.\n    xmin = xcenter - w / 2.\n    ymax = ycenter + h / 2.\n    xmax = xcenter + w / 2.\n    if output_xyxy:\n        out = torch.stack([xmin, ymin, xmax, ymax], dim=1)\n    else:\n        out = torch.stack([ymin, xmin, ymax, xmax], dim=1)\n    return out\n\n\ndef _generate_anchor_configs(min_level, max_level, num_scales, aspect_ratios):\n    \"\"\"Generates mapping from output level to a list of anchor configurations.\n\n    A configuration is a tuple of (num_anchors, scale, aspect_ratio).\n\n    Args:\n        min_level: integer number of minimum level of the output feature pyramid.\n\n        max_level: integer number of maximum level of the output feature pyramid.\n\n        num_scales: integer number representing intermediate scales added on each level.\n            For instances, num_scales=2 adds two additional anchor scales [2^0, 2^0.5] on each level.\n\n        aspect_ratios: list of tuples representing the aspect ratio anchors added on each level.\n            For instances, aspect_ratios = [(1, 1), (1.4, 0.7), (0.7, 1.4)] adds three anchors on each level.\n\n    Returns:\n        anchor_configs: a dictionary with keys as the levels of anchors and\n            values as a list of anchor configuration.\n    \"\"\"\n    anchor_configs = {}\n    for level in range(min_level, max_level + 1):\n        anchor_configs[level] = []\n        for scale_octave in range(num_scales):\n            for aspect in aspect_ratios:\n                anchor_configs[level].append((2 ** level, scale_octave / float(num_scales), aspect))\n    return anchor_configs\n\n\ndef _generate_anchor_boxes(image_size, anchor_scale, anchor_configs):\n    \"\"\"Generates multiscale anchor boxes.\n\n    Args:\n        image_size: integer number of input image size. The input image has the same dimension for\n            width and height. The image_size should be divided by the largest feature stride 2^max_level.\n\n        anchor_scale: float number representing the scale of size of the base\n            anchor to the feature stride 2^level.\n\n        anchor_configs: a dictionary with keys as the levels of anchors and\n            values as a list of anchor configuration.\n\n    Returns:\n        anchor_boxes: a numpy array with shape [N, 4], which stacks anchors on all feature levels.\n\n    Raises:\n        ValueError: input size must be the multiple of largest feature stride.\n    \"\"\"\n    boxes_all = []\n    for _, configs in anchor_configs.items():\n        boxes_level = []\n        for config in configs:\n            stride, octave_scale, aspect = config\n            if image_size % stride != 0:\n                raise ValueError(\"input size must be divided by the stride.\")\n            base_anchor_size = anchor_scale * stride * 2 ** octave_scale\n            anchor_size_x_2 = base_anchor_size * aspect[0] / 2.0\n            anchor_size_y_2 = base_anchor_size * aspect[1] / 2.0\n\n            x = np.arange(stride / 2, image_size, stride)\n            y = np.arange(stride / 2, image_size, stride)\n            xv, yv = np.meshgrid(x, y)\n            xv = xv.reshape(-1)\n            yv = yv.reshape(-1)\n\n            boxes = np.vstack((yv - anchor_size_y_2, xv - anchor_size_x_2,\n                               yv + anchor_size_y_2, xv + anchor_size_x_2))\n            boxes = np.swapaxes(boxes, 0, 1)\n            boxes_level.append(np.expand_dims(boxes, axis=1))\n        # concat anchors on the same level to the reshape NxAx4\n        boxes_level = np.concatenate(boxes_level, axis=1)\n        boxes_all.append(boxes_level.reshape([-1, 4]))\n\n    anchor_boxes = np.vstack(boxes_all)\n    return anchor_boxes\n\n\ndef generate_detections(cls_outputs, box_outputs, anchor_boxes, indices, classes, image_scale):\n    \"\"\"Generates detections with RetinaNet model outputs and anchors.\n\n    Args:\n        cls_outputs: a torch tensor with shape [N, 1], which has the highest class\n            scores on all feature levels. The N is the number of selected\n            top-K total anchors on all levels.  (k being MAX_DETECTION_POINTS)\n\n        box_outputs: a torch tensor with shape [N, 4], which stacks box regression\n            outputs on all feature levels. The N is the number of selected top-k\n            total anchors on all levels. (k being MAX_DETECTION_POINTS)\n\n        anchor_boxes: a torch tensor with shape [N, 4], which stacks anchors on all\n            feature levels. The N is the number of selected top-k total anchors on all levels.\n\n        indices: a torch tensor with shape [N], which is the indices from top-k selection.\n\n        classes: a torch tensor with shape [N], which represents the class\n            prediction on all selected anchors from top-k selection.\n\n        image_scale: a float tensor representing the scale between original image\n            and input image for the detector. It is used to rescale detections for\n            evaluating with the original groundtruth annotations.\n\n    Returns:\n        detections: detection results in a tensor with shape [MAX_DETECTION_POINTS, 6],\n            each row representing [x, y, width, height, score, class]\n    \"\"\"\n    anchor_boxes = anchor_boxes[indices, :]\n\n    # apply bounding box regression to anchors\n    boxes = decode_box_outputs(box_outputs.T.float(), anchor_boxes.T, output_xyxy=True)\n\n    scores = cls_outputs.sigmoid().squeeze(1).float()\n    top_detection_idx = batched_nms(boxes, scores, classes, iou_threshold=NMS_THRESHOLD)\n\n    # keep only topk scoring predictions\n    top_detection_idx = top_detection_idx[:MAX_DETECTIONS_PER_IMAGE]\n    boxes = boxes[top_detection_idx]\n    scores = scores[top_detection_idx, None]\n    classes = classes[top_detection_idx, None]\n\n    # xyxy to xywh & rescale to original image\n    boxes[:, 2] -= boxes[:, 0]\n    boxes[:, 3] -= boxes[:, 1]\n    boxes *= image_scale\n\n    classes += 1  # back to class idx with background class = 0\n\n    # stack em and pad out to MAX_DETECTIONS_PER_IMAGE if necessary\n    detections = torch.cat([boxes, scores, classes.float()], dim=1)\n    if len(top_detection_idx) < MAX_DETECTIONS_PER_IMAGE:\n        detections = torch.cat([\n            detections,\n            torch.zeros(\n                (MAX_DETECTIONS_PER_IMAGE - len(top_detection_idx), 6), device=detections.device, dtype=detections.dtype)\n        ], dim=0)\n    return detections\n\n\nclass Anchors(nn.Module):\n    \"\"\"RetinaNet Anchors class.\"\"\"\n\n    def __init__(self, min_level, max_level, num_scales, aspect_ratios, anchor_scale, image_size):\n        \"\"\"Constructs multiscale RetinaNet anchors.\n\n        Args:\n            min_level: integer number of minimum level of the output feature pyramid.\n\n            max_level: integer number of maximum level of the output feature pyramid.\n\n            num_scales: integer number representing intermediate scales added\n                on each level. For instances, num_scales=2 adds two additional\n                anchor scales [2^0, 2^0.5] on each level.\n\n            aspect_ratios: list of tuples representing the aspect ratio anchors added\n                on each level. For instances, aspect_ratios =\n                [(1, 1), (1.4, 0.7), (0.7, 1.4)] adds three anchors on each level.\n\n            anchor_scale: float number representing the scale of size of the base\n                anchor to the feature stride 2^level.\n\n            image_size: integer number of input image size. The input image has the\n                same dimension for width and height. The image_size should be divided by\n                the largest feature stride 2^max_level.\n        \"\"\"\n        super(Anchors, self).__init__()\n        self.min_level = min_level\n        self.max_level = max_level\n        self.num_scales = num_scales\n        self.aspect_ratios = aspect_ratios\n        self.anchor_scale = anchor_scale\n        self.image_size = image_size\n        self.config = self._generate_configs()\n        self.register_buffer('boxes', self._generate_boxes())\n\n    def _generate_configs(self):\n        \"\"\"Generate configurations of anchor boxes.\"\"\"\n        return _generate_anchor_configs(self.min_level, self.max_level, self.num_scales, self.aspect_ratios)\n\n    def _generate_boxes(self):\n        \"\"\"Generates multiscale anchor boxes.\"\"\"\n        boxes = _generate_anchor_boxes(self.image_size, self.anchor_scale, self.config)\n        boxes = torch.from_numpy(boxes).float()\n        return boxes\n\n    def get_anchors_per_location(self):\n        return self.num_scales * len(self.aspect_ratios)\n\n\n# FIXME PyTorch port of this class and subclasses not tested yet, needed for training\nclass AnchorLabeler(nn.Module):\n    \"\"\"Labeler for multiscale anchor boxes.\n    \"\"\"\n\n    def __init__(self, anchors, num_classes, match_threshold=0.5):\n        \"\"\"Constructs anchor labeler to assign labels to anchors.\n\n        Args:\n            anchors: an instance of class Anchors.\n\n            num_classes: integer number representing number of classes in the dataset.\n\n            match_threshold: float number between 0 and 1 representing the threshold\n                to assign positive labels for anchors.\n        \"\"\"\n        super(AnchorLabeler, self).__init__()\n        similarity_calc = region_similarity_calculator.IouSimilarity()\n        matcher = argmax_matcher.ArgMaxMatcher(\n            match_threshold,\n            unmatched_threshold=match_threshold,\n            negatives_lower_than_unmatched=True,\n            force_match_for_each_row=True)\n        box_coder = faster_rcnn_box_coder.FasterRcnnBoxCoder()\n\n        self.target_assigner = target_assigner.TargetAssigner(similarity_calc, matcher, box_coder)\n        self.anchors = anchors\n        self.match_threshold = match_threshold\n        self.num_classes = num_classes\n\n    def _unpack_labels(self, labels):\n        \"\"\"Unpacks an array of labels into multiscales labels.\"\"\"\n        labels_unpacked = []\n        anchors = self.anchors\n        count = 0\n        for level in range(anchors.min_level, anchors.max_level + 1):\n            feat_size = int(anchors.image_size / 2 ** level)\n            steps = feat_size ** 2 * anchors.get_anchors_per_location()\n            indices = torch.arange(count, count + steps, device=labels.device)\n            count += steps\n            labels_unpacked.append(\n                torch.index_select(labels, 0, indices).view([feat_size, feat_size, -1]))\n        return labels_unpacked\n\n    def label_anchors(self, gt_boxes, gt_labels):\n        \"\"\"Labels anchors with ground truth inputs.\n\n        Args:\n            gt_boxes: A float tensor with shape [N, 4] representing groundtruth boxes.\n                For each row, it stores [y0, x0, y1, x1] for four corners of a box.\n\n            gt_labels: A integer tensor with shape [N, 1] representing groundtruth classes.\n\n        Returns:\n            cls_targets_dict: ordered dictionary with keys [min_level, min_level+1, ..., max_level].\n                The values are tensor with shape [height_l, width_l, num_anchors]. The height_l and width_l\n                represent the dimension of class logits at l-th level.\n\n            box_targets_dict: ordered dictionary with keys [min_level, min_level+1, ..., max_level].\n                The values are tensor with shape [height_l, width_l, num_anchors * 4]. The height_l and\n                width_l represent the dimension of bounding box regression output at l-th level.\n\n            num_positives: scalar tensor storing number of positives in an image.\n        \"\"\"\n        gt_box_list = box_list.BoxList(gt_boxes)\n        anchor_box_list = box_list.BoxList(self.anchors.boxes)\n\n        # cls_weights, box_weights are not used\n        cls_targets, _, box_targets, _, matches = self.target_assigner.assign(anchor_box_list, gt_box_list, gt_labels)\n\n        # class labels start from 1 and the background class = -1\n        cls_targets -= 1\n        cls_targets = cls_targets.long()\n\n        # Unpack labels.\n        cls_targets_dict = self._unpack_labels(cls_targets)\n        box_targets_dict = self._unpack_labels(box_targets)\n        num_positives = (matches.match_results != -1).float().sum()\n\n        return cls_targets_dict, box_targets_dict, num_positives\n\n\n\"\"\" PyTorch EfficientDet support benches\n\nHacked together by Ross Wightman\n\"\"\"\nimport torch\nimport torch.nn as nn\n#from .anchors import Anchors, AnchorLabeler, generate_detections, MAX_DETECTION_POINTS\nfrom effdet.loss import DetectionLoss\n\n\ndef _post_process(config, cls_outputs, box_outputs):\n    \"\"\"Selects top-k predictions.\n\n    Post-proc code adapted from Tensorflow version at: https://github.com/google/automl/tree/master/efficientdet\n    and optimized for PyTorch.\n\n    Args:\n        config: a parameter dictionary that includes `min_level`, `max_level`,  `batch_size`, and `num_classes`.\n\n        cls_outputs: an OrderDict with keys representing levels and values\n            representing logits in [batch_size, height, width, num_anchors].\n\n        box_outputs: an OrderDict with keys representing levels and values\n            representing box regression targets in [batch_size, height, width, num_anchors * 4].\n    \"\"\"\n    batch_size = cls_outputs[0].shape[0]\n    cls_outputs_all = torch.cat([\n        cls_outputs[level].permute(0, 2, 3, 1).reshape([batch_size, -1, config.num_classes])\n        for level in range(config.num_levels)], 1)\n\n    box_outputs_all = torch.cat([\n        box_outputs[level].permute(0, 2, 3, 1).reshape([batch_size, -1, 4])\n        for level in range(config.num_levels)], 1)\n\n    _, cls_topk_indices_all = torch.topk(cls_outputs_all.reshape(batch_size, -1), dim=1, k=MAX_DETECTION_POINTS)\n    indices_all = cls_topk_indices_all / config.num_classes\n    classes_all = cls_topk_indices_all % config.num_classes\n\n    box_outputs_all_after_topk = torch.gather(\n        box_outputs_all, 1, indices_all.unsqueeze(2).expand(-1, -1, 4))\n\n    cls_outputs_all_after_topk = torch.gather(\n        cls_outputs_all, 1, indices_all.unsqueeze(2).expand(-1, -1, config.num_classes))\n    cls_outputs_all_after_topk = torch.gather(\n        cls_outputs_all_after_topk, 2, classes_all.unsqueeze(2))\n\n    return cls_outputs_all_after_topk, box_outputs_all_after_topk, indices_all, classes_all\n\n\nclass DetBenchEval(nn.Module):\n    def __init__(self, model, config):\n        super(DetBenchEval, self).__init__()\n        self.config = config\n        self.model = model\n        self.anchors = Anchors(\n            config.min_level, config.max_level,\n            config.num_scales, config.aspect_ratios,\n            config.anchor_scale, config.image_size)\n\n    def forward(self, x, image_scales):\n        class_out, box_out = self.model(x)\n        class_out, box_out, indices, classes = _post_process(self.config, class_out, box_out)\n\n        batch_detections = []\n        # FIXME we may be able to do this as a batch with some tensor reshaping/indexing, PR welcome\n        for i in range(x.shape[0]):\n            detections = generate_detections(\n                class_out[i], box_out[i], self.anchors.boxes, indices[i], classes[i], image_scales[i])\n            batch_detections.append(detections)\n        return torch.stack(batch_detections, dim=0)\n\n\nclass DetBenchTrain(nn.Module):\n    def __init__(self, model, config):\n        super(DetBenchTrain, self).__init__()\n        self.config = config\n        self.model = model\n        anchors = Anchors(\n            config.min_level, config.max_level,\n            config.num_scales, config.aspect_ratios,\n            config.anchor_scale, config.image_size)\n        self.anchor_labeler = AnchorLabeler(anchors, config.num_classes, match_threshold=0.5)\n        self.loss_fn = DetectionLoss(self.config)\n\n    def forward(self, x, gt_boxes, gt_labels):\n        class_out, box_out = self.model(x)\n\n        cls_targets = []\n        box_targets = []\n        num_positives = []\n        # FIXME this may be a bottleneck, would be faster if batched, or should be done in loader/dataset?\n        for i in range(x.shape[0]):\n            gt_class_out, gt_box_out, num_positive = self.anchor_labeler.label_anchors(gt_boxes[i], gt_labels[i])\n            cls_targets.append(gt_class_out)\n            box_targets.append(gt_box_out)\n            num_positives.append(num_positive)\n\n        return self.loss_fn(class_out, box_out, cls_targets, box_targets, num_positives)\n","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Hyperparameters","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"SIZE = 1024\n\nWEIGHT_FILE1 = '../input/effdet5fold/stac2.bin'\nWEIGHT_FILE2 = '../input/effdet5fold/splitbn.bin'\n\nSTAGE1_THRESHOLD = 0.25\nSTAGE1_IOU_THR = 0.475\nSTAGE1_SKIP_THR = 0.41\n\nSTAGE1_SUPPRESS = 0.125\n\nSTAGE2_THRESHOLD = 0.37\nSTAGE2_IOU_THR = 0.44\nSTAGE2_SKIP_THR = 0.43\n\nSTAGE2_SUPPRESS = 0.125\n\nMAX_BOX = 240\nMIN_BOX = 10\n\nEPOCHS_1 = 13\nEPOCHS_2 = 13","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# WBF Source Code (Hidden)","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"# coding: utf-8\n__author__ = 'ZFTurbo: https://kaggle.com/zfturbo'\n\n\nimport warnings\nimport numpy as np\nfrom numba import jit\n\n\n@jit(nopython=True)\ndef bb_intersection_over_union(A, B) -> float:\n    xA = max(A[0], B[0])\n    yA = max(A[1], B[1])\n    xB = min(A[2], B[2])\n    yB = min(A[3], B[3])\n\n    # compute the area of intersection rectangle\n    interArea = max(0, xB - xA) * max(0, yB - yA)\n\n    if interArea == 0:\n        return 0.0\n\n    # compute the area of both the prediction and ground-truth rectangles\n    boxAArea = (A[2] - A[0]) * (A[3] - A[1])\n    boxBArea = (B[2] - B[0]) * (B[3] - B[1])\n\n    iou = interArea / float(boxAArea + boxBArea - interArea)\n    \n    center_x1 = (A[2] + A[0]) / 2\n    center_y1 = (A[3] + A[1]) / 2\n    center_x2 = (B[2] + B[0]) / 2\n    center_y2 = (B[3] + B[1]) / 2\n    d_2 = (center_x1 - center_x2) ** 2 + (center_y1 - center_y2) ** 2\n    c_2 = (max(A[2], B[2]) - min(A[0], B[0])) ** 2 + (\n            max(A[3], B[3]) - min(A[1], B[1])) ** 2\n    \n    d_iou = max(min(iou - d_2 / c_2, 1),-1)\n    \n    return d_iou\n\ndef prefilter_boxes(boxes, scores, labels, weights, thr):\n    # Create dict with boxes stored by its label\n    new_boxes = dict()\n\n    for t in range(len(boxes)):\n\n        if len(boxes[t]) != len(scores[t]):\n            print('Error. Length of boxes arrays not equal to length of scores array: {} != {}'.format(len(boxes[t]), len(scores[t])))\n            exit()\n\n        if len(boxes[t]) != len(labels[t]):\n            print('Error. Length of boxes arrays not equal to length of labels array: {} != {}'.format(len(boxes[t]), len(labels[t])))\n            exit()\n\n        for j in range(len(boxes[t])):\n            score = scores[t][j]\n            if score < thr:\n                continue\n            label = int(labels[t][j])\n            box_part = boxes[t][j]\n            x1 = float(box_part[0])\n            y1 = float(box_part[1])\n            x2 = float(box_part[2])\n            y2 = float(box_part[3])\n\n            # Box data checks\n            if x2 < x1:\n                warnings.warn('X2 < X1 value in box. Swap them.')\n                x1, x2 = x2, x1\n            if y2 < y1:\n                warnings.warn('Y2 < Y1 value in box. Swap them.')\n                y1, y2 = y2, y1\n            if x1 < 0:\n                warnings.warn('X1 < 0 in box. Set it to 0.')\n                x1 = 0\n            if x1 > 1:\n                warnings.warn('X1 > 1 in box. Set it to 1. Check that you normalize boxes in [0, 1] range.')\n                x1 = 1\n            if x2 < 0:\n                warnings.warn('X2 < 0 in box. Set it to 0.')\n                x2 = 0\n            if x2 > 1:\n                warnings.warn('X2 > 1 in box. Set it to 1. Check that you normalize boxes in [0, 1] range.')\n                x2 = 1\n            if y1 < 0:\n                warnings.warn('Y1 < 0 in box. Set it to 0.')\n                y1 = 0\n            if y1 > 1:\n                warnings.warn('Y1 > 1 in box. Set it to 1. Check that you normalize boxes in [0, 1] range.')\n                y1 = 1\n            if y2 < 0:\n                warnings.warn('Y2 < 0 in box. Set it to 0.')\n                y2 = 0\n            if y2 > 1:\n                warnings.warn('Y2 > 1 in box. Set it to 1. Check that you normalize boxes in [0, 1] range.')\n                y2 = 1\n            if (x2 - x1) * (y2 - y1) == 0.0:\n                warnings.warn(\"Zero area box skipped: {}.\".format(box_part))\n                continue\n\n            b = [int(label), float(score) * weights[t], x1, y1, x2, y2]\n            if label not in new_boxes:\n                new_boxes[label] = []\n            new_boxes[label].append(b)\n\n    # Sort each list in dict by score and transform it to numpy array\n    for k in new_boxes:\n        current_boxes = np.array(new_boxes[k])\n        new_boxes[k] = current_boxes[current_boxes[:, 1].argsort()[::-1]]\n\n    return new_boxes\n\n\ndef get_weighted_box(boxes, conf_type='avg'):\n    \"\"\"\n    Create weighted box for set of boxes\n    :param boxes: set of boxes to fuse\n    :param conf_type: type of confidence one of 'avg' or 'max'\n    :return: weighted box\n    \"\"\"\n\n    box = np.zeros(6, dtype=np.float32)\n    conf = 0\n    conf_list = []\n    for b in boxes:\n        box[2:] += (b[1] * b[2:])\n        conf += b[1]\n        conf_list.append(b[1])\n    box[0] = boxes[0][0]\n    if conf_type == 'avg':\n        box[1] = conf / len(boxes)\n    elif conf_type == 'max':\n        box[1] = np.array(conf_list).max()\n    box[2:] /= conf\n    return box\n\n\ndef find_matching_box(boxes_list, new_box, match_iou):\n    best_iou = match_iou\n    best_index = -1\n    for i in range(len(boxes_list)):\n        box = boxes_list[i]\n        if box[0] != new_box[0]:\n            continue\n        iou = bb_intersection_over_union(box[2:], new_box[2:])\n        if iou > best_iou:\n            best_index = i\n            best_iou = iou\n\n    return best_index, best_iou\n\n\ndef weighted_boxes_fusion(boxes_list, scores_list, labels_list, weights=None, iou_thr=0.55, skip_box_thr=0.0, conf_type='avg', allows_overflow=False):\n    '''\n    :param boxes_list: list of boxes predictions from each model, each box is 4 numbers.\n    It has 3 dimensions (models_number, model_preds, 4)\n    Order of boxes: x1, y1, x2, y2. We expect float normalized coordinates [0; 1]\n    :param scores_list: list of scores for each model\n    :param labels_list: list of labels for each model\n    :param weights: list of weights for each model. Default: None, which means weight == 1 for each model\n    :param iou_thr: IoU value for boxes to be a match\n    :param skip_box_thr: exclude boxes with score lower than this variable\n    :param conf_type: how to calculate confidence in weighted boxes. 'avg': average value, 'max': maximum value\n    :param allows_overflow: false if we want confidence score not exceed 1.0\n    :return: boxes: boxes coordinates (Order of boxes: x1, y1, x2, y2).\n    :return: scores: confidence scores\n    :return: labels: boxes labels\n    '''\n\n    if weights is None:\n        weights = np.ones(len(boxes_list))\n    if len(weights) != len(boxes_list):\n        print('Warning: incorrect number of weights {}. Must be: {}. Set weights equal to 1.'.format(len(weights), len(boxes_list)))\n        weights = np.ones(len(boxes_list))\n    weights = np.array(weights)\n\n    if conf_type not in ['avg', 'max']:\n        print('Unknown conf_type: {}. Must be \"avg\" or \"max\"'.format(conf_type))\n        exit()\n\n    filtered_boxes = prefilter_boxes(boxes_list, scores_list, labels_list, weights, skip_box_thr)\n    if len(filtered_boxes) == 0:\n        return np.zeros((0, 4)), np.zeros((0,)), np.zeros((0,))\n\n    overall_boxes = []\n    for label in filtered_boxes:\n        boxes = filtered_boxes[label]\n        new_boxes = []\n        weighted_boxes = []\n\n        # Clusterize boxes\n        for j in range(0, len(boxes)):\n            index, best_iou = find_matching_box(weighted_boxes, boxes[j], iou_thr)\n            if index != -1:\n                new_boxes[index].append(boxes[j])\n                weighted_boxes[index] = get_weighted_box(new_boxes[index], conf_type)\n            else:\n                new_boxes.append([boxes[j].copy()])\n                weighted_boxes.append(boxes[j].copy())# Eval Bench Definition (Hidden)\n\n        # Rescale confidence based on number of models and boxes\n        for i in range(len(new_boxes)):\n            if not allows_overflow:\n                weighted_boxes[i][1] = weighted_boxes[i][1] * min(weights.sum(), len(new_boxes[i])) / weights.sum()\n            else:\n                weighted_boxes[i][1] = weighted_boxes[i][1] * len(new_boxes[i]) / weights.sum()\n        overall_boxes.append(np.array(weighted_boxes))\n\n    overall_boxes = np.concatenate(overall_boxes, axis=0)\n    overall_boxes = overall_boxes[overall_boxes[:, 1].argsort()[::-1]]\n    boxes = overall_boxes[:, 2:]\n    scores = overall_boxes[:, 1]\n    labels = overall_boxes[:, 0]\n    return boxes, scores, labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_valid_transforms():\n    return A.Compose([\n            A.Resize(height=SIZE, width=SIZE, p=1.0),\n            ToTensorV2(p=1.0),\n        ], p=1.0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_ROOT_PATH = '../input/global-wheat-detection/test'\n\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, image_ids, transforms=None):\n        super().__init__()\n        self.image_ids = image_ids\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        image = cv2.imread(f'{DATA_ROOT_PATH}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n        if self.transforms:\n            sample = {'image': image}\n            sample = self.transforms(**sample)\n            image = sample['image']\n        return image, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dataset = DatasetRetriever(\n    image_ids=np.array([path.split('/')[-1][:-4] for path in glob(f'{DATA_ROOT_PATH}/*.jpg')]),\n    transforms=get_valid_transforms()\n)\n\ndef collate_fn(batch):\n    return tuple(zip(*batch))\n\ndata_loader = DataLoader(\n    dataset,\n    batch_size=4,\n    shuffle=False,\n    num_workers=2,\n    drop_last=False,\n    collate_fn=collate_fn\n)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_net(checkpoint_path):\n    config = get_efficientdet_config('tf_efficientdet_d6')\n    net = EfficientDet(config, pretrained_backbone=False)\n\n    config.num_classes = 1\n    config.image_size=SIZE\n    net.class_net = HeadNet(config, num_outputs=config.num_classes, norm_kwargs=dict(eps=.001, momentum=.01))\n\n    checkpoint = torch.load(checkpoint_path)\n    \n    newc = {}\n    for k,v in checkpoint['model_state_dict'].items():\n        if 'aux_bn' not in k:\n            newc[k] = v\n    net.load_state_dict(newc)\n\n    del checkpoint\n    gc.collect()\n\n    net = DetBenchEval(net, config)\n    net.eval();\n    return net.cuda()\n\nnet = load_net(WEIGHT_FILE1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# TTA Code (Hidden)","execution_count":null},{"metadata":{"trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"class BaseWheatTTA:\n    \"\"\" author: @shonenkov \"\"\"\n    image_size = SIZE\n\n    def augment(self, image):\n        raise NotImplementedError\n    \n    def batch_augment(self, images):\n        raise NotImplementedError\n    \n    def deaugment_boxes(self, boxes):\n        raise NotImplementedError\n\nclass TTAHorizontalFlip(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n\n    def augment(self, image):\n        return image.flip(1)\n    \n    def batch_augment(self, images):\n        return images.flip(2)\n    \n    def deaugment_boxes(self, boxes):\n        boxes[:, [1,3]] = self.image_size - boxes[:, [3,1]]\n        return boxes\n\nclass TTAVerticalFlip(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n    \n    def augment(self, image):\n        return image.flip(2)\n    \n    def batch_augment(self, images):\n        return images.flip(3)\n    \n    def deaugment_boxes(self, boxes):\n        boxes[:, [0,2]] = self.image_size - boxes[:, [2,0]]\n        return boxes\n    \nclass TTARotate90(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n    \n    def augment(self, image):\n        return torch.rot90(image, 1, (1, 2))\n\n    def batch_augment(self, images):\n        return torch.rot90(images, 1, (2, 3))\n    \n    def deaugment_boxes(self, boxes):\n        res_boxes = boxes.copy()\n        res_boxes[:, [0,2]] = self.image_size - boxes[:, [1,3]]\n        res_boxes[:, [1,3]] = boxes[:, [2,0]]\n        return res_boxes\n    \nclass TTARotate180(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n    \n    def augment(self, image):\n        return torch.rot90(image, 2, (1, 2))\n\n    def batch_augment(self, images):\n        return torch.rot90(images, 2, (2, 3))\n    \n    def deaugment_boxes(self, boxes):\n        boxes[:, [0,1,2,3]] = self.image_size - boxes[:, [2,3,0,1]]\n        return boxes\n    \nclass TTARotate270(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n    \n    def augment(self, image):\n        return torch.rot90(image, 3, (1, 2))\n\n    def batch_augment(self, images):\n        return torch.rot90(images, 3, (2, 3))\n    \n    def deaugment_boxes(self, boxes):\n        res_boxes = boxes.copy()\n        res_boxes[:, [0,2]] = boxes[:, [1,3]]\n        res_boxes[:, [1,3]] = self.image_size - boxes[:, [2,0]]\n        return res_boxes\n    \nclass TTACompose(BaseWheatTTA):\n    \"\"\" author: @shonenkov \"\"\"\n    def __init__(self, transforms):\n        self.transforms = transforms\n        \n    def augment(self, image):\n        for transform in self.transforms:\n            image = transform.augment(image)\n        return image\n    \n    def batch_augment(self, images):\n        for transform in self.transforms:\n            images = transform.batch_augment(images)\n        return images\n    \n    def prepare_boxes(self, boxes):\n        result_boxes = boxes.copy()\n        result_boxes[:,0] = np.min(boxes[:, [0,2]], axis=1)\n        result_boxes[:,2] = np.max(boxes[:, [0,2]], axis=1)\n        result_boxes[:,1] = np.min(boxes[:, [1,3]], axis=1)\n        result_boxes[:,3] = np.max(boxes[:, [1,3]], axis=1)\n        return result_boxes\n    \n    def deaugment_boxes(self, boxes):\n        for transform in self.transforms[::-1]:\n            boxes = transform.deaugment_boxes(boxes)\n        return self.prepare_boxes(boxes)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from itertools import product\n\ntta_combinations = [[TTARotate270()],[None],[TTARotate90()],[TTARotate180()],[TTAVerticalFlip(),TTARotate270()],[TTAVerticalFlip(),TTARotate90()],[TTAVerticalFlip()],[TTAHorizontalFlip()] ]\n\ntta_transforms = []\nfor tta_combination in tta_combinations:\n    print([tta_transform for tta_transform in tta_combination if tta_transform])\n    tta_transforms.append(TTACompose([tta_transform for tta_transform in tta_combination if tta_transform]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(tta_transforms)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def make_tta_predictions(images, score_threshold=STAGE1_THRESHOLD):\n    with torch.no_grad():\n        images = torch.stack(images).float().cuda()\n        predictions = []\n        for tta_transform in tta_transforms:\n            result = []\n            det = net(tta_transform.batch_augment(images.clone()), torch.tensor([1]*images.shape[0]).float().cuda())\n\n            for i in range(images.shape[0]):\n                boxes = det[i].detach().cpu().numpy()[:,:4]    \n                scores = det[i].detach().cpu().numpy()[:,4]\n                indexes = np.where(scores > score_threshold)[0]\n                boxes = boxes[indexes]\n                boxes[:, 2] = boxes[:, 2] + boxes[:, 0]\n                boxes[:, 3] = boxes[:, 3] + boxes[:, 1]\n                boxes = tta_transform.deaugment_boxes(boxes.copy())\n                result.append({\n                    'boxes': boxes,\n                    'scores': scores[indexes],\n                })\n            predictions.append(result)\n        del images\n        gc.collect()\n    return predictions\n\ndef run_wbf(predictions, image_index, image_size=SIZE, iou_thr=STAGE1_IOU_THR, skip_box_thr=STAGE1_SKIP_THR, weights=None):\n    boxes = [(prediction[image_index]['boxes']/(image_size-1)).tolist() for prediction in predictions]\n    scores = [prediction[image_index]['scores'].tolist() for prediction in predictions]\n    labels = [np.ones(prediction[image_index]['scores'].shape[0]).astype(int).tolist() for prediction in predictions]\n    if (len(boxes)==0): return boxes, scores, labels\n    try:\n        boxes, scores, labels = weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    except:\n        return [], [], []\n    boxes = boxes*(image_size-1)\n    return boxes, scores, labels","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Generating Pseudo-Labels","execution_count":null},{"metadata":{"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(\"[{1}, {2}, {3}, {4}]\".format(j[0], j[1][0], j[1][1], j[1][2], j[1][3]))\n    return pred_strings","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from tqdm import tqdm\n\nresults = []\n\nfor images, image_ids in tqdm(data_loader):\n    predictions = make_tta_predictions(images)\n    for i, image in enumerate(images):\n        \n        boxes, scores, labels = run_wbf(predictions, image_index=i)\n        \n        boxes = (boxes).round().astype(np.int32).clip(min=0, max=1023)\n        image_id = image_ids[i]\n\n        \n        score_threshold = STAGE1_SUPPRESS\n        indexes = np.where(scores>score_threshold)\n        boxes = boxes[indexes]\n        scores = scores[indexes]\n        \n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n\n        bboxes = (format_prediction_string(boxes, scores))\n        for bbox in bboxes:\n            result = {\n                'image_id': image_id,\n                'width': 1024,\n                'height': 1024,\n                'bbox': bbox,\n                'source': 'pseudo'\n            }\n            results.append(result)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.DataFrame(results, columns=['image_id', 'width', 'height', 'bbox', 'source'])\ntest_df.to_csv('pseudo.csv', index=False)\ntest_df.head()\nprint(len(test_df))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del net\nimport gc\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Pseudo-Labels for Model 2","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"net = load_net(WEIGHT_FILE2)\n\nresults = []\n\nfor images, image_ids in tqdm(data_loader):\n    predictions = make_tta_predictions(images)\n    for i, image in enumerate(images):\n        \n        boxes, scores, labels = run_wbf(predictions, image_index=i)\n        \n        boxes = (boxes).round().astype(np.int32).clip(min=0, max=1023)\n        image_id = image_ids[i]\n\n        \n        score_threshold = STAGE1_SUPPRESS\n        indexes = np.where(scores>score_threshold)\n        boxes = boxes[indexes]\n        scores = scores[indexes]\n        \n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n\n        bboxes = (format_prediction_string(boxes, scores))\n        for bbox in bboxes:\n            result = {\n                'image_id': image_id,\n                'width': 1024,\n                'height': 1024,\n                'bbox': bbox,\n                'source': 'pseudo'\n            }\n            results.append(result)\n            \ntest_df = pd.DataFrame(results, columns=['image_id', 'width', 'height', 'bbox', 'source'])\ntest_df.to_csv('pseudo2.csv', index=False)\ntest_df.head()\nprint(len(test_df))\n\ndel net\nimport gc\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preparing PL Model 1","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport os\nfrom datetime import datetime\nimport time\nimport random\nimport cv2\nimport pandas as pd\nimport numpy as np\nimport albumentations as A\nimport matplotlib.pyplot as plt\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom sklearn.model_selection import StratifiedKFold\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\nfrom glob import glob\n\nSEED = 42\n\ndef seed_everything(seed):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n    torch.backends.cudnn.benchmark = True\n\nseed_everything(SEED)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Dataset ","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv('pseudo.csv')\n\nbad_boxes = [3687, 117344,173,113947,52868,2159,2169,121633,121634,147504,118211,52727,147552]\n\nmarking = pd.concat([pd.read_csv('../input/global-wheat-detection/train.csv'),test_df]) #if len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10 else pd.concat([test_df, test_df])\n\nif len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10: \n    marking.drop(bad_boxes)\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)\n\ntargets = set(marking.source.values)\nif len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10:\n    targets.remove('arvalis_3')\n    targets.remove('usask_1')\n\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\ndf_folds = marking[['image_id']].copy()\ndf_folds.loc[:, 'bbox_count'] = 1\ndf_folds = df_folds.groupby('image_id').count()\ndf_folds.loc[:, 'source'] = marking[['image_id', 'source']].groupby('image_id').min()['source']\ndf_folds.loc[:, 'stratify_group'] = np.char.add(\n    df_folds['source'].values.astype(str),\n    df_folds['bbox_count'].apply(lambda x: f'_{x // 15}').values.astype(str)\n)\ndf_folds.loc[:, 'fold'] = 0\n\nprint(set(df_folds.source.values))\n\nfor fold_number, (train_index, val_index) in enumerate(skf.split(X=df_folds.index, y=df_folds['stratify_group'])):\n    df_folds.loc[df_folds.iloc[val_index].index, 'fold'] = fold_number\n\ndf_folds = pd.concat([ df_folds.loc[df_folds['source'] == i, :] for i in targets])\n\ndf_folds.loc[df_folds['source']=='pseudo','fold'] = 1\ndf_folds.loc[df_folds['fold']==4,'fold'] = 1","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"def get_train_transforms():\n    return A.Compose(\n        [\n            A.RandomSizedCrop(min_max_height=(800, 1024), height=1024, width=1024, p=0.5),\n            A.OneOf([\n                A.HueSaturationValue(hue_shift_limit=0.2, sat_shift_limit= 0.2, \n                                     val_shift_limit=0.2, p=0.9),\n                A.RandomBrightnessContrast(brightness_limit=0.2, \n                                           contrast_limit=0.2, p=0.9),\n            ],p=0.9),\n            A.ToGray(p=0.01),\n            A.HorizontalFlip(p=0.5),\n            A.VerticalFlip(p=0.5),\n            A.RandomRotate90(p=0.5),\n        A.Transpose(p=0.5),\n        A.JpegCompression(quality_lower=85, quality_upper=95, p=0.2),\n        A.OneOf([\n        A.Blur(blur_limit=3, p=1.0),\n        A.MedianBlur(blur_limit=3, p=1.0)\n        ],p=0.1),\n            A.Resize(height=SIZE, width=SIZE, p=1),\n            A.Cutout(num_holes=8, max_h_size=64, max_w_size=64, fill_value=0, p=0.5),\n            ToTensorV2(p=1.0),\n        ], \n        p=1.0, \n        bbox_params=A.BboxParams(\n            format='pascal_voc',\n            min_area=0, \n            min_visibility=0,\n            label_fields=['labels']\n        )\n    )\n\ndef get_valid_transforms():\n    return A.Compose(\n        [\n            A.Resize(height=SIZE, width=SIZE, p=1.0),\n            ToTensorV2(p=1.0),\n        ], \n        p=1.0, \n        bbox_params=A.BboxParams(\n            format='pascal_voc',\n            min_area=0, \n            min_visibility=0,\n            label_fields=['labels']\n        )\n    )\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#!mkdir /kaggle/working/pseudoset\n#!cp -r /kaggle/input/global-wheat-detection/train/* /kaggle/working/pseudoset\n#!cp -r /kaggle/input/global-wheat-detection/test/* /kaggle/working/pseudoset","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"TRAIN_ROOT_PATH = '/kaggle/input/global-wheat-detection/train'\nTEST_ROOT_PATH = '/kaggle/input/global-wheat-detection/test'\nDATASET_PATH = '/kaggle/working/pseudoset'\n\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, marking, image_ids, transforms=None, test=False):\n        super().__init__()\n\n        self.image_ids = image_ids\n        self.marking = marking\n        self.transforms = transforms\n        self.test = test\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        \n        if self.test or random.random() > 0.33:\n            image, boxes = self.load_image_and_boxes(index)\n        else:\n            image, boxes = self.load_cutmix_image_and_boxes(index)\n\n        # there is only one class\n        labels = torch.ones((boxes.shape[0],), dtype=torch.int64)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = labels\n        target['image_id'] = torch.tensor([index])\n\n        if self.transforms:\n            for i in range(10):\n                sample = self.transforms(**{\n                    'image': image,\n                    'bboxes': target['boxes'],\n                    'labels': labels\n                })\n                if len(sample['bboxes']) > 0:\n                    image = sample['image']\n                    target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)\n                    target['boxes'][:,[0,1,2,3]] = target['boxes'][:,[1,0,3,2]]  #yxyx: be warning\n                    break\n\n        return image, target, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]\n\n    def load_image_and_boxes(self, index):\n        image_id = self.image_ids[index]\n        records = self.marking[self.marking['image_id'] == image_id]\n        \n        PATH = TEST_ROOT_PATH if (records.iloc[0].source == 'pseudo') else TRAIN_ROOT_PATH\n        image = cv2.imread(f'{PATH}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n\n        boxes = records[['x', 'y', 'w', 'h']].values\n        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]\n        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]\n        return image, boxes\n\n    def load_mixup_image_and_boxes(self, index):\n        image, boxes = self.load_image_and_boxes(index)\n        r_image, r_boxes = self.load_image_and_boxes(random.randint(0, self.image_ids.shape[0] - 1))\n        return (image+r_image)/2, np.vstack((boxes, r_boxes)).astype(np.int32)\n\n    def load_cutmix_image_and_boxes(self, index, imsize=1024):\n        \"\"\" \n        This implementation of cutmix author:  https://www.kaggle.com/nvnnghia \n        Refactoring and adaptation: https://www.kaggle.com/shonenkov\n        \"\"\"\n        w, h = imsize, imsize\n        s = imsize // 2\n    \n        xc, yc = [int(random.uniform(imsize * 0.25, imsize * 0.75)) for _ in range(2)]  # center x, y\n        indexes = [index] + [random.randint(0, self.image_ids.shape[0] - 1) for _ in range(3)]\n\n        result_image = np.full((imsize, imsize, 3), 1, dtype=np.float32)\n        result_boxes = []\n\n        for i, index in enumerate(indexes):\n            image, boxes = self.load_image_and_boxes(index)\n            if i == 0:\n                x1a, y1a, x2a, y2a = max(xc - w, 0), max(yc - h, 0), xc, yc  # xmin, ymin, xmax, ymax (large image)\n                x1b, y1b, x2b, y2b = w - (x2a - x1a), h - (y2a - y1a), w, h  # xmin, ymin, xmax, ymax (small image)\n            elif i == 1:  # top right\n                x1a, y1a, x2a, y2a = xc, max(yc - h, 0), min(xc + w, s * 2), yc\n                x1b, y1b, x2b, y2b = 0, h - (y2a - y1a), min(w, x2a - x1a), h\n            elif i == 2:  # bottom left\n                x1a, y1a, x2a, y2a = max(xc - w, 0), yc, xc, min(s * 2, yc + h)\n                x1b, y1b, x2b, y2b = w - (x2a - x1a), 0, max(xc, w), min(y2a - y1a, h)\n            elif i == 3:  # bottom right\n                x1a, y1a, x2a, y2a = xc, yc, min(xc + w, s * 2), min(s * 2, yc + h)\n                x1b, y1b, x2b, y2b = 0, 0, min(w, x2a - x1a), min(y2a - y1a, h)\n            result_image[y1a:y2a, x1a:x2a] = image[y1b:y2b, x1b:x2b]\n            padw = x1a - x1b\n            padh = y1a - y1b\n\n            boxes[:, 0] += padw\n            boxes[:, 1] += padh\n            boxes[:, 2] += padw\n            boxes[:, 3] += padh\n\n            result_boxes.append(boxes)\n\n        result_boxes = np.concatenate(result_boxes, 0)\n        np.clip(result_boxes[:, 0:], 0, 2 * s, out=result_boxes[:, 0:])\n        result_boxes = result_boxes.astype(np.int32)\n        result_boxes = result_boxes[np.where((result_boxes[:,2]-result_boxes[:,0])*(result_boxes[:,3]-result_boxes[:,1]) > 0)]\n        return result_image, result_boxes\n\nclass AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\nimport warnings\n\nwarnings.filterwarnings(\"ignore\")\n\nclass Fitter:\n    \n    def __init__(self, model, device, config):\n        self.config = config\n        self.epoch = 0\n\n        self.base_dir = f'./{config.folder}'\n        if not os.path.exists(self.base_dir):\n            os.makedirs(self.base_dir)\n        \n        self.log_path = f'{self.base_dir}/log.txt'\n        self.best_summary_loss = 10**5\n\n        self.model = model\n        self.device = device\n\n        param_optimizer = list(self.model.named_parameters())\n        no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']\n        optimizer_grouped_parameters = [\n            {'params': [p for n, p in param_optimizer if not any(nd in n for nd in no_decay)], 'weight_decay': 0.001},\n            {'params': [p for n, p in param_optimizer if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}\n        ] \n\n        self.optimizer = torch.optim.AdamW(self.model.parameters(), lr=config.lr)\n        self.scheduler = config.SchedulerClass(self.optimizer, **config.scheduler_params)\n        self.log(f'Fitter prepared. Device is {self.device}')\n        \n        opt_level = 'O1'\n        #model, optimizer = amp.initialize(self.model, self.optimizer, opt_level=opt_level)\n        #self.model = model\n        #self.optimizer = optimizer\n        \n    def fit(self, train_loader, validation_loader):\n        for e in range(self.config.n_epochs):\n            if self.config.verbose:\n                lr = self.optimizer.param_groups[0]['lr']\n                timestamp = datetime.utcnow().isoformat()\n                self.log(f'\\n{timestamp}\\nLR: {lr}')\n\n            t = time.time()\n            summary_loss = self.train_one_epoch(train_loader)\n\n            self.log(f'[RESULT]: Train. Epoch: {self.epoch}, summary_loss: {summary_loss.avg:.5f}, time: {(time.time() - t):.5f}')\n\n            t = time.time()\n            summary_loss = self.validation(validation_loader)\n\n            self.log(f'[RESULT]: Val. Epoch: {self.epoch}, summary_loss: {summary_loss.avg:.5f}, time: {(time.time() - t):.5f}')\n            #if summary_loss.avg < self.best_summary_loss:\n            self.best_summary_loss = summary_loss.avg\n            self.model.eval()\n            self.save(f'{self.base_dir}/best-checkpoint.bin')\n\n            if self.config.validation_scheduler:\n                self.scheduler.step(metrics=summary_loss.avg)\n\n            self.epoch += 1\n            \n            if len(glob(f'../input/global-wheat-detection/test/*.jpg')) == 10: break\n\n    def validation(self, val_loader):\n        self.model.eval()\n        summary_loss = AverageMeter()\n        t = time.time()\n        for step, (images, targets, image_ids) in enumerate(val_loader):\n            if self.config.verbose:\n                if step % self.config.verbose_step == 0:\n                    print(\n                        f'Val Step {step}/{len(val_loader)}, ' + \\\n                        f'summary_loss: {summary_loss.avg:.5f}, ' + \\\n                        f'time: {(time.time() - t):.5f}', end='\\r'\n                    )\n            with torch.no_grad():\n                images = torch.stack(images)\n                batch_size = images.shape[0]\n                images = images.to(self.device).float()\n                boxes = [target['boxes'].to(self.device).float() for target in targets]\n                labels = [target['labels'].to(self.device).float() for target in targets]\n\n                loss, _, _ = self.model(images, boxes, labels)\n                summary_loss.update(loss.detach().item(), batch_size)\n\n        return summary_loss\n\n    def train_one_epoch(self, train_loader):\n        self.model.train()\n        summary_loss = AverageMeter()\n        t = time.time()\n        for step, (images, targets, image_ids) in enumerate(train_loader):\n            if self.config.verbose:\n                if step % self.config.verbose_step == 0:\n                    print(\n                        f'Train Step {step}/{len(train_loader)}, ' + \\\n                        f'summary_loss: {summary_loss.avg:.5f}, ' + \\\n                        f'time: {(time.time() - t):.5f}', end='\\r'\n                    )\n            \n            images = torch.stack(images)\n            images = images.to(self.device).float()\n            batch_size = images.shape[0]\n            boxes = [target['boxes'].to(self.device).float() for target in targets]\n            labels = [target['labels'].to(self.device).float() for target in targets]\n            \n            loss, _, _ = self.model(images, boxes, labels)\n            \n            loss.backward()\n\n            summary_loss.update(loss.detach().item(), batch_size)\n\n            if (step+1) % 1 == 0:             # Wait for several backward steps\n                self.optimizer.step()\n                self.optimizer.zero_grad()\n\n            if self.config.step_scheduler:\n                self.scheduler.step()\n                \n            if len(glob(f'../input/global-wheat-detection/test/*.jpg')) == 10 and step == 5: break\n\n        return summary_loss\n    \n    def save(self, path):\n        self.model.eval()\n        torch.save({\n            'model_state_dict': self.model.model.state_dict(),\n            'optimizer_state_dict': self.optimizer.state_dict(),\n            'scheduler_state_dict': self.scheduler.state_dict(),\n            'best_summary_loss': self.best_summary_loss,\n            'epoch': self.epoch,\n        }, path)\n\n    def load(self, path):\n        checkpoint = torch.load(path)\n        self.model.model.load_state_dict(checkpoint['model_state_dict'])\n        self.optimizer.load_state_dict(checkpoint['optimizer_state_dict'])\n        self.scheduler.load_state_dict(checkpoint['scheduler_state_dict'])\n        self.best_summary_loss = checkpoint['best_summary_loss']\n        self.epoch = checkpoint['epoch'] + 1\n        \n    def log(self, message):\n        if self.config.verbose:\n            print(message)\n        with open(self.log_path, 'a+') as logger:\n            logger.write(f'{message}\\n')\n\ndef collate_fn(batch):\n    return tuple(zip(*batch))","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-input":true,"trusted":true},"cell_type":"code","source":"from effdet import get_efficientdet_config, EfficientDet, DetBenchTrain\nfrom effdet.efficientdet import HeadNet\n\ndef get_net(checkpoint_path):\n    config = get_efficientdet_config('tf_efficientdet_d6')\n    net = EfficientDet(config, pretrained_backbone=False)\n\n    config.num_classes = 1\n    config.image_size= SIZE\n    net.class_net = HeadNet(config, num_outputs=config.num_classes, norm_kwargs=dict(eps=.001, momentum=.01))\n\n    checkpoint = torch.load(checkpoint_path)\n    newc = {}\n    \n    for k,v in checkpoint['model_state_dict'].items():\n        if 'aux_bn' not in k: newc[k]=v\n    net.load_state_dict(newc)\n\n    del checkpoint\n    gc.collect()\n\n    for param in net.backbone.parameters():\n        param.requires_grad = False\n        \n    net = DetBenchTrain(net, config)\n    return net.cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = DatasetRetriever(\n    image_ids=df_folds[df_folds['fold'] == 1].index.values,\n    marking=marking,\n    transforms=get_train_transforms(),\n    test=False,\n)\n\nvalidation_dataset = DatasetRetriever(\n    image_ids=df_folds[df_folds['fold'] == 0].index.values,\n    marking=marking,\n    transforms=get_valid_transforms(),\n    test=True,\n)\n\n\nclass TrainGlobalConfig:\n    num_workers = 4\n    batch_size = 4\n    n_epochs = EPOCHS_1\n    lr = 0.0001 * 0.05\n\n    folder = 'pseudo'\n\n    verbose = True\n    verbose_step = 1\n\n    step_scheduler = False  # do scheduler.step after optimizer.step\n    validation_scheduler = True  # do scheduler.step after validation stage loss\n\n    SchedulerClass = torch.optim.lr_scheduler.ReduceLROnPlateau\n    scheduler_params = dict(\n        mode='min',\n        factor=0.5,\n        patience=6,\n        verbose=False, \n        threshold=0.0001,\n        threshold_mode='abs',\n        cooldown=0, \n        min_lr=1e-8,\n        eps=1e-08\n    )\n\ndef run_training():\n    device = torch.device('cuda:0')\n    net.to(device)\n\n    train_loader = torch.utils.data.DataLoader(\n        train_dataset,\n        batch_size=TrainGlobalConfig.batch_size,\n        sampler=RandomSampler(train_dataset),\n        pin_memory=False,\n        drop_last=True,\n        num_workers=TrainGlobalConfig.num_workers,\n        collate_fn=collate_fn,\n    )\n    val_loader = torch.utils.data.DataLoader(\n        validation_dataset, \n        batch_size=TrainGlobalConfig.batch_size,\n        num_workers=TrainGlobalConfig.num_workers,\n        shuffle=False,\n        sampler=SequentialSampler(validation_dataset),\n        pin_memory=False,\n        collate_fn=collate_fn,\n    )\n\n    fitter = Fitter(model=net, device=device, config=TrainGlobalConfig)\n    fitter.fit(train_loader, val_loader)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.cuda.empty_cache()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = get_net(WEIGHT_FILE1)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Training","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"run_training()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del net\ngc.collect()\ntorch.cuda.empty_cache()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#net.model.load_state_dict(torch.load('./pseudo/best-checkpoint.bin')['model_state_dict'])","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Preparing PL Model 2","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"test_df = pd.read_csv('pseudo2.csv')\n\nbad_boxes = [3687, 117344,173,113947,52868,2159,2169,121633,121634,147504,118211,52727,147552]\n\nmarking = pd.concat([pd.read_csv('../input/global-wheat-detection/train.csv'),test_df]) if len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10 else pd.concat([test_df, test_df])\n\nif len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10: \n    marking.drop(bad_boxes)\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)\n\ntargets = set(marking.source.values)\nif len(glob(f'../input/global-wheat-detection/test/*.jpg')) != 10:\n    targets.remove('arvalis_3')\n    targets.remove('usask_1')\n\nskf = StratifiedKFold(n_splits=5, shuffle=True, random_state=42)\n\ndf_folds = marking[['image_id']].copy()\ndf_folds.loc[:, 'bbox_count'] = 1\ndf_folds = df_folds.groupby('image_id').count()\ndf_folds.loc[:, 'source'] = marking[['image_id', 'source']].groupby('image_id').min()['source']\ndf_folds.loc[:, 'stratify_group'] = np.char.add(\n    df_folds['source'].values.astype(str),\n    df_folds['bbox_count'].apply(lambda x: f'_{x // 15}').values.astype(str)\n)\ndf_folds.loc[:, 'fold'] = 0\n\nprint(set(df_folds.source.values))\n\nfor fold_number, (train_index, val_index) in enumerate(skf.split(X=df_folds.index, y=df_folds['stratify_group'])):\n    df_folds.loc[df_folds.iloc[val_index].index, 'fold'] = fold_number\n\ndf_folds = pd.concat([ df_folds.loc[df_folds['source'] == i, :] for i in targets])\n\ndf_folds.loc[df_folds['source']=='pseudo','fold'] = 2\ndf_folds.loc[df_folds['fold']==3,'fold'] = 2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = DatasetRetriever(\n    image_ids=df_folds[df_folds['fold'] == 2].index.values,\n    marking=marking,\n    transforms=get_train_transforms(),\n    test=False,\n)\n\nvalidation_dataset = DatasetRetriever(\n    image_ids=df_folds[df_folds['fold'] == 0].index.values,\n    marking=marking,\n    transforms=get_valid_transforms(),\n    test=True,\n)\n\n\nclass TrainGlobalConfig:\n    num_workers = 4\n    batch_size = 4\n    n_epochs = EPOCHS_2\n    lr = 0.0001 * 0.05\n\n    folder = 'pseudo2'\n\n    verbose = True\n    verbose_step = 1\n\n    step_scheduler = False  # do scheduler.step after optimizer.step\n    validation_scheduler = True  # do scheduler.step after validation stage loss\n\n    SchedulerClass = torch.optim.lr_scheduler.ReduceLROnPlateau\n    scheduler_params = dict(\n        mode='min',\n        factor=0.5,\n        patience=6,\n        verbose=False, \n        threshold=0.0001,\n        threshold_mode='abs',\n        cooldown=0, \n        min_lr=1e-8,\n        eps=1e-08\n    )\n\ndef run_training():\n    device = torch.device('cuda:0')\n    net.to(device)\n\n    train_loader = torch.utils.data.DataLoader(\n        train_dataset,\n        batch_size=TrainGlobalConfig.batch_size,\n        sampler=RandomSampler(train_dataset),\n        pin_memory=False,\n        drop_last=True,\n        num_workers=TrainGlobalConfig.num_workers,\n        collate_fn=collate_fn,\n    )\n    val_loader = torch.utils.data.DataLoader(\n        validation_dataset, \n        batch_size=TrainGlobalConfig.batch_size,\n        num_workers=TrainGlobalConfig.num_workers,\n        shuffle=False,\n        sampler=SequentialSampler(validation_dataset),\n        pin_memory=False,\n        collate_fn=collate_fn,\n    )\n\n    fitter = Fitter(model=net, device=device, config=TrainGlobalConfig)\n    fitter.fit(train_loader, val_loader)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"net = get_net(WEIGHT_FILE2)\nrun_training()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"del net\ngc.collect()\ntorch.cuda.empty_cache()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Final Inference","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_net():\n    config = get_efficientdet_config('tf_efficientdet_d6')\n    net = EfficientDet(config, pretrained_backbone=False)\n\n    config.num_classes = 1\n    config.image_size=SIZE\n    net.class_net = HeadNet(config, num_outputs=config.num_classes, norm_kwargs=dict(eps=.001, momentum=.01))\n\n\n    net = DetBenchEval(net, config)\n    net.eval()\n    \n    net.model.load_state_dict(torch.load('./pseudo2/best-checkpoint.bin')['model_state_dict'])\n\n    return net.cuda()\n\nnet2 = load_net()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def load_net():\n    config = get_efficientdet_config('tf_efficientdet_d6')\n    net = EfficientDet(config, pretrained_backbone=False)\n\n    config.num_classes = 1\n    config.image_size=SIZE\n    net.class_net = HeadNet(config, num_outputs=config.num_classes, norm_kwargs=dict(eps=.001, momentum=.01))\n\n\n    net = DetBenchEval(net, config)\n    net.eval()\n    \n    net.model.load_state_dict(torch.load('./pseudo/best-checkpoint.bin')['model_state_dict'])\n\n    return net.cuda()\n\nnet = load_net()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"DATA_ROOT_PATH = '../input/global-wheat-detection/test'\n\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, image_ids, transforms=None):\n        super().__init__()\n        self.image_ids = image_ids\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        image = cv2.imread(f'{DATA_ROOT_PATH}/{image_id}.jpg', cv2.IMREAD_COLOR)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n        if self.transforms:\n            sample = {'image': image}\n            sample = self.transforms(**sample)\n            image = sample['image']\n        return image, image_id\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]\n\ntta_combinations = [[TTARotate270()],[None],[TTARotate90()],[TTARotate180()],[TTAVerticalFlip(),TTARotate270()],[TTAVerticalFlip(),TTARotate90()],[TTAVerticalFlip()],[TTAHorizontalFlip()] ]\n\ntta_transforms = []\nfor tta_combination in tta_combinations:\n    print([tta_transform for tta_transform in tta_combination if tta_transform])\n    tta_transforms.append(TTACompose([tta_transform for tta_transform in tta_combination if tta_transform]))\n\ndef make_tta_predictions(images, score_threshold=STAGE2_THRESHOLD):\n    with torch.no_grad():\n    #with amp.disable_casts():\n        #print('disabling fp16')\n        images = torch.stack(images).float().cuda()\n        predictions = []\n        predictions2 = []\n        for tta_transform in tta_transforms:\n            result = []\n            det = net(tta_transform.batch_augment(images.clone()), torch.tensor([1]*images.shape[0]).float().cuda())\n\n            for i in range(images.shape[0]):\n                boxes = det[i].detach().cpu().numpy()[:,:4]    \n                scores = det[i].detach().cpu().numpy()[:,4]\n                indexes = np.where(scores > score_threshold)[0]\n                boxes = boxes[indexes]\n                boxes[:, 2] = boxes[:, 2] + boxes[:, 0]\n                boxes[:, 3] = boxes[:, 3] + boxes[:, 1]\n                boxes = tta_transform.deaugment_boxes(boxes.copy())\n                result.append({\n                    'boxes': boxes,\n                    'scores': scores[indexes],\n                })\n            predictions.append(result)\n        for tta_transform in tta_transforms:\n            result = []\n            det = net2(tta_transform.batch_augment(images.clone()), torch.tensor([1]*images.shape[0]).float().cuda())\n\n            for i in range(images.shape[0]):\n                boxes = det[i].detach().cpu().numpy()[:,:4]    \n                scores = det[i].detach().cpu().numpy()[:,4]\n                indexes = np.where(scores > score_threshold)[0]\n                boxes = boxes[indexes]\n                boxes[:, 2] = boxes[:, 2] + boxes[:, 0]\n                boxes[:, 3] = boxes[:, 3] + boxes[:, 1]\n                boxes = tta_transform.deaugment_boxes(boxes.copy())\n                result.append({\n                    'boxes': boxes,\n                    'scores': scores[indexes],\n                })\n            predictions2.append(result)\n    return predictions, predictions2\n\nWEIGHTS = [3] * 16 + [2] * 16\ndef run_wbf(predictions, predictions2, image_index, image_size=SIZE, iou_thr=STAGE2_IOU_THR, skip_box_thr=STAGE2_SKIP_THR, weights=None):\n    boxes = [(prediction[image_index]['boxes']/(image_size-1)).tolist() for prediction in predictions]\n    scores = [prediction[image_index]['scores'].tolist() for prediction in predictions]\n    labels = [np.ones(prediction[image_index]['scores'].shape[0]).astype(int).tolist() for prediction in predictions]\n    \n    boxes2 = [(prediction[image_index]['boxes']/(image_size-1)).tolist() for prediction in predictions2]\n    scores2 = [prediction[image_index]['scores'].tolist() for prediction in predictions2]\n    labels2 = [np.ones(prediction[image_index]['scores'].shape[0]).astype(int).tolist() for prediction in predictions2]\n    if (len(boxes)==0) and (len(boxes2)==0): return boxes, scores, labels\n    try:\n        boxes, scores, labels = weighted_boxes_fusion(boxes+boxes2, scores+scores2, labels+labels2, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    except:\n        return [], [], []\n    boxes = boxes*(image_size-1)\n    return boxes, scores, labels","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport numpy as np\nimport pandas as pd\nfrom glob import glob\nfrom torch.utils.data import Dataset,DataLoader\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nimport cv2\nimport gc\nfrom matplotlib import pyplot as plt\nfrom effdet import get_efficientdet_config, EfficientDet\nfrom effdet.efficientdet import HeadNet\n\ndef get_valid_transforms():\n    return A.Compose([\n            A.Resize(height=SIZE, width=SIZE, p=1.0),\n            ToTensorV2(p=1.0),\n        ], p=1.0)\n\ndataset = DatasetRetriever(\n    image_ids=np.array([path.split('/')[-1][:-4] for path in glob(f'{DATA_ROOT_PATH}/*.jpg')]),\n    transforms=get_valid_transforms()\n)\n\ndef collate_fn(batch):\n    return tuple(zip(*batch))\n\ndata_loader = DataLoader(\n    dataset,\n    batch_size=2,\n    shuffle=False,\n    num_workers=2,\n    drop_last=False,\n    collate_fn=collate_fn\n)\n\ndef 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    return \" \".join(pred_strings)\n\nconfig = get_efficientdet_config('tf_efficientdet_d6')\nconfig.num_classes = 1\nconfig.image_size= SIZE\nnet.model.load_state_dict(torch.load('./pseudo/best-checkpoint.bin')['model_state_dict'])\nnet = DetBenchEval(net.model, config).cuda()#load_net('/kaggle/working/pseudo/last-checkpoint.bin')\nnet.eval()\n\n\nresults = []\n\nfor images, image_ids in data_loader:\n    predictions, predictions2 = make_tta_predictions(images)\n    for i, image in enumerate(images):\n        boxes, scores, labels = run_wbf(predictions, predictions2, image_index=i)\n        boxes = (boxes).round().astype(np.int32).clip(min=0, max=1023)\n        image_id = image_ids[i]\n\n        score_threshold = STAGE2_SUPPRESS\n        indexes = np.where(scores>score_threshold)\n        boxes = boxes[indexes]\n        scores = scores[indexes]\n        \n        if (len(boxes) == 0):\n            result = {\n                'image_id': image_id,\n                'PredictionString': \"\"\n            }\n        else:\n            boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n            boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n            \n            indexes = np.where(boxes[:,2]*boxes[:,3] < MAX_BOX*MAX_BOX)\n            boxes = boxes[indexes]\n            scores = scores[indexes]\n            \n            indexes = np.where(boxes[:,2]*boxes[:,3] > MIN_BOX*MIN_BOX)\n            boxes = boxes[indexes]\n            scores = scores[indexes]\n            \n            if (len(boxes) == 0):\n                result = {\n                    'image_id': image_id,\n                    'PredictionString': \"\"\n                }\n            else:\n                result = {\n                    'image_id': image_id,\n                    'PredictionString': format_prediction_string(boxes, scores)\n                }\n        results.append(result)\n\ntest_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm pseudo.csv\n!rm -r pseudo\n#!rm -r apexpytorch","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"!rm pseudo2.csv\n!rm pseudo2","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Sanity Check on 9 Images","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import os\n\nfig, ax = plt.subplots(3, 3, figsize=(30, 30))\nDIR_TEST = '../input/global-wheat-detection/test'\n\nfor i1 in range(3):\n    for j1 in range(3):\n        num = j1*3 + i1\n        img_pth = os.path.join(DIR_TEST, test_df.image_id[num]+'.jpg')\n        image = cv2.imread(img_pth)\n        b = [float(i) for i in test_df.PredictionString[num].split(' ')]\n        boxes = []\n        i = 0\n        while i < len(b):\n            boxes.append([int(b[i+1]),int(b[i+2]),int(b[i+3]),int(b[i+4]),float(b[i])])\n            i+=5\n        boxes = np.array(boxes)\n        for box in boxes.astype(float):\n            cv2.rectangle(image,(int(box[0]), int(box[1])),(int(box[0])+int(box[2]),  int(box[1])+int(box[3])),(0, 32, 255), 3)\n            cv2.putText(image, str(box[4]), (int(box[0]), int(box[1])+20), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (36,255,12), 2)\n        ax[i1][j1].imshow(image)","execution_count":null,"outputs":[]},{"metadata":{"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}