{"cells":[{"metadata":{},"cell_type":"markdown","source":"<h2 align=center style=\"color:red; border:1px dotted red\">Chest X-ray - Faster RCNN</h2>"},{"metadata":{},"cell_type":"markdown","source":"<pre>\n\n                 .=.\n         .---._.-.=.-._.---.\n        / ':-(_.-: :-._)-:` \\\n       / /' (__.-: :-.__) `\\ \\\n      / /  (___.-` '-.___)  \\ \\\n     / /   (___.-'^`-.___)   \\ \\\n    / /    (___.-'=`-.___)    \\ \\\n   / /     (____.'=`.____)     \\ \\\n  / /       (___.'=`.___)       \\ \\\n (_.;       `---'.=.`---'       ;._)\n</pre>\n\n### By Alin Cijov"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":true},"cell_type":"code","source":"import numpy as np\nimport pandas as pd\nimport pydicom\nimport time\n\nimport torch\nimport torchvision\nimport torchvision.transforms as T\nfrom collections import defaultdict, deque\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor\nfrom torchvision.models.detection import FasterRCNN\n\nimport cv2\nimport os\n\nfrom PIL import Image\nfrom skimage import exposure\nfrom pydicom.pixel_data_handlers.util import apply_voi_lut\nimport matplotlib.pyplot as plt\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"path = '../input/vinbigdata-chest-xray-abnormalities-detection/'\ndf = pd.read_csv(path + 'train.csv')\ndf.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# replace NaN by 0\ndf = df.fillna(0)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 align=center style=\"color:red; border:1px dotted red\">Dataset</h2>"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"class XrayDataset(object):\n    def __init__(self, df, path, transforms=None):\n        # select only those classes that have boxes\n        self.df = df[df['class_name'] != 'No finding']\n        self.transforms = transforms\n        self.categories = df['class_name'].unique()\n        self.idx_to_categories = {k:v for k,v in enumerate(self.categories)}\n        self.categories_to_idx = {v:k for k,v in enumerate(self.categories)}\n        self.images_paths = path + \"train/\" + df['image_id'] + \".dicom\"\n        self.boxes = self.df[['x_min','y_min','x_max','y_max']]\n        \n    def __len__(self):\n        return len(self.images_paths)\n    \n    \n    def get_image(self, dicom):\n        intercept = dicom.RescaleIntercept if \"RescaleIntercept\" in dicom else 0.0\n        slope = dicom.RescaleSlope if \"RescaleSlope\" in dicom else 1.0\n        image = apply_voi_lut(dicom.pixel_array, dicom)\n        if dicom.PhotometricInterpretation == \"MONOCHROME1\":\n            image = np.amax(image) - image\n        \n        if slope != 1:\n            image = slope * image.astype(np.float64)\n            image = image.astype(np.int16)\n            \n        image = np.stack([image, image, image])\n        image = image - np.min(image)\n\n        image = image / image.max()\n        image = exposure.equalize_hist(image)\n        image = image.astype('float32')\n\n        image = image.transpose(1,2,0)\n        \n        return image\n    \n    def __getitem__(self, idx):\n        dicom = pydicom.read_file(self.images_paths.iloc[idx])\n        img = self.get_image(dicom)\n        \n        boxes = np.expand_dims(self.boxes.iloc[idx].values, axis=0)\n        area = (boxes[:, 3] - boxes[:, 1]) * (boxes[:, 2] - boxes[:, 0])\n        \n        target = {}\n        target['boxes'] = torch.tensor(boxes)\n        target['labels'] = torch.tensor([self.categories_to_idx[self.df.iloc[idx].class_name]])\n        target['area'] = torch.as_tensor(area, dtype=torch.float32)\n        target['iscrowd'] = torch.zeros((self.df.iloc[idx].shape[0],), dtype=torch.int64)\n        \n        if self.transforms is not None:\n            img = self.transforms(img)\n        \n        return img, target","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_transform(train, dim_size):\n    transforms = []\n    transforms.append(T.ToTensor())\n    if train:\n        transforms.append(T.Resize(dim_size))\n        transforms.append(T.RandomHorizontalFlip(0.5))\n    return T.Compose(transforms)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dim_size = (256, 256)\nxrayds = XrayDataset(df, path, get_transform(train=True, dim_size=dim_size))\n\nimg, target = xrayds[100]\nplt.imshow(img.permute(1, 2, 0))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"num_classes = len(xrayds.categories)\n\ndataset = XrayDataset(df, path, get_transform(train=True, dim_size=dim_size))\ndataset_test = XrayDataset(df, path, get_transform(train=True, dim_size=dim_size))\n\n# use only 100 dicom files for demo\nnr_dicom = 100\nindices = torch.randperm(nr_dicom).tolist()\ndataset = torch.utils.data.Subset(dataset, indices)\n\n\ndef collate_fn(batch):\n    return list(zip(*batch))\n\n# define training and validation data loaders\ndata_loader = torch.utils.data.DataLoader(\n    dataset, batch_size=2, shuffle=True, num_workers=4,\n    collate_fn=collate_fn)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 align=center style=\"color:red; border:1px dotted red\">Training</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\n\nmodel = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)\n\n# get number of input features for the classifier\nin_features = model.roi_heads.box_predictor.cls_score.in_features\n\n# replace the pre-trained head with a new one\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes)\n\nmodel = model.to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"params = [p for p in model.parameters() if p.requires_grad]\n\noptimizer = torch.optim.SGD(params, lr=0.0001,\n                            momentum=0.9, weight_decay=0.0001)\n\nlr_scheduler = torch.optim.lr_scheduler.StepLR(optimizer,\n                                               step_size=3,\n                                               gamma=0.1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loss_epoch = []\nfor epoch in range(5):\n    \n    loss_iteration = []\n    for i, (images, targets) in enumerate(data_loader):\n        \n        images = list(image.to(device).type(torch.cuda.FloatTensor) for image in images)\n        targets = [{k: v.to(device) for k, v in t.items()} for t in targets]\n\n        loss_dict = model(images, targets)\n\n        losses = sum(loss for loss in loss_dict.values())\n        loss_value = losses.item()\n        loss_iteration.append(loss_value)\n\n        optimizer.zero_grad()\n        losses.backward()\n        optimizer.step()\n\n        if i % 10 == 0:\n            print(\"Epoch:{:4d}, Iteration:{:4d}, Loss:{:4.4f}\"\n                  .format(epoch, i, loss_iteration[-1]))\n            \n    loss_epoch.append(np.array(loss_iteration).mean())\n    \n    if lr_scheduler is not None:\n        lr_scheduler.step()","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<h2 align=center style=\"color:red; border:1px dotted red\">Analyze</h2>"},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.figure(figsize=(14,7))\nplt.xlabel('Epoch', fontsize=15)\nplt.ylabel('Loss', fontsize=15)\nplt.title(\"Mean Loss per Epoch\", fontsize=15)\nplt.plot(loss_epoch)","execution_count":null,"outputs":[]}],"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":4,"nbformat_minor":4}