{"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 pandas as pd\nimport os\nimport numpy as np \nimport pandas as pd \nfrom datetime import datetime\nimport time\nimport random\nfrom tqdm import tqdm_notebook as tqdm # progress bar\nimport matplotlib.pyplot as plt\nimport matplotlib.patches as patches\nimport torch\nimport torch.nn as nn\nfrom torch.utils.data import Dataset,DataLoader\nfrom torch.utils.data.sampler import SequentialSampler, RandomSampler\nimport torchvision\nfrom torchvision.models.detection.faster_rcnn import FastRCNNPredictor, FasterRCNN\nfrom torchvision.models.detection.backbone_utils import resnet_fpn_backbone\nfrom sklearn.model_selection import StratifiedKFold\nfrom sklearn.model_selection import train_test_split\nimport cv2\nimport albumentations as A\nfrom albumentations.pytorch.transforms import ToTensorV2\nfrom sklearn.model_selection import StratifiedKFold\nfrom glob import glob\nimport numba\nimport re\nfrom numba import jit\nfrom PIL import Image\nimport gc\nimport warnings\nwarnings.filterwarnings('ignore')","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:07:58.565490Z","iopub.execute_input":"2021-07-24T07:07:58.566016Z","iopub.status.idle":"2021-07-24T07:08:03.540957Z","shell.execute_reply.started":"2021-07-24T07:07:58.565905Z","shell.execute_reply":"2021-07-24T07:08:03.539930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data from this competition","metadata":{}},{"cell_type":"code","source":"def get_bbox(row):\n    bboxes = []\n    bbox = []\n    for i, l in enumerate(row.label.split(' ')):\n        if (i % 6 == 0) | (i % 6 == 1):\n            continue\n        bbox.append(float(l))\n        if i % 6 == 5:\n            bboxes.append(bbox)\n            bbox = []  \n            \n    return bboxes\n    \n\ndef scale_box(row):\n    if row['class'] == 'opacity':\n        scale_x = 256/row.dim1\n        scale_y = 256/row.dim0\n\n        scaled_boxes = []\n        for box in row.xyxy:\n            x = int(np.round(box[0]*scale_x, 4))\n            y = int(np.round(box[1]*scale_y, 4))\n            w = int(np.round(box[2]*(scale_x), 4))\n            h = int(np.round(box[3]*scale_y, 4))\n            scaled_boxes.append([x, y, w, h])\n\n        return scaled_boxes\n\ndf = pd.read_csv('../input/siim-covid19-detection/train_image_level.csv')\ndf['class'] = df.apply(lambda row: row.label.split(' ')[0], axis=1)\ndf['filename'] = df.apply(lambda row: row.id[:-6], axis=1)\n\nmeta = pd.read_csv('../input/siim-covid19-resized-to-256px-png/meta.csv')\nmeta.columns = ['filename', 'dim0', 'dim1', 'split']\n\ndf = df.merge(meta, on='filename', how='left')\n\ndf['xyxy'] = df.apply(get_bbox, axis=1)\ndf['xyxy'] = df.apply(scale_box, axis=1)\n# df.drop(columns=['split'], inplace=True)\n\ndf.head(3)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:03.542412Z","iopub.execute_input":"2021-07-24T07:08:03.542884Z","iopub.status.idle":"2021-07-24T07:08:04.793413Z","shell.execute_reply.started":"2021-07-24T07:08:03.542852Z","shell.execute_reply":"2021-07-24T07:08:04.792575Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"opacity = {}\nnone = []\n\nfor index, row in df.iterrows():\n    name = row.filename\n    if row['class'] == 'opacity':\n        opacity[name]= row.xyxy\n    else:\n        none.append(name)\n        \nlen(opacity), len(none)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:04.794897Z","iopub.execute_input":"2021-07-24T07:08:04.795297Z","iopub.status.idle":"2021-07-24T07:08:05.480440Z","shell.execute_reply.started":"2021-07-24T07:08:04.795267Z","shell.execute_reply":"2021-07-24T07:08:05.479598Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Data from RSNA Pneumonia Detection Challenge","metadata":{}},{"cell_type":"code","source":"old_competition_df = pd.read_csv('../input/rsna-pneumonia-detection-challenge/stage_2_train_labels.csv')\n\nextract_box = lambda row: [i*256/1024 for i in [row['x'], row['y'], row['x']+row['width'], row['y']+row['height']]]\n\nfor index, row in old_competition_df.iterrows():\n    pid = row['patientId']\n    if row.Target == 1:\n        if pid not in opacity:\n            opacity[pid] = []\n        opacity[pid].append(extract_box(row))\n    ''' want less negative samples\n    else:\n        if none[-1] != pid:\n            none.append(pid)\n    '''\n            \nlen(opacity), len(none)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:05.481679Z","iopub.execute_input":"2021-07-24T07:08:05.482120Z","iopub.status.idle":"2021-07-24T07:08:08.829597Z","shell.execute_reply.started":"2021-07-24T07:08:05.482091Z","shell.execute_reply":"2021-07-24T07:08:08.828451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Split","metadata":{}},{"cell_type":"code","source":"data = opacity.copy()\n\n'''\nfor name in none:\n    data[name] = None\n'''\n    \ntrain, valid  = [i.to_dict() for i in train_test_split(pd.Series(data), train_size=0.8, random_state=42)]\n\nlen(train), len(valid)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:41.818925Z","iopub.execute_input":"2021-07-24T07:08:41.819326Z","iopub.status.idle":"2021-07-24T07:08:41.859869Z","shell.execute_reply.started":"2021-07-24T07:08:41.819293Z","shell.execute_reply":"2021-07-24T07:08:41.858793Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Dataset","metadata":{}},{"cell_type":"code","source":"class LungDataset(Dataset):\n\n    def __init__(self, data):\n        super().__init__()\n        self.all_names, self.all_boxes = zip(*data.items())\n\n    def __getitem__(self, index: int):\n        \n        name = self.all_names[index]\n        boxes = self.all_boxes[index]\n        \n        if '-' in name:\n            img = cv2.imread(f'../input/rsna-256/{name}.png', 0)\n        else:\n            img = cv2.imread(f'../input/siim-covid19-resized-to-256px-png/train/{name}.png', 0)\n                \n        if boxes != None:\n            transform = A.Compose([\n                A.HorizontalFlip(p=.5),\n                A.RandomGamma(p=1),\n                A.ShiftScaleRotate(rotate_limit=10, p=.5),\n                A.Cutout(p=.3),\n                A.RandomBrightness(p=.5),\n                ToTensorV2()\n            ], bbox_params=A.BboxParams(format='pascal_voc', label_fields=[]))\n            \n            sample = transform(image=img, bboxes=boxes)\n\n            tmp = np.array(sample['bboxes'])\n            \n            assert np.all(tmp[:, 3]>tmp[:, 1]) & np.all(tmp[:, 2]>tmp[:, 0])\n          \n            target = {\"boxes\": torch.as_tensor(sample['bboxes'], dtype=torch.float32),\n                      \"labels\": torch.ones((len(boxes)), dtype=torch.int64),\n                      \"image_id\": torch.tensor([index]),\n                      \"area\": torch.as_tensor((tmp[:,2]-tmp[:,0])*(tmp[:,3]-tmp[:,1]), dtype=torch.float32),\n                      \"iscrowd\": torch.zeros(len(boxes), dtype=torch.int64)}\n        else:\n            transform= A.Compose([\n                A.HorizontalFlip(p=.5),\n                A.RandomGamma(p=1),\n                A.ShiftScaleRotate(rotate_limit=10, p=.5),\n                A.Cutout(p=.3),\n                A.RandomBrightness(p=.5),\n                ToTensorV2()\n            ])\n            \n            sample = transform(image=img)\n            \n            target = {\"boxes\": torch.zeros((0,4), dtype=torch.float32),\n                      \"labels\": torch.zeros(0, dtype=torch.int64),\n                      \"image_id\": torch.tensor([index]),\n                      \"area\": torch.zeros(0, dtype=torch.float32),\n                      \"iscrowd\": torch.zeros((0), dtype=torch.int64)}\n            \n        return sample['image']/255, target\n        \n    def __len__(self) -> int:\n        return len(self.all_names)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:44.488003Z","iopub.execute_input":"2021-07-24T07:08:44.488436Z","iopub.status.idle":"2021-07-24T07:08:44.508273Z","shell.execute_reply.started":"2021-07-24T07:08:44.488400Z","shell.execute_reply":"2021-07-24T07:08:44.506930Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Show One Image Using Dataset","metadata":{}},{"cell_type":"code","source":"def plot_box(img, boxes, ax=None): # box format: xyxy\n    ax = plt.gca() if ax is None else ax\n    for box in boxes:\n        rect = patches.Rectangle((box[0], box[1]), box[2]-box[0], box[3]-box[1], linewidth=1, edgecolor='r', facecolor='none')\n        ax.add_patch(rect)\n    ax.imshow(img, cmap='gray')\n    \ntrain_dataset = LungDataset(train)\nvalid_dataset = LungDataset(valid)\n\nimage, target = train_dataset[31]\n\nimage = image.reshape(256, 256)\nboxes = target['boxes'].tolist()\n\nplot_box(image, boxes)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:48.561309Z","iopub.execute_input":"2021-07-24T07:08:48.561767Z","iopub.status.idle":"2021-07-24T07:08:48.993254Z","shell.execute_reply.started":"2021-07-24T07:08:48.561731Z","shell.execute_reply":"2021-07-24T07:08:48.992121Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"target","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:50.137185Z","iopub.execute_input":"2021-07-24T07:08:50.137671Z","iopub.status.idle":"2021-07-24T07:08:50.185653Z","shell.execute_reply.started":"2021-07-24T07:08:50.137624Z","shell.execute_reply":"2021-07-24T07:08:50.184869Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Show Multiple Images Using DataLoader","metadata":{}},{"cell_type":"code","source":"def get_train_data_loader(train_dataset, batch_size=16):\n    return DataLoader(\n        train_dataset,\n        batch_size = batch_size,\n        shuffle = True,\n        num_workers = 4,\n        collate_fn = collate_fn\n    )\n\ndef get_valid_data_loader(valid_dataset, batch_size=16):\n    return DataLoader(\n        valid_dataset,\n        batch_size = batch_size,\n        shuffle = True,\n        num_workers = 4,\n        collate_fn = collate_fn\n    )    \n\ndef collate_fn(batch):\n    return tuple(zip(*batch))\n\ntrain_data_loader = get_train_data_loader(train_dataset, batch_size=16)\nvalid_data_loader = get_valid_data_loader(valid_dataset, batch_size=16)\ndata = iter(valid_data_loader)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:08:51.856471Z","iopub.execute_input":"2021-07-24T07:08:51.857189Z","iopub.status.idle":"2021-07-24T07:08:51.960989Z","shell.execute_reply.started":"2021-07-24T07:08:51.857146Z","shell.execute_reply":"2021-07-24T07:08:51.958896Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"images, targets = next(data)\n\nfig, ax = plt.subplots(figsize=(20, 20), nrows=4, ncols=4)\n\nfor i in range(16):    \n    boxes = targets[i]['boxes'].cpu().numpy().astype(np.int32)\n    image = images[i].reshape(256, 256)\n    \n    plot_box(image, boxes, ax[i // 4][i % 4])\n    \nplt.savefig('lungs.png')","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:09:11.949215Z","iopub.execute_input":"2021-07-24T07:09:11.949701Z","iopub.status.idle":"2021-07-24T07:09:15.544414Z","shell.execute_reply.started":"2021-07-24T07:09:11.949644Z","shell.execute_reply":"2021-07-24T07:09:15.543088Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# Train","metadata":{}},{"cell_type":"code","source":"%%capture\n!git clone https://github.com/pytorch/vision.git\n!cp vision/references/detection/utils.py .\n!cp vision/references/detection/transforms.py .\n!cp vision/references/detection/coco_eval.py .\n!cp vision/references/detection/engine.py .\n!cp vision/references/detection/coco_utils.py .\n!pip install -U 'git+https://github.com/cocodataset/cocoapi.git#subdirectory=PythonAPI'","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:10:43.997597Z","iopub.execute_input":"2021-07-24T07:10:43.998007Z","iopub.status.idle":"2021-07-24T07:11:16.373867Z","shell.execute_reply.started":"2021-07-24T07:10:43.997975Z","shell.execute_reply":"2021-07-24T07:11:16.372306Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = torchvision.models.detection.fasterrcnn_resnet50_fpn(pretrained=True)\nnum_classes = 2 # opacity + none\nin_features = model.roi_heads.box_predictor.cls_score.in_features\nmodel.roi_heads.box_predictor = FastRCNNPredictor(in_features, num_classes) \n# model.load_state_dict(torch.load('../input/siim-packages/weight/epoch4.pth'))\n\ndevice = torch.device('cuda') if torch.cuda.is_available() else torch.device('cpu')\nmodel.to(device)\n\nparams = [p for p in model.parameters() if p.requires_grad]\noptimizer = torch.optim.Adam(params)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:12:53.181288Z","iopub.execute_input":"2021-07-24T07:12:53.181755Z","iopub.status.idle":"2021-07-24T07:12:53.935546Z","shell.execute_reply.started":"2021-07-24T07:12:53.181710Z","shell.execute_reply":"2021-07-24T07:12:53.934622Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from engine import train_one_epoch, evaluate\n\nnum_epochs = 2\n\nfor epoch in range(num_epochs):\n    train_one_epoch(model, optimizer, train_data_loader, device, epoch, print_freq=10)\n    torch.save(model.state_dict(), f'epoch{epoch}.pth')\n    evaluate(model, valid_data_loader, device=device)","metadata":{"execution":{"iopub.status.busy":"2021-07-24T07:12:53.941814Z","iopub.execute_input":"2021-07-24T07:12:53.942159Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}