{"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":"try:\n    import pylibjpeg\nexcept:\n    ! pip install -q /kaggle/input/rsna-2022-whl//kaggle/input/rsna-2022-whl/Pillow-9.2.0-cp37-cp37m-manylinux_2_28_x86_64.whl\n    ! pip install -q /kaggle/input/rsna-2022-whl/certifi-2022.6.15-py3-none-any.whl\n    ! pip install -q /kaggle/input/rsna-2022-whl/charset_normalizer-2.1.1-py3-none-any.whl\n    ! pip install -q /kaggle/input/rsna-2022-whl/pydicom-2.3.0-py3-none-any.whl\n    ! pip install -q /kaggle/input/rsna-2022-whl/pylibjpeg-1.4.0-py3-none-any.whl\n ","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2023-01-08T01:02:02.24328Z","iopub.execute_input":"2023-01-08T01:02:02.244214Z"}}},{"cell_type":"markdown","source":"try:\n    import pylibjpeg\nexcept:\n    !pip install -q /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 -q /kaggle/input/rsna-bcd-whl-ds/python_gdcm-3.0.20-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl\n    # !pip install -q /kaggle/input/rsna-bcd-whl-ds/pylibjpeg-1.4.0-py3-none-any.whl\n    !pip install -q /kaggle/input/rsna-bcd-whl-ds/dicomsdl-0.109.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:08:04.810132Z","iopub.execute_input":"2023-01-08T01:08:04.810533Z","iopub.status.idle":"2023-01-08T01:08:04.820137Z","shell.execute_reply.started":"2023-01-08T01:08:04.810502Z","shell.execute_reply":"2023-01-08T01:08:04.818884Z"}}},{"cell_type":"code","source":"# install pydicom requirements\n!conda install '/kaggle/input/pydicom-conda-helper/libjpeg-turbo-2.1.0-h7f98852_0.tar.bz2' --offline -yq\n!conda install '/kaggle/input/pydicom-conda-helper/libgcc-ng-9.3.0-h2828fa1_19.tar.bz2' --offline -yq\n!cp ../input/gdcm-conda-install/gdcm.tar .\n!tar -xvzf gdcm.tar\n!conda install --offline ./gdcm/gdcm-2.8.9-py37h71b2a6d_0.tar.bz2 -q\n!conda install '/kaggle/input/pydicom-conda-helper/conda-4.10.1-py37h89c1867_0.tar.bz2' --offline -yq\n!conda install '/kaggle/input/pydicom-conda-helper/certifi-2020.12.5-py37h89c1867_1.tar.bz2' --offline -yq\n!conda install '/kaggle/input/pydicom-conda-helper/openssl-1.1.1k-h7f98852_0.tar.bz2' --offline -yq\n!rm -rf gdcm/ gdcm.tar","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:25:45.738524Z","iopub.execute_input":"2023-01-08T01:25:45.739117Z","iopub.status.idle":"2023-01-08T01:26:41.650726Z","shell.execute_reply.started":"2023-01-08T01:25:45.739025Z","shell.execute_reply":"2023-01-08T01:26:41.649492Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Required Libraries","metadata":{}},{"cell_type":"code","source":"import glob\nimport os\nimport sys\nsys.path.append('../input/timm-pytorch-image-models/pytorch-image-models-master')\nimport timm \nimport cv2\nimport matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport torch\nfrom timm import create_model\nfrom tqdm.notebook import tqdm\nfrom joblib import Parallel, delayed\nimport cv2","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:26:49.879227Z","iopub.execute_input":"2023-01-08T01:26:49.879612Z","iopub.status.idle":"2023-01-08T01:26:53.525455Z","shell.execute_reply.started":"2023-01-08T01:26:49.879577Z","shell.execute_reply":"2023-01-08T01:26:53.524294Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Path,Kaggle and Wandb Environment Variables","metadata":{}},{"cell_type":"code","source":"RSNA_2022_PATH = '/kaggle/input/rsna-breast-cancer-detection'\nPNG_TEST_IMAGES_PATH = f'test'\nMODELS_PATH = '/kaggle/input/weights-eff-b4'\nDCM_TEST_IMAGES_PATH = f'/kaggle/input/rsna-breast-cancer-detection/test_images'\ntry:\n    from kaggle_secrets import UserSecretsClient\n    IS_KAGGLE = True\nexcept:\n    IS_KAGGLE = False\n\n    DEBUG = True\n\nif not IS_KAGGLE:\n    print('Running locally')\n    RSNA_2022_PATH = 'data'\n    DCM_TEST_IMAGES_PATH = f'data/test_images'\n    MODELS_PATH = 'models_roi_1024_v2'\n\nAUX_TARGET_NCLASSES = [2, 2, 6, 2, 2, 2, 4, 5, 2, 10, 10]\n\nDEVICE = 'cuda' if torch.cuda.is_available() else 'cpu'\nif DEVICE == 'cuda':\n    BATCH_SIZE = 16\nelse:\n    BATCH_SIZE = 2","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:26:56.513789Z","iopub.execute_input":"2023-01-08T01:26:56.514488Z","iopub.status.idle":"2023-01-08T01:26:56.521284Z","shell.execute_reply.started":"2023-01-08T01:26:56.514452Z","shell.execute_reply":"2023-01-08T01:26:56.520241Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Configure the Size of the Images","metadata":{}},{"cell_type":"code","source":"class CFG:\n    resize_dim = 1024\n    aspect_ratio = True\n    img_size = [1024, 512]","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:00.364169Z","iopub.execute_input":"2023-01-08T01:27:00.364529Z","iopub.status.idle":"2023-01-08T01:27:00.369719Z","shell.execute_reply.started":"2023-01-08T01:27:00.364498Z","shell.execute_reply":"2023-01-08T01:27:00.368416Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Load the Test Data Frame","metadata":{}},{"cell_type":"code","source":"def load_df_test():\n    df_test = pd.read_csv(f'{RSNA_2022_PATH}/test.csv')\n    return df_test\n\ndf_test = load_df_test()\n\ndf_test","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:06.006782Z","iopub.execute_input":"2023-01-08T01:27:06.007185Z","iopub.status.idle":"2023-01-08T01:27:06.036701Z","shell.execute_reply.started":"2023-01-08T01:27:06.007152Z","shell.execute_reply":"2023-01-08T01:27:06.035694Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset Class","metadata":{}},{"cell_type":"markdown","source":"BreastCancerDataset class returns individual images. It uses a dataframe parameter df as a source of metadata to locate and load images from path folder.","metadata":{}},{"cell_type":"code","source":"from concurrent.futures import ProcessPoolExecutor, ThreadPoolExecutor\nimport re\nimport pydicom\n\ndef fit_image(fname, size=1024):\n    # 1. Read, resize\n    patient = fname.split('/')[-2]\n    image = fname.split('/')[-1][:-4]\n    dicom = pydicom.dcmread(fname)\n    img = dicom.pixel_array\n    img = (img - img.min()) / (img.max() - img.min())\n    if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        img = 1 - img\n    img = cv2.resize(img, (size, size))\n    # 2. Crop\n    X = img\n    # Some images have narrow exterior \"frames\" that complicate selection of the main data. Cutting off the frame\n    X = X[5:-5, 5:-5]\n    \n    # regions of non-empty pixels\n    output= cv2.connectedComponentsWithStats((X > 0.05).astype(np.uint8)[:, :], 8, cv2.CV_32S)\n\n    # stats.shape == (N, 5), where N is the number of regions, 5 dimensions correspond to:\n    # left, top, width, height, area_size\n    stats = output[2]\n    \n    # finding max area which always corresponds to the breast data. \n    idx = stats[1:, 4].argmax() + 1\n    x1, y1, w, h = stats[idx][:4]\n    x2 = x1 + w\n    y2 = y1 + h\n    \n    # cutting out the breast data\n    X_fit = X[y1: y2, x1: x2]\n    \n    patient_id, im_id = os.path.basename(os.path.dirname(fname)), os.path.basename(fname)[:-4]\n    os.makedirs(f'{PNG_TEST_IMAGES_PATH}/test_images/{patient_id}', exist_ok=True)\n    cv2.imwrite(f'{PNG_TEST_IMAGES_PATH}/test_images/{patient_id}/{im_id}.png', (X_fit[:, :] * 255).astype(np.uint8))\n\ndef fit_all_images(all_images):\n    with ThreadPoolExecutor(2) as p:\n        for i in tqdm(p.map(fit_image, all_images), total=len(all_images)):\n            pass\n\nall_images = glob.glob('/kaggle/input/rsna-breast-cancer-detection/test_images/*/*') \n# all_images = glob.glob('/kaggle/input/rsna-breast-cancer-detection/train_images/10006/*')\nfit_all_images(all_images)","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:13.975117Z","iopub.execute_input":"2023-01-08T01:27:13.975836Z","iopub.status.idle":"2023-01-08T01:27:17.147136Z","shell.execute_reply.started":"2023-01-08T01:27:13.975799Z","shell.execute_reply":"2023-01-08T01:27:17.145934Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torchvision\nfrom PIL import Image\n\ndef get_transforms(aug=False):\n\n    def transforms(img):\n        img = img.convert('RGB')#.resize((512, 512))\n        if aug:\n            tfm = [\n                torchvision.transforms.RandomHorizontalFlip(0.5),\n                torchvision.transforms.RandomRotation(degrees=(-5, 5)), \n                torchvision.transforms.RandomResizedCrop((1024, 512), scale=(0.8, 1), ratio=(0.45, 0.55)) \n            ]\n        else:\n            tfm = [\n                torchvision.transforms.RandomHorizontalFlip(0.5),\n                torchvision.transforms.Resize((1024, 512))\n            ]\n        img = torchvision.transforms.Compose(tfm + [            \n            torchvision.transforms.ToTensor(),\n            torchvision.transforms.Normalize(mean=0.2179, std=0.0529),\n            \n        ])(img)\n        return img\n\n    return lambda img: transforms(img)\n\ntfm = get_transforms(aug=False)\nimg = Image.open(f\"{PNG_TEST_IMAGES_PATH}/test_images/10008/68070693.png\")\nplt.imshow(np.array(img), cmap='gray')\nplt.show()","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:20.729212Z","iopub.execute_input":"2023-01-08T01:27:20.729587Z","iopub.status.idle":"2023-01-08T01:27:21.002971Z","shell.execute_reply.started":"2023-01-08T01:27:20.729556Z","shell.execute_reply":"2023-01-08T01:27:21.002041Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from PIL import Image\n\n\nclass BreastCancerDataSet(torch.utils.data.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\n        path = f'{self.path}/test_images/{self.df.iloc[i].patient_id}/{self.df.iloc[i].image_id}.png'\n        try:\n            img = Image.open(path).convert('RGB')\n        except Exception as ex:\n            print(path, ex)\n            return None\n\n        if self.transforms is not None:\n            img = self.transforms(img)\n\n\n        return img\n\n    def __len__(self):\n        return len(self.df)\n\nds_test = BreastCancerDataSet(df_test, PNG_TEST_IMAGES_PATH, get_transforms(False))\n\nX, y_cancer, y_aux = ds_test[2]\nprint(X.shape, y_cancer.shape, y_aux.shape)","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:26.849951Z","iopub.execute_input":"2023-01-08T01:27:26.850614Z","iopub.status.idle":"2023-01-08T01:27:26.909263Z","shell.execute_reply.started":"2023-01-08T01:27:26.850572Z","shell.execute_reply":"2023-01-08T01:27:26.908207Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class BreastCancerModel(torch.nn.Module):\n    def __init__(self, aux_classes, model_type='seresnext50_32x4d', dropout=0.):\n        super().__init__()\n        self.model = create_model(model_type, pretrained=False, num_classes=0, drop_rate=dropout)\n\n        self.backbone_dim = self.model(torch.randn(1, 3, 512, 512)).shape[-1]\n\n        self.nn_cancer = torch.nn.Sequential(\n            torch.nn.Linear(self.backbone_dim, 1),\n        )\n        self.nn_aux = torch.nn.ModuleList([\n            torch.nn.Linear(self.backbone_dim, n) for n in aux_classes\n        ])\n\n    def forward(self, x):\n        # returns logits\n        x = self.model(x)\n\n        cancer = self.nn_cancer(x).squeeze()\n        aux = []\n        for nn in self.nn_aux:\n            aux.append(nn(x).squeeze())\n        return cancer, aux\n\n    def predict(self, x):\n        cancer, aux = self.forward(x)\n        sigaux = []\n        for a in aux:\n            sigaux.append(torch.softmax(a, dim=-1))\n        return torch.sigmoid(cancer), sigaux\n\n\nwith torch.no_grad():\n    model = BreastCancerModel(AUX_TARGET_NCLASSES, model_type='efficientnet_b2')\n    pred, aux = model.predict(torch.randn(2, 3, 512, 512))\n    print('efficientnet_b2', pred.shape, len(aux))\n\ndel model","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:30.809215Z","iopub.execute_input":"2023-01-08T01:27:30.809577Z","iopub.status.idle":"2023-01-08T01:27:32.473429Z","shell.execute_reply.started":"2023-01-08T01:27:30.809544Z","shell.execute_reply":"2023-01-08T01:27:32.472367Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def load_model(name, dir='.', model=None):\n    data = torch.load(os.path.join(dir, f'{name}'), map_location=DEVICE)\n    if model is None:\n        model = BreastCancerModel(AUX_TARGET_NCLASSES, data['model_type'])\n    model.load_state_dict(data['model'])\n    # print(data['threshold'], data['model_type'])\n    return model, data['threshold'], data['model_type']","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:37.219532Z","iopub.execute_input":"2023-01-08T01:27:37.220132Z","iopub.status.idle":"2023-01-08T01:27:37.227231Z","shell.execute_reply.started":"2023-01-08T01:27:37.220095Z","shell.execute_reply":"2023-01-08T01:27:37.225763Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models = []\nfor fname in tqdm(sorted(os.listdir(MODELS_PATH))):\n    model, thres, model_type = load_model(fname, MODELS_PATH)\n    model = model.to(DEVICE)\n    models.append((model, thres))\n    print(f'fname:{fname}, model_type:{model_type}, thres:{thres}')","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:41.019Z","iopub.execute_input":"2023-01-08T01:27:41.019733Z","iopub.status.idle":"2023-01-08T01:27:57.526316Z","shell.execute_reply.started":"2023-01-08T01:27:41.019697Z","shell.execute_reply":"2023-01-08T01:27:57.525279Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def models_predict(models, ds, max_batches=1e9):\n    dl_test = torch.utils.data.DataLoader(ds, batch_size=BATCH_SIZE, shuffle=False, num_workers=os.cpu_count())\n    for m, thres in models:\n        m.eval()\n\n    with torch.no_grad():\n        predictions = []\n        for idx, X in enumerate(tqdm(dl_test, mininterval=30)):\n            pred = torch.zeros(len(X), len(models))\n            for idx, (m, thres) in enumerate(models):\n                preds = m.predict(X.to(DEVICE))[0].squeeze()\n                pred[:, idx] = preds.cpu()\n            predictions.append(pred.mean(dim=-1))\n            \n            if idx >= max_batches:\n                break\n        return torch.concat(predictions).numpy()\n\nprint(models_predict([(BreastCancerModel(AUX_TARGET_NCLASSES, 'seresnext50_32x4d').to(DEVICE), 0.5),\n                    (BreastCancerModel(AUX_TARGET_NCLASSES, 'seresnext50_32x4d').to(DEVICE), 0.1)], ds_test, max_batches=2))\n","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:27:57.528222Z","iopub.execute_input":"2023-01-08T01:27:57.529213Z","iopub.status.idle":"2023-01-08T01:28:06.754794Z","shell.execute_reply.started":"2023-01-08T01:27:57.529174Z","shell.execute_reply":"2023-01-08T01:28:06.753562Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"models_pred = models_predict(models, ds_test)","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:28:06.757724Z","iopub.execute_input":"2023-01-08T01:28:06.758427Z","iopub.status.idle":"2023-01-08T01:28:07.795224Z","shell.execute_reply.started":"2023-01-08T01:28:06.758384Z","shell.execute_reply":"2023-01-08T01:28:07.793944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_test['cancer'] = models_pred","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:28:07.797373Z","iopub.execute_input":"2023-01-08T01:28:07.79803Z","iopub.status.idle":"2023-01-08T01:28:07.806862Z","shell.execute_reply.started":"2023-01-08T01:28:07.797987Z","shell.execute_reply":"2023-01-08T01:28:07.805846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub = df_test.groupby('prediction_id')[['cancer']].mean()\ndf_sub","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:28:10.299032Z","iopub.execute_input":"2023-01-08T01:28:10.299404Z","iopub.status.idle":"2023-01-08T01:28:10.312694Z","shell.execute_reply.started":"2023-01-08T01:28:10.299373Z","shell.execute_reply":"2023-01-08T01:28:10.311597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_sub.to_csv('submission.csv', index=True)\n!head submission.csv","metadata":{"execution":{"iopub.status.busy":"2023-01-08T01:28:13.434144Z","iopub.execute_input":"2023-01-08T01:28:13.434522Z","iopub.status.idle":"2023-01-08T01:28:14.419758Z","shell.execute_reply.started":"2023-01-08T01:28:13.434489Z","shell.execute_reply":"2023-01-08T01:28:14.418224Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}