{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.7.6","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19989,"databundleVersionId":1160143,"sourceType":"competition"},{"sourceId":1154184,"sourceType":"datasetVersion","datasetId":652413},{"sourceId":1164586,"sourceType":"datasetVersion","datasetId":659763},{"sourceId":1164617,"sourceType":"datasetVersion","datasetId":659784},{"sourceId":1219292,"sourceType":"datasetVersion","datasetId":648709},{"sourceId":6024453,"sourceType":"datasetVersion","datasetId":648967},{"sourceId":10113011,"sourceType":"datasetVersion","datasetId":6239292},{"sourceId":10122746,"sourceType":"datasetVersion","datasetId":6246427},{"sourceId":211721311,"sourceType":"kernelVersion"}],"dockerImageVersionId":29928,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Dependencies and imports","metadata":{}},{"cell_type":"code","source":"!pip install --no-deps '../input/timm-package/timm-0.1.26-py3-none-any.whl' > /dev/null\n!pip install --no-deps '../input/pycocotools/pycocotools-2.0-cp37-cp37m-linux_x86_64.whl' > /dev/null","metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-12-06T22:28:35.660347Z","iopub.execute_input":"2024-12-06T22:28:35.660892Z","iopub.status.idle":"2024-12-06T22:29:44.396171Z","shell.execute_reply.started":"2024-12-06T22:28:35.66084Z","shell.execute_reply":"2024-12-06T22:29:44.395135Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\n# 添加搜索路径 这里的作用是： python在import的时候，会先从当前目录，已安装和第三方库进行搜索，这里sys.insert可以进行路径的\n# 添加和整理，同时前面的0代表的是优先级别，数字越小，优先级别越高\nsys.path.insert(0, \"../input/timm-efficientdet-pytorch\")\nsys.path.insert(0, \"../input/omegaconf\")\nsys.path.insert(0, \"../input/weightedboxesfusion\")\n\nimport ensemble_boxes \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, DetBenchEval\nfrom effdet.efficientdet import HeadNet\nimport os\nfrom datetime import datetime\nimport time\nimport random\nfrom sklearn.model_selection import StratifiedKFold\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.398917Z","iopub.execute_input":"2024-12-06T22:29:44.399329Z","iopub.status.idle":"2024-12-06T22:29:44.408203Z","shell.execute_reply.started":"2024-12-06T22:29:44.399286Z","shell.execute_reply":"2024-12-06T22:29:44.407489Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# TTA","metadata":{}},{"cell_type":"code","source":"class BaseWheatTTA:\n    \"\"\" author: @shonenkov \"\"\"\n    image_size = 512\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 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)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.409288Z","iopub.execute_input":"2024-12-06T22:29:44.40951Z","iopub.status.idle":"2024-12-06T22:29:44.429185Z","shell.execute_reply.started":"2024-12-06T22:29:44.409489Z","shell.execute_reply":"2024-12-06T22:29:44.42843Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from itertools import product\n\ntta_transforms = []\nfor tta_combination in product([TTAHorizontalFlip(), None], \n                               [TTAVerticalFlip(), None],\n                               [TTARotate90(), None]):\n    tta_transforms.append(TTACompose([tta_transform for tta_transform in tta_combination if tta_transform]))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.430306Z","iopub.execute_input":"2024-12-06T22:29:44.430557Z","iopub.status.idle":"2024-12-06T22:29:44.441634Z","shell.execute_reply.started":"2024-12-06T22:29:44.430525Z","shell.execute_reply":"2024-12-06T22:29:44.440965Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def make_tta_predictions(images, score_threshold=0.25):\n    with torch.no_grad():\n        images = torch.stack(images).float().cuda()\n        predictions = []\n        for net in nets:\n            prediction=[]\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                prediction.append(result)\n            predictions.append(prediction)\n    return predictions\n\n# 执行模型的融合\ndef run_wbf(predictions, image_index, image_size=512, iou_thr=0.44, skip_box_thr=0.43, weights=None):\n    boxes = []\n    scores = []\n    labels = []\n    \n    # 遍历每个 prediction 中的所有 result，并收集相应的数据\n    for prediction in predictions:\n        for result in prediction:\n            # 提取 boxes, scores, labels 并进行归一化\n            boxes.append((result[image_index]['boxes'] / (image_size - 1)).tolist())\n            scores.append(result[image_index]['scores'].tolist())\n            labels.append(np.ones(result[image_index]['scores'].shape[0]).astype(int).tolist())\n\n    boxes, scores, labels = ensemble_boxes.ensemble_boxes_wbf.weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n    boxes = boxes*(image_size-1)\n    return boxes, scores, labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.444225Z","iopub.execute_input":"2024-12-06T22:29:44.444489Z","iopub.status.idle":"2024-12-06T22:29:44.459283Z","shell.execute_reply.started":"2024-12-06T22:29:44.444464Z","shell.execute_reply":"2024-12-06T22:29:44.458569Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Predict","metadata":{}},{"cell_type":"code","source":"DEVICE = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.460885Z","iopub.execute_input":"2024-12-06T22:29:44.461232Z","iopub.status.idle":"2024-12-06T22:29:44.47335Z","shell.execute_reply.started":"2024-12-06T22:29:44.461199Z","shell.execute_reply":"2024-12-06T22:29:44.472696Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def get_valid_transforms():\n    return A.Compose([\n            A.Resize(height=512, width=512, p=1.0),\n            ToTensorV2(p=1.0),\n        ], p=1.0)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.474817Z","iopub.execute_input":"2024-12-06T22:29:44.475163Z","iopub.status.idle":"2024-12-06T22:29:44.489634Z","shell.execute_reply.started":"2024-12-06T22:29:44.475129Z","shell.execute_reply":"2024-12-06T22:29:44.488796Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_ROOT_PATH = '../input/global-wheat-detection/train'\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]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.490681Z","iopub.execute_input":"2024-12-06T22:29:44.491012Z","iopub.status.idle":"2024-12-06T22:29:44.502599Z","shell.execute_reply.started":"2024-12-06T22:29:44.490976Z","shell.execute_reply":"2024-12-06T22:29:44.501942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"marking = 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)\nmarking","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:44.503667Z","iopub.execute_input":"2024-12-06T22:29:44.503993Z","iopub.status.idle":"2024-12-06T22:29:45.134143Z","shell.execute_reply.started":"2024-12-06T22:29:44.503961Z","shell.execute_reply":"2024-12-06T22:29:45.13339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"marking_test = marking[marking['source'] == 'rres_1']\ntest_image_ids=marking_test['image_id'].drop_duplicates().to_numpy()\nprint(len(test_image_ids))\nprint(test_image_ids[:5])\n\ndataset = DatasetRetriever(\n    image_ids=test_image_ids,\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=4,\n    drop_last=False,\n    collate_fn=collate_fn\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:45.135172Z","iopub.execute_input":"2024-12-06T22:29:45.135411Z","iopub.status.idle":"2024-12-06T22:29:45.154016Z","shell.execute_reply.started":"2024-12-06T22:29:45.135386Z","shell.execute_reply":"2024-12-06T22:29:45.153333Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def load_net(checkpoint_path):\n    config = get_efficientdet_config('tf_efficientdet_d5')\n    net = EfficientDet(config, pretrained_backbone=False)\n\n    config.num_classes = 1\n    config.image_size=512\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    net.load_state_dict(checkpoint['model_state_dict'])\n\n    del checkpoint\n    gc.collect()\n\n    net = DetBenchEval(net, config)\n    net.eval();\n    return net.cuda()\n\nnets = [\n    #load_net('/kaggle/input/effdet-5-folds-pl/pl-fold0-best-checkpoint1.bin'),\n    # load_net('/kaggle/input/effdet-5-folds-pl/pl-fold1-best-checkpoint1.bin'),\n    # load_net('/kaggle/input/effdet-5-folds-pl/pl-fold2-best-checkpoint1.bin')\n    # load_net('/kaggle/input/effdet-5-folds-pl/pl-fold3-best-checkpoint1.bin'),\n    # load_net('/kaggle/input/effdet-5-folds-pl/pl-fold4-best-checkpoint1.bin')\n    load_net('/kaggle/input/gwd-pseudo-labeling-674aeb/plabel_model/best-checkpoint1.bin')\n]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:45.155181Z","iopub.execute_input":"2024-12-06T22:29:45.155511Z","iopub.status.idle":"2024-12-06T22:29:55.17494Z","shell.execute_reply.started":"2024-12-06T22:29:45.155478Z","shell.execute_reply":"2024-12-06T22:29:55.174083Z"}},"outputs":[],"execution_count":null},{"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    return \" \".join(pred_strings)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:55.175949Z","iopub.execute_input":"2024-12-06T22:29:55.176206Z","iopub.status.idle":"2024-12-06T22:29:55.181015Z","shell.execute_reply.started":"2024-12-06T22:29:55.176181Z","shell.execute_reply":"2024-12-06T22:29:55.180263Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"results = []\npreds = []\n\nfor images, image_ids in data_loader:\n    predictions = make_tta_predictions(images)\n    for i, image in enumerate(images):\n        boxes, scores, labels = run_wbf(predictions, image_index=i)\n        boxes = (boxes*2).astype(np.int32).clip(min=0, max=1023)\n        image_id = image_ids[i]\n        \n        boxes[:, 2] = boxes[:, 2] - boxes[:, 0]\n        boxes[:, 3] = boxes[:, 3] - boxes[:, 1]\n\n        result = {\n            'image_id': image_id,\n            'PredictionString': format_prediction_string(boxes, scores)\n        }\n        results.append(result)\n\n        for j in range(len(boxes)):\n            preds.append({\n                'image_id': image_id,\n                'x': boxes[j, 0],\n                'y': boxes[j, 1],\n                'w': boxes[j, 2],\n                'h': boxes[j, 3],\n                'score': scores[j]\n            })\n\nprint(len(preds))\nprint(preds[:5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:29:55.182203Z","iopub.execute_input":"2024-12-06T22:29:55.182459Z","iopub.status.idle":"2024-12-06T22:36:44.21565Z","shell.execute_reply.started":"2024-12-06T22:29:55.182434Z","shell.execute_reply":"2024-12-06T22:36:44.214438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_df = pd.DataFrame(results, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:36:44.217095Z","iopub.execute_input":"2024-12-06T22:36:44.217341Z","iopub.status.idle":"2024-12-06T22:36:44.43012Z","shell.execute_reply.started":"2024-12-06T22:36:44.217316Z","shell.execute_reply":"2024-12-06T22:36:44.42926Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Compute mAP","metadata":{}},{"cell_type":"code","source":"# 计算IoU的函数\ndef calculate_iou(box1, box2):\n    x1, y1, w1, h1 = box1\n    x2, y2, w2, h2 = box2\n    \n    # 计算两个框的交集\n    x1_int = max(x1, x2)\n    y1_int = max(y1, y2)\n    x2_int = min(x1 + w1, x2 + w2)\n    y2_int = min(y1 + h1, y2 + h2)\n    \n    # 计算交集区域的面积\n    intersection_w = max(0, x2_int - x1_int)\n    intersection_h = max(0, y2_int - y1_int)\n    intersection_area = intersection_w * intersection_h\n    \n    # 计算两个框的并集\n    box1_area = w1 * h1\n    box2_area = w2 * h2\n    union_area = box1_area + box2_area - intersection_area\n    \n    # 计算IoU\n    iou = intersection_area / union_area if union_area > 0 else 0\n    return iou\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:36:44.431384Z","iopub.execute_input":"2024-12-06T22:36:44.431738Z","iopub.status.idle":"2024-12-06T22:36:44.438948Z","shell.execute_reply.started":"2024-12-06T22:36:44.431701Z","shell.execute_reply":"2024-12-06T22:36:44.438046Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 计算AP的函数，并统计FN\ndef calculate_ap(preds_df, marking_test, iou_threshold=0.5):\n    aps = []\n    \n    for image_id in preds_df['image_id'].unique():\n        pred_boxes = preds_df[preds_df['image_id'] == image_id]\n        true_boxes = marking_test[marking_test['image_id'] == image_id]\n        \n        # 按照分数降序排列预测框\n        pred_boxes = pred_boxes.sort_values(by='score', ascending=False)\n        \n        true_boxes_matched = set()\n        pred_matches = []\n        \n        # 计算每个预测框的IoU\n        for _, pred_row in pred_boxes.iterrows():\n            pred_box = (pred_row['x'], pred_row['y'], pred_row['w'], pred_row['h'])\n            pred_score = pred_row['score']\n            \n            best_iou = 0\n            best_match = None\n            \n            for idx, true_row in true_boxes.iterrows():\n                if idx in true_boxes_matched:\n                    continue\n                \n                true_box = (true_row['x'], true_row['y'], true_row['w'], true_row['h'])\n                iou = calculate_iou(pred_box, true_box)\n                \n                if iou > best_iou:\n                    best_iou = iou\n                    best_match = idx\n            \n            if best_iou >= iou_threshold:\n                pred_matches.append(1)\n                true_boxes_matched.add(best_match)\n            else:\n                pred_matches.append(0)\n        \n        # 统计 FN (未匹配的真实框)\n        fn = len(true_boxes) - len(true_boxes_matched)\n        \n        # 计算TP和FP\n        tp = np.sum(pred_matches)\n        fp = len(pred_matches) - tp\n        \n        ap=tp/(tp+fp+fn)\n        aps.append(ap)\n    \n    mean_ap = np.mean(aps)\n    return mean_ap\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:36:44.440308Z","iopub.execute_input":"2024-12-06T22:36:44.440643Z","iopub.status.idle":"2024-12-06T22:36:44.452462Z","shell.execute_reply.started":"2024-12-06T22:36:44.440609Z","shell.execute_reply":"2024-12-06T22:36:44.451814Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def calculate_mean_mAP(preds_df, marking_test, iou_thresholds=[0.5, 0.55, 0.6, 0.65, 0.7, 0.75]):\n    aps = []\n    \n    for threshold in iou_thresholds:\n        ap= calculate_ap(preds_df, marking_test, iou_threshold=threshold)\n        aps.append(ap)\n        print(f\"mAP at IoU threshold {threshold}: {ap}\")\n    \n    print(aps)\n    mean_map = np.mean(aps)\n    return mean_map\n\npreds_df=pd.DataFrame(preds)\n\n# 计算多个阈值的mAP\nmap_score= calculate_mean_mAP(preds_df, marking_test)\nprint(f\"Mean mAP across all thresholds: {map_score}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-06T22:36:44.453804Z","iopub.execute_input":"2024-12-06T22:36:44.454122Z"}},"outputs":[],"execution_count":null}]}