{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.14","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"},{"sourceId":124135,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":104483,"modelId":128684},{"sourceId":116839,"sourceType":"modelInstanceVersion","isSourceIdPinned":true,"modelInstanceId":98213,"modelId":122392}],"dockerImageVersionId":30776,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport pandas as pd\nimport numpy as np\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import models \nimport torchvision.transforms as T\nfrom torch.utils.data import Dataset, DataLoader\nimport torch.nn.functional as F\n\nimport pydicom\nfrom PIL import Image,ImageOps\nimport random\nfrom sklearn.preprocessing import LabelEncoder, label_binarize\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import roc_auc_score ,accuracy_score,classification_report,roc_curve,auc\nfrom sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay,accuracy_score\n\nimport matplotlib.pyplot as plt\nimport cv2\nimport seaborn as sns\nfrom skimage.measure import regionprops, label\nimport time\n\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-10-01T04:36:29.613477Z","iopub.execute_input":"2024-10-01T04:36:29.613775Z","iopub.status.idle":"2024-10-01T04:36:43.053362Z","shell.execute_reply.started":"2024-10-01T04:36:29.613741Z","shell.execute_reply":"2024-10-01T04:36:43.052555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#file path\nbase_path = '/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification'\n\n#train path\ntrain_label = os.path.join(base_path,'train_label_coordinates.csv')\ntrain_series = os.path.join(base_path,'train_series_descriptions.csv')\ntrain_ = os.path.join(base_path,'train.csv')\nimg_train_path = os.path.join(base_path,'train_images')\n\n#test path\ntest_series=os.path.join(base_path,'test_series_descriptions.csv')\nimg_test_path = os.path.join(base_path,'test_images')","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.054758Z","iopub.execute_input":"2024-10-01T04:36:43.055243Z","iopub.status.idle":"2024-10-01T04:36:43.060888Z","shell.execute_reply.started":"2024-10-01T04:36:43.055209Z","shell.execute_reply":"2024-10-01T04:36:43.059879Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def reconstruct_df(df):\n    series = ['Sagittal T2/STIR', 'Sagittal T1', 'Axial T2']\n    conditions = ['spinal_canal_stenosis', 'neural_foraminal_narrowing', 'subarticular_stenosis']\n    df_name=[pd.DataFrame(),pd.DataFrame(),pd.DataFrame()]\n    \n    for i,(se, cond) in enumerate(zip(series, conditions)):\n        filtered_df = df[df['series_description'] == se] # Filter the dataframe based on 'series_description'\n\n        # Select columns to keep\n        columns_to_keep = filtered_df.columns[:8].tolist()\n        columns_to_keep += [col for col in filtered_df.columns[8:] if cond in col]\n\n        #filter and update\n        filtered_df = filtered_df[columns_to_keep] \n        df_name[i] = filtered_df\n    \n    return df_name[0],df_name[1],df_name[2]\n\ndef xy_spinal_neural(df):\n    # Required levels and associated columns\n    required_levels = ['L1/L2', 'L2/L3', 'L3/L4', 'L4/L5', 'L5/S1']\n\n    ## filterout data which having both level\n    df_filtered = df.groupby(['study_id','series_id','instance_number']).filter(\n    lambda group: set(required_levels).issubset(group['level'].unique()))\n\n    # make localize \n    grouped = df_filtered.groupby(['study_id', 'series_id', 'instance_number'])\n    result_rows = []\n    for (study_id, series_id, instance_number), group in grouped:\n        # Create a dictionary to store the data for this group\n        row_data = {'study_id': study_id, 'series_id': series_id, 'instance_number': instance_number}\n    \n        # Check if all other columns have the same value in the group, if so, keep them\n        for col in group.columns:\n            if col not in ['level', 'x', 'y']:  # Exclude 'level', 'x', and 'y' columns\n                if group[col].nunique() == 1:  # Check if all values in this column are the same\n                    row_data[col] = group[col].iloc[0]  # Take the unique value\n\n\n        # Extract x and y coordinates for each required level\n        for level in required_levels:\n            level_data = group[group['level'] == level]\n            if not level_data.empty:\n                row_data[f'x_level_{level.lower().replace(\"/\", \"_\")}'] = level_data['x'].values[0]\n                row_data[f'y_level_{level.lower().replace(\"/\", \"_\")}'] = level_data['y'].values[0]\n\n        # Add the row data to the result_rows list\n        result_rows.append(row_data)\n\n    # Convert the result_rows list to a DataFrame\n    result = pd.DataFrame(result_rows)\n    return result\n\n\ndef xy_subarticular(df):\n    # Required levels and associated columns\n    require_condition=['Right Subarticular Stenosis','Left Subarticular Stenosis']\n\n    ## filterout data which having both level\n    df_filtered = df.groupby(['study_id','series_id','instance_number','level']).filter(\n    lambda group: set(require_condition).issubset(group['condition'].unique()))\n\n    # make localize \n    grouped = df_filtered.groupby(['study_id', 'series_id', 'instance_number','level'])\n    result_rows = []\n    for (study_id, series_id, instance_number,level), group in grouped:\n        # Create a dictionary to store the data for this group\n        row_data = {'study_id': study_id, 'series_id': series_id, 'instance_number': instance_number,'level':level}\n    \n        # Check if all other columns have the same value in the group, if so, keep them\n        for col in group.columns:\n            if col not in ['series_description','condition','x', 'y']:  # Exclude 'level', 'x', and 'y' columns\n                if group[col].nunique() == 1:  # Check if all values in this column are the same\n                    row_data[col] = group[col].iloc[0]  # Take the unique value\n\n        # Extract x and y coordinates for each required level\n        for condition in require_condition:\n            condition_data = group[group['condition'] == condition]\n            if not condition_data.empty:\n                row_data[f'x_level_{condition.split(\" \")[0]}'] = condition_data['x'].values[0]\n                row_data[f'y_level_{condition.split(\" \")[0]}'] = condition_data['y'].values[0]\n\n        # Add the row data to the result_rows list\n        result_rows.append(row_data)\n\n    # Convert the result_rows list to a DataFrame\n    df_result = pd.DataFrame(result_rows)\n    \n    #dummy varables\n    columns_to_encode = 'level'\n    df_encoded = pd.get_dummies(df_result[columns_to_encode], columns=columns_to_encode, prefix=columns_to_encode)\n    df_encoded = df_encoded.astype(float)# Convert boolean True/False to 1.0/0.0\n    df_result['level_array'] = df_encoded.values.tolist()\n    #result=pd.concat([df_result,df_encoded],axis=1)\n    df_result = df_result.drop(columns=columns_to_encode)\n    \n    return df_result","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.063059Z","iopub.execute_input":"2024-10-01T04:36:43.063371Z","iopub.status.idle":"2024-10-01T04:36:43.082851Z","shell.execute_reply.started":"2024-10-01T04:36:43.063334Z","shell.execute_reply":"2024-10-01T04:36:43.081939Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def get_level_labels(level_code):\n    levels = {0:'l1_l2', 1:'l2_l3', 2:'l3_l4', 3:'l4_l5', 4:'l5_s1'}\n    return levels[level_code]\n\ndef data_process_subarticular(df):\n    location_level  = [col for col in df.columns if '_level_' in col]\n    condition_columns = [col for col in df.columns if '_subarticular_stenosis_' in col]\n    df['level_label']=df['level_array'].apply(lambda row: get_level_labels(row.index(1)))\n\n    # Melt the DataFrame to create a row for each condition\n    df_melted = pd.melt(df, id_vars=['study_id', 'series_id', 'instance_number','level_array','level_label'], \n                        value_vars=condition_columns, \n                        var_name='condition_level', value_name='severity')\n    df_split= df_melted['condition_level'].str.split('_',expand=True)\n    df_melted['level'] = df_split[3]+'_'+df_split[4]\n    df_melted['left_right']=df_split[0]\n    df_melted= df_melted[df_melted['level_label']==df_melted['level']]\n    df_melted = df_melted.drop(columns=['level'])\n    \n    df_location=df.copy()\n    df_location = df_location.drop(columns=condition_columns)\n    df_location=df_location.drop(columns=['level_array']) #, 'condition'])\n    \n    # Merge the DataFrames on common columns\n    merged_df = pd.merge(df_melted, df_location, on=['study_id', 'series_id', 'instance_number','level_label'], how='left')\n\n    # Function to extract x and y based on the level\n    def get_coordinates(row):\n        left_right = row['left_right']\n        if left_right == 'right':\n            return row['x_level_Right'], row['y_level_Right']\n        elif left_right == 'left':\n            return row['x_level_Left'], row['y_level_Left']\n        else:\n            return None, None\n\n    # Apply the function to create x and y columns\n    merged_df[['x', 'y']] = merged_df.apply(get_coordinates, axis=1, result_type='expand')\n    merged_df = merged_df.sort_values(by=['study_id', 'series_id', 'instance_number'])\n    df_final=merged_df.drop(columns=location_level)\n    \n    dummy_var=pd.get_dummies(df_final['severity'],columns=['severity'])\n    dummy_var=dummy_var[['Normal/Mild','Moderate','Severe']]\n    dummy_var=dummy_var.astype('float')\n    df_final['label_array']=dummy_var.values.tolist()\n    \n    # create image_id columns\n    df_final['image_id'] = [f\"{row['study_id']}_{row['series_id']}_{row['instance_number']}\" for _, row in df_final.iterrows()]\n    \n    # Map the \"level\" column to create \"level_id\"\n    level_mapping = {\n    'right': 1,\n    'left': 2,\n    }\n    df_final['leri_id'] = df_final['left_right'].map(level_mapping)\n\n    return df_final","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.085711Z","iopub.execute_input":"2024-10-01T04:36:43.086078Z","iopub.status.idle":"2024-10-01T04:36:43.099824Z","shell.execute_reply.started":"2024-10-01T04:36:43.086037Z","shell.execute_reply":"2024-10-01T04:36:43.099004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def plot_severity_value(spinal_train, spinal_ori2):\n    # Create the subplots\n    f, ax = plt.subplots(1, 2, figsize=(10, 5))\n\n    # Plot 1: Severity distribution in spinal_train\n    severity_counts = spinal_train['severity'].value_counts()\n    bars = ax[0].bar(severity_counts.index, severity_counts.values)\n    ax[0].set_xlabel('Severity')\n    ax[0].set_ylabel('Frequency')\n    ax[0].set_title('Distribution of Severity in spinal_train')\n    for bar in bars:\n        height = bar.get_height()\n        ax[0].text(bar.get_x() + bar.get_width() / 2, height, f'{height}', ha='center', va='bottom')\n\n    # Plot 2: Severity distribution in spinal_ori2\n    severity_counts = spinal_ori2['severity'].value_counts()\n    bars = ax[1].bar(severity_counts.index, severity_counts.values)\n    ax[1].set_xlabel('Severity')\n    ax[1].set_ylabel('Frequency')\n    ax[1].set_title('Distribution of Severity in spinal_ori2')\n    for bar in bars:\n        height = bar.get_height()\n        ax[1].text(bar.get_x() + bar.get_width() / 2, height, f'{height}', ha='center', va='bottom')\n    \n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.100880Z","iopub.execute_input":"2024-10-01T04:36:43.101185Z","iopub.status.idle":"2024-10-01T04:36:43.114209Z","shell.execute_reply.started":"2024-10-01T04:36:43.101139Z","shell.execute_reply":"2024-10-01T04:36:43.113323Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def group_by_counts(df_train,df_ori2): \n    # Group by both 'severity' and 'level' and count the occurrences\n    severity_level_counts = df_train.groupby(['severity', 'left_right']).size().reset_index(name='count')\n    # Display the grouped counts\n    print('train_set: \\n',severity_level_counts)\n    print('*' *30)\n\n    severity_level_counts = df_ori2.groupby(['severity', 'left_right']).size().reset_index(name='count')\n    # Display the grouped counts\n    print('ori2_set: \\n',severity_level_counts)\n    print('*' *30)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.115169Z","iopub.execute_input":"2024-10-01T04:36:43.115537Z","iopub.status.idle":"2024-10-01T04:36:43.124488Z","shell.execute_reply.started":"2024-10-01T04:36:43.115504Z","shell.execute_reply":"2024-10-01T04:36:43.123635Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def data_balance(df,n_normal=50):\n    normal = df[df['severity']=='Normal/Mild']\\\n    .groupby('left_right')\\\n    .apply(lambda x : x.sample(n=min(n_normal,len(x)), random_state =42))\\\n    .reset_index(drop=True)\n    \n    moderate = df[df['severity']=='Moderate']\\\n    .groupby('left_right')\\\n    .apply(lambda x : x.sample(n=min(n_normal,len(x)), random_state =42))\\\n    .reset_index(drop=True)\n    \n    severe = df[df['severity']=='Severe']\n    \n    concat_set = pd.concat([normal,moderate,severe])\n    final_set = concat_set.sample(frac=1, random_state=42).reset_index(drop=True)\n    \n    return final_set","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.125439Z","iopub.execute_input":"2024-10-01T04:36:43.125702Z","iopub.status.idle":"2024-10-01T04:36:43.139011Z","shell.execute_reply.started":"2024-10-01T04:36:43.125672Z","shell.execute_reply":"2024-10-01T04:36:43.138315Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df = pd.read_csv(train_)\nseries_df = pd.read_csv(train_series)\nlabel_df = pd.read_csv(train_label)\ndf = pd.merge(label_df, series_df , on=['study_id','series_id'])\ndf = pd.merge(df,train_df,on = 'study_id')\n\n_, _,df_subarticular = reconstruct_df(df)\n\n# subarticular\ndf_subarticular_xy =xy_subarticular(df_subarticular)\nprint(df_subarticular_xy.shape)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:43.140052Z","iopub.execute_input":"2024-10-01T04:36:43.140387Z","iopub.status.idle":"2024-10-01T04:36:57.010021Z","shell.execute_reply.started":"2024-10-01T04:36:43.140348Z","shell.execute_reply":"2024-10-01T04:36:57.009106Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_subarticular_xy.head()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:57.011268Z","iopub.execute_input":"2024-10-01T04:36:57.011622Z","iopub.status.idle":"2024-10-01T04:36:57.038222Z","shell.execute_reply.started":"2024-10-01T04:36:57.011580Z","shell.execute_reply":"2024-10-01T04:36:57.037380Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_train_df, sub_val_df=train_test_split(df_subarticular_xy,test_size=0.2,random_state=219)\nprint(f\"size for train:{len(sub_train_df)}\")\nprint(f\"size for validation:{len(sub_val_df)}\")","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:57.041832Z","iopub.execute_input":"2024-10-01T04:36:57.042218Z","iopub.status.idle":"2024-10-01T04:36:57.051701Z","shell.execute_reply.started":"2024-10-01T04:36:57.042185Z","shell.execute_reply":"2024-10-01T04:36:57.050779Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_train=data_process_subarticular(sub_train_df)\nsub_val=data_process_subarticular(sub_val_df)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:57.052882Z","iopub.execute_input":"2024-10-01T04:36:57.053241Z","iopub.status.idle":"2024-10-01T04:36:58.574825Z","shell.execute_reply.started":"2024-10-01T04:36:57.053206Z","shell.execute_reply":"2024-10-01T04:36:58.574045Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sub_val.head()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:58.575874Z","iopub.execute_input":"2024-10-01T04:36:58.576161Z","iopub.status.idle":"2024-10-01T04:36:58.594943Z","shell.execute_reply.started":"2024-10-01T04:36:58.576117Z","shell.execute_reply":"2024-10-01T04:36:58.594147Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plot_severity_value(sub_train,sub_val)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:58.596359Z","iopub.execute_input":"2024-10-01T04:36:58.596771Z","iopub.status.idle":"2024-10-01T04:36:59.121236Z","shell.execute_reply.started":"2024-10-01T04:36:58.596725Z","shell.execute_reply":"2024-10-01T04:36:59.120290Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"group_by_counts(sub_train,sub_val)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.122529Z","iopub.execute_input":"2024-10-01T04:36:59.123225Z","iopub.status.idle":"2024-10-01T04:36:59.140701Z","shell.execute_reply.started":"2024-10-01T04:36:59.123176Z","shell.execute_reply":"2024-10-01T04:36:59.139846Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_set=data_balance(sub_train,n_normal=430)\nval_set=data_balance(sub_val,n_normal=110)\n\nprint(train_set.shape)\nprint(val_set.shape)\n\nplot_severity_value(train_set,val_set)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.142083Z","iopub.execute_input":"2024-10-01T04:36:59.142403Z","iopub.status.idle":"2024-10-01T04:36:59.585051Z","shell.execute_reply.started":"2024-10-01T04:36:59.142371Z","shell.execute_reply":"2024-10-01T04:36:59.584193Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_set.head()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.586437Z","iopub.execute_input":"2024-10-01T04:36:59.586813Z","iopub.status.idle":"2024-10-01T04:36:59.605963Z","shell.execute_reply.started":"2024-10-01T04:36:59.586768Z","shell.execute_reply":"2024-10-01T04:36:59.605166Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"########################### predict mask and level################","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.606927Z","iopub.execute_input":"2024-10-01T04:36:59.607209Z","iopub.status.idle":"2024-10-01T04:36:59.615610Z","shell.execute_reply.started":"2024-10-01T04:36:59.607178Z","shell.execute_reply":"2024-10-01T04:36:59.614914Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class subarticular_lo_Dataset(Dataset):\n    def __init__(self, df, image_dir,input_size=128, transform=None):\n        self.df = df\n        self.img_dir = image_dir\n        self.input_size=input_size\n        self.transform = transform\n\n        # Default transform if none provided\n        if self.transform is None:\n            self.transform = T.Compose([\n                T.Resize((self.input_size, self.input_size)),\n                T.ToTensor()\n            ])\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        # Get the image and mask for the given index\n        image, image_id,level = self.get_images(idx)\n\n        # Apply transformations to the image (if any)\n        image = self.transform(image)\n\n        # Ensure image and mask are of type float32 for model compatibility\n        image = torch.tensor(image, dtype=torch.float32)\n        level = torch.tensor(level, dtype=torch.long)\n        \n        return image, image_id, level\n\n    def get_images(self, idx):\n        # Fetch the row for the given index\n        row = self.df.iloc[idx]\n\n        # Load DICOM image\n        dicom_path = os.path.join(self.img_dir, str(row['study_id']), str(row['series_id']), f\"{str(row['instance_number'])}.dcm\")\n        dicom = pydicom.dcmread(dicom_path)\n        image = dicom.pixel_array\n\n        # Normalize the image to the range 0-255 and convert it to RGB\n        image_normalized = np.interp(image, (0, 1810), (0, 255)).astype(np.uint8)  #(n,n)\n        rgb_image_pil = Image.fromarray(image_normalized)\n        \n        # Image_id\n        image_id = row['image_id']\n        \n        #level\n        level = float(row['level_array'].index(1))\n\n        return rgb_image_pil, image_id,level","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.616623Z","iopub.execute_input":"2024-10-01T04:36:59.616933Z","iopub.status.idle":"2024-10-01T04:36:59.627952Z","shell.execute_reply.started":"2024-10-01T04:36:59.616902Z","shell.execute_reply":"2024-10-01T04:36:59.627068Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def model_loc(model_mask,model_rl, data_loader):\n    \n    device_mask = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    device_rl = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n    model_mask.to(device_mask)\n    model_rl.to(device_rl)\n    print(f'model unet in {device_mask}, mdoel left right in {device_rl}')\n    \n    images_id, coor_outputs, levels,ori_level = [],[],[],[]\n    \n    model_mask.eval()\n    model_rl.eval()\n    with torch.no_grad():\n        for images, image_id,ori_lev in data_loader:\n            inputs_mask,input_leris = images.to(device_mask), images.to(device_rl)\n            \n            output_mask = model_mask(inputs_mask)\n            output_leris = model_rl(input_leris)\n            \n            _, preds_mask = torch.max(output_mask, 1)\n            _, preds_leris = torch.max(output_leris, 1)\n            \n            # Append NumPy arrays\n            images_id.extend(image_id) \n            coor_outputs.append(preds_mask.cpu().numpy())\n            levels.extend(preds_leris.cpu().numpy())\n            ori_level.extend(ori_lev.numpy())\n    \n    # Concatenate predictions\n    coor_outputs = np.concatenate(coor_outputs, axis=0)\n    \n    # Create DataFrame\n    df_output = pd.DataFrame({\n        'image_id': images_id,\n        'mask': list(coor_outputs),  # Ensure mask column is properly formatted\n        'level': levels,\n        'ori_level':ori_level\n    })\n    \n    return df_output\n\ndef model_plot(test_dataset, output):\n    f, ax = plt.subplots(1, 2, figsize=(13,8 ))\n    \n    img, _,_= test_dataset\n    image = img.permute(1, 2, 0)\n    #height, weight = image.shape[:2]\n\n    # Original image with label scatter plot\n    ax[0].imshow(image, cmap='gray')\n    #ax[0].imshow(mask, cmap='jet', alpha=0.5)\n        \n    # Model prediction\n    ax[1].imshow(image, cmap='gray')\n    ax[1].imshow(output,cmap='jet',alpha=0.5)\n\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.629054Z","iopub.execute_input":"2024-10-01T04:36:59.629441Z","iopub.status.idle":"2024-10-01T04:36:59.644231Z","shell.execute_reply.started":"2024-10-01T04:36:59.629397Z","shell.execute_reply":"2024-10-01T04:36:59.643359Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Conv2dReLU(nn.Module):\n    def __init__(self, in_channels, out_channels, kernel_size=3, stride=1, padding=1, use_batchnorm=True):\n        super().__init__()\n        self.conv = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding, bias=not use_batchnorm)\n        self.bn = nn.BatchNorm2d(out_channels) if use_batchnorm else nn.Identity()\n        self.relu = nn.ReLU(inplace=True)\n\n    def forward(self, x):\n        x = self.conv(x)\n        x = self.bn(x)\n        x = self.relu(x)\n        return x\n\n#class Conv2Conv\n\nclass DecoderBlock(nn.Module):\n    def __init__(self, in_channels, out_channels):\n        super(DecoderBlock, self).__init__()\n        self.conv1 = Conv2dReLU(in_channels, out_channels)\n        self.conv2 = Conv2dReLU(out_channels, out_channels)\n        \n    def forward(self, x, skip):\n        x = torch.cat([x, skip], dim=1)  # Skip connection\n        x = self.conv1(x)\n        x = self.conv2(x)\n        return x\n\nclass MobileNetV2Encoder(nn.Module):\n    def __init__(self, in_channels=1, pretrained=False):\n        super(MobileNetV2Encoder, self).__init__()\n        mobilenet_v2 = models.mobilenet_v2(pretrained=pretrained)\n        mobilenet_v2.features[0][0] = nn.Conv2d(in_channels, 32, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)\n\n        # Extract layers from the pretrained MobileNetV2\n        self.enc0 = mobilenet_v2.features[0:2]  # 32 channels    [1, 16, 128, 128]\n        self.enc1 = mobilenet_v2.features[2:4]  # 24 channels    [1, 24, 64, 64]\n        self.enc2 = mobilenet_v2.features[4:7]  # 32 channels    [1, 32, 32, 32]\n        self.enc3 = mobilenet_v2.features[7:14]  # 96 channels   [1, 96, 16, 16]\n        self.enc4 = mobilenet_v2.features[14:18]  # 320 channels  [1, 320, 8, 8]\n        self.bottleneck = mobilenet_v2.features[18:] # 1280 channels  [1, 1280, 8, 8]\n        \n\n    def forward(self, x):\n        features = []\n        x = self.enc0(x)  # Downsample 1\n        features.append(x)\n        \n        x = self.enc1(x)  # Downsample 2\n        features.append(x)\n        \n        x = self.enc2(x)  # Downsample 3\n        features.append(x)\n        \n        x = self.enc3(x)  # Downsample 4\n        features.append(x)\n        \n        x = self.enc4(x)\n        features.append(x)\n        \n        x=self.bottleneck(x)\n        return x, features\n\nclass UNetMobileNetV2(nn.Module):\n    def __init__(self, in_channels=1, out_channels=6, pretrained=True):\n        super(UNetMobileNetV2, self).__init__()\n        self.encoder = MobileNetV2Encoder(in_channels=in_channels,pretrained=pretrained)\n\n        # Bottleneck output is 1280 from MobileNetV2\n        self.bottleneck = Conv2dReLU(320, 1280)\n        \n        # Upsampling layers\n        self.upconv4 = nn.ConvTranspose2d(1280, 320, kernel_size=2, stride=2)  # Upsample to 512\n        self.upconv3 = nn.ConvTranspose2d(208, 96, kernel_size=2, stride=2)   # Upsample to 256\n        self.upconv2 = nn.ConvTranspose2d(96, 96, kernel_size=2, stride=2)   # Upsample to 128\n        self.upconv1 = nn.ConvTranspose2d(64, 64, kernel_size=2, stride=2)     # Upsample to 64\n        self.upconv0 = nn.ConvTranspose2d(32, 32, kernel_size=2, stride=2)\n\n        # Decoder\n        self.dec4 = DecoderBlock(320+96, 208)  # Decoder for bottleneck and enc3\n        self.dec3 = DecoderBlock(96+32, 96)   # Decoder for dec4 and enc2\n        self.dec2 = DecoderBlock(96+24, 64)   # Decoder for dec3 and enc1\n        self.dec1 = DecoderBlock(64+16, 32)   # Decoder for dec2 and enc0\n\n        # Final segmentation head\n        self.segmentation_head = nn.Conv2d(32, out_channels, kernel_size=1)\n\n    def forward(self, x):\n        # Encoder\n        bottleneck, features = self.encoder(x)\n       \n        x = self.upconv4(bottleneck) \n        x = self.dec4(x, features[3])  \n        \n        x = self.upconv3(x)\n        x = self.dec3(x, features[2])  \n        \n        x = self.upconv2(x)\n        x = self.dec2(x, features[1])  \n       \n        x = self.upconv1(x)\n        x = self.dec1(x, features[0]) \n        #print(f'dec4 {x.shape}')\n       \n        # Final segmentation head\n        x = self.upconv0(x) \n        x = self.segmentation_head(x)\n        return x\n\nclass subarticular_resnet(nn.Module):\n    def __init__(self, num_classes=2):\n        super(subarticular_resnet, self).__init__()\n        self.resnet = models.resnet50(pretrained=False)\n        \n        # Modify the first convolutional layer to accept 1 channel instead of 3\n        self.resnet.conv1 = nn.Conv2d(1, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)\n        \n        # Modify the fully connected layer for 2-class output\n        num_ftrs = self.resnet.fc.in_features\n        self.resnet.fc = nn.Linear(num_ftrs, num_classes)\n\n    def forward(self, x):\n        return self.resnet(x)\n    ","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.645674Z","iopub.execute_input":"2024-10-01T04:36:59.646031Z","iopub.status.idle":"2024-10-01T04:36:59.672161Z","shell.execute_reply.started":"2024-10-01T04:36:59.645990Z","shell.execute_reply":"2024-10-01T04:36:59.671253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = subarticular_lo_Dataset(train_set, img_train_path,input_size=128,transform=None)\nval_dataset = subarticular_lo_Dataset(val_set, img_train_path,input_size=128,transform=None)\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=False)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.673096Z","iopub.execute_input":"2024-10-01T04:36:59.673500Z","iopub.status.idle":"2024-10-01T04:36:59.688180Z","shell.execute_reply.started":"2024-10-01T04:36:59.673456Z","shell.execute_reply":"2024-10-01T04:36:59.687460Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_mask = UNetMobileNetV2(in_channels=1, out_channels=3, pretrained=False)\nmodel_mask.load_state_dict(torch.load('/kaggle/input/mobile_unet_128/pytorch/default/1/lo_last_sub_Unet_128.pth'))\n\nmodel_rl = subarticular_resnet(num_classes=5)\nmodel_rl.load_state_dict(torch.load('/kaggle/input/lr_sub/pytorch/default/1/lr_subarticular.pth'))","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:36:59.689078Z","iopub.execute_input":"2024-10-01T04:36:59.689394Z","iopub.status.idle":"2024-10-01T04:37:01.943532Z","shell.execute_reply.started":"2024-10-01T04:36:59.689359Z","shell.execute_reply":"2024-10-01T04:37:01.942581Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"df_mask_train = model_loc(model_mask, model_rl, train_loader)\ndf_mask_val = model_loc(model_mask, model_rl, val_loader)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:37:01.944600Z","iopub.execute_input":"2024-10-01T04:37:01.944881Z","iopub.status.idle":"2024-10-01T04:38:22.422890Z","shell.execute_reply.started":"2024-10-01T04:37:01.944849Z","shell.execute_reply":"2024-10-01T04:38:22.422081Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"_,_,i=train_dataset[3]\nprint(i)\n\nmodel_plot(train_dataset[3], df_mask_train['mask'][3])","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:22.424018Z","iopub.execute_input":"2024-10-01T04:38:22.424333Z","iopub.status.idle":"2024-10-01T04:38:22.983624Z","shell.execute_reply.started":"2024-10-01T04:38:22.424299Z","shell.execute_reply":"2024-10-01T04:38:22.982722Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model_plot(val_dataset[150], df_mask_val['mask'][150])","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:22.984963Z","iopub.execute_input":"2024-10-01T04:38:22.985663Z","iopub.status.idle":"2024-10-01T04:38:23.518949Z","shell.execute_reply.started":"2024-10-01T04:38:22.985615Z","shell.execute_reply":"2024-10-01T04:38:23.518032Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def classification_matrix(df):\n    # classification report\n    report = classification_report(df['ori_level'], df['level'])\n    print(\"Classification Report:\")\n    print(report)\n\n    # Confusion Matrix\n    cm = confusion_matrix(df['ori_level'], df['level'])\n\n    #label\n    labels=np.arange(df['level'].nunique())\n\n    # Plot Confusion Matrix\n    plt.figure(figsize=(8, 6))\n    sns.heatmap(cm, annot=True, fmt='d', cmap='Blues', \n                    xticklabels=labels, yticklabels=labels)\n    plt.xlabel('Predicted')\n    plt.ylabel('True')\n    plt.title('Confusion Matrix')\n    plt.show()\n    ","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:23.520045Z","iopub.execute_input":"2024-10-01T04:38:23.520386Z","iopub.status.idle":"2024-10-01T04:38:23.530052Z","shell.execute_reply.started":"2024-10-01T04:38:23.520350Z","shell.execute_reply":"2024-10-01T04:38:23.529177Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classification_matrix(df_mask_val)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:23.531267Z","iopub.execute_input":"2024-10-01T04:38:23.532022Z","iopub.status.idle":"2024-10-01T04:38:23.892630Z","shell.execute_reply.started":"2024-10-01T04:38:23.531975Z","shell.execute_reply":"2024-10-01T04:38:23.891711Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"classification_matrix(df_mask_train)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:23.898088Z","iopub.execute_input":"2024-10-01T04:38:23.898399Z","iopub.status.idle":"2024-10-01T04:38:24.258660Z","shell.execute_reply.started":"2024-10-01T04:38:23.898367Z","shell.execute_reply":"2024-10-01T04:38:24.257677Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"##################### train severity ########################","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:38:24.260011Z","iopub.execute_input":"2024-10-01T04:38:24.260333Z","iopub.status.idle":"2024-10-01T04:38:24.264578Z","shell.execute_reply.started":"2024-10-01T04:38:24.260298Z","shell.execute_reply":"2024-10-01T04:38:24.263538Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class SubarticularSevereDataset(Dataset):\n    def __init__(self, df, image_dir, Unet_mask_df, transform=None):\n        self.df = df\n        self.img_dir = image_dir\n        self.transform = transform\n        self.Unet_mask_df = Unet_mask_df\n        \n        # Initialize transformation if not provided\n        if self.transform is None:\n            self.transform = T.Compose([\n                T.Resize((64, 64)),  # Ensure the final size is handled correctly\n                T.ToTensor(),\n                # T.Normalize(norm_mean, norm_std)  # Uncomment if normalization is needed\n            ])\n    \n    def __len__(self):\n        return len(self.df)\n    \n    def __getitem__(self, idx):\n        # Get the image and label for the given index\n        image, label = self.get_image_label(idx)\n        \n        # Apply transformations\n        image = self.transform(image)\n        \n        image = torch.tensor(image, dtype=torch.float32)\n        label = torch.tensor(label, dtype=torch.long)\n        \n        return image, label\n    \n    def get_image_label(self, idx):\n        row = self.df.iloc[idx]\n        mask_id = row['image_id']\n        mask_row = self.Unet_mask_df[self.Unet_mask_df['image_id'] == mask_id].iloc[0]\n        \n        dicom_path = os.path.join(self.img_dir, str(row['study_id']), str(row['series_id']), f\"{str(row['instance_number'])}.dcm\")\n        dicom = pydicom.dcmread(dicom_path)\n        image = dicom.pixel_array\n        \n        # Normalize the image\n        image_normalized = np.interp(image, (0, 1810), (0, 255)).astype(np.uint8)\n        \n        # Convert to PIL Image\n        rgb_image_pil = Image.fromarray(image_normalized)\n        \n        # Resize the image using PIL\n        rgb_image_pil = rgb_image_pil.resize((128, 128), Image.BILINEAR)\n        \n        # Get cropped image\n        cropped_image = self.crop_mask(row, mask_row, rgb_image_pil)\n        \n        # Get label\n        label = row['label_array'].index(1)\n        \n        return cropped_image, label\n    \n    def crop_mask(self, row, mask_row, ori_image_pil):\n        level = row['leri_id']\n        mask_np = mask_row['mask']\n        labeled_mask = (mask_np == level).astype(int)\n        regions = regionprops(labeled_mask)\n        \n        # Initialize cropped image with zeros\n        cropped_img = np.zeros((8, 8), dtype=np.uint8)\n        \n        # Crop the image using the bounding boxes from the mask regions\n        for region in regions:\n            minr, minc, maxr, maxc = region.bbox\n            y, x = (minr + maxr) / 2, (minc + maxc) / 2\n            size_half = 8 // 2\n            x_start, x_end = max(0, x - size_half), min(ori_image_pil.width, x + size_half)\n            y_start, y_end = max(0, y - size_half), min(ori_image_pil.height, y + size_half)\n            cropped_pil_img = ori_image_pil.crop((x_start, y_start, x_end, y_end))\n            cropped_img = np.array(cropped_pil_img)\n        \n        # Ensure the image is a PIL Image if more transformations are needed\n        return Image.fromarray(cropped_img)\n","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:50:34.954832Z","iopub.execute_input":"2024-10-01T04:50:34.955512Z","iopub.status.idle":"2024-10-01T04:50:34.979117Z","shell.execute_reply.started":"2024-10-01T04:50:34.955458Z","shell.execute_reply":"2024-10-01T04:50:34.978381Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = SubarticularSevereDataset(train_set, img_train_path, df_mask_train,transform=None)\nval_dataset = SubarticularSevereDataset(val_set, img_train_path, df_mask_val, transform=None)\n\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:50:35.384752Z","iopub.execute_input":"2024-10-01T04:50:35.385339Z","iopub.status.idle":"2024-10-01T04:50:35.390829Z","shell.execute_reply.started":"2024-10-01T04:50:35.385299Z","shell.execute_reply":"2024-10-01T04:50:35.389876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img,a = train_dataset[1]\nimage = img.permute(1, 2, 0)\nprint(a)\nplt.imshow(image)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:50:38.232111Z","iopub.execute_input":"2024-10-01T04:50:38.233006Z","iopub.status.idle":"2024-10-01T04:50:38.503080Z","shell.execute_reply.started":"2024-10-01T04:50:38.232966Z","shell.execute_reply":"2024-10-01T04:50:38.502140Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"img,a = val_dataset[1]\nimage = img.permute(1, 2, 0)\nprint(a)\nplt.imshow(image)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:50:38.520588Z","iopub.execute_input":"2024-10-01T04:50:38.520891Z","iopub.status.idle":"2024-10-01T04:50:38.800302Z","shell.execute_reply.started":"2024-10-01T04:50:38.520859Z","shell.execute_reply":"2024-10-01T04:50:38.799433Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Display all images from val2_dataset on a grid\ndef show_random_dataset(val2_dataset , frac=2):\n    num_images = len(val2_dataset)\n    half_num_images = num_images // frac  # Get half the dataset\n    selected_indices = random.sample(range(num_images), half_num_images)  # Randomly select half\n\n    cols = 8  # Define the number of columns\n    rows = (half_num_images // cols) + (1 if half_num_images % cols != 0 else 0)  # Calculate number of rows\n\n    fig, axes = plt.subplots(rows, cols, figsize=(15, rows * 2))\n\n    # Flatten axes array for easy iteration\n    axes = axes.flatten()\n\n    for i, idx in enumerate(selected_indices):\n        img, label = val2_dataset[idx]\n\n        # Convert tensor image to NumPy array if necessary\n        if isinstance(img, torch.Tensor):\n            img = img.permute(1, 2, 0).numpy()  # Adjust shape from (C, H, W) to (H, W, C)\n\n        # Show image on the subplot\n        axes[i].imshow(img)\n        axes[i].set_title(f'{idx} Label: {label}')\n        axes[i].axis('off')\n\n    # Turn off remaining empty subplots\n    for j in range(i + 1, len(axes)):\n        axes[j].axis('off')\n\n    plt.tight_layout()\n    plt.show()","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:47:23.731906Z","iopub.execute_input":"2024-10-01T04:47:23.732614Z","iopub.status.idle":"2024-10-01T04:47:23.741466Z","shell.execute_reply.started":"2024-10-01T04:47:23.732564Z","shell.execute_reply":"2024-10-01T04:47:23.740574Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_random_dataset(val_dataset , frac=3)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:51:05.859502Z","iopub.execute_input":"2024-10-01T04:51:05.859890Z","iopub.status.idle":"2024-10-01T04:51:27.233899Z","shell.execute_reply.started":"2024-10-01T04:51:05.859852Z","shell.execute_reply":"2024-10-01T04:51:27.232253Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"show_random_dataset(train_dataset , frac=3)#show_all_dataset(train_dataset)","metadata":{"execution":{"iopub.status.busy":"2024-10-01T04:53:20.999247Z","iopub.execute_input":"2024-10-01T04:53:20.999909Z","iopub.status.idle":"2024-10-01T04:54:39.078227Z","shell.execute_reply.started":"2024-10-01T04:53:20.999869Z","shell.execute_reply":"2024-10-01T04:54:39.076153Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}