{"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":"- CAUSION: IN ORDER TO SHORTEN THE TRAINGING AND TESTING TIME WE ONLY PROVIDED THE CODE TRAINING ON THE SIZE OF 256*256","metadata":{}},{"cell_type":"markdown","source":"# install some packages","metadata":{}},{"cell_type":"code","source":"!pip install /kaggle/input/rsna-2022-whl/{pydicom-2.3.0-py3-none-any.whl,pylibjpeg-1.4.0-py3-none-any.whl,python_gdcm-3.0.15-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl}\n!pip install /kaggle/input/nvidia-dali-wheel/nvidia_dali_nightly_cuda110-1.22.0.dev20221213-6757685-py3-none-manylinux2014_x86_64.whl\n!pip install /kaggle/input/nvidia-dali-wheel/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_kg_hide-input":true,"_kg_hide-output":true,"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Import packages","metadata":{}},{"cell_type":"code","source":"import sys\nsys.path.append('/kaggle/input/rsnacode/')\nimport os\n# os.environ[\"CUDA_VISIBLE_DEVICES\"] = '1'\nimport gc\nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport sklearn\nimport torch\nfrom PIL import Image\nfrom sklearn.model_selection import GroupKFold, StratifiedGroupKFold\nfrom sklearn.preprocessing import LabelEncoder\nimport sys\nimport timm\nfrom timm import create_model, list_models\nfrom timm.data import create_transform\nfrom torch.cuda.amp import GradScaler, autocast\nfrom tqdm import tqdm\nimport random\nimport wandb\nfrom wandb import AlertLevel\nimport torchvision\nfrom torch.utils.data import Dataset\nfrom torch.nn import functional as F\nfrom torch.nn import Module, Linear, Sequential, ModuleList, ReLU, Dropout, Flatten\nfrom torch import nn\nfrom torch.utils.data import DataLoader\nfrom torch.optim import Adam, SGD, AdamW, lr_scheduler\nimport warnings\nwarnings.filterwarnings('ignore')\n\n\nos.environ['WANDB_API_KEY'] = 'YOUR API KEY' # I set offline.\ngc.collect()\ntorch.cuda.empty_cache()\n\nfrom utils import seed_everything, init_logger, get_timediff, optimal_f1, gc_collect, add_weight_decay, get_parameter_number\nfrom model import GeM, BreastCancerModel\nfrom dataset import BreastCancerDataSet_16bit, BreastCancerDataSet_8bit, mixup_augmentation, get_transforms_8bit, get_transforms_16bit\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# CFG","metadata":{}},{"cell_type":"code","source":"class CFG:\n    image_size =  (256, 256)\n    tta = True\n    \n    seed = 1788\n    num_workers = 5\n    valid_batch_size = 16\n    gpu_parallel = False\n    device = 'cuda' if torch.cuda.is_available() else 'cpu'\n    df_path = f'/kaggle/input/vindr-only-csv/vindr.csv'\n\n    normalize_mean= [0.485, 0.456, 0.406]  # [0.21596, 0.21596, 0.21596]\n    normalize_std = [0.229, 0.224, 0.225]  # [0.18558, 0.18558, 0.18558]\n\n    target = 'cancer'\n    ensemble = True\n\n\nimages_dir = f'/kaggle/input/vindr-only-csv/'\noutput_dir = '/kaggle/working/'","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"seed_everything(CFG.seed)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{}},{"cell_type":"code","source":"df_train = pd.read_csv(CFG.df_path)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from albumentations import (\n    HorizontalFlip, VerticalFlip, IAAPerspective, ShiftScaleRotate, CLAHE, RandomRotate90,\n    Transpose, ShiftScaleRotate, Blur, OpticalDistortion, GridDistortion, HueSaturationValue,\n    IAAAdditiveGaussianNoise, GaussNoise, MotionBlur, MedianBlur, IAAPiecewiseAffine, RandomResizedCrop,\n    IAASharpen, IAAEmboss, RandomBrightnessContrast, Flip, OneOf, Compose, Normalize, Cutout, CoarseDropout, ShiftScaleRotate, \n    CenterCrop, Resize, RandomCrop, GaussianBlur, JpegCompression, Downscale, ElasticTransform, Affine, ToFloat\n)\nimport albumentations as A\nfrom albumentations.pytorch import ToTensorV2\n\ndef get_transforms(*, data):\n    if data == 'train':\n        return Compose([\n            Normalize(mean=CFG.normalize_mean, std=CFG.normalize_std,),\n            ToTensorV2(),\n            ])\n        \n    elif data == 'valid':\n        return Compose([\n            ToFloat(max_value=65535.0),\n            Resize(CFG.image_size[0], CFG.image_size[1]),\n            ToTensorV2(),\n        ])","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class BreastCancerDataSet(Dataset):\n    def __init__(self, df, path, transforms=None):\n        super().__init__()\n        self.df = df\n        self.path = path\n        self.transforms = transforms\n\n    def __getitem__(self, i):\n        path = f'{self.path}/{self.df.iloc[i].patient_id}/{self.df.iloc[i].image_id}.png'\n        try:\n            # img = Image.open(path).convert('RGB')\n            # 16bit\n            img = Image.open(path)\n            img = np.array(img).astype(np.uint16)\n            if img.ndim == 2:\n                img = np.repeat(img[:, :, np.newaxis], 3, axis=-1)\n        except Exception as ex:\n            print(path, ex)\n            return None\n\n        if self.transforms:\n            img = self.transforms(image=np.array(img))[\"image\"]\n\n        if CFG.target in self.df.columns:\n            cancer_target = torch.as_tensor(self.df.iloc[i].cancer)\n            return img, cancer_target\n\n        return img\n\n    def __len__(self):\n        return len(self.df)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# model","metadata":{}},{"cell_type":"code","source":"class BreastCancerModel(Module):\n    def __init__(self, model_arch, dropout=0.):\n        super().__init__()\n        self.model = create_model(\n            model_arch, \n            pretrained=True, \n            num_classes=0, \n            drop_rate=dropout,\n            global_pool=\"\", \n            )\n        self.num_feats = self.model.num_features\n\n        self.cancer_logits = Linear(self.num_feats, 1)\n        \n        self.fc_dropout = nn.Dropout(0)\n        self.global_pool = GeM(p_trainable=True)\n\n    def forward(self, x):\n        x = self.model(x) # (bs, num_feats) /  (bs, num_feats, 16, 16)\n        x = self.global_pool(x) # (bs, num_feats, 1, 1)\n        x = x[:,:,0,0] # # (bs, num_feats)\n        cancer_logits = self.cancer_logits(self.fc_dropout(x)).squeeze() # (bs)\n        return cancer_logits","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train and Test","metadata":{}},{"cell_type":"code","source":"def test_func(model, dataloader):\n    model = model.to(CFG.device)\n    cancer_pred_list = []\n    with torch.no_grad():\n        model.eval()\n        for X in tqdm(dataloader, desc='Preds'):\n            with autocast(enabled=True):\n                X = X.to(CFG.device)\n                pred_c = model(X).view(-1)\n                if CFG.tta:\n                    pred_c2 = model(torch.flip(X, dims=[-1])).view(-1) # horizontal mirror\n                    pred_c = (pred_c + pred_c2) / 2\n                \n                cancer_pred_list.append(torch.sigmoid(pred_c))\n        \n        pred = torch.concat(cancer_pred_list).cpu().numpy()\n        return pred","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def gen_predictions(models, df_train, folds):\n    df_train_predictions = []\n    for model, fold in zip(models, folds):\n        ds_valid = BreastCancerDataSet(df_train.query('split == @fold'), images_dir, get_transforms(data=\"valid\"))\n        valid_dataloader  = DataLoader(ds_valid, batch_size=CFG.valid_batch_size, shuffle=False, num_workers=CFG.num_workers, pin_memory=False)\n        pred_cancer = test_func(model, valid_dataloader)\n        print(f'Test fold:{fold}')\n        \n        df_pred = pd.DataFrame(data=pred_cancer, columns=['cancer_pred_proba'])\n\n        df = pd.concat(\n            [df_train.query('split == @fold').reset_index(drop=True), df_pred],\n            axis=1\n        ).sort_values(['patient_id', 'image_id'])\n        df_train_predictions.append(df)\n    df_train_predictions = pd.concat(df_train_predictions)\n    return df_train_predictions\n\n\ndef gen_predictions_ensemble(models, df_train):\n    df_pred_all = []\n    for model in models:\n        ds_valid = BreastCancerDataSet(df_train, images_dir, get_transforms(data=\"valid\"))\n        valid_dataloader  = DataLoader(ds_valid, batch_size=CFG.valid_batch_size, shuffle=False, num_workers=CFG.num_workers, pin_memory=False)\n        pred_cancer = test_func(model, valid_dataloader)\n        \n        df_pred_all.append(pred_cancer)\n    \n    # mean of predictions\n    df_preds = np.array(df_pred_all).mean(axis=0)\n    \n    df_preds = pd.DataFrame(data=df_preds, columns=['cancer_pred_proba'])\n    df = pd.concat(\n        [df_train, df_preds],\n        axis=1\n    ).sort_values(['patient_id', 'image_id'])\n        \n    return df\n\n\n\ndef load_model(path, backbone, model=None):\n    state_dict = torch.load(path, map_location=CFG.device)\n    if model is None:\n        model = BreastCancerModel(backbone)\n    model.load_state_dict(state_dict['model'])\n\n    print(f\"load model:{backbone}, thres:{state_dict['threshold']}, \")\n    return model, state_dict['threshold'], state_dict['model_arch']\n\n# Load Models here\n\nmodel_paths = [\n        \"./output/0001/0001_model_f0_ep10.pth\", \n        \"./output/0001/0001_model_f1_ep12.pth\", \n        \"./output/0001/0001_model_f2_ep7.pth\", \n        \"./output/0001/0001_model_f3_ep9.pth\", \n        \"./output/0001/0001_model_f4_ep8.pth\", \n]\n\nbackbones = [\n    \"tf_efficientnetv2_s\",\n    \"tf_efficientnetv2_s\",\n    \"tf_efficientnetv2_s\",\n    \"tf_efficientnetv2_s\",\n    \"tf_efficientnetv2_s\",\n]\n\nfolds = [0,1,2,3,4]\n\nassert len(model_paths) == len(folds) == len(backbones), f\"got folds:{len(folds)}, model_paths:{len(model_paths)},  backbones:{len(backbones)}\"\n\n\nmodels = []\n\nfor m_path, backbone in zip(model_paths, backbones):\n    model, thres, model_arch = load_model(m_path, backbone)\n    model = model.to(CFG.device)\n    models.append(model)\n    print(f'm_path:{m_path}, model_arch:{model_arch}, thres:{thres}')\n\nif CFG.ensemble:\n    df_pred = gen_predictions_ensemble(models, df_train)\nelse:\n    df_pred = gen_predictions(models, df_train, folds)\n\ndf_pred.to_csv(f'{output_dir}/train_predictions_0001.csv', index=False)\n\n\n\nprint(f'F1 CV score (multiple thresholds): {sklearn.metrics.f1_score(df_pred[\"cancer\"], df_pred[\"cancer_pred\"])}')\n\n\n\ndf_pred_all = df_pred.groupby(['patient_id', 'laterality']).agg(\n    cancer_max=('cancer_pred_proba', 'max'), cancer_mean=('cancer_pred_proba', 'mean'), cancer=('cancer', 'max')\n)\nprint(f'ALL pF1 CV score. Mean , single threshold: {optimal_f1(df_pred_all[\"cancer\"].values, df_pred_all[\"cancer_mean\"].values)}', )\nprint(f'ALL pF1 CV score. Max  , single threshold: {optimal_f1(df_pred_all[\"cancer\"].values, df_pred_all[\"cancer_max\"].values)}', )\n\ndf_pred1 = df_pred[df_pred[\"site_id\"]==1].groupby(['patient_id', 'laterality']).agg(\n    cancer_max=('cancer_pred_proba', 'max'), cancer_mean=('cancer_pred_proba', 'mean'), cancer=('cancer', 'max')\n)\nprint(f'SITE1 pF1 CV score. Mean , single threshold: {optimal_f1(df_pred1[\"cancer\"].values, df_pred1[\"cancer_mean\"].values)}', )\nprint(f'SITE1 pF1 CV score. Max  , single threshold: {optimal_f1(df_pred1[\"cancer\"].values, df_pred1[\"cancer_max\"].values)}', )\n\ndf_pred2 = df_pred[df_pred[\"site_id\"]==2].groupby(['patient_id', 'laterality']).agg(\n    cancer_max=('cancer_pred_proba', 'max'), cancer_mean=('cancer_pred_proba', 'mean'), cancer=('cancer', 'max')\n)\nprint(f'SITE2 pF1 CV score. Mean , single threshold: {optimal_f1(df_pred2[\"cancer\"].values, df_pred2[\"cancer_mean\"].values)}', )\nprint(f'SITE2 pF1 CV score. Max  , single threshold: {optimal_f1(df_pred2[\"cancer\"].values, df_pred2[\"cancer_max\"].values)}', )\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}