{"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":"!conda install gdcm -c conda-forge -y","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:25:44.758151Z","iopub.execute_input":"2021-06-22T08:25:44.758532Z","iopub.status.idle":"2021-06-22T08:26:46.006554Z","shell.execute_reply.started":"2021-06-22T08:25:44.758454Z","shell.execute_reply":"2021-06-22T08:26:46.005471Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision\nfrom torchvision import models, transforms\n\nfrom sklearn.model_selection import train_test_split\nfrom PIL import Image\nfrom tqdm import tqdm\nimport copy\nimport glob\nimport time\nimport numpy as np\nimport pandas as pd\nimport pydicom\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:26:46.008317Z","iopub.execute_input":"2021-06-22T08:26:46.008657Z","iopub.status.idle":"2021-06-22T08:26:48.073024Z","shell.execute_reply.started":"2021-06-22T08:26:46.008617Z","shell.execute_reply":"2021-06-22T08:26:48.072201Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"study_csv = pd.read_csv('../input/siim-covid19-detection/train_study_level.csv')\nstudy = study_csv.to_numpy()[:, 1:]\nX = [_id.split('_')[0] for _id in study_csv['id']]\ny = np.where(study == 1)[1]\nX_train, X_test, y_train, y_test = train_test_split(X, y, random_state=42, test_size=0.2, stratify=y)","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:26:48.074678Z","iopub.execute_input":"2021-06-22T08:26:48.074986Z","iopub.status.idle":"2021-06-22T08:26:48.112406Z","shell.execute_reply.started":"2021-06-22T08:26:48.074959Z","shell.execute_reply":"2021-06-22T08:26:48.111553Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def read_xray(path, voi_lut = True, fix_monochrome = True):\n    # Original from: https://www.kaggle.com/raddar/convert-dicom-to-np-array-the-correct-way\n    dicom = pydicom.read_file(path)\n    \n    # VOI LUT (if available by DICOM device) is used to transform raw DICOM data to \n    # \"human-friendly\" view\n    if voi_lut:\n        data = apply_voi_lut(dicom.pixel_array, dicom)\n    else:\n        data = dicom.pixel_array\n        \n    # depending on this value, X-ray may look inverted - fix that:\n    if fix_monochrome and dicom.PhotometricInterpretation == \"MONOCHROME1\":\n        data = np.amax(data) - data\n        \n    data = data - np.min(data)\n    data = data / np.max(data)\n    data = (data * 255).astype(np.uint8)\n    data = np.repeat(data[..., np.newaxis], 3, -1)\n         \n    return data","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:36:30.796714Z","iopub.execute_input":"2021-06-22T08:36:30.797061Z","iopub.status.idle":"2021-06-22T08:36:30.804993Z","shell.execute_reply.started":"2021-06-22T08:36:30.797028Z","shell.execute_reply":"2021-06-22T08:36:30.804161Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Covid19Dataset(Dataset):\n    def __init__(self, root_dir, studies, labels, transform):\n        self.root_dir = root_dir\n        self.image_paths = []\n        self.labels = []\n        self.transform = transform\n        \n        for study, label in tqdm(zip(studies, labels)):\n            p = f'{root_dir}/{study}/*/*'\n            images = glob.glob(p)\n            self.image_paths += images\n            self.labels += [label] * len(images)\n            \n        assert len(self.image_paths) == len(self.labels)\n        \n    def __len__(self):\n        return len(self.image_paths)\n    \n    def __getitem__(self, idx):\n        path = self.image_paths[idx]\n        label = self.labels[idx]\n        \n        pixel_array = read_xray(path)\n        image = Image.fromarray(pixel_array)\n        image = self.transform(image)\n        \n        return image, label","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:26:48.1227Z","iopub.execute_input":"2021-06-22T08:26:48.123099Z","iopub.status.idle":"2021-06-22T08:26:48.132718Z","shell.execute_reply.started":"2021-06-22T08:26:48.123061Z","shell.execute_reply":"2021-06-22T08:26:48.13162Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def train_model(model, dataloaders, criterion, optimizer, num_epochs):\n    since = time.time()\n\n    val_acc_history = []\n\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                model.train()  # Set model to training mode\n            else:\n                model.eval()   # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n\n            # Iterate over data.\n            for inputs, labels in tqdm(dataloaders[phase]):\n                inputs = inputs.to(device)\n                labels = labels.to(device)\n\n                # zero the parameter gradients\n                optimizer.zero_grad()\n\n                # forward\n                # track history if only in train\n                with torch.set_grad_enabled(phase == 'train'):\n                    # Get model outputs and calculate loss\n                    outputs = model(inputs)\n                    loss = criterion(outputs, labels)\n                    _, preds = torch.max(outputs, 1)\n\n                    # backward + optimize only if in training phase\n                    if phase == 'train':\n                        loss.backward()\n                        optimizer.step()\n\n                # statistics\n                running_loss += loss.item() * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / len(dataloaders[phase].dataset)\n            epoch_acc = running_corrects.double() / len(dataloaders[phase].dataset)\n\n            print('{} Loss: {:.4f} Acc: {:.4f}'.format(phase, epoch_loss, epoch_acc))\n\n            # deep copy the model\n            if phase == 'val' and epoch_acc > best_acc:\n                best_acc = epoch_acc\n                best_model_wts = copy.deepcopy(model.state_dict())\n            if phase == 'val':\n                val_acc_history.append(epoch_acc)\n\n        print()\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))\n    print('Best val Acc: {:4f}'.format(best_acc))\n\n    # load best model weights\n    model.load_state_dict(best_model_wts)\n    return model, val_acc_history\n\ndef initialize_model(num_classes):\n    model = models.resnet50(pretrained=True)\n    num_ftrs = model.fc.in_features\n    model.fc = nn.Linear(num_ftrs, num_classes)\n    return model","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:26:48.134014Z","iopub.execute_input":"2021-06-22T08:26:48.134556Z","iopub.status.idle":"2021-06-22T08:26:48.153192Z","shell.execute_reply.started":"2021-06-22T08:26:48.134508Z","shell.execute_reply":"2021-06-22T08:26:48.152327Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"transform = transforms.Compose([\n    transforms.Resize((800, 800)),\n    transforms.ToTensor(),\n])\n\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\ntrain_set = Covid19Dataset('../input/siim-covid19-detection/train', X_train, y_train, transform)\nval_set = Covid19Dataset('../input/siim-covid19-detection/train', X_test, y_test, transform)\ndataloaders = {\n    'train': DataLoader(train_set, batch_size=4, shuffle=True),\n    'val': DataLoader(val_set, batch_size=4, shuffle=True),\n}","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:26:48.154671Z","iopub.execute_input":"2021-06-22T08:26:48.155058Z","iopub.status.idle":"2021-06-22T08:27:11.030998Z","shell.execute_reply.started":"2021-06-22T08:26:48.155009Z","shell.execute_reply":"2021-06-22T08:27:11.029844Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Number of classes in the dataset\nnum_classes = 4\n\n# Number of epochs to train for\nnum_epochs = 5\n\nmodel = initialize_model(num_classes)\nmodel = model.to(device)\noptimizer = optim.SGD(model.parameters(), lr=0.001, momentum=0.9)\ncriterion = nn.CrossEntropyLoss()\nmodel, hist = train_model(model, dataloaders, criterion, optimizer, num_epochs=num_epochs)\ntorch.save(model.state_dict(), 'resnet50.pt')","metadata":{"execution":{"iopub.status.busy":"2021-06-22T08:37:31.361154Z","iopub.execute_input":"2021-06-22T08:37:31.361492Z"},"trusted":true},"execution_count":null,"outputs":[]}]}