{"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":"# RBCD PyTorch⚡Timm Infer\n\n## Training notebook: [RBCD PyTorch⚡Timm Train](https://www.kaggle.com/code/clemchris/rbcd-pytorch-timm-train)","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19"}},{"cell_type":"code","source":"!pip install dicomsdl pytorch_lightning timm --no-index --find-links=../input/rbcd-downloads","metadata":{"_kg_hide-output":true,"execution":{"iopub.status.busy":"2022-12-27T07:28:14.686381Z","iopub.execute_input":"2022-12-27T07:28:14.686779Z","iopub.status.idle":"2022-12-27T07:28:27.510241Z","shell.execute_reply.started":"2022-12-27T07:28:14.686694Z","shell.execute_reply":"2022-12-27T07:28:27.509109Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Imports","metadata":{}},{"cell_type":"code","source":"import multiprocessing as mp\nfrom pathlib import Path\nfrom typing import Tuple\n\nimport cv2\nimport numpy as np\nimport pandas as pd\nimport dicomsdl\nimport pytorch_lightning as pl\nimport seaborn as sns\nimport timm\nimport torch\nfrom joblib import delayed\nfrom joblib import Parallel\nfrom PIL import Image\nfrom timm.data.transforms_factory import create_transform\nfrom timm.loss import BinaryCrossEntropy\nfrom torch.utils.data import DataLoader\nfrom torch.utils.data import Dataset\nfrom tqdm.notebook import tqdm","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:27.514155Z","iopub.execute_input":"2022-12-27T07:28:27.514455Z","iopub.status.idle":"2022-12-27T07:28:32.661097Z","shell.execute_reply.started":"2022-12-27T07:28:27.514425Z","shell.execute_reply":"2022-12-27T07:28:32.660025Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Paths & Settings","metadata":{}},{"cell_type":"code","source":"KAGGLE_DIR = Path(\"/\") / \"kaggle\"\n\nINPUT_DIR = KAGGLE_DIR / \"input\"\nOUTPUT_DIR = KAGGLE_DIR / \"working\"\n\nDATA_ROOT_DIR = INPUT_DIR / \"rsna-breast-cancer-detection\"\n\nTEST_IMAGES_DIR = DATA_ROOT_DIR / \"test_images\"\nTEST_CSV_PATH = DATA_ROOT_DIR / \"test.csv\"\n\nOUTPUT_TEST_IMAGES_DIR = OUTPUT_DIR / \"test_images\"\nOUTPUT_TEST_IMAGES_DIR.mkdir(exist_ok=True)\n\nACCELERATOR = \"gpu\"\nBATCH_SIZE = 16\nDEVICES = 1\nIMAGE_SIZE = 1024\nNUM_WORKERS = mp.cpu_count()\nPRECISION = 16","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:32.662585Z","iopub.execute_input":"2022-12-27T07:28:32.663182Z","iopub.status.idle":"2022-12-27T07:28:32.671576Z","shell.execute_reply.started":"2022-12-27T07:28:32.663147Z","shell.execute_reply":"2022-12-27T07:28:32.670603Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"THRESHOLD = 0.68\nCHECKPOINT_PATH = sorted(Path(INPUT_DIR / \"rbcd-pytorch-timm-train\").glob(\"**/*.ckpt\"))[0]\nCHECKPOINT_PATH","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:32.674343Z","iopub.execute_input":"2022-12-27T07:28:32.674712Z","iopub.status.idle":"2022-12-27T07:28:32.713514Z","shell.execute_reply.started":"2022-12-27T07:28:32.674677Z","shell.execute_reply":"2022-12-27T07:28:32.712667Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Convert DCM to PNG","metadata":{}},{"cell_type":"code","source":"image_paths = sorted(TEST_IMAGES_DIR.glob(\"*/*.dcm\"))\nimage_paths ","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:32.714721Z","iopub.execute_input":"2022-12-27T07:28:32.715137Z","iopub.status.idle":"2022-12-27T07:28:32.733951Z","shell.execute_reply.started":"2022-12-27T07:28:32.715103Z","shell.execute_reply":"2022-12-27T07:28:32.732978Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def convert_dcm_to_png(image_path, size, output_image_dir):\n    patient_id = image_path.parent.name\n    image_id = image_path.stem\n\n    dicom = dicomsdl.open(str(image_path))\n    img = dicom.pixelData()\n\n    img = (img - img.min()) / (img.max() - img.min())\n\n    if dicom.getPixelDataInfo()[\"PhotometricInterpretation\"] == \"MONOCHROME1\":\n        img = 1 - img\n\n    img = cv2.resize(img, (size, size))\n\n    output_image_path = output_image_dir / f\"{patient_id}_{image_id}.png\"\n    cv2.imwrite(str(output_image_path), (img * 255).astype(np.uint8))","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:32.735517Z","iopub.execute_input":"2022-12-27T07:28:32.735879Z","iopub.status.idle":"2022-12-27T07:28:32.743289Z","shell.execute_reply.started":"2022-12-27T07:28:32.735847Z","shell.execute_reply":"2022-12-27T07:28:32.74221Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_ = Parallel(n_jobs=NUM_WORKERS)(\n    delayed(convert_dcm_to_png)(image_path, size=IMAGE_SIZE, output_image_dir=OUTPUT_TEST_IMAGES_DIR)\n    for image_path in tqdm(image_paths)\n)","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:32.745112Z","iopub.execute_input":"2022-12-27T07:28:32.74545Z","iopub.status.idle":"2022-12-27T07:28:35.23513Z","shell.execute_reply.started":"2022-12-27T07:28:32.745417Z","shell.execute_reply":"2022-12-27T07:28:35.234Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Prepare Data","metadata":{}},{"cell_type":"code","source":"def prepare_data(csv_path, images_dir, create_splits: bool = False):\n    df = pd.read_csv(csv_path)\n\n    df[\"image\"] = (\n        str(images_dir)\n        + \"/\"\n        + df[\"patient_id\"].astype(str)\n        + \"_\"\n        + df[\"image_id\"].astype(str)\n        + \".png\"\n    )\n    \n    if create_splits:\n        skf = StratifiedGroupKFold(n_splits=NUM_SPLITS)\n        for fold, (_, val_) in enumerate(\n            skf.split(X=df, y=df.cancer, groups=df.patient_id)\n        ):\n            df.loc[val_, \"fold\"] = fold\n            \n    # Save\n    file_path = csv_path.name\n    df.to_csv(file_path, index=False)\n    \n    print(f\"Created {file_path} with {len(df)} rows\")\n    \n    return df","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.236781Z","iopub.execute_input":"2022-12-27T07:28:35.23717Z","iopub.status.idle":"2022-12-27T07:28:35.246288Z","shell.execute_reply.started":"2022-12-27T07:28:35.237127Z","shell.execute_reply":"2022-12-27T07:28:35.244585Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_df = prepare_data(TEST_CSV_PATH, OUTPUT_TEST_IMAGES_DIR)","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.24784Z","iopub.execute_input":"2022-12-27T07:28:35.248576Z","iopub.status.idle":"2022-12-27T07:28:35.28103Z","shell.execute_reply.started":"2022-12-27T07:28:35.248535Z","shell.execute_reply":"2022-12-27T07:28:35.280038Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{}},{"cell_type":"code","source":"class RBCDDataset(Dataset):\n    def __init__(self, df, transform):\n        self.df = df\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        row = self.df.iloc[idx]\n\n        image = Image.open(row.image).convert(\"RGB\")\n\n        if self.transform is not None:\n            image = self.transform(image)\n\n        try:\n            return image, row.cancer\n        except:\n            return image","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.284447Z","iopub.execute_input":"2022-12-27T07:28:35.28474Z","iopub.status.idle":"2022-12-27T07:28:35.293114Z","shell.execute_reply.started":"2022-12-27T07:28:35.284714Z","shell.execute_reply":"2022-12-27T07:28:35.292118Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# LightningDataModule","metadata":{}},{"cell_type":"code","source":"class TimmDataModule(pl.LightningDataModule):\n    def __init__(\n        self,\n        batch_size: int,\n        data_csv_path: str,\n        num_workers: int,\n    ):\n        super().__init__()\n\n        self.save_hyperparameters()\n\n        self.df = pd.read_csv(data_csv_path)\n\n        self.spatial_size = (IMAGE_SIZE, IMAGE_SIZE)\n\n        self.val_transform = self._init_val_transform()\n\n    def _init_val_transform(self):\n        return create_transform(\n            input_size=self.spatial_size,\n            is_training=False,\n            interpolation=\"bilinear\",\n        )\n    \n    def setup(self, stage=None):\n        self.predict_dataset = self._dataset(self.df, self.val_transform)\n\n    def predict_dataloader(self):\n        return self._dataloader(self.predict_dataset)\n\n    def _dataset(self, df, transform):\n        return RBCDDataset(df=df, transform=transform)\n    \n    def _dataloader(self, dataset, train=False):\n        return DataLoader(\n            dataset,\n            batch_size=self.hparams.batch_size,\n            shuffle=train,\n            num_workers=self.hparams.num_workers,\n        )","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.294446Z","iopub.execute_input":"2022-12-27T07:28:35.294902Z","iopub.status.idle":"2022-12-27T07:28:35.305404Z","shell.execute_reply.started":"2022-12-27T07:28:35.294868Z","shell.execute_reply":"2022-12-27T07:28:35.304474Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# LightningModule","metadata":{}},{"cell_type":"code","source":"class TimmModule(pl.LightningModule):\n    def __init__(\n        self,\n        model_name: str,\n    ):\n        super().__init__()\n        \n        self.save_hyperparameters()\n\n        self.model = self._init_model()\n\n    def _init_model(self):\n        return timm.create_model(\n            self.hparams.model_name,\n            pretrained=False,\n            num_classes=1,\n        )\n    \n    def forward(self, images):\n        return self.model(images)\n    \n    def predict_step(self, batch, batch_idx):\n        images = batch\n        logits = self(images).view(-1)\n        preds = logits.sigmoid()\n        return preds","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.306742Z","iopub.execute_input":"2022-12-27T07:28:35.307204Z","iopub.status.idle":"2022-12-27T07:28:35.319802Z","shell.execute_reply.started":"2022-12-27T07:28:35.307166Z","shell.execute_reply":"2022-12-27T07:28:35.318934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Infer","metadata":{}},{"cell_type":"code","source":"data_module = TimmDataModule(\n    batch_size=BATCH_SIZE,\n    data_csv_path=\"test.csv\",\n    num_workers=NUM_WORKERS,\n)\n\nmodule = TimmModule.load_from_checkpoint(CHECKPOINT_PATH)\n\ntrainer = pl.Trainer(\n    accelerator=ACCELERATOR,\n    devices=DEVICES,\n    logger=None,\n    precision=16 if ACCELERATOR == \"gpu\" else 32,\n)\n\npredictions = trainer.predict(module, datamodule=data_module)\n\npredictions = torch.cat(predictions).numpy()\n    \nprint(predictions.shape)","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:35.321049Z","iopub.execute_input":"2022-12-27T07:28:35.321461Z","iopub.status.idle":"2022-12-27T07:28:49.932991Z","shell.execute_reply.started":"2022-12-27T07:28:35.321427Z","shell.execute_reply":"2022-12-27T07:28:49.93163Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Submit","metadata":{}},{"cell_type":"code","source":"test_df[\"cancer\"] = predictions\n\ntest_df[\"cancer\"] = (test_df[\"cancer\"] > THRESHOLD).astype(int)\n\nsub_df = test_df[[\"prediction_id\", \"cancer\"]].groupby(\"prediction_id\").mean().reset_index()\n\nsub_df.to_csv(\"submission.csv\",index=False)\nsub_df","metadata":{"execution":{"iopub.status.busy":"2022-12-27T07:28:49.935405Z","iopub.execute_input":"2022-12-27T07:28:49.935841Z","iopub.status.idle":"2022-12-27T07:28:49.966314Z","shell.execute_reply.started":"2022-12-27T07:28:49.935798Z","shell.execute_reply":"2022-12-27T07:28:49.965214Z"},"trusted":true},"execution_count":null,"outputs":[]}]}