{"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":"code","source":"!pip install --no-deps -qq /kaggle/input/dicomsdl--0-109-2/dicomsdl-0.109.2-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl\n!pip install --no-deps -qq /kaggle/input/segmentation-models-pytorch-021/wheels/munch-2.5.0-py2.py3-none-any.whl\n!pip install --no-deps -qq /kaggle/input/segmentation-models-pytorch-021/wheels/pretrainedmodels-0.7.4-py3-none-any.whl\n!pip install --no-deps -qq /kaggle/input/segmentation-models-pytorch-021/wheels/timm-0.4.12-py3-none-any.whl\n!pip install --no-deps -qq /kaggle/input/segmentation-models-pytorch-021/wheels/efficientnet_pytorch-0.6.3-py3-none-any.whl\n!pip install --no-deps -qq /kaggle/input/segmentation-models-pytorch-021/wheels/segmentation_models_pytorch-0.2.1-py3-none-any.whl","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:22:06.322796Z","iopub.execute_input":"2023-10-14T13:22:06.323115Z","iopub.status.idle":"2023-10-14T13:24:44.064816Z","shell.execute_reply.started":"2023-10-14T13:22:06.323088Z","shell.execute_reply":"2023-10-14T13:24:44.063558Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import os\nimport cv2\nimport glob\nimport gc\nimport sys\nimport pydicom\nimport dicomsdl\nimport zipfile\nimport numpy as np\nimport pandas as pd\nimport seaborn as sns\nimport matplotlib.pyplot as plt\nimport pickle\nimport gzip\n\nfrom tqdm import tqdm\nfrom joblib import Parallel, delayed\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nfrom multiprocessing import Pool\n\nimport torch\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch import nn\nimport torch.cuda.amp as amp\nimport segmentation_models_pytorch as smp\n\nsys.path.append('/kaggle/input/resnet-3d-rsna-atd')\nsys.path.append('/kaggle/input/covn3d-same')\nsys.path.append('/kaggle/input/rsna-atd-lib')\nfrom resnet3d import generate_model\nimport timm\nimport timm_new\n\n#For dataloader using cuda\ntorch.multiprocessing.set_start_method('spawn')","metadata":{"_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","papermill":{"duration":37.821192,"end_time":"2023-08-28T10:32:54.924905","exception":false,"start_time":"2023-08-28T10:32:17.103713","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:44.067478Z","iopub.execute_input":"2023-10-14T13:24:44.067847Z","iopub.status.idle":"2023-10-14T13:24:50.347886Z","shell.execute_reply.started":"2023-10-14T13:24:44.06781Z","shell.execute_reply":"2023-10-14T13:24:50.346636Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Parameters","metadata":{"papermill":{"duration":0.006136,"end_time":"2023-08-28T10:32:54.938683","exception":false,"start_time":"2023-08-28T10:32:54.932547","status":"completed"},"tags":[]}},{"cell_type":"code","source":"RESOL = 160\nBATCH_SIZE = 4\nDEVICE = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nDEBUG = False\nN_DEBUG_SAMPLES = 20\n\nUP_RESOL = 128\nN_CHANNELS = 6\nPREPROC_NORM_OR_STD = False # True: normalization, False: standardization\n\nBASE_PATH = '/kaggle/input/rsna-2023-abdominal-trauma-detection'\nSAVE_PATH = '/tmp'\nMASK_SAVE_PATH = f'{SAVE_PATH}/mask_preprocessed'\nMASK_VALID_PATH = f'{SAVE_PATH}/mask_validation'\n\nDATA_PATH = f'{BASE_PATH}/test_images'\nif DEBUG:\n    DATA_PATH = f'{BASE_PATH}/train_images'\nN_PREPROCESS_CHUNKS = 4\nN_PROCESS_CROP = 4\n\n#kernel_type = 'timm3d_res50d_unet4b_128_128_128_dsv2_flip12_shift333p7_gd1p5_bs4_lr3e4_20x50ep'\n#kernel_type = 'timm3d_res50d_unet4b_128_128_128_dsv2_flip12_shift333p7_gd1p5_bs4_lr3e4_20x50ep_fold0_best_0.9.pth'\nseg_model_path = '/kaggle/input/rsna-atd-weights/231001_timm3d_res10tc_CV0.938.pt'\nload_kernel = None\nload_last = True\nn_blocks = 4\nbackbone = 'timm/resnet10t.c3_in1k'\n\nbackbone_classifier = 'timm/resnetrs50.tf_in1k'\n# weights_classifier = '/kaggle/input/1007-resnetrs50-cv0460/timm_resnetrs50.tf_in1k_lr0.0002_epochs_500_resol128_batch12-cv0460.pt'\nweights_classifier = '/kaggle/input/1007-resnetrs50-cv0460/timm_resnetrs50.tf_in1k_lr0.0002_epochs_500_resol128_batch12-cv0454.pt'\nweights_classifier1_2 = '/kaggle/input/1010-resnet50-cv04827/timm_resnetrs50.tf_in1k_lr0.0002_epochs_500_resol128_batch12_fold1-cv04827.pt'\n\nbackbone_classifier2 = 'timm/resnet10t.c3_in1k'\nweights_classifier2 = '/kaggle/input/rsna-atd-weights/231002_timm_resnet10t.c3_in1k_lr0.005_epochs_200_resol128_batch24.pt2'\n\nbackbone_classifiers3 = 'timm/resnet10t.c3_in1k'\nweights_classifiers3 = '/kaggle/input/rsna-atd-weights/timm_resnet10t_LSTM_CV0.44.pt'\n\n\ndata_dir = '../input/rsna-2022-cervical-spine-fracture-detection'\nuse_amp = True\nnum_workers = 0\nout_dim = 5\nn_blocks = 4\ndrop_rate = 0.2\ndrop_path_rate = 0.2\np_mixup = 0.0\n\nchan_keys = ['bowel', 'left_kidney', 'right_kidney', 'liver', 'spleen', 'total']\nchan_dict = {}\nfor i in range(0, 6):\n    chan_dict[i] = chan_keys[i]\n\nlog_dir = f'{SAVE_PATH}/seg_models_backup'\nmodel_dir = f'{SAVE_PATH}/seg_models_backup'\nseg_inference_dir = f'{SAVE_PATH}/seg_infer_results'\norigin_img_dir = f'{SAVE_PATH}/3d_preprocessed'\ncropped_img_dir   = f'{SAVE_PATH}/3d_preprocessed_crop'\nos.makedirs(log_dir, exist_ok=True)\nos.makedirs(model_dir, exist_ok=True)\nos.makedirs(MASK_VALID_PATH, exist_ok=True)\nos.makedirs(seg_inference_dir, exist_ok = True)\nos.makedirs(cropped_img_dir, exist_ok = True)\nos.makedirs(origin_img_dir, exist_ok = True)\nDEVICE","metadata":{"papermill":{"duration":0.076614,"end_time":"2023-08-28T10:32:55.02093","exception":false,"start_time":"2023-08-28T10:32:54.944316","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:50.649298Z","iopub.execute_input":"2023-10-14T13:24:50.650025Z","iopub.status.idle":"2023-10-14T13:24:50.920202Z","shell.execute_reply.started":"2023-10-14T13:24:50.649972Z","shell.execute_reply":"2023-10-14T13:24:50.919317Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transforms_valid = transforms.Compose([\n])","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:50.923226Z","iopub.execute_input":"2023-10-14T13:24:50.923483Z","iopub.status.idle":"2023-10-14T13:24:50.927441Z","shell.execute_reply.started":"2023-10-14T13:24:50.923462Z","shell.execute_reply":"2023-10-14T13:24:50.926452Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(f'{BASE_PATH}/train.csv')\ntrain_meta = pd.read_csv(f'{BASE_PATH}/train_series_meta.csv')\ntrain_df = train_df.sort_values(by=['patient_id'])\n\nn_chunk = 8\npatients = os.listdir(DATA_PATH)\nn_patients = len(patients)\nrng_patients = np.linspace(0, n_patients+1, n_chunk+1, dtype = int)\npatients_cts = glob.glob(f'{DATA_PATH}/*/*')\nn_cts = len(patients_cts)\npatients_cts_arr = np.zeros((n_cts, 2), int)\ndata_paths=[]\nfor i in range(0, n_cts):\n    patient, ct = patients_cts[i].split('/')[-2:]\n    patients_cts_arr[i] = patient, ct\n    data_paths.append(f'{SAVE_PATH}/3d_preprocessed/{patients_cts_arr[i,0]}_{patients_cts_arr[i,1]}.pkl')\nTRAIN_IMG_PATH = BASE_PATH + '/processed' \n\n#Generate tables for training\ndf_data = pd.DataFrame(patients_cts_arr, columns = ['patient_id', 'series'])\n\n#5-fold splitting\ntrain_df['fold'] = 0\nlabels = train_df[['bowel_healthy','bowel_injury',\n                    'extravasation_healthy','extravasation_injury',\n                    'kidney_healthy','kidney_low','kidney_high',\n                    'liver_healthy','liver_low','liver_high',\n                    'spleen_healthy','spleen_low','spleen_high',\n                    'any_injury']].to_numpy()\n\n\n#df_data = df_data.join(train_df.set_index('patient_id'), on='patient_id')\ndf_data['path']=data_paths\n\n#For mask paths\nmask_paths = []\ncropped_paths = []\nfor i in range(0, len(df_data)):\n    row = df_data.iloc[i]\n    file_name = row['path'].split('/')[-1]\n    mask_paths.append(f'{seg_inference_dir}/{file_name}')\n    cropped_paths.append(f'{cropped_img_dir}/{file_name}')\ndf_data['mask_path'] = mask_paths\ndf_data['cropped_path'] = cropped_paths\n\ndf_data.to_csv(f'{SAVE_PATH}/data_meta.csv', index = False)\n","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:50.928609Z","iopub.execute_input":"2023-10-14T13:24:50.929663Z","iopub.status.idle":"2023-10-14T13:24:50.985975Z","shell.execute_reply.started":"2023-10-14T13:24:50.929633Z","shell.execute_reply":"2023-10-14T13:24:50.985066Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_data","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:50.987258Z","iopub.execute_input":"2023-10-14T13:24:50.987608Z","iopub.status.idle":"2023-10-14T13:24:51.002247Z","shell.execute_reply.started":"2023-10-14T13:24:50.987577Z","shell.execute_reply":"2023-10-14T13:24:51.000992Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Preprocess images to 3D data","metadata":{"papermill":{"duration":0.00547,"end_time":"2023-08-28T10:32:55.032132","exception":false,"start_time":"2023-08-28T10:32:55.026662","status":"completed"},"tags":[]}},{"cell_type":"markdown","source":"## Parameters\nReference: https://www.kaggle.com/code/theoviel/get-started-quicker-dicom-png-conversion","metadata":{"papermill":{"duration":0.005361,"end_time":"2023-08-28T10:32:55.043343","exception":false,"start_time":"2023-08-28T10:32:55.037982","status":"completed"},"tags":[]}},{"cell_type":"code","source":"BASE_PATH = '/kaggle/input/rsna-2023-abdominal-trauma-detection'\nTEST_PATH = f'{BASE_PATH}/train_images/'\n\nprint('Number of test patients :', len(os.listdir(TEST_PATH)))","metadata":{"papermill":{"duration":0.017412,"end_time":"2023-08-28T10:32:55.066252","exception":false,"start_time":"2023-08-28T10:32:55.04884","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:51.003435Z","iopub.execute_input":"2023-10-14T13:24:51.004199Z","iopub.status.idle":"2023-10-14T13:24:51.166319Z","shell.execute_reply.started":"2023-10-14T13:24:51.004166Z","shell.execute_reply":"2023-10-14T13:24:51.16526Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"n_chunk = 4\npatients = os.listdir(TEST_PATH)\n#patients = patients[:8]\nn_patients = len(patients)\n\n#if(n_patients==3):\n#    n_chunk = 3\n#    rng_patients = np.linspace(0, n_patients, n_chunk+1, dtype = int)\n#else:\nrng_patients = np.linspace(0, n_patients, n_chunk+1, dtype = int)\n\n#rng_patients\n#patients\n#if DEBUG:\n#    rng_patients = [0, n_patients]","metadata":{"papermill":{"duration":0.013634,"end_time":"2023-08-28T10:32:55.085505","exception":false,"start_time":"2023-08-28T10:32:55.071871","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:51.167785Z","iopub.execute_input":"2023-10-14T13:24:51.168443Z","iopub.status.idle":"2023-10-14T13:24:51.175528Z","shell.execute_reply.started":"2023-10-14T13:24:51.168408Z","shell.execute_reply":"2023-10-14T13:24:51.174641Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def compress(name, data):\n    with gzip.open(name, 'wb') as f:\n        pickle.dump(data, f)\n\ndef decompress(name):\n    with gzip.open(name, 'rb') as f:\n        data = pickle.load(f)\n    return data\n\ndef compress_fast(name, data):\n    with open(name, 'wb') as f:\n        pickle.dump(data, f)\n\ndef decompress_fast(name):\n    with open(name, 'rb') as f:\n        data = pickle.load(f)\n    return data","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.176933Z","iopub.execute_input":"2023-10-14T13:24:51.17784Z","iopub.status.idle":"2023-10-14T13:24:51.189782Z","shell.execute_reply.started":"2023-10-14T13:24:51.177809Z","shell.execute_reply":"2023-10-14T13:24:51.188961Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_path = TEST_PATH\nsave_folder = '/tmp/3d_processed'\n\ntry:\n    os.makedirs(save_folder)\nexcept:\n    print('save folder already exists!')","metadata":{"papermill":{"duration":0.014139,"end_time":"2023-08-28T10:32:55.105473","exception":false,"start_time":"2023-08-28T10:32:55.091334","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:51.190931Z","iopub.execute_input":"2023-10-14T13:24:51.191816Z","iopub.status.idle":"2023-10-14T13:24:51.201569Z","shell.execute_reply.started":"2023-10-14T13:24:51.191786Z","shell.execute_reply":"2023-10-14T13:24:51.200501Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data & Model","metadata":{"papermill":{"duration":0.005554,"end_time":"2023-08-28T10:32:55.116684","exception":false,"start_time":"2023-08-28T10:32:55.11113","status":"completed"},"tags":[]}},{"cell_type":"code","source":"#Returns GPU array\ndef standardize_pixel_array(pixel_array, dcm_rows):\n    \"\"\"\n    Source : https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection/discussion/427217\n    \"\"\"\n    # Correct DICOM pixel_array if PixelRepresentation == 1.\n    for z in range(0, len(pixel_array)):\n        if int(dcm_rows[z]['PixelRepresentation']) == 1:\n            bit_shift = dcm_rows[z]['BitsAllocated'] - dcm_rows[z]['BitsStored']\n            dtype = pixel_array[z].dtype \n            pixel_array[z] = (pixel_array[z] << bit_shift).astype(dtype) >>  bit_shift\n\n    pixel_array = torch.from_numpy(pixel_array.astype(np.float16)).to(DEVICE).to(torch.float16)    \n\n    for z in range(0, len(pixel_array)):\n        intercept = float(dcm_rows[z]['RescaleIntercept'])\n        slope = float(dcm_rows[z]['RescaleSlope'])\n        center = int(dcm_rows[z]['WindowCenter'])\n        width = int(dcm_rows[z]['WindowWidth'])\n        low = center - width / 2\n        high = center + width / 2    \n        \n        pixel_array[z] = (pixel_array[z] * slope) + intercept\n        pixel_array[z] = torch.clip(pixel_array[z], low, high)\n        \n    gc.collect()    \n    return pixel_array","metadata":{"papermill":{"duration":0.015737,"end_time":"2023-08-28T10:32:55.361199","exception":false,"start_time":"2023-08-28T10:32:55.345462","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:51.202761Z","iopub.execute_input":"2023-10-14T13:24:51.2038Z","iopub.status.idle":"2023-10-14T13:24:51.214864Z","shell.execute_reply.started":"2023-10-14T13:24:51.203769Z","shell.execute_reply":"2023-10-14T13:24:51.213982Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def resize_norm_or_std(data, resize_shape, is_norm = PREPROC_NORM_OR_STD):  \n    #resize xy\n    data = transforms.Resize((int(resize_shape[1]), int(resize_shape[2])), antialias = True)(data)\n    \n    #zyx to xzy\n    data = torch.permute(data, (2, 0, 1))\n    #Resize yz\n    data = transforms.Resize((int(resize_shape[0]), int(resize_shape[1])), antialias = True)(data)\n    #xzy to zyx\n    data = torch.permute(data, (1, 2, 0))\n\n    if is_norm:\n        bottom = torch.min(data)\n        data -= bottom\n        top    = torch.max(data)\n        data/=top\n        del top, bottom\n    else:\n        avg = torch.mean(data, (0, 1, 2))\n        std = torch.std(data, (0, 1, 2))\n        data = (data-avg)/std\n        del avg, std\n\n    gc.collect()\n    #torch.cuda.empty_cache()\n    return data\n\n# Read each slice and stack them to make 3d data\ndef process_3d(save_path, data_path = DATA_PATH):\n    tmp = save_path.split('/')[-1][:-4]\n    tmp = tmp.split('_')\n    patient, study = int(tmp[0]), int(tmp[1])\n    imgs = {}    \n    \n    # To load only needed slices\n    imgs = {}    \n    for f in sorted(glob.glob(data_path + f'/{patient}/{study}/*.dcm')):  \n        pos_z = -int((f.split('/')[-1])[:-4])\n        imgs[pos_z] = f\n        \n    sample_z = np.linspace(0, len(imgs)-1, RESOL, dtype=int)\n    dcm_rows = []\n    imgs_3d  = []\n    for i, k in enumerate(sorted(imgs.keys())):\n        if not np.isin([i], sample_z)[0]:\n            continue        \n        f= imgs[k]\n        opened_dicom = dicomsdl.open(f)\n        img = opened_dicom.pixelData(storedvalue=True)\n        params = opened_dicom.getPixelDataInfo()\n        \n        imgs_3d.append(img[None])\n        dcm_rows.append(params)\n\n    imgs_3d = np.vstack(imgs_3d)\n    imgs_3d = standardize_pixel_array(imgs_3d, dcm_rows)\n    \n    min_imgs = torch.min(imgs_3d)\n    max_imgs = torch.max(imgs_3d)\n        \n    imgs_3d = ((imgs_3d - min_imgs) / (max_imgs - min_imgs + 1e-6))\n\n    if str(dcm_rows[0]['PhotometricInterpretation']) == \"MONOCHROME1\":\n        imgs_3d = 1.0 - imgs_3d\n\n    imgs_3d = resize_norm_or_std(imgs_3d, [RESOL, RESOL, RESOL])\n\n    #Save the image\n    #compress(save_path, imgs_3d)         4             \n\n    del imgs, img\n    gc.collect()\n    return imgs_3d","metadata":{"papermill":{"duration":0.022683,"end_time":"2023-08-28T10:32:55.389838","exception":false,"start_time":"2023-08-28T10:32:55.367155","status":"completed"},"tags":[],"execution":{"iopub.status.busy":"2023-10-14T13:24:51.216408Z","iopub.execute_input":"2023-10-14T13:24:51.216823Z","iopub.status.idle":"2023-10-14T13:24:51.232798Z","shell.execute_reply.started":"2023-10-14T13:24:51.216793Z","shell.execute_reply":"2023-10-14T13:24:51.231871Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SEGDataset(Dataset):\n    def __init__(self, df, mode, transform):\n\n        self.df = df.reset_index()\n        self.mode = mode\n        self.transform = transform\n\n    def __len__(self):\n        return self.df.shape[0]\n\n    def __getitem__(self, index):\n        row = self.df.iloc[index]\n        \n        #try:\n        #    data_3d = decompress(row['path'])\n        #except:\n        data_3d = process_3d(row['path']).unsqueeze(0).to(torch.float16)\n            \n        #data_3d = torch.from_numpy(data_3d).to(torch.float32)\n        #file_name = row['path'].split('/')[-1]\n        #save_path = f'{seg_inference_dir}/{file_name}'\n        save_path = row['mask_path']\n\n        return data_3d, save_path","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.237528Z","iopub.execute_input":"2023-10-14T13:24:51.238404Z","iopub.status.idle":"2023-10-14T13:24:51.247829Z","shell.execute_reply.started":"2023-10-14T13:24:51.238374Z","shell.execute_reply":"2023-10-14T13:24:51.246853Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Segmentation models","metadata":{}},{"cell_type":"code","source":"class TimmSegModel(nn.Module):\n    def __init__(self, backbone, segtype='unet', pretrained=False):\n        super(TimmSegModel, self).__init__()\n\n        self.encoder = timm_new.create_model(\n            backbone,\n            in_chans=1,\n            features_only=True,\n            drop_rate=drop_rate,\n            drop_path_rate=drop_path_rate,\n            pretrained=False\n        )\n        g = self.encoder(torch.rand(1, 1, 64, 64))\n        encoder_channels = [1] + [_.shape[1] for _ in g]\n        decoder_channels = [256, 128, 64, 32, 16]\n        if segtype == 'unet':\n            self.decoder = smp.unet.decoder.UnetDecoder(\n                encoder_channels=encoder_channels[:n_blocks+1],\n                decoder_channels=decoder_channels[:n_blocks],\n                n_blocks=n_blocks,\n            )\n\n        self.segmentation_head = nn.Conv2d(decoder_channels[n_blocks-1], out_dim, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))\n\n    def forward(self,x):\n        global_features = [0] + self.encoder(x)[:n_blocks]\n        seg_features = self.decoder(*global_features)\n        seg_features = self.segmentation_head(seg_features)\n        return seg_features","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.249269Z","iopub.execute_input":"2023-10-14T13:24:51.250129Z","iopub.status.idle":"2023-10-14T13:24:51.263256Z","shell.execute_reply.started":"2023-10-14T13:24:51.250097Z","shell.execute_reply":"2023-10-14T13:24:51.262318Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from timm.models.layers.conv2d_same import Conv2dSame\nfrom conv3d_same import Conv3dSame\n\n\ndef convert_3d(module):\n\n    module_output = module\n    if isinstance(module, torch.nn.BatchNorm2d):\n        module_output = torch.nn.BatchNorm3d(\n            module.num_features,\n            module.eps,\n            module.momentum,\n            module.affine,\n            module.track_running_stats,\n        )\n        if module.affine:\n            with torch.no_grad():\n                module_output.weight = module.weight\n                module_output.bias = module.bias\n        module_output.running_mean = module.running_mean\n        module_output.running_var = module.running_var\n        module_output.num_batches_tracked = module.num_batches_tracked\n        if hasattr(module, \"qconfig\"):\n            module_output.qconfig = module.qconfig\n            \n    elif isinstance(module, Conv2dSame):\n        module_output = Conv3dSame(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.Conv2d):\n        module_output = torch.nn.Conv3d(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n            padding_mode=module.padding_mode\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.MaxPool2d):\n        module_output = torch.nn.MaxPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            dilation=module.dilation,\n            ceil_mode=module.ceil_mode,\n        )\n    elif isinstance(module, torch.nn.AvgPool2d):\n        module_output = torch.nn.AvgPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            ceil_mode=module.ceil_mode,\n        )\n\n    for name, child in module.named_children():\n        module_output.add_module(\n            name, convert_3d(child)\n        )\n    del module\n\n    return module_output","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.264755Z","iopub.execute_input":"2023-10-14T13:24:51.26539Z","iopub.status.idle":"2023-10-14T13:24:51.283156Z","shell.execute_reply.started":"2023-10-14T13:24:51.26536Z","shell.execute_reply":"2023-10-14T13:24:51.282206Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Semgmentation inference","metadata":{}},{"cell_type":"code","source":"def infer_func(model, loader_valid):\n    model.eval()\n    ths = [0.1]\n    bar = tqdm(loader_valid)\n    counter = 0\n    \n    with torch.no_grad():\n        with amp.autocast():\n            for images, save_paths in bar:\n                images = images.cuda()\n                logits = model(images)\n                for thi, th in enumerate(ths):\n                    for i in range(logits.shape[0]):                    \n                        y_pred = ((logits[i].sigmoid()> th).float().detach().cpu().numpy()+0.1).astype(np.uint8)\n                        compress(save_paths[i], y_pred)\n    del images, logits, y_pred\n    gc.collect()\n    torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.284805Z","iopub.execute_input":"2023-10-14T13:24:51.285142Z","iopub.status.idle":"2023-10-14T13:24:51.293382Z","shell.execute_reply.started":"2023-10-14T13:24:51.285113Z","shell.execute_reply":"2023-10-14T13:24:51.292153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_data = pd.read_csv(f'{SAVE_PATH}/data_meta.csv')\nif DEBUG:\n    df_data = df_data.iloc[:N_DEBUG_SAMPLES]\n\nmask_paths = []\ncropped_paths = []\nfor i in range(0, len(df_data)):\n    row = df_data.iloc[i]\n    file_name = row['path'].split('/')[-1]\n    mask_paths.append(f'{seg_inference_dir}/{file_name}')\n    cropped_paths.append(f'{cropped_img_dir}/{file_name}')\ndf_data['mask_path'] = mask_paths\ndf_data['cropped_path'] = cropped_paths\ndf_data.tail()\n\ndf_data.to_csv(f'{SAVE_PATH}/data_meta.csv', index = False)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.294724Z","iopub.execute_input":"2023-10-14T13:24:51.295334Z","iopub.status.idle":"2023-10-14T13:24:51.310481Z","shell.execute_reply.started":"2023-10-14T13:24:51.295305Z","shell.execute_reply":"2023-10-14T13:24:51.309663Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def run(fold):\n    model_file = seg_model_path\n\n    dataset_train = SEGDataset(df_data, 'valid', transform=transforms_valid)\n    loader_train = torch.utils.data.DataLoader(dataset_train, batch_size=BATCH_SIZE, shuffle=False, num_workers=num_workers)\n\n    model = TimmSegModel(backbone, pretrained=True)\n    model = convert_3d(model)\n\n    model.load_state_dict(torch.load(model_file))\n    model = model.to(DEVICE)\n\n    print(len(dataset_train))\n\n    infer_func(model, loader_train)\n\n    del model, dataset_train, loader_train\n    gc.collect()\n    torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.311824Z","iopub.execute_input":"2023-10-14T13:24:51.312434Z","iopub.status.idle":"2023-10-14T13:24:51.326257Z","shell.execute_reply.started":"2023-10-14T13:24:51.312405Z","shell.execute_reply":"2023-10-14T13:24:51.325278Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"run(0)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:24:51.327588Z","iopub.execute_input":"2023-10-14T13:24:51.328181Z","iopub.status.idle":"2023-10-14T13:25:05.42235Z","shell.execute_reply.started":"2023-10-14T13:24:51.32815Z","shell.execute_reply":"2023-10-14T13:25:05.421402Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#!cp /tmp/seg_infer_results/26883_57967* /kaggle/working","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:05.42406Z","iopub.execute_input":"2023-10-14T13:25:05.424401Z","iopub.status.idle":"2023-10-14T13:25:05.428444Z","shell.execute_reply.started":"2023-10-14T13:25:05.424368Z","shell.execute_reply":"2023-10-14T13:25:05.427465Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## New Crop operations","metadata":{}},{"cell_type":"code","source":"#Returns GPU array\ndef standardize_pixel_array(pixel_array, dcm_rows):\n    \"\"\"\n    Source : https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection/discussion/427217\n    \"\"\"\n    # Correct DICOM pixel_array if PixelRepresentation == 1.\n    #pixel_array = dcm.pixel_array\n    #pixel_array = cp.array(pixel_array)    \n    for z in range(0, len(pixel_array)):\n        if int(dcm_rows[z]['PixelRepresentation']) == 1:\n            bit_shift = dcm_rows[z]['BitsAllocated'] - dcm_rows[z]['BitsStored']\n            dtype = pixel_array[z].dtype \n            pixel_array[z] = (pixel_array[z] << bit_shift).astype(dtype) >>  bit_shift\n    #         pixel_array = pydicom.pixel_data_handlers.util.apply_modality_lut(new_array, dcm)\n\n    pixel_array = torch.from_numpy(pixel_array.astype(np.float16)).to(DEVICE).to(torch.float32)    \n\n    for z in range(0, len(pixel_array)):\n        intercept = float(dcm_rows[z]['RescaleIntercept'])\n        slope = float(dcm_rows[z]['RescaleSlope'])\n        center = int(dcm_rows[z]['WindowCenter'])\n        width = int(dcm_rows[z]['WindowWidth'])\n        low = center - width / 2\n        high = center + width / 2    \n        \n        pixel_array[z] = (pixel_array[z] * slope) + intercept\n        pixel_array[z] = torch.clip(pixel_array[z], low, high)\n        \n    gc.collect()\n    \n    return pixel_array\n","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:05.429969Z","iopub.execute_input":"2023-10-14T13:25:05.430629Z","iopub.status.idle":"2023-10-14T13:25:05.440785Z","shell.execute_reply.started":"2023-10-14T13:25:05.430598Z","shell.execute_reply":"2023-10-14T13:25:05.439826Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#The order of the crop region data format\n#Z start/end, Y start/end, X start/end for each mask channels + total region for the extravasation prediction\ndef calc_crop_region(mask):\n    crop_range = np.zeros((6, 6))\n    crop_range[:,::2]=10000\n    mask_z = np.max(mask, axis = (2, 3)).astype(bool)\n    mask_y = np.max(mask, axis = (1, 3)).astype(bool)\n    mask_x = np.max(mask, axis = (1, 2)).astype(bool)\n    \n    template_range = np.arange(0, RESOL)\n\n    for mi in range(0, 5):\n        zrange = template_range[mask_z[mi]]\n        yrange = template_range[mask_y[mi]]\n        xrange = template_range[mask_x[mi]]\n        # For incomplete organ\n        if(len(zrange)==0):\n            zrange = template_range.copy()\n            yrange = template_range.copy()\n            xrange = template_range.copy()\n\n        crop_range[mi] = np.min(zrange), np.max(zrange)+1, np.min(yrange), np.max(yrange)+1, np.min(xrange), np.max(xrange)+1\n\n    crop_range[5] = np.min(crop_range[:5, 0]), np.max(crop_range[:5, 1]), np.min(crop_range[:5, 2]), \\\n                    np.max(crop_range[:5, 3]), np.min(crop_range[:5,4]), np.max(crop_range[:5, 5])\n    \n    crop_range[:,:2]/=len(mask_z[0])\n    crop_range[:,2:4]/=len(mask_y[0])\n    crop_range[:,4:6]/=len(mask_x[0])\n\n    # Then make extravasation (# 5 mask) to reference one and convert other mask's crop respective to it\n    # --> To minimize the loading size due to speed issue.\n    zmin, rel_zrange = crop_range[5,0], crop_range[5,1]-crop_range[5,0]\n    ymin, rel_yrange = crop_range[5,2], crop_range[5,3]-crop_range[5,2]\n    xmin, rel_xrange = crop_range[5,4], crop_range[5,5]-crop_range[5,4]\n\n    crop_range[:5,:2] = (crop_range[:5,:2]-zmin)/rel_zrange\n    crop_range[:5,2:4] = (crop_range[:5,2:4]-ymin)/rel_yrange\n    crop_range[:5,4:6] = (crop_range[:5,4:6]-xmin)/rel_xrange\n\n    return crop_range\n\ndef crop_resize_avg_and_std_3d(data, region, resize_shape):  \n    shapes = data.shape\n    region[:2]*=shapes[0]\n    region[2:4]*=shapes[1]\n    region[4:6]*=shapes[2]\n    region = region.astype(int)\n\n    cropped = torch.clone(data[region[0]:region[1], region[2]:region[3], region[4]:region[5]])    \n\n    #resize xy\n    cropped = transforms.Resize((int(resize_shape[1]), int(resize_shape[2])), antialias = True)(cropped)\n    #slices = []\n    #for i in range(0, len(cropped)):\n    #    slices.append(cv2.resize(cropped[i], (resize_shape[2], resize_shape[1]))[None])\n    \n    #slices = np.vstack(slices)\n    #resized_cropped = np.zeros(resize_shape)\n    \n    #zyx to xzy\n    cropped = torch.permute(cropped, (2, 0, 1))\n    cropped = transforms.Resize((int(resize_shape[0]), int(resize_shape[1])), antialias = True)(cropped)\n    #xzy to zyx\n    cropped = torch.permute(cropped, (1, 2, 0))\n    #for i in range(0, len(slices[0,0])):\n    #    resized_cropped[:,:,i] = cv2.resize(slices[:,:,i], (resize_shape[1], resize_shape[0]))\n\n        \n    #std = torch.std(cropped, (0, 1, 2))\n    #avg = torch.mean(cropped, (0, 1, 2))\n    min_imgs = torch.min(cropped)\n    max_imgs = torch.max(cropped)\n    #for debugging   \n    cropped = ((cropped - min_imgs) / (max_imgs - min_imgs + 1e-6))\n    \n    del min_imgs, max_imgs, shapes, region\n    gc.collect()\n    torch.cuda.empty_cache()\n    return cropped\n\n# Read each slice and stack them to make 3d data\ndef process_3d_crop(save_path, mask_path, resize_shapes, data_path = DATA_PATH):\n    tmp = save_path.split('/')[-1][:-4]\n    tmp = tmp.split('_')\n    patient, study = int(tmp[0]), int(tmp[1])\n    \n    mask = decompress(mask_path)\n    crop_regions = calc_crop_region(mask)\n    absolute_crop = crop_regions[5].copy() # To load minimum pixels...\n\n    del mask\n    gc.collect()\n    crop_regions[5] = 0, 1, 0, 1, 0, 1\n\n    imgs = {}    \n    \n    for f in sorted(glob.glob(data_path + f'/{patient}/{study}/*.dcm')):  \n        pos_z = -int((f.split('/')[-1])[:-4])\n        imgs[pos_z] = f\n\n    imgs_3d = []\n    n_imgs = len(imgs)    \n    z_crop_range= (absolute_crop[0:2]*n_imgs).astype(int)\n    #print(z_crop_range)\n    \n    dcm_rows = []\n    for i, k in enumerate(sorted(imgs.keys())):\n        #if i in sample_z:\n        if(i >= z_crop_range[0] and i < z_crop_range[1]):\n            IS_XY_CROP = False\n            f = imgs[k]\n            #Exception for the corrupted dicom file\n            if (f=='/kaggle/input/rsna-2023-abdominal-trauma-detection/test_images/3124/5842/514.dcm'):\n                continue\n            #try:            \n            opened_dicom = dicomsdl.open(f)\n            img = opened_dicom.pixelData(storedvalue=True)\n            params = opened_dicom.getPixelDataInfo()\n\n            if not IS_XY_CROP:\n                img_shape = np.shape(img)\n                xy_crop_range = absolute_crop[2:].copy()   \n                xy_crop_range[0:2]*=img_shape[0]\n                xy_crop_range[2:4]*=img_shape[1]            \n                xy_crop_range = xy_crop_range.astype(int)                \n                IS_XY_CROP = True\n                \n            img = img[xy_crop_range[0]:xy_crop_range[1], xy_crop_range[2]:xy_crop_range[3]]             \n\n            #dcm_row = pd.DataFrame.from_dict(params)                   \n            dcm_rows.append(params)                  \n            imgs_3d.append(img[None])\n\n    del opened_dicom\n    gc.collect()\n                \n    imgs_3d = np.vstack(imgs_3d)\n\n    imgs_3d  = standardize_pixel_array(imgs_3d, dcm_rows)\n\n    min_imgs = torch.min(imgs_3d)\n    max_imgs = torch.max(imgs_3d)\n    for i in range(0, 2):\n        min_imgs = torch.min(min_imgs)\n        max_imgs = torch.max(max_imgs)\n        \n    imgs_3d = ((imgs_3d - min_imgs) / (max_imgs - min_imgs + 1e-6))\n\n    #print(dcm_rows[0].PhotometricInterpretation)\n    if str(dcm_rows[0]['PhotometricInterpretation']) == \"MONOCHROME1\":\n        imgs_3d = 1.0 - imgs_3d\n\n    #Loaded original imgs_3d    \n    #processed_img_3d = np.zeros((6, RESOL, RESOL, RESOL))\n    \n    origin_shape = imgs_3d.shape\n    for i in range(0, 6):    \n        #To deal with almost not detected slices\n        try:   \n            # To deal with possible noises\n            if(((crop_regions[i,1]-crop_regions[i,0]) < 10/origin_shape[0]) or \n                ((crop_regions[i,3]-crop_regions[i,2]) < 10/origin_shape[1]) or \n                ((crop_regions[i,5]-crop_regions[i,4]) < 10/origin_shape[2])):\n                dummy_failure_function()\n            \n            processed_img_3d = (crop_resize_avg_and_std_3d(imgs_3d, crop_regions[i], resize_shapes[i])).to(torch.float16).to('cpu')\n            compress_fast(f'{save_path}_{i}', processed_img_3d)      \n\n            del processed_img_3d\n            gc.collect()\n        except:\n            processed_img_3d = (crop_resize_avg_and_std_3d(imgs_3d, np.array([0, 1, 0, 1, 0, 1]), resize_shapes[i])).to(torch.float16).to('cpu')\n            compress_fast(f'{save_path}_{i}', processed_img_3d)\n            del processed_img_3d\n            gc.collect()  \n\n    del imgs, img, imgs_3d\n    gc.collect()\n    torch.cuda.empty_cache()","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:05.442284Z","iopub.execute_input":"2023-10-14T13:25:05.44259Z","iopub.status.idle":"2023-10-14T13:25:05.466119Z","shell.execute_reply.started":"2023-10-14T13:25:05.442562Z","shell.execute_reply":"2023-10-14T13:25:05.465175Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"resize_shapes = np.zeros((6, 3), int)\nresize_shapes[0] = 131, 107, 148\nresize_shapes[1] = 107, 129, 150\nresize_shapes[2] = 105, 138, 144\nresize_shapes[3] = 77, 150, 180\nresize_shapes[4] =  85, 155, 158\nresize_shapes[5] = 123, 109, 155\n\n# Preprocess dataset\nrng_samples = np.linspace(0, len(df_data), N_PROCESS_CROP+1, dtype = int)\ndef process_3d_wrapper(process_ind, rng_samples = rng_samples, data_meta_df = df_data, resize_shapes = resize_shapes):\n    for i in tqdm(range(rng_samples[process_ind], rng_samples[process_ind+1])):\n        process_3d_crop(data_meta_df.iloc[i]['cropped_path'], data_meta_df.iloc[i]['mask_path'], resize_shapes)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:05.467315Z","iopub.execute_input":"2023-10-14T13:25:05.468244Z","iopub.status.idle":"2023-10-14T13:25:05.486424Z","shell.execute_reply.started":"2023-10-14T13:25:05.468213Z","shell.execute_reply":"2023-10-14T13:25:05.48536Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"%%time\nParallel(n_jobs = N_PROCESS_CROP)(delayed(process_3d_wrapper)(i) for i in range(N_PROCESS_CROP))","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:05.487516Z","iopub.execute_input":"2023-10-14T13:25:05.488408Z","iopub.status.idle":"2023-10-14T13:25:20.199507Z","shell.execute_reply.started":"2023-10-14T13:25:05.488377Z","shell.execute_reply":"2023-10-14T13:25:20.196747Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Final inference model","metadata":{}},{"cell_type":"code","source":"def convert_3d(module):\n    module_output = module\n    if isinstance(module, torch.nn.BatchNorm2d):\n        module_output = torch.nn.BatchNorm3d(\n            module.num_features,\n            module.eps,\n            module.momentum,\n            module.affine,\n            module.track_running_stats,\n        )\n        if module.affine:\n            with torch.no_grad():\n                module_output.weight = module.weight\n                module_output.bias = module.bias\n        module_output.running_mean = module.running_mean\n        module_output.running_var = module.running_var\n        module_output.num_batches_tracked = module.num_batches_tracked\n        if hasattr(module, \"qconfig\"):\n            module_output.qconfig = module.qconfig\n            \n    elif isinstance(module, Conv2dSame):\n        module_output = Conv3dSame(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.Conv2d):\n        module_output = torch.nn.Conv3d(\n            in_channels=module.in_channels,\n            out_channels=module.out_channels,\n            kernel_size=module.kernel_size[0],\n            stride=module.stride[0],\n            padding=module.padding[0],\n            dilation=module.dilation[0],\n            groups=module.groups,\n            bias=module.bias is not None,\n            padding_mode=module.padding_mode\n        )\n        module_output.weight = torch.nn.Parameter(module.weight.unsqueeze(-1).repeat(1,1,1,1,module.kernel_size[0]))\n\n    elif isinstance(module, torch.nn.MaxPool2d):\n        module_output = torch.nn.MaxPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            dilation=module.dilation,\n            ceil_mode=module.ceil_mode,\n        )\n    elif isinstance(module, torch.nn.AvgPool2d):\n        module_output = torch.nn.AvgPool3d(\n            kernel_size=module.kernel_size,\n            stride=module.stride,\n            padding=module.padding,\n            ceil_mode=module.ceil_mode,\n        )\n\n    for name, child in module.named_children():\n        module_output.add_module(\n            name, convert_3d(child)\n        )\n    del module\n\n    return module_output\n\n\nclass Timm3DModel(nn.Module):\n    def __init__(self, backbone, n_channels, n_labels, segtype='unet', pretrained=False):\n        super(Timm3DModel, self).__init__()\n        self.n_labels = n_labels\n        self.encoder = timm_new.create_model(\n            backbone,\n            in_chans=n_channels,\n            features_only=True,\n            drop_rate=drop_rate,\n            drop_path_rate=drop_path_rate,\n            pretrained=pretrained\n        )\n        g = self.encoder(torch.rand(1, n_channels, 64, 64))\n        encoder_channels = [1] + [_.shape[1] for _ in g]\n        decoder_channels = [256, 128, 64, 32, 16]\n\n        self.avgpool = nn.AvgPool2d(5, 4, 2)\n        \n        [_.shape[1] for _ in g]\n        self.convs1x1 = nn.ModuleList()    \n        self.batchnorms = nn.ModuleList()    \n        self.batchnorms13 = nn.ModuleList()\n        for i in range(0, len(g)):\n            self.convs1x1.append(nn.Conv2d(g[i].shape[1], self.n_labels, 1))\n        del g\n        gc.collect()\n        \n    def forward(self,x):\n        batch_size = x.shape[0]\n        global_features = self.encoder(x)[:n_blocks]        \n        for i in range(0, len(global_features)):\n            global_features[i] = self.convs1x1[i](global_features[i])\n        return global_features\n    \n    \nclass Timm3DModelClassifier(nn.Module):\n    def __init__(self, backbone, n_channels, n_labels, segtype='unet', pretrained=False):\n        super(Timm3DModelClassifier, self).__init__()\n        self.model_3d = Timm3DModel(backbone, n_channels, n_labels, segtype, pretrained)\n        self.model_3d = convert_3d(self.model_3d)\n        self.n_channels = n_channels\n        self.n_labels = n_labels    \n        \n    def forward(self, x):\n        batch_size = x.shape[0]\n        x = self.model_3d(x)\n        pooled_features = []\n        for i in range(0, len(x)):\n            pooled_features.append(torch.reshape(torch.mean(x[i], dim = (2, 3, 4)), (batch_size, self.n_labels, 1)))\n        pooled_features = torch.cat(pooled_features, dim=2)     \n        labels = torch.mean(pooled_features, dim = 2)\n        return labels\n    \nclass AbdominalClassifier(nn.Module):\n    def __init__(self, device = DEVICE):\n        super().__init__()\n        self.device = device\n        self.upsample = torch.nn.Upsample(size = [UP_RESOL, UP_RESOL, UP_RESOL])\n        \n        self.model3d_bowel        = Timm3DModelClassifier(backbone_classifier, 1, 2)      \n        self.model3d_extrav       = Timm3DModelClassifier(backbone_classifier, 1, 2)\n        self.model3d_kidney_left  = Timm3DModelClassifier(backbone_classifier, 1, 3)\n        self.model3d_kidney_right = Timm3DModelClassifier(backbone_classifier, 1, 3)\n        self.model3d_liver        = Timm3DModelClassifier(backbone_classifier, 1, 3)\n        self.model3d_spleen       = Timm3DModelClassifier(backbone_classifier, 1, 3)\n        \n        self.flatten  = nn.Flatten()\n        self.dropout  = nn.Dropout(p=0.5)\n        self.softmax  = nn.Softmax(dim=1)        \n        self.maxpool  = nn.MaxPool1d(5, 1)\n        \n    def forward(self, x_bowel, x_kidney_left, x_kidney_right, x_liver, x_spleen, x_total):\n        bowel_label        = self.model3d_bowel(x_bowel)\n        extrav_label       = self.model3d_extrav(x_total)\n        kidney_label_left  = self.model3d_kidney_left(x_kidney_left)\n        kidney_label_right = self.model3d_kidney_right(x_kidney_right)\n        kidney_label       = (kidney_label_left + kidney_label_right)/2\n        liver_label        = self.model3d_liver(x_liver)\n        spleen_label       = self.model3d_spleen(x_spleen)\n        \n        bowel_soft = self.softmax(bowel_label)\n        extrav_soft = self.softmax(extrav_label)\n        kidney_soft = self.softmax(kidney_label)\n        liver_soft = self.softmax(liver_label)\n        spleen_soft = self.softmax(spleen_label)\n        \n        labels = torch.cat([bowel_soft, extrav_soft, kidney_soft, liver_soft, spleen_soft], dim = 1)\n\n        return labels\n    \n    \nclass AbdominalClassifier2(nn.Module):\n    def __init__(self, device = DEVICE):\n        super().__init__()\n        self.device = device\n        self.upsample = torch.nn.Upsample(size = [UP_RESOL, UP_RESOL, UP_RESOL])\n        \n        self.model3d_bowel        = Timm3DModelClassifier(backbone_classifier2, 1, 2)      \n        self.model3d_extrav       = Timm3DModelClassifier(backbone_classifier2, 1, 2)\n        self.model3d_kidney_left  = Timm3DModelClassifier(backbone_classifier2, 1, 3)\n        self.model3d_kidney_right = Timm3DModelClassifier(backbone_classifier2, 1, 3)\n        self.model3d_liver        = Timm3DModelClassifier(backbone_classifier2, 1, 3)\n        self.model3d_spleen       = Timm3DModelClassifier(backbone_classifier2, 1, 3)\n        \n        self.flatten  = nn.Flatten()\n        self.dropout  = nn.Dropout(p=0.5)\n        self.softmax  = nn.Softmax(dim=1)        \n        self.maxpool  = nn.MaxPool1d(5, 1)\n        \n    def forward(self, x_bowel, x_kidney_left, x_kidney_right, x_liver, x_spleen, x_total):\n        bowel_label        = self.model3d_bowel(x_bowel)\n        extrav_label       = self.model3d_extrav(x_total)\n        kidney_label_left  = self.model3d_kidney_left(x_kidney_left)\n        kidney_label_right = self.model3d_kidney_right(x_kidney_right)\n        kidney_label       = (kidney_label_left + kidney_label_right)/2\n        liver_label        = self.model3d_liver(x_liver)\n        spleen_label       = self.model3d_spleen(x_spleen)\n        \n        bowel_soft = self.softmax(bowel_label)\n        extrav_soft = self.softmax(extrav_label)\n        kidney_soft = self.softmax(kidney_label)\n        liver_soft = self.softmax(liver_label)\n        spleen_soft = self.softmax(spleen_label)\n        \n        labels = torch.cat([bowel_soft, extrav_soft, kidney_soft, liver_soft, spleen_soft], dim = 1)\n\n        return labels","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:25:20.202565Z","iopub.execute_input":"2023-10-14T13:25:20.205262Z","iopub.status.idle":"2023-10-14T13:25:20.293166Z","shell.execute_reply.started":"2023-10-14T13:25:20.205221Z","shell.execute_reply":"2023-10-14T13:25:20.292092Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Timm3DModelClassifierEmbed(nn.Module):\n    def __init__(self, backbone, n_channels, n_labels, segtype='unet', pretrained=False):\n        super(Timm3DModelClassifierEmbed, self).__init__()\n        self.model_3d = Timm3DModel(backbone, n_channels, n_labels, segtype, pretrained)\n        self.model_3d = convert_3d(self.model_3d)\n        self.n_channels = n_channels\n        self.n_labels = n_labels                        \n        \n    def forward(self, x):\n        batch_size = x.shape[0]\n        x = self.model_3d(x)\n        pooled_features = []\n        for i in range(0, len(x)):\n            pooled_features.append(torch.reshape(torch.mean(x[i], dim = (2, 3, 4)), (batch_size, self.n_labels, 1)))\n        pooled_features = torch.cat(pooled_features, dim=2)     \n        labels = nn.Flatten()(pooled_features)\n        #labels = torch.mean(pooled_features, dim = 2)\n        return labels\n\n# LSTM\nclass AbdominalClassifierLSTM(nn.Module):\n    def __init__(self, device = DEVICE):\n        super().__init__()\n        self.device = device\n        \n        self.model3d_bowel        = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)      \n        self.model3d_extrav       = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)\n        self.model3d_kidney_left  = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)\n        self.model3d_kidney_right = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)\n        self.model3d_liver        = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)\n        self.model3d_spleen       = Timm3DModelClassifierEmbed(backbone_classifiers3, 1, 32)\n        \n        self.flatten  = nn.Flatten()\n        self.dropout  = nn.Dropout(p=0.5)\n        self.softmax  = nn.Softmax(dim=1)        \n        self.maxpool  = nn.MaxPool1d(5, 1)\n        \n        self.lstm = nn.LSTM(input_size =128, hidden_size = 256, num_layers=5, batch_first=True, bidirectional=True)\n        self.head = nn.Linear(512, 13)\n        \n    def forward(self, x_bowel, x_kidney_left, x_kidney_right, x_liver, x_spleen, x_total):\n        bs = x_bowel.shape[0]\n        \n        bowel_emb        = torch.reshape(self.model3d_bowel(x_bowel), (bs, 1, 128))\n        extrav_emb       = torch.reshape(self.model3d_extrav(x_total), (bs, 1, 128))\n        kidney_left_emb  = torch.reshape(self.model3d_kidney_left(x_kidney_left), (bs, 1, 128))\n        kidney_right_emb = torch.reshape(self.model3d_kidney_right(x_kidney_right), (bs, 1, 128))\n        liver_emb        = torch.reshape(self.model3d_liver(x_liver), (bs, 1, 128))\n        spleen_emb       = torch.reshape(self.model3d_spleen(x_spleen), (bs, 1, 128))\n        \n        all_embs = torch.cat([bowel_emb, extrav_emb, kidney_left_emb, kidney_right_emb, liver_emb, spleen_emb], dim = 1)\n        \n        all_embs = self.lstm(all_embs)\n        labels   = torch.mean(all_embs[0], dim = 1) \n        labels   = self.head(labels)\n\n        bowel_soft = self.softmax(labels[:,:2])\n        extrav_soft = self.softmax(labels[:,2:4])\n        kidney_soft = self.softmax(labels[:,4:7])\n        liver_soft = self.softmax(labels[:,7:10])\n        spleen_soft = self.softmax(labels[:,10:13])\n\n        labels = torch.cat([bowel_soft, extrav_soft, kidney_soft, liver_soft, spleen_soft], dim = 1)\n\n        return labels","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:28:34.369343Z","iopub.execute_input":"2023-10-14T13:28:34.369707Z","iopub.status.idle":"2023-10-14T13:28:34.384772Z","shell.execute_reply.started":"2023-10-14T13:28:34.369666Z","shell.execute_reply":"2023-10-14T13:28:34.383568Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Inference with cropped regions","metadata":{}},{"cell_type":"code","source":"class AbdominalCTDataset(Dataset):\n    def __init__(self, meta_df, is_train = True, transform_set = None, remain_transforms_set = None):\n        self.meta_df = meta_df\n        self.is_train = is_train\n\n    def __len__(self):\n        return len(self.meta_df)\n    \n    def __getitem__(self, idx):\n        row = self.meta_df.iloc[idx]        \n\n        data_3ds = {}\n        base_name = self.meta_df.iloc[idx]['cropped_path']            \n        for j in range(0, 6):\n            data_3d = decompress_fast(f'{base_name}_{j}').unsqueeze(0).to(torch.float32)\n            #data_3d = torch.from_numpy(data_3d)\n            data_3ds[chan_dict[j]] = data_3d  \n\n\n        return data_3ds['bowel'], data_3ds['left_kidney'], data_3ds['right_kidney'], \\\n                data_3ds['liver'], data_3ds['spleen'], data_3ds['total']\n\ntest_dataset = AbdominalCTDataset(df_data)","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:28:34.883228Z","iopub.execute_input":"2023-10-14T13:28:34.886075Z","iopub.status.idle":"2023-10-14T13:28:34.896791Z","shell.execute_reply.started":"2023-10-14T13:28:34.886033Z","shell.execute_reply":"2023-10-14T13:28:34.895857Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# model = AbdominalClassifier()\n# model.load_state_dict(torch.load(weights_classifier))\n# model.to(DEVICE)    \n# model.eval()\ndevice = torch.device(\"cuda:0\")  # for the first GPU\nmodel = AbdominalClassifier() # resnet50\nmodel.load_state_dict(torch.load(weights_classifier, map_location=device))\nmodel.to(DEVICE)    \nmodel.eval()\n\ndevice = torch.device(\"cuda:0\")  # for the first GPU\nmodel1_2 = AbdominalClassifier() # resnet50\nmodel1_2.load_state_dict(torch.load(weights_classifier1_2, map_location=device))\nmodel1_2.to(DEVICE)    \nmodel1_2.eval()\n\n\ndevice = torch.device(\"cuda:0\")  # for the first GPU\nmodel2 = AbdominalClassifier2() # resnet10\nmodel2.load_state_dict(torch.load(weights_classifier2, map_location=device))\nmodel2.to(DEVICE)    \nmodel2.eval()\n\n\ndevice = torch.device(\"cuda:0\")  # for the first GPU\nmodel3 = AbdominalClassifierLSTM() # resnet10\nmodel3.load_state_dict(torch.load(weights_classifiers3, map_location=device))\nmodel3.to(DEVICE)    \nmodel3.eval()\n\ndummy=0\n\npredss=[]\npredss2 = []\npredss1_2 = []\npredss3 = []\n#bar = tqdm(test_loader)\n\nwith torch.cuda.amp.autocast(enabled=False):  \n    with torch.inference_mode():\n        for i in tqdm(range(0, len(test_dataset))):\n            X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot = test_dataset[i]\n            X_bowel, X_lkid, X_rkid = X_bowel.unsqueeze(0).to(DEVICE), X_lkid.unsqueeze(0).to(DEVICE), X_rkid.unsqueeze(0).to(DEVICE)\n            X_liv,   X_spl,  X_tot  = X_liv.unsqueeze(0).to(DEVICE),   X_spl.unsqueeze(0).to(DEVICE),  X_tot.unsqueeze(0).to(DEVICE)            \n            preds = model(X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot).detach().cpu().numpy()  # model (resnet50)\n            preds2 = model2(X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot).detach().cpu().numpy()  # model2 (resnet10)                        \n            preds1_2 = model1_2(X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot).detach().cpu().numpy()  # model2 (resnet10)\n            preds3 = model3(X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot).detach().cpu().numpy()  # LSTM\n\n            predss.append(preds)\n            predss2.append(preds2)\n            predss1_2.append(preds1_2)\n            predss3.append(preds3)\n            del X_bowel, X_lkid, X_rkid, X_liv, X_spl, X_tot\n            gc.collect()\n            \n        \n\npredss = np.vstack(predss)\npredss2 = np.vstack(predss2)\npredss1_2 = np.vstack(predss1_2)\npredss3 = np.vstack(predss3)\n                \n#del images\n#gc.collect()\ntorch.cuda.empty_cache()\n\ntarget_cols =  ['bowel_healthy','bowel_injury',\n                    'extravasation_healthy','extravasation_injury',\n                    'kidney_healthy','kidney_low','kidney_high',\n                    'liver_healthy','liver_low','liver_high',\n                    'spleen_healthy','spleen_low','spleen_high']\n\n# avg preds\navg_preds = (predss + predss2 + predss1_2+predss3) / 4\n\ndf_data[target_cols] = avg_preds\n#preds = np.vstack(preds)            \n\ntry:\n    df_data = df_data.drop('series', axis = 1)\nexcept:\n    df_data = df_data.drop('sample', axis = 1)\n\n# # More sofisticated postprocessing    \n# bowel_extrav =  \\\n#             df_data.groupby(['patient_id']).agg('max')[['bowel_injury', 'extravasation_injury']].to_numpy()\n\n# df_data = df_data.groupby(['patient_id']).agg('mean')\n\n# df_data['bowel_healthy'] = 1 - bowel_extrav[:,0]\n# df_data['bowel_injury']  = bowel_extrav[:,0]\n# df_data['extravasation_healthy'] = 1- bowel_extrav[:,1]\n# df_data['extravasation_injury'] =  bowel_extrav[:,1]\n\n# patient_id = df_data.index\n# df_data = df_data.reset_index()\n\n# df_data['patient_id'] = patient_id\n\n# patient_id 별로 'bowel_injury'와 'extravasation_injury'의 최대값을 계산\nmax_values_injury = df_data.groupby('patient_id')[['bowel_injury', 'extravasation_injury']].transform('max')\nmax_values_healthy = df_data.groupby('patient_id')[['bowel_healthy', 'extravasation_healthy', 'kidney_healthy', 'liver_healthy', 'spleen_healthy']].transform('max')\n\nmean_low_value = df_data.groupby('patient_id')[['kidney_low', 'liver_low', 'spleen_low']].transform('mean')\nmean_high_value = df_data.groupby('patient_id')[['kidney_high', 'liver_high', 'spleen_high']].transform('mean')\n\n# 계산된 최대값을 바탕으로 새로운 컬럼을 생성/갱신\ndf_data['bowel_injury'] = max_values_injury['bowel_injury']\ndf_data['extravasation_injury'] = max_values_injury['extravasation_injury']\n\ndf_data['bowel_healthy'] = max_values_healthy['bowel_healthy']\ndf_data['extravasation_healthy'] = max_values_healthy['extravasation_healthy']\ndf_data['kidney_healthy'] = max_values_healthy['kidney_healthy']\ndf_data['liver_healthy'] = max_values_healthy['liver_healthy']\ndf_data['spleen_healthy'] = max_values_healthy['spleen_healthy']\n\ndf_data['kidney_low'] = mean_low_value['kidney_low']\ndf_data['liver_low'] = mean_low_value['liver_low']\ndf_data['spleen_low'] = mean_low_value['spleen_low']\n\ndf_data['kidney_high'] = mean_high_value['kidney_high']\ndf_data['liver_high'] = mean_high_value['liver_high']\ndf_data['spleen_high'] = mean_high_value['spleen_high']\n\n\n\ndf_data","metadata":{"execution":{"iopub.status.busy":"2023-10-14T13:28:35.033182Z","iopub.execute_input":"2023-10-14T13:28:35.035965Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_df = pd.read_csv('/kaggle/input/rsna-2023-abdominal-trauma-detection/sample_submission.csv')\nif not DEBUG:\n    for i in range(0, len(df_data)):\n        row = df_data.iloc[i]\n        patient_id = row['patient_id']\n        sample_df.loc[sample_df['patient_id']==patient_id,target_cols] = row[target_cols].to_numpy()\n#Extravasation \nsample_df.to_csv('submission.csv', index = False)\nsample_df","metadata":{"papermill":{"duration":0.057976,"end_time":"2023-08-28T10:33:10.606289","exception":false,"start_time":"2023-08-28T10:33:10.548313","status":"completed"},"tags":[],"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}