{"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":1084583,"sourceType":"datasetVersion","datasetId":604593},{"sourceId":1154184,"sourceType":"datasetVersion","datasetId":652413},{"sourceId":1164586,"sourceType":"datasetVersion","datasetId":659763},{"sourceId":1164617,"sourceType":"datasetVersion","datasetId":659784},{"sourceId":6024453,"sourceType":"datasetVersion","datasetId":648967},{"sourceId":12367383,"sourceType":"datasetVersion","datasetId":7797609}],"dockerImageVersionId":29928,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Really good training pipeline for pytorch EfficientDet \n\nHi everyone!\n\nMy name is Alex Shonenkov, I am DL/NLP/CV/TS research engineer. Especially I am in Love with NLP & DL.\n\nRecently I have created kernel for this competition about Weighted Boxes Fusion:\n- [WBF approach for ensemble](https://www.kaggle.com/shonenkov/wbf-approach-for-ensemble)\n\n\nI hope it is useful for you, my friends! If you didn't read this kernel, don't forget to do it! :)\n\n\nToday I would like to share really good training pipeline for this competition using SOTA [EfficientDet: Scalable and Efficient Object Detection](https://arxiv.org/pdf/1911.09070.pdf)","metadata":{}},{"cell_type":"markdown","source":"## Main Idea\n \nI read [all public kernels about EfficientDet in kaggle community](https://www.kaggle.com/search?q=efficientdet+in%3Anotebooks) and understand that kaggle don't have really good working public kernels with good score. Why? You can see below picture about COCO AP for different architectures, I think everyone should be able to use such a strong tools EfficientDet for own research, lets do it!\n\n<img src='https://miro.medium.com/max/2400/0*ApAKUWtseHcvRV2U.png' width=400>   \n\n","metadata":{}},{"cell_type":"markdown","source":"## Dependencies and imports\n\nIn this kernel used github repos [efficientdet-pytorch](https://github.com/rwightman/efficientdet-pytorch) and [pytorch-image-models](https://github.com/rwightman/pytorch-image-models) by [@rwightman](https://www.kaggle.com/rwightman). Don't forget add stars ;)","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":"2025-07-13T08:50:34.222079Z","iopub.execute_input":"2025-07-13T08:50:34.22227Z","iopub.status.idle":"2025-07-13T08:51:44.057181Z","shell.execute_reply.started":"2025-07-13T08:50:34.222249Z","shell.execute_reply":"2025-07-13T08:51:44.056131Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nsys.path.insert(0, \"../input/timm-efficientdet-pytorch\")\nsys.path.insert(0, \"../input/omegaconf\")\n\nimport 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)","metadata":{"trusted":true,"_kg_hide-input":true,"_kg_hide-output":true,"execution":{"iopub.status.busy":"2025-07-13T08:54:02.340608Z","iopub.execute_input":"2025-07-13T08:54:02.340935Z","iopub.status.idle":"2025-07-13T08:54:05.730117Z","shell.execute_reply.started":"2025-07-13T08:54:02.340904Z","shell.execute_reply":"2025-07-13T08:54:05.729211Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"About data splitting you can read [here](https://www.kaggle.com/shonenkov/wbf-approach-for-ensemble):","metadata":{}},{"cell_type":"code","source":"# Make sure you have this import at the top of your notebook\nfrom pycocotools.coco import COCO\nfrom torch.utils.data import Dataset # Ensure this is imported\n# UPDATED RoboflowDataset class with debugging prints\nclass RoboflowDataset(Dataset):\n    def __init__(self, images_dir, coco_annotation_path, transforms=None):\n        super().__init__()\n\n        self.images_dir = images_dir\n        self.coco = COCO(coco_annotation_path)\n        self.image_ids = list(sorted(self.coco.imgs.keys()))\n        self.transforms = transforms\n        coco_cat_ids = sorted(self.coco.getCatIds())\n        self.cat_id_to_label = {cat_id: i for i, cat_id in enumerate(coco_cat_ids)}\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        img_info = self.coco.loadImgs(image_id)[0]\n        image_path = os.path.join(self.images_dir, img_info['file_name'])\n\n        # Load image\n        image = cv2.imread(image_path, cv2.IMREAD_COLOR)\n\n        # --- DEBUGGING CHECK ---\n        if image is None:\n            print(f\"ERROR: Could not read image at path: {image_path}\")\n            # You can either raise an error or return None, None, None\n            # to handle this case in your training loop if some images are corrupt.\n            raise FileNotFoundError(f\"Image not found at {image_path}\")\n        # ---------------------\n\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n\n        ann_ids = self.coco.getAnnIds(imgIds=image_id)\n        anns = self.coco.loadAnns(ann_ids)\n\n        boxes = []\n        labels = []\n        for ann in anns:\n            x, y, w, h = ann['bbox']\n            boxes.append([x, y, x + w, y + h])\n            labels.append(self.cat_id_to_label[ann['category_id']])\n\n        target = {\n            'boxes': torch.as_tensor(boxes, dtype=torch.float32),\n            'labels': torch.as_tensor(labels, dtype=torch.int64),\n            'image_id': torch.tensor([image_id])\n        }\n\n        if self.transforms:\n            sample = {'image': image, 'bboxes': target['boxes'], 'labels': target['labels']}\n            sample = self.transforms(**sample)\n            image = sample['image']\n\n            if len(sample['bboxes']) > 0:\n                target['boxes'] = torch.stack(tuple(map(torch.tensor, zip(*sample['bboxes'])))).permute(1, 0)\n            else:\n                target['boxes'] = torch.zeros((0, 4), dtype=torch.float32)\n\n        return image, target, image_id\n\n    def __len__(self) -> int:\n        return len(self.image_ids)\n\n    def get_num_classes(self):\n        return len(self.cat_id_to_label)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:12:50.871488Z","iopub.execute_input":"2025-07-13T09:12:50.871803Z","iopub.status.idle":"2025-07-13T09:12:50.885859Z","shell.execute_reply.started":"2025-07-13T09:12:50.871777Z","shell.execute_reply":"2025-07-13T09:12:50.884988Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\n\ndef get_train_transforms():\n    return A.Compose(\n        [\n            A.RandomSizedCrop(min_max_height=(800, 800), 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.Resize(height=512, width=512, 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=512, width=512, 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    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:00:31.047341Z","iopub.execute_input":"2025-07-13T09:00:31.047674Z","iopub.status.idle":"2025-07-13T09:00:31.057294Z","shell.execute_reply.started":"2025-07-13T09:00:31.047645Z","shell.execute_reply":"2025-07-13T09:00:31.056404Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Run this in a new notebook cell to see the first 5 files in the directory\n!ls /kaggle/input/airspace-objects/train/images/ | head -n 5","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:13:10.969925Z","iopub.execute_input":"2025-07-13T09:13:10.97021Z","iopub.status.idle":"2025-07-13T09:13:11.998467Z","shell.execute_reply.started":"2025-07-13T09:13:10.970187Z","shell.execute_reply":"2025-07-13T09:13:11.997754Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Define paths to your Roboflow dataset\n# This path is now set to your specific dataset location.\nROBOFLOW_DATA_DIR = '/kaggle/input/airspace-objects' \n\n# Assuming your dataset from Roboflow has the standard train/valid folders\nTRAIN_IMG_DIR = f'{ROBOFLOW_DATA_DIR}/train/images/'\nTRAIN_COCO_ANN = f'{ROBOFLOW_DATA_DIR}/train/_annotations.coco.json'\n\nVALID_IMG_DIR = f'{ROBOFLOW_DATA_DIR}/valid/images/'\nVALID_COCO_ANN = f'{ROBOFLOW_DATA_DIR}/valid/_annotations.coco.json'\n\n# Create the datasets using the RoboflowDataset class\ntrain_dataset = RoboflowDataset(\n    images_dir=TRAIN_IMG_DIR,\n    coco_annotation_path=TRAIN_COCO_ANN,\n    transforms=get_train_transforms(),\n)\n\nvalidation_dataset = RoboflowDataset(\n    images_dir=VALID_IMG_DIR,\n    coco_annotation_path=VALID_COCO_ANN,\n    transforms=get_valid_transforms(),\n)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:00:59.655649Z","iopub.execute_input":"2025-07-13T09:00:59.655938Z","iopub.status.idle":"2025-07-13T09:00:59.710847Z","shell.execute_reply.started":"2025-07-13T09:00:59.655913Z","shell.execute_reply":"2025-07-13T09:00:59.709997Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Albumentations","metadata":{}},{"cell_type":"code","source":"def get_train_transforms():\n    return A.Compose(\n        [\n            A.RandomSizedCrop(min_max_height=(800, 800), 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.Resize(height=512, width=512, 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=512, width=512, 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    )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:05:00.074885Z","iopub.execute_input":"2025-07-13T09:05:00.075162Z","iopub.status.idle":"2025-07-13T09:05:00.084124Z","shell.execute_reply.started":"2025-07-13T09:05:00.075138Z","shell.execute_reply":"2025-07-13T09:05:00.083184Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Dataset","metadata":{}},{"cell_type":"code","source":"# 1. Get one sample from your NEW train_dataset\nimage, target, image_id = train_dataset[1] \n\n# 2. Prepare the image and boxes for display\n# The image is a tensor, so we convert it to a NumPy array for plotting\nnumpy_image = image.permute(1,2,0).cpu().numpy().copy() # Use .copy() to make it writable\nboxes = target['boxes'].cpu().numpy().astype(np.int32)\n\n# 3. Draw the bounding boxes on the image\nfig, ax = plt.subplots(1, 1, figsize=(16, 8))\n\nfor box in boxes:\n    # Your RoboflowDataset provides boxes in [xmin, ymin, xmax, ymax] format\n    # cv2.rectangle needs the top-left and bottom-right corners\n    cv2.rectangle(\n        numpy_image,\n        (box[0], box[1]), # Top-left corner (x_min, y_min)\n        (box[2], box[3]), # Bottom-right corner (x_max, y_max)\n        (0, 1, 0), # Color in green\n        2 # Thickness\n    )\n\n# 4. Show the image\nax.set_axis_off()\nax.imshow(numpy_image)\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-07-13T09:06:51.727611Z","iopub.execute_input":"2025-07-13T09:06:51.727931Z","iopub.status.idle":"2025-07-13T09:06:51.798225Z","shell.execute_reply.started":"2025-07-13T09:06:51.727904Z","shell.execute_reply":"2025-07-13T09:06:51.796886Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"## Fitter","metadata":{}},{"cell_type":"code","source":"class 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","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import 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    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            self.save(f'{self.base_dir}/last-checkpoint.bin')\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-{str(self.epoch).zfill(3)}epoch.bin')\n                for path in sorted(glob(f'{self.base_dir}/best-checkpoint-*epoch.bin'))[:-3]:\n                    os.remove(path)\n\n            if self.config.validation_scheduler:\n                self.scheduler.step(metrics=summary_loss.avg)\n\n            self.epoch += 1\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            self.optimizer.zero_grad()\n            \n            loss, _, _ = self.model(images, boxes, labels)\n            \n            loss.backward()\n\n            summary_loss.update(loss.detach().item(), batch_size)\n\n            self.optimizer.step()\n\n            if self.config.step_scheduler:\n                self.scheduler.step()\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')","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"class TrainGlobalConfig:\n    num_workers = 2\n    batch_size = 4 \n    n_epochs = 3 # n_epochs = 40\n    lr = 0.0002\n\n    folder = 'effdet5-cutmix-augmix'\n\n    # -------------------\n    verbose = True\n    verbose_step = 1\n    # -------------------\n\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.OneCycleLR\n#     scheduler_params = dict(\n#         max_lr=0.001,\n#         epochs=n_epochs,\n#         steps_per_epoch=int(len(train_dataset) / batch_size),\n#         pct_start=0.1,\n#         anneal_strategy='cos', \n#         final_div_factor=10**5\n#     )\n    \n    SchedulerClass = torch.optim.lr_scheduler.ReduceLROnPlateau\n    scheduler_params = dict(\n        mode='min',\n        factor=0.5,\n        patience=1,\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    # --------------------","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def collate_fn(batch):\n    return tuple(zip(*batch))\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)","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from effdet import get_efficientdet_config, EfficientDet, DetBenchTrain\nfrom effdet.efficientdet import HeadNet\n\ndef get_net():\n    config = get_efficientdet_config('tf_efficientdet_d5')\n    net = EfficientDet(config, pretrained_backbone=False)\n    checkpoint = torch.load('../input/efficientdet/efficientdet_d5-ef44aea8.pth')\n    net.load_state_dict(checkpoint)\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    return DetBenchTrain(net, config)\n\nnet = get_net()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"code","source":"run_training()","metadata":{"trusted":true},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"### Thank you for reading my kernel!\n\nSo, I have prepared good training SOTA-model baseline for you, my friends! I have used n_epochs = 40 and have got best checkpoint single model that gives 0.7176 LB. You can see [here](https://www.kaggle.com/shonenkov/inference-efficientdet) inference kernel.\n\nJust recently I have started publishing my works, if you like this format of notebooks I would like continue to make kernels.","metadata":{}}]}