{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"pygments_lexer":"ipython3","nbconvert_exporter":"python","version":"3.6.4","file_extension":".py","codemirror_mode":{"name":"ipython","version":3},"name":"python","mimetype":"text/x-python"}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"Reference\n\nhttps://www.kaggle.com/morizin/14-class-efficientdet-detection-train/notebook\n\nhttps://www.kaggle.com/backtracking/efficientdet-inference\n\n","metadata":{}},{"cell_type":"code","source":"!pip install pandas --upgrade\n!pip install timm\n!pip install omegaconf\n!pip install pycocotools\n!pip install effdet\n!pip install albumentations==0.4.6\n!pip install ensemble-boxes ","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import sys\nsys.path.insert(0, \"timm-efficientdet-pytorch\")\nsys.path.insert(0, \"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\nimport pandas as pd\nfrom effdet import get_efficientdet_config, EfficientDet, DetBenchTrain, DetBenchPredict\nfrom effdet.efficientdet import HeadNet\nfrom tqdm import tqdm\nfrom ensemble_boxes import *\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 = False\n\nseed_everything(SEED)","metadata":{"_kg_hide-input":true,"_kg_hide-output":true,"id":"3IhTRiEVWZXz","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Preparation","metadata":{"id":"NIl3twAVWZX1"}},{"cell_type":"code","source":"from google.colab import drive\ndrive.mount('/content/drive')","metadata":{"id":"EDmG4cnhYf5f","outputId":"5faa0ad9-61a0-4ecb-9d21-16e4cc8d94ef"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# set env variable\nos.environ[\"KAGGLE_USERNAME\"] = 'justin95214gmailcom'\nos.environ[\"KAGGLE_KEY\"] = \"7602e5a85f354e1de4bf81c6620338fc\"\n# download dataset\n!kaggle datasets download -d xhlulu/vinbigdata-chest-xray-resized-png-1024x1024\n!kaggle datasets download -d sylevan/vinbigdatachestxrayabnormalitiesdetection\n# make dataset folder and unzip\n!mkdir ./data\n!mkdir ./data/images\n!unzip -qq \"./vinbigdata-chest-xray-resized-png-1024x1024.zip\" -d \"./data/images\"\n!unzip -qq \"./vinbigdatachestxrayabnormalitiesdetection.zip\" -d \"./data\"\n!rm ./vinbigdata-chest-xray-resized-png-1024x1024.zip\n!rm ./vinbigdatachestxrayabnormalitiesdetection.zip\n\nmeta_df = pd.read_csv('./data/train.csv')\ndim = pd.read_csv('./data/images/train_meta.csv')\nprint(\"The number of images: \", len(os.listdir('./data/images/train')))\nprint(meta_df.head())","metadata":{"id":"oXM7TpYEYn2x","outputId":"4ad6d9a0-c890-4d41-c78d-eea8cab148cd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"dataframe = pd.read_csv('./data/train.csv')\ndataframe = dataframe[dataframe['class_id'] != 14].reset_index(drop= True)\nmeta_df = dataframe","metadata":{"id":"zIy1pjW2WZX2","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"meta_df = meta_df.merge(dim)\nmeta_df['frac_x_min'] = meta_df['x_min']/meta_df['dim1']\nmeta_df['frac_y_min'] = meta_df['y_min']/meta_df['dim0']\nmeta_df['frac_x_max'] = meta_df['x_max']/meta_df['dim1']\nmeta_df['frac_y_max'] = meta_df['y_max']/meta_df['dim0']\nmeta_df['1024_x_min'] = meta_df['frac_x_min']*1024\nmeta_df['1024_y_min'] = meta_df['frac_y_min']*1024\nmeta_df['1024_x_max'] = meta_df['frac_x_max']*1024\nmeta_df['1024_y_max'] = meta_df['frac_y_max']*1024\nmeta_df = meta_df.loc[:,['image_id','class_id','rad_id','1024_x_min','1024_y_min','1024_x_max','1024_y_max']]\nmeta_df.columns = ['image_id','class_id','rad_id','x_min','y_min','x_max','y_max']\ndataframe = meta_df","metadata":{"id":"VlhN6HK6aH5-"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"np.random.seed(0)\nimage_names = np.random.permutation(dataframe.image_id.unique())\nvalid_images_len = int(len(image_names)*0.2)\nimages_valid = image_names[:valid_images_len]\nimages_train = image_names[valid_images_len:]\nimages_valid = dataframe[ dataframe.image_id.isin(images_valid)].image_id.unique()\nimages_train = dataframe[~dataframe.image_id.isin(images_valid)].image_id.unique()","metadata":{"id":"IU6DV-t0WZX3","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Albumentations","metadata":{"id":"U9XuCpIxWZX4"}},{"cell_type":"code","source":"def get_train_transforms():\n    return A.Compose(\n        [\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.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.HorizontalFlip(p=0.5),\n        A.VerticalFlip(p=0.5),\n        A.RandomRotate90(p=0.5),\n        A.Transpose(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":{"id":"gjsrq-hsWZX6","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dataset","metadata":{"id":"Ju9WJoW6WZX8"}},{"cell_type":"code","source":"TRAIN_ROOT_PATH = './data/images/train'\n\nclass DatasetRetriever(Dataset):\n\n    def __init__(self, marking, image_ids, transforms=None):\n        super().__init__()\n\n        self.image_ids = image_ids\n        self.marking = marking\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        \n        image, boxes, labels = self.load_image_and_boxes(index)\n        \n        target = {}\n        target['boxes'] = boxes\n        target['labels'] = torch.tensor(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        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        \n        image = cv2.imread(f'{TRAIN_ROOT_PATH}/{image_id}.png', cv2.IMREAD_COLOR).copy().astype(np.float32)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n        records = self.marking[self.marking['image_id'] == image_id]\n        boxes = records[['x_min', 'y_min', 'x_max', 'y_max']].values\n        labels = records['class_id'].values\n        return image, boxes, labels","metadata":{"id":"QE1Xxp1oWZX-","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = DatasetRetriever(\n    image_ids=images_train,\n    marking=dataframe,\n    transforms=get_train_transforms()\n)\n\nvalidation_dataset = DatasetRetriever(\n    image_ids=images_valid,\n    marking=dataframe,\n    transforms=get_valid_transforms()\n)","metadata":{"id":"MaY5xqJzWZX_","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Fitter","metadata":{"id":"tlk_EtNiWZYA"}},{"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":{"id":"Whq4I-HaWZYB","trusted":true},"execution_count":null,"outputs":[]},{"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        f = ''\n        train_losses = []\n        valid_losses = []\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            train_losses.append(summary_loss.avg)\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            valid_losses.append(summary_loss.avg)\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                \n                try:\n                    os.remove(f)\n                except:pass\n                f = f'{self.base_dir}/best-checkpoint-{str(self.epoch).zfill(3)}epoch.bin'\n\n            if self.config.validation_scheduler:\n                self.scheduler.step(metrics=summary_loss.avg)\n\n            self.epoch += 1\n\n        return train_losses, valid_losses\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                img_scale = torch.tensor([1.0] * self.config.batch_size,\n                                                       dtype=torch.float).to(self.device)\n                img_size = torch.tensor([images[0].shape[-2:]] * self.config.batch_size,\n                                                      dtype=torch.float).to(self.device)\n                target = {'bbox':boxes, 'cls':labels, 'img_scale':img_scale, 'img_size':img_size}       \n                result = self.model(images, target)\n                loss = result['loss']\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            result = self.model(images, {'bbox':boxes, 'cls':labels})\n            loss = result['loss']\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')\n\n    def make_pred(self, test_dataloader):\n        results = []\n        for images, image_ids in tqdm(test_dataloader):\n            predictions = self.make_predictions(images)\n            for i, image in enumerate(images):\n                boxes, scores, labels = self.run_wbf(predictions, image_index=i)\n                #boxes = (boxes * 2).astype(np.int32).clip(min=0, max=1023)\n                boxes = boxes.astype(np.int32)\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': self.format_prediction_string(boxes, scores, labels, image_id)\n                }\n                results.append(result)  \n        \n        return results     \n\n    def make_predictions(self, images, score_threshold=0.22):\n        images = torch.stack(images).cuda().float()\n        img_scale = torch.tensor([1.0] * self.config.batch_size,\n                                                        dtype=torch.float).to(self.device)\n        img_size = torch.tensor([images[0].shape[-2:]] * self.config.batch_size,\n                                                    dtype=torch.float).to(self.device)\n        \n        target = {'img_scale':img_scale, 'img_size':img_size}\n        predictions = []\n        with torch.no_grad():\n            self.model.eval()\n            det = self.model(images, target)\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                labels = det[i].detach().cpu().numpy()[:, 5]\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                predictions.append({\n                    'boxes': boxes[indexes],\n                    'scores': scores[indexes],\n                    'labels': labels[indexes]\n                })\n        return [predictions]\n\n    def run_wbf(self, predictions, image_index, image_size=512, iou_thr=0.3, \n                skip_box_thr=0.1, 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 = [prediction[image_index]['labels'].tolist() for prediction in predictions]\n        boxes, scores, labels = ensemble_boxes_wbf.weighted_boxes_fusion(boxes, scores, labels, weights=None, iou_thr=iou_thr, skip_box_thr=skip_box_thr)\n        #boxes, scores, labels = soft_nms(boxes, scores, labels, weights=None, iou_thr=iou_thr)\n        #boxes, scores, labels = nms(boxes, scores, labels, weights=None, iou_thr=iou_thr)\n        boxes = boxes*(image_size-1)\n        return boxes, scores, labels\n\n    def format_prediction_string(self, boxes, scores, labels, image_id):\n        w,h = test_dim[test_dim['image_id'] == image_id][['width', 'height']].values[0]\n        xfac= int(w)/512\n        yfac= int(h)/512\n        pred_strings = []\n        for pred in zip(labels, scores, boxes):\n            pred_strings.append(\"{0} {1:.4f} {2} {3} {4} {5}\".format(int(pred[0]), pred[1], int(pred[2][0]*xfac), int(pred[2][1]*yfac), \n                                                                                                                      int(pred[2][2]*xfac), int(pred[2][3]*yfac)))\n        # for pred in zip(labels, scores, boxes):\n        #     pred_strings.append(\"{0} {1:.4f} {2} {3} {4} {5}\".format(int(pred[0]), pred[1], pred[2][0], pred[2][1], pred[2][2], pred[2][3]))\n\n        if len(pred_strings) == 0:\n            return str(\"14 1 0 0 1 1\")\n        return \" \".join(pred_strings)","metadata":{"id":"_TgN1HIzWZYB","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TrainGlobalConfig:\n    num_workers = 2\n    batch_size = 4\n    n_epochs = 20\n    lr = 0.0002\n    folder = '/content/drive/MyDrive/Colab Notebooks/인기응 프로젝트/effdet1-models'\n    verbose = True\n    verbose_step = 1\n    step_scheduler = False\n    validation_scheduler = True\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    )","metadata":{"id":"vZRCmMAbWZYD","trusted":true},"execution_count":null,"outputs":[]},{"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    train_loss, valid_loss = fitter.fit(train_loader, val_loader)\n\n    return train_loss, valid_loss","metadata":{"id":"vu6bTLvEWZYE","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_net(mode):\n    config = get_efficientdet_config('tf_efficientdet_d4')\n    config.num_classes = 14\n    config.image_size = [512,512]\n    config.norm_kwargs=dict(eps=.001, momentum=.01)\n    net = EfficientDet(config, pretrained_backbone=True)\n    net.class_net = HeadNet(config, num_outputs=config.num_classes)\n    if mode == 'Train':\n        return DetBenchTrain(net, config)\n    elif mode == 'Test':\n        return DetBenchPredict(net)\n\nnet = get_net('Train')","metadata":{"id":"sgdr8saoWZYF","outputId":"d8188233-c4f1-4ace-c2fc-ccd7a9e22eda","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# training","metadata":{"id":"VnjMZUv18nTl"}},{"cell_type":"code","source":"train_loss, valid_loss = run_training()","metadata":{"scrolled":true,"id":"YJwJI6UpWZYG","outputId":"5d88a447-f7c1-4913-9c17-239e6629a160","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# inference","metadata":{"id":"6drkceTMyVIB"}},{"cell_type":"code","source":"test_dim = pd.read_csv('/content/drive/MyDrive/Colab Notebooks/인기응 프로젝트/test.csv')","metadata":{"id":"jzKddItmCcbq"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_test_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    )","metadata":{"id":"Q9GjyNBbzx71"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"TEST_ROOT_PATH = './data/images/test'\n\nclass TestDatasetRetriever(Dataset):\n    def __init__(self, marking, image_ids, transforms=None):\n        super().__init__()\n        self.image_ids = image_ids\n        self.marking = marking\n        self.transforms = transforms\n\n    def __getitem__(self, index: int):\n        image_id = self.image_ids[index]\n        image = cv2.imread(f'{TEST_ROOT_PATH}/{image_id}.png', cv2.IMREAD_COLOR).copy().astype(np.float32)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32)\n        image /= 255.0\n\n        if self.transforms:\n            sample = self.transforms(**{'image': image})\n        image = sample['image']\n        return image, image_id\n\n    def __len__(self) -> int:\n        return self.image_ids.shape[0]","metadata":{"id":"5a9ilMJKLhEd"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images_test = np.array([path[:-4] for path in os.listdir(TEST_ROOT_PATH)])\n\ntest_dataset = TestDatasetRetriever(\n    image_ids=images_test,\n    marking=dataframe,\n    transforms=get_test_transforms()\n)","metadata":{"id":"EYUfoBEMzpzl"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"net = get_net('Test')","metadata":{"id":"CzvfxU0G_L2n"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def run_test():\n    device = torch.device('cuda:0')\n    net.to(device)\n\n    test_loader = torch.utils.data.DataLoader(\n        test_dataset, \n        batch_size=TrainGlobalConfig.batch_size,\n        num_workers=TrainGlobalConfig.num_workers,\n        shuffle=False,\n        sampler=SequentialSampler(test_dataset),\n        pin_memory=False,\n        collate_fn=collate_fn,\n    )\n  \n    fitter = Fitter(model=net, device=device, config=TrainGlobalConfig)\n    fitter.load('/content/drive/MyDrive/Colab Notebooks/인기응 프로젝트/effdet1-models/best-checkpoint-007epoch.bin')\n    result = fitter.make_pred(test_loader)\n\n    return result","metadata":{"id":"MfaUKt-E1w-R"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"preds = run_test()","metadata":{"id":"5kWUqUr52tf8","outputId":"666b97b5-ee76-4229-c4e1-256993ce41b9"},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = pd.DataFrame(preds, columns=['image_id', 'PredictionString'])\ntest_df.to_csv('submission.csv', index=False)\ntest_df.head()","metadata":{"id":"9V-Ak6z-2tds","outputId":"45784dc9-c88b-4443-da76-804e4c9be3d5"},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 결과시각화","metadata":{"id":"42BviJErlFv1"}},{"cell_type":"code","source":"device = torch.device('cuda:0')\nnet.to(device)\n\ntest_loader = torch.utils.data.DataLoader(\n    test_dataset, \n    batch_size=TrainGlobalConfig.batch_size,\n    num_workers=TrainGlobalConfig.num_workers,\n    shuffle=False,\n    sampler=SequentialSampler(test_dataset),\n    pin_memory=False,\n    collate_fn=collate_fn,\n)\n\nfitter = Fitter(model=net, device=device, config=TrainGlobalConfig)\nfitter.load('/content/drive/MyDrive/Colab Notebooks/인기응 프로젝트/effdet1-models/best-checkpoint-025epoch.bin')\n\nmapping = {0: 'Aortic enlargement', 1: 'Atelectasis', 2: 'Calcification', 3: 'Cardiomegaly', 4: 'Consolidation', 5: 'ILD',6: 'Infiltration', 7: 'Lung Opacity', \n           8: 'Nodule/Mass', 9: 'Other lesion', 10: 'Pleural effusion', 11: 'Pleural thickening',12: 'Pneumothorax', 13: 'Pulmonary fibrosis'}\n\nfont = cv2.FONT_HERSHEY_SIMPLEX\nfontScale = 1\nthickness = 3\ncolor = (1, 0, 0)\nfor j, (images, image_ids) in enumerate(test_loader):\n    if j >= 10:\n        break\n    predictions = fitter.make_predictions(images=images, score_threshold=0.2)\n    i = 1\n    sample = images[i].permute(1, 2, 0).cpu().numpy()\n    boxes, scores, labels = fitter.run_wbf(predictions, image_index=i)\n    if len(labels) > 0:\n        boxes = boxes.astype(np.int32)\n        fig, ax = plt.subplots(1, 1, figsize=(8, 8))\n        for score, box, label in zip(scores, boxes, labels):\n            cv2.rectangle(sample, (box[0], box[1]), (box[2], box[3]), (0, 1, 1), thickness)\n            cv2.putText(sample, mapping[label] + \"-\" + str(round(score, 2)), (box[0], box[1]),\n                        font, fontScale, color, thickness, cv2.LINE_AA)\n        ax.set_axis_off()\n        ax.imshow(sample)\n        plt.show()","metadata":{"id":"jvrbZTKiHgnr","outputId":"1ebd213f-4c85-4579-eaf1-e0c8b4dd8f40"},"execution_count":null,"outputs":[]}]}