{"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":"import os\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom pydicom import dcmread\nfrom PIL import Image\nimport matplotlib.pyplot as plt\nfrom tqdm import tqdm\n\n\nimport torch\nimport torch.nn as nn\nimport torchvision\nimport torchvision.transforms as transforms\nfrom torch.utils import data","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:35.915180Z","iopub.execute_input":"2022-07-08T08:36:35.915552Z","iopub.status.idle":"2022-07-08T08:36:38.387219Z","shell.execute_reply.started":"2022-07-08T08:36:35.915465Z","shell.execute_reply":"2022-07-08T08:36:38.386446Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preparing labels","metadata":{}},{"cell_type":"code","source":"label_data = pd.read_csv('../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\ncolumns = ['patientId', 'Target']\n\nlabel_data = label_data.filter(columns)\nlabel_data.head(5)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:38.389136Z","iopub.execute_input":"2022-07-08T08:36:38.389601Z","iopub.status.idle":"2022-07-08T08:36:38.464864Z","shell.execute_reply.started":"2022-07-08T08:36:38.389563Z","shell.execute_reply":"2022-07-08T08:36:38.463946Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Dividing labels for train and validation set","metadata":{}},{"cell_type":"code","source":"train_labels, val_labels = train_test_split(label_data.values, test_size=0.1)\nprint(train_labels.shape)\nprint(val_labels.shape)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:38.466226Z","iopub.execute_input":"2022-07-08T08:36:38.466571Z","iopub.status.idle":"2022-07-08T08:36:38.478342Z","shell.execute_reply.started":"2022-07-08T08:36:38.466534Z","shell.execute_reply":"2022-07-08T08:36:38.477303Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(f'patientId: {train_labels[0][0]}, Target: {train_labels[0][1]}')","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:38.479752Z","iopub.execute_input":"2022-07-08T08:36:38.480126Z","iopub.status.idle":"2022-07-08T08:36:38.485377Z","shell.execute_reply.started":"2022-07-08T08:36:38.480092Z","shell.execute_reply":"2022-07-08T08:36:38.484379Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Preparing train and validation image paths","metadata":{}},{"cell_type":"code","source":"train_f = '../input/rsna-pneumonia-detection-challenge/stage_2_train_images'\ntest_f = '../input/rsna-pneumonia-detection-challenge/stage_2_test_images'\n\ntrain_paths = [os.path.join(train_f, image[0]) for image in train_labels]\nval_paths = [os.path.join(train_f, image[0]) for image in val_labels]\n\nprint(len(train_paths))\nprint(len(val_paths))","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:38.489185Z","iopub.execute_input":"2022-07-08T08:36:38.489542Z","iopub.status.idle":"2022-07-08T08:36:38.569210Z","shell.execute_reply.started":"2022-07-08T08:36:38.489507Z","shell.execute_reply":"2022-07-08T08:36:38.568565Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Show some samples from data","metadata":{}},{"cell_type":"code","source":"def imshow(num_to_show=9):\n    \n    plt.figure(figsize=(10,10))\n    \n    for i in range(num_to_show):\n        plt.subplot(3, 3, i+1)\n        plt.grid(False)\n        plt.xticks([])\n        plt.yticks([])\n        \n        img_dcm = dcmread(f'{train_paths[i+20]}.dcm')\n        img_np = img_dcm.pixel_array\n        plt.imshow(img_np, cmap=plt.cm.binary)\n        plt.xlabel(train_labels[i+20][1])\n\nimshow()","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:38.570654Z","iopub.execute_input":"2022-07-08T08:36:38.570990Z","iopub.status.idle":"2022-07-08T08:36:39.666380Z","shell.execute_reply.started":"2022-07-08T08:36:38.570957Z","shell.execute_reply":"2022-07-08T08:36:39.663717Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Composing transformations","metadata":{}},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.RandomHorizontalFlip(),\n    transforms.Resize(224),\n    transforms.ToTensor()])","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:39.667408Z","iopub.execute_input":"2022-07-08T08:36:39.667736Z","iopub.status.idle":"2022-07-08T08:36:39.673035Z","shell.execute_reply.started":"2022-07-08T08:36:39.667702Z","shell.execute_reply":"2022-07-08T08:36:39.672168Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Write a custom dataset ","metadata":{}},{"cell_type":"code","source":"class Dataset(data.Dataset):\n    \n    def __init__(self, paths, labels, transform=None):\n        self.paths = paths\n        self.labels = labels\n        self.transform = transform\n    \n    def __getitem__(self, index):\n        image = dcmread(f'{self.paths[index]}.dcm')\n        image = image.pixel_array\n        image = image / 255.0\n\n        image = (255*image).clip(0, 255).astype(np.uint8)\n        image = Image.fromarray(image).convert('RGB')\n\n        label = self.labels[index][1]\n        \n        if self.transform is not None:\n            image = self.transform(image)\n            \n        return image, label\n    \n    def __len__(self):\n        \n        return len(self.paths)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:39.674380Z","iopub.execute_input":"2022-07-08T08:36:39.675209Z","iopub.status.idle":"2022-07-08T08:36:39.767725Z","shell.execute_reply.started":"2022-07-08T08:36:39.675170Z","shell.execute_reply":"2022-07-08T08:36:39.766889Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Check the custom dataset","metadata":{}},{"cell_type":"code","source":"train_dataset = Dataset(train_paths, train_labels, transform=transform)\nimage = iter(train_dataset)\nimg, label = next(image)\nprint(f'Tensor:{img}, Label:{label}')\nimg = np.transpose(img, (1, 2, 0))\nplt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:39.769392Z","iopub.execute_input":"2022-07-08T08:36:39.769802Z","iopub.status.idle":"2022-07-08T08:36:40.032942Z","shell.execute_reply.started":"2022-07-08T08:36:39.769765Z","shell.execute_reply":"2022-07-08T08:36:40.031959Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Train image shape","metadata":{}},{"cell_type":"code","source":"img.shape","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:40.034355Z","iopub.execute_input":"2022-07-08T08:36:40.034707Z","iopub.status.idle":"2022-07-08T08:36:40.040810Z","shell.execute_reply.started":"2022-07-08T08:36:40.034672Z","shell.execute_reply":"2022-07-08T08:36:40.039804Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Prepare training and validation dataloader","metadata":{}},{"cell_type":"code","source":"train_dataset = Dataset(train_paths, train_labels, transform=transform)\nval_dataset = Dataset(val_paths, val_labels, transform=transform)\ntrain_loader = data.DataLoader(dataset=train_dataset, batch_size=128, shuffle=True)\nval_loader = data.DataLoader(dataset=val_dataset, batch_size=128, shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:40.042230Z","iopub.execute_input":"2022-07-08T08:36:40.042585Z","iopub.status.idle":"2022-07-08T08:36:40.050045Z","shell.execute_reply.started":"2022-07-08T08:36:40.042550Z","shell.execute_reply":"2022-07-08T08:36:40.048968Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Check dataloader","metadata":{}},{"cell_type":"code","source":"batch = iter(train_loader)\nimages, labels = next(batch)\n\nimage_grid = torchvision.utils.make_grid(images[:4])\nimage_np = image_grid.numpy()\nimg = np.transpose(image_np, (1, 2, 0))\nplt.imshow(img)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:40.051474Z","iopub.execute_input":"2022-07-08T08:36:40.052074Z","iopub.status.idle":"2022-07-08T08:36:44.617215Z","shell.execute_reply.started":"2022-07-08T08:36:40.052039Z","shell.execute_reply":"2022-07-08T08:36:44.616293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Specify device object","metadata":{}},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:44.618793Z","iopub.execute_input":"2022-07-08T08:36:44.619151Z","iopub.status.idle":"2022-07-08T08:36:44.706195Z","shell.execute_reply.started":"2022-07-08T08:36:44.619109Z","shell.execute_reply":"2022-07-08T08:36:44.705284Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Load pre-trained ResNet18 and fine-tune","metadata":{}},{"cell_type":"code","source":"model = torchvision.models.resnet18(pretrained=True)\nnum_ftrs = model.fc.in_features\n# Here the size of each output sample is set to 2.\n# Alternatively, it can be generalized to nn.Linear(num_ftrs, len(class_names)).\nmodel.fc = nn.Linear(num_ftrs, 2)\n\nmodel.to(device)\n\ncriterion = nn.CrossEntropyLoss()\n\n# Observe that all parameters are being optimized\noptimizer = torch.optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\n\n# Decay LR by a factor of 0.1 every 7 epochs\nexp_lr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.1)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:44.707741Z","iopub.execute_input":"2022-07-08T08:36:44.708376Z","iopub.status.idle":"2022-07-08T08:36:49.682839Z","shell.execute_reply.started":"2022-07-08T08:36:44.708290Z","shell.execute_reply":"2022-07-08T08:36:49.681967Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"print(model)","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:49.684098Z","iopub.execute_input":"2022-07-08T08:36:49.684432Z","iopub.status.idle":"2022-07-08T08:36:49.693037Z","shell.execute_reply.started":"2022-07-08T08:36:49.684398Z","shell.execute_reply":"2022-07-08T08:36:49.691944Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Write a train code and RUN","metadata":{}},{"cell_type":"code","source":"num_epochs = 20\n# Train the model\ntotal_step = len(train_loader)\nfor epoch in range(num_epochs):\n    # Training step\n    for i, (images, labels) in tqdm(enumerate(train_loader)):\n        images = images.to(device)\n        labels = labels.to(device)\n        \n        # Forward pass\n        outputs = model(images)\n        loss = criterion(outputs, labels)\n        \n        # Backward and optimize\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n        \n        if (i+1) % 2000 == 0:\n            \n            print(\"Epoch [{}/{}], Step [{}/{}], Loss: {:.4f}\"\n                   .format(epoch+1, num_epochs, i+1, total_step, loss.item()))\n\n\n    # Validation step\n    correct = 0\n    total = 0  \n    for images, labels in tqdm(val_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        predictions = model(images)\n        _, predicted = torch.max(predictions, 1)\n        total += labels.size(0)\n        correct += (labels == predicted).sum()\n    print(f'Epoch: {epoch+1}/{num_epochs}, Val_Acc: {100*correct/total}')","metadata":{"execution":{"iopub.status.busy":"2022-07-08T08:36:49.694844Z","iopub.execute_input":"2022-07-08T08:36:49.695653Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"## Test model","metadata":{}},{"cell_type":"code","source":"model.eval()\n\ncorrect = 0\ntotal = 0  \nfor images, labels in tqdm(val_loader):\n    images = images.to(device)\n    labels = labels.to(device)\n    predictions = model(images)\n    _, predicted = torch.max(predictions, 1)\n    total += labels.size(0)\n    correct += (labels == predicted).sum()\nprint(f'Val_Acc: {100*correct/total}')","metadata":{"trusted":true},"execution_count":null,"outputs":[]}]}