{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":71549,"databundleVersionId":8561470,"sourceType":"competition"}],"dockerImageVersionId":30732,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nimport numpy as np\nimport pandas as pd\nimport torch\nimport os\nimport pydicom\n\nzero1 = torch.zeros((0, 60, 588, 416))\n# zero2 = torch.zeros((1, 60, 588, 416))\n# print(torch.cat((zero1, zero2), dim=0).shape)\n\nlengthArray = []\ntrain_path = \"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images\"\nfor study in os.listdir(train_path)[:20]:\n    studyArray = torch.zeros((0, 60, 588, 416))\n    for series in os.listdir(os.path.join(train_path, study)):\n        lengthArray.append(len(os.listdir(os.path.join(os.path.join(train_path, study), series))))\n#         seriesArray = torch.zeros((60, 588, 416))\n#         i = 0\n#         for instance in os.listdir(os.path.join(os.path.join(train_path, study), series)):\n#             print(os.path.join(os.path.join(os.path.join(train_path, study), series), instance))\n#             instance_dicom = pydicom.dcmread(os.path.join(os.path.join(os.path.join(train_path, study), series), instance))\n#             instance_data = torch.from_numpy(instance_dicom.pixel_array.astype(np.uint8))\n# #             instance_data = instance_data.expand_dims(axis = 0).\n#             print(type(instance_data))\n#             print(instance_data.shape)\n#             seriesArray[i] = instance_data\n# #             seriesArray = torch.cat((seriesArray, instance_data), dim = 0)\n#             i += 1\n#         seriesArray = seriesArray.expand_dims(axis = 0).\n#         studyArray = torch.cat((studyArray, seriesArray), dim = 0)\n    print(studyArray)\n\nplt.plot(np.arange(len(lengthArray)), sorted(lengthArray))","metadata":{"execution":{"iopub.status.busy":"2024-06-19T10:48:44.210661Z","iopub.execute_input":"2024-06-19T10:48:44.211094Z","iopub.status.idle":"2024-06-19T10:48:45.106526Z","shell.execute_reply.started":"2024-06-19T10:48:44.211061Z","shell.execute_reply":"2024-06-19T10:48:45.105413Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\nimport torch\nimport numpy as np\nimport pandas as pd\n\ntsdDF = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv\")\nprint(tsdDF[(tsdDF[\"study_id\"] == 1737682527) & (tsdDF[\"series_id\"] == 2291122880)])\n\nmyImage = pydicom.dcmread(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/1737682527/2291122880/12.dcm\")\nplt.imshow(myImage.pixel_array, cmap = \"Blues_r\")\nprint(myImage.pixel_array.shape)\ndata = torch.from_numpy(myImage.pixel_array.astype(np.uint8))\nprint(data.shape)","metadata":{"execution":{"iopub.status.busy":"2024-06-19T10:40:03.366333Z","iopub.execute_input":"2024-06-19T10:40:03.367146Z","iopub.status.idle":"2024-06-19T10:40:03.669614Z","shell.execute_reply.started":"2024-06-19T10:40:03.367111Z","shell.execute_reply":"2024-06-19T10:40:03.668165Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import pydicom\nimport matplotlib.pyplot as plt\nimport torch\nfrom torch import nn\nimport numpy as np\nimport pandas as pd\nimport os\nimport glob\nimport scipy.ndimage\n\ndef load_dicom(filename):\n    ds = pydicom.dcmread(filename)\n    return ds.pixel_array\n\ndef load_dicom_line(path):\n    t_paths = sorted(\n        glob.glob(os.path.join(path, \"*\")), \n        key=lambda x: int(os.path.splitext(os.path.basename(x))[0].split(\"-\")[-1]),\n    )\n    images = []\n    for filename in t_paths:\n        data = load_dicom(filename)\n        if data.max() == 0:\n            continue\n        images.append(data)\n    return images\n\ndef imageReshape(arr, shapeArr):\n    zoom_factors = [n / o for n, o in zip(shapeArr, arr.shape)]\n\n    # Resize the array using interpolation\n    resized_array = scipy.ndimage.zoom(arr, zoom_factors)\n\n    return resized_array\n\ndef getArrayFromDicoms(dicomList):\n    seriesArray = np.zeros((0, dicomList[0].shape[0], dicomList[0].shape[1]))\n    for image in dicomList:\n        seriesArray = np.concatenate((seriesArray, np.expand_dims(imageReshape(image, (dicomList[0].shape[0], dicomList[0].shape[1])), axis = 0)), axis = 0)\n    return imageReshape(seriesArray, (34, 512, 512))\n\nclass AxialDataset(torch.utils.data.Dataset):\n    def __init__(self, train_df, train_series, test):\n        train_df = train_df.reset_index(drop = True)\n        print(\"Dataset object initiated\")\n        if not test:\n            #study_id    condition1    ...    condition25\n            #train_df is in wide format. Convert to long\n            train_df = pd.melt(train_df, id_vars = ['study_id'], var_name = 'Condition', value_name = 'Severity')\n        #study_id    Condition    Severity\n        #We should one hot encode this dataset here.\n            train_df = pd.get_dummies(train_df, columns = ['Severity', 'Condition'])\n        #study_id  Severity_Moderate  Severity_Normal/Mild Severity_Severe  Condition1  Condition2  ...  Condition25\n        else:\n            #row_id severity2 severity1 severity3\n            train_df[['study_id', 'Condition']] = train_df['row_id'].str.split(pat = '_', n = 1, expand = True)\n            train_df['study_id'] = train_df['study_id'].astype(int)\n            #row_id severity2 severity1 severity3 study_id condition\n            train_df = train_df.drop('row_id', axis = 1)\n            train_df = pd.get_dummies(train_df, columns = ['Condition'])\n            \n            #severity2 severity1 severity3 study_id condition1 ... condition25\n            cols = list(train_df.columns)\n            cols = [cols[3], cols[1], cols[0], cols[2]] + cols[4:]\n            train_df = train_df[cols]\n        #study_id  Severity_Moderate  Severity_Normal/Mild Severity_Severe  Condition1  Condition2  ...  Condition25\n        imagesArray = np.zeros((0, 1, 34, 512, 512))\n        for i in range(train_df.shape[0]):\n            print(f\"Reading test? {test}, iteration {i}\")\n            temp = train_df['study_id'][i]\n            \n            series_id = train_series[\n                (train_series['study_id'] == train_df['study_id'][i]) & (train_series['series_description'] == \"Axial T2\")\n            ].reset_index(drop = 1)['series_id'][0]\n            if test:\n                \n                imagesArray = np.concatenate(\n                    (\n                        imagesArray, \n                        np.expand_dims(\n                            getArrayFromDicoms(\n                                load_dicom_line(\n                                    f\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_images/{train_df['study_id'][i]}/{series_id}\"\n                                )\n                            )/255,\n                            axis = (0, 1)\n                        )\n                    ), \n                    axis = 0\n                )\n            else:\n                imagesArray = np.concatenate(\n                    (\n                        imagesArray,\n                        np.expand_dims(\n                            getArrayFromDicoms(\n                                load_dicom_line(\n                                    f\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/{train_df['study_id'][i]}/{series_id}\"\n                                )\n                            )/255,\n                            axis = (0, 1)\n                        )\n                    ), \n                    axis = 0\n                )\n        self.imageTensor = torch.Tensor(imagesArray)\n        self.conditionTensor = torch.Tensor(train_df.iloc[:, 4:].to_numpy())\n        self.outputTensor = torch.Tensor(train_df.iloc[:, 1:4].to_numpy())\n#   Image    Condition1to25    Severity1to3\n# One for each study, repeated over 25 conditions.\n#Could optimise this with an image lookup table.\n    def __len__(self):\n        return len(self.imageTensor)\n\n    def __getitem__(self, idx):\n        return self.imageTensor[idx], self.conditionTensor[idx], self.outputTensor[idx]\n\n\nclass NeuralNetwork(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.convolutionStack = nn.Sequential(\n            nn.Conv3d(1, 6, (5, 15, 15)),\n            #(6, 30, 498, 498)\n            nn.MaxPool3d(2),\n            #(6, 15, 249, 249)\n            nn.Conv3d(6, 16, (5, 15, 15)),\n            #(16, 11, 235, 235)\n            nn.MaxPool3d(2),\n            #(16, 5, 117, 117)\n            nn.Conv3d(16, 32, (3, 55, 55)),\n            #(32, 3, 63, 63)\n            nn.MaxPool3d(2),\n            #(32, 1, 31, 31)\n            nn.Flatten(),\n            #32*31*31\n        )\n        self.linear_relu_stack = nn.Sequential(\n            nn.Linear(31*31*32+25, 128),\n            nn.ReLU(),\n            nn.Linear(128, 64),\n            nn.ReLU(),\n            nn.Dropout(p=0.1),\n            nn.Linear(64, 32),\n            nn.ReLU(),\n            nn.Dropout(p=0.1),\n            nn.Linear(32, 16),\n            nn.ReLU(),\n            nn.Dropout(p=0.1),\n            nn.Linear(16, 8),\n            nn.ReLU(),\n            nn.Dropout(p=0.1),\n            nn.Linear(8, 3),\n            nn.Softmax(dim = 0),\n        )\n\n    def forward(self, x, y):\n        # x = self.flatten(x)\n        print(y.shape)\n        logits = self.convolutionStack(x)\n        print(logits.shape)\n        logits = self.linear_relu_stack(torch.cat((logits, y), dim = 1))\n        return logits\n\ndef train_loop(myLoader, model, loss_fn, optimizer, epochIndex):\n    running_loss = 0\n    model.train(True)\n    i = 0\n    for x1, y1, z1 in myLoader:\n        pred = model(x1, y1)\n        loss = loss_fn(pred, z1)\n\n        loss.backward()\n        optimizer.step()\n        optimizer.zero_grad()\n\n        print('  batch {} loss: {}'.format(i + 1, loss.item()))\n        running_loss += loss.item()\n        i += 1\n    return running_loss/i\n\ndef validation_loop(myLoader, model, loss_fn, optimizer, epochIndex):\n    running_loss = 0.\n    i = 0\n    model.eval()\n    for x1, y1, z1 in myLoader:\n        pred = model(x1, y1)\n        loss = loss_fn(pred, z1)\n\n\n        print('  batch {} validation loss: {}'.format(i + 1, loss.item()))\n        running_loss += loss.item()\n        i += 1\n    return running_loss/i\n\ndef make_submission(myDataset, model, dfSample):\n    running_loss = 0.\n    i = 0\n    model.eval()\n    with torch.no_grad():\n        for x1, y1, z1 in myDataset:\n            z1 = model(x1.unsqueeze(0), y1)\n    \n    dfSample.iloc[:, -3:] = pd.DataFrame(myDataset.outputTensor.numpy(), columns = list(dfSample.columns)[-3:])\n    #Replace -3 and -2\n    dfSample.iloc[-3, :], dfSample.iloc[-2, :] = dfSample.iloc[-2, :], dfSample.iloc[-3, :]\n#     dfSample = dfSample[(lambda x: x[:-3] + [x[-2]] + [x[-3]] + [x[-1]])(list(dfSample.columns))]\n    dfSample.to_csv(\"submission.csv\", index = False)\n\ntrain_series = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_series_descriptions.csv\")\ntrain_df = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train.csv\")\n# train_df = pd.concat((train_df[train_df['spinal_canal_stenosis_l1_l2'] == 'Severe'].sample(1), train_df[train_df['spinal_canal_stenosis_l1_l2'] == 'Moderate'].sample(1)))\ntest_df = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/sample_submission.csv\")\ntest_series = pd.read_csv(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/test_series_descriptions.csv\")\nprint(train_df.shape)\ntrainDataset = AxialDataset(train_df, train_series, test = 0)\ntrainDataLoader = torch.utils.data.DataLoader(trainDataset, batch_size = 64, shuffle = True)\nprint(\"Dataset 1 initialised\")\ntestDataset = AxialDataset(test_df, test_series, test = 1)\ntestDataLoader = torch.utils.data.DataLoader(testDataset, batch_size = 64, shuffle = True)\nprint(\"Dataset 2 initialised\")\n\nmodel = NeuralNetwork()\nprint(\"Neural network initialised\")\nfor epoch in range(20):\n    loss_fn = nn.CrossEntropyLoss()\n    learning_rate = 0.001\n    optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n    print('EPOCH {}:'.format(epoch+1))\n\n    avg_loss = train_loop(trainDataLoader, model, loss_fn, optimizer, epoch)\n    avg_vloss = validation_loop(trainDataLoader, model, loss_fn, optimizer, epoch)\n    \n    print('LOSS train {} valid {}'.format(avg_loss, avg_vloss))\n\nmake_submission(testDataLoader, model, test_df)","metadata":{"execution":{"iopub.status.busy":"2024-06-23T14:53:52.687410Z","iopub.execute_input":"2024-06-23T14:53:52.688014Z","iopub.status.idle":"2024-06-23T14:58:17.694817Z","shell.execute_reply.started":"2024-06-23T14:53:52.687972Z","shell.execute_reply":"2024-06-23T14:58:17.691790Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import matplotlib.pyplot as plt\nprint(pydicom.dcmread(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/74782131/3401861580/22.dcm\").pixel_array.shape)\nprint(pydicom.dcmread(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/74782131/3401861580/25.dcm\").pixel_array.shape)","metadata":{"execution":{"iopub.status.busy":"2024-06-23T14:12:49.791861Z","iopub.execute_input":"2024-06-23T14:12:49.792427Z","iopub.status.idle":"2024-06-23T14:12:49.846354Z","shell.execute_reply.started":"2024-06-23T14:12:49.792386Z","shell.execute_reply":"2024-06-23T14:12:49.844880Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"#### 16, 15?, 12, 16, 26, 4, 60","metadata":{}},{"cell_type":"code","source":"x = np.array([1, 2])\ny = np.expand_dims(x, axis=(2, 1))\ny","metadata":{"execution":{"iopub.status.busy":"2024-06-23T11:44:16.714761Z","iopub.execute_input":"2024-06-23T11:44:16.715232Z","iopub.status.idle":"2024-06-23T11:44:16.723957Z","shell.execute_reply.started":"2024-06-23T11:44:16.715197Z","shell.execute_reply":"2024-06-23T11:44:16.722504Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(pydicom.dcmread(\"/kaggle/input/rsna-2024-lumbar-spine-degenerative-classification/train_images/100206310/1012284084/1.dcm\").pixel_array)","metadata":{"execution":{"iopub.status.busy":"2024-06-23T11:59:51.704217Z","iopub.execute_input":"2024-06-23T11:59:51.704844Z","iopub.status.idle":"2024-06-23T11:59:51.731275Z","shell.execute_reply.started":"2024-06-23T11:59:51.704795Z","shell.execute_reply":"2024-06-23T11:59:51.729876Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}