{"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"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":29653,"databundleVersionId":2420395,"sourceType":"competition"},{"sourceId":848739,"sourceType":"datasetVersion","datasetId":251095},{"sourceId":2425289,"sourceType":"datasetVersion","datasetId":1467572},{"sourceId":69306964,"sourceType":"kernelVersion"}],"dockerImageVersionId":30121,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"markdown","source":"# Import things","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-07-18T04:22:55.955919Z","iopub.execute_input":"2021-07-18T04:22:55.956524Z","iopub.status.idle":"2021-07-18T04:22:56.527271Z","shell.execute_reply.started":"2021-07-18T04:22:55.956406Z","shell.execute_reply":"2021-07-18T04:22:56.526277Z"}}},{"cell_type":"code","source":"package_path = \"../input/efficientnet-pytorch/EfficientNet-PyTorch/EfficientNet-PyTorch-master/\"\nimport sys \nsys.path.append(package_path)\n\nimport os\nimport glob\nimport time\nimport random\n\nimport numpy as np\nimport pandas as pd\n\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport cv2\n\nimport torch\nfrom torch import nn\nfrom torch.utils import data as torch_data\nfrom torch.nn import functional as F\n\nimport efficientnet_pytorch\n\nfrom torch.utils.data import Dataset, DataLoader\n","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.033413Z","iopub.execute_input":"2021-07-25T04:06:57.033766Z","iopub.status.idle":"2021-07-25T04:06:57.040276Z","shell.execute_reply.started":"2021-07-25T04:06:57.033732Z","shell.execute_reply":"2021-07-25T04:06:57.039256Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nseed = 123\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)\n\nclass X3D:\n    XS=0\n    S=1\n    M=2\n    L=3\n    \nx3d_config = {\n    'input_clip_length': [4, 13, 16, 16],\n    'depth_factor': [2.2, 2.2, 2.2, 5.0],\n    'width_factor': [1, 1, 1, 2.9]\n}\n\nclass CFG:\n    img_size = 256\n    n_frames = 10\n    \n    cnn_features = 256\n    lstm_hidden = 32\n    \n    n_fold = 5\n    n_epochs = 10","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.042079Z","iopub.execute_input":"2021-07-25T04:06:57.042522Z","iopub.status.idle":"2021-07-25T04:06:57.055952Z","shell.execute_reply.started":"2021-07-25T04:06:57.042466Z","shell.execute_reply":"2021-07-25T04:06:57.054697Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Model","metadata":{}},{"cell_type":"code","source":"class CNN(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.map = nn.Conv2d(in_channels=4, out_channels=3, kernel_size=1)\n        self.net = efficientnet_pytorch.EfficientNet.from_name(\"efficientnet-b0\")\n#         checkpoint = torch.load(\"../input/efficientnet-pytorch/efficientnet-b0-08094119.pth\")\n#         self.net.load_state_dict(checkpoint)\n        \n        n_features = self.net._fc.in_features\n        self.net._fc = nn.Linear(in_features=n_features, out_features=CFG.cnn_features, bias=True)\n    \n    def forward(self, x):\n        x = F.relu(self.map(x))\n        out = self.net(x)\n        return out\n\nclass Model(nn.Module):\n    def __init__(self):\n        super(Model, self).__init__()\n        self.cnn = CNN()\n        self.rnn = nn.LSTM(CFG.cnn_features, CFG.lstm_hidden, 2, batch_first=True)\n        self.fc = nn.Linear(CFG.lstm_hidden, 1, bias=True)\n\n    def forward(self, x):\n        # x shape: BxTxCxHxW\n        batch_size, timesteps, C, H, W = x.size()\n        c_in = x.view(batch_size * timesteps, C, H, W)\n        c_out = self.cnn(c_in)\n        r_in = c_out.view(batch_size, timesteps, -1)\n        output, (hn, cn) = self.rnn(r_in)\n        \n        out = self.fc(hn[-1])\n        return out","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.058368Z","iopub.execute_input":"2021-07-25T04:06:57.05887Z","iopub.status.idle":"2021-07-25T04:06:57.073319Z","shell.execute_reply.started":"2021-07-25T04:06:57.058832Z","shell.execute_reply":"2021-07-25T04:06:57.072377Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data Processing","metadata":{}},{"cell_type":"code","source":"def load_dicom(path):\n    dicom = pydicom.read_file(path)\n    data = dicom.pixel_array\n    data = data - np.min(data)\n    if np.max(data) != 0:\n        data = data / np.max(data)\n        \n    data = np.float32(cv2.resize(data, (CFG.img_size, CFG.img_size)))\n    return torch.tensor(data)\n\ndef load_dicom_line(path):\n    t_paths = sorted(\n        glob.glob(os.path.join(path, \"*\")), \n        key=lambda x: int(x[:-4].split(\"-\")[-1]),\n    )\n    images = []\n    for filename in t_paths:\n        data = load_dicom(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n        \n    return images\n\ndef load_image(path):\n    image = cv2.imread(path, 0)\n    if image is None:\n        return np.zeros((CFG.img_size, CFG.img_size))\n    \n    image = cv2.resize(image, (CFG.img_size, CFG.img_size)) / 255\n    return torch.tensor(image)\n\ndef get_valid_frames(t_paths):\n    res = []\n    for path in t_paths:\n        img = load_dicom(path)\n        if img.view(-1).mean(0) != 0:\n            res.append(path)\n    return res\n    \n\ndef uniform_temporal_subsample(x, num_samples):\n    '''\n        Moddified from https://github.com/facebookresearch/pytorchvideo/blob/d7874f788bc00a7badfb4310a912f6e531ffd6d3/pytorchvideo/transforms/functional.py#L19\n        Args:\n            x: input list\n            num_samples: The number of equispaced samples to be selected\n        Returns:\n            Output list     \n    '''\n    t = len(x)\n    indices = torch.linspace(0, t - 1, num_samples)\n    indices = torch.clamp(indices, 0, t - 1).long()\n    return [x[i] for i in indices]","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.075266Z","iopub.execute_input":"2021-07-25T04:06:57.075908Z","iopub.status.idle":"2021-07-25T04:06:57.090346Z","shell.execute_reply.started":"2021-07-25T04:06:57.075865Z","shell.execute_reply":"2021-07-25T04:06:57.089375Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class TestDataRetriever(Dataset):\n    def __init__(self, paths, transform=None):\n        self.paths = paths\n        self.transform = transform\n          \n    def __len__(self):\n        return len(self.paths)\n    \n    def read_video(self, vid_paths):\n        video = [load_dicom(path) for path in vid_paths]\n        if len(video)==0:\n            video = torch.zeros(CFG.n_frames, CFG.img_size, CFG.img_size)\n        else:\n            video = torch.stack(video) # T * C * H * W\n#         video = torch.transpose(video, 0, 1) # C * T * H * W\n        return video\n    \n    def __getitem__(self, index):\n        _id = self.paths[index]\n        patient_path = f\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/test/{str(_id).zfill(5)}/\"\n        channels = []\n        for t in [\"FLAIR\",\"T1w\", \"T1wCE\", \"T2w\"]:\n            t_paths = sorted(\n                glob.glob(os.path.join(patient_path, t, \"*\")), \n                key=lambda x: int(x[:-4].split(\"-\")[-1]),\n            )\n            num_samples = CFG.n_frames\n#             t_paths = get_valid_frames(t_paths)\n            if len(t_paths) < num_samples:\n                in_frames_path = t_paths\n            else:\n                in_frames_path = uniform_temporal_subsample(t_paths, num_samples)\n            \n            channel = self.read_video(in_frames_path)\n            if channel.shape[0] == 0:\n                print(\"1 channel empty\")\n                channel = torch.zeros(num_samples, CFG.img_size, CFG.img_size)\n            channels.append(channel)\n        \n        channels = torch.stack(channels).transpose(0,1)\n        return {\"X\": channels.float(), \"id\": _id}","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.091999Z","iopub.execute_input":"2021-07-25T04:06:57.092453Z","iopub.status.idle":"2021-07-25T04:06:57.106058Z","shell.execute_reply.started":"2021-07-25T04:06:57.09241Z","shell.execute_reply":"2021-07-25T04:06:57.104867Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/train_labels.csv\")\ndf.head(10)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.107443Z","iopub.execute_input":"2021-07-25T04:06:57.107988Z","iopub.status.idle":"2021-07-25T04:06:57.128967Z","shell.execute_reply.started":"2021-07-25T04:06:57.107945Z","shell.execute_reply":"2021-07-25T04:06:57.128183Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference","metadata":{}},{"cell_type":"code","source":"models = []\nfor i in range(1, CFG.n_fold+1):\n    model = Model()\n    model.to(device)\n    checkpoint = torch.load(f\"../input/rnsa-21-cnn-lstm-train/best-model-{i}.pth\")\n    model.load_state_dict(checkpoint[\"model_state_dict\"])\n    model.eval()\n    \n    models.append(model)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:57.151892Z","iopub.execute_input":"2021-07-25T04:06:57.152161Z","iopub.status.idle":"2021-07-25T04:06:58.127663Z","shell.execute_reply.started":"2021-07-25T04:06:57.152136Z","shell.execute_reply":"2021-07-25T04:06:58.126521Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.read_csv(\"../input/rsna-miccai-brain-tumor-radiogenomic-classification/sample_submission.csv\")\n\ntest_data_retriever = TestDataRetriever(\n    submission[\"BraTS21ID\"].values\n)\n\ntest_loader = torch_data.DataLoader(\n    test_data_retriever,\n    batch_size=4,\n    shuffle=False,\n    num_workers=8,\n)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:58.12936Z","iopub.execute_input":"2021-07-25T04:06:58.129915Z","iopub.status.idle":"2021-07-25T04:06:58.140009Z","shell.execute_reply.started":"2021-07-25T04:06:58.129871Z","shell.execute_reply":"2021-07-25T04:06:58.138913Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"y_pred = []\nids = []\n\nfor e, batch in enumerate(test_loader):\n    print(f\"{e}/{len(test_loader)}\", end=\"\\r\")\n    with torch.no_grad():\n        tmp_pred = np.zeros((batch[\"X\"].shape[0], ))\n        for model in models:\n            tmp_res = torch.sigmoid(model(batch[\"X\"].to(device))).cpu().numpy().squeeze()\n            tmp_pred += tmp_res\n            \n        tmp_pred = tmp_pred/len(models)\n        y_pred.extend(tmp_pred)\n        ids.extend(batch[\"id\"].numpy().tolist())","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:06:58.142364Z","iopub.execute_input":"2021-07-25T04:06:58.142852Z","iopub.status.idle":"2021-07-25T04:07:12.28528Z","shell.execute_reply.started":"2021-07-25T04:06:58.142809Z","shell.execute_reply":"2021-07-25T04:07:12.284337Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission = pd.DataFrame({\"BraTS21ID\": ids, \"MGMT_value\": y_pred})\nsubmission.to_csv(\"submission.csv\", index=False)","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:07:12.287191Z","iopub.execute_input":"2021-07-25T04:07:12.287553Z","iopub.status.idle":"2021-07-25T04:07:12.300256Z","shell.execute_reply.started":"2021-07-25T04:07:12.287508Z","shell.execute_reply":"2021-07-25T04:07:12.299322Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"execution":{"iopub.status.busy":"2021-07-25T04:07:12.30323Z","iopub.execute_input":"2021-07-25T04:07:12.303515Z","iopub.status.idle":"2021-07-25T04:07:12.323045Z","shell.execute_reply.started":"2021-07-25T04:07:12.303483Z","shell.execute_reply":"2021-07-25T04:07:12.321773Z"},"trusted":true},"execution_count":null,"outputs":[]}]}