{"cells":[{"metadata":{"trusted":true,"collapsed":true,"_uuid":"b6c3d432f06bf6c59a5136549d3cb675fe0f25f6"},"cell_type":"code","source":"TEST = False\nSAMPLE_SIZE = 10000","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"17ed98b52e46b8461539e6d93ef54798d0f4fa54"},"cell_type":"markdown","source":"Import libs"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"collapsed":true},"cell_type":"code","source":"# import libs\nimport glob, pylab, pandas as pd\nimport pydicom, numpy as np\nimport random\nimport json\nimport time\nimport copy\nimport pydicom\nimport torchvision\nimport sys\nimport math\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.optim import lr_scheduler\nfrom torch.autograd import Variable\nfrom PIL import Image, ImageDraw, ImageFont\nimport matplotlib.pyplot as plt\nfrom matplotlib import patches, patheffects\nfrom multiprocessing import Pool\n\nfrom sklearn.model_selection import train_test_split\nfrom torchvision import datasets, transforms\nfrom torchvision import transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom torch.optim import lr_scheduler\nfrom pathlib import Path\nfrom tqdm import tqdm     \n\n# from fastai.conv_learner import *\n# from fastai.dataset import *\n# from fastai.dataset import ImageClassifierData","execution_count":null,"outputs":[]},{"metadata":{"_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","trusted":true,"scrolled":true,"collapsed":true},"cell_type":"code","source":"# see input dir\n!ls ../input","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"3d7f0ddd940806b8ca11a50fa9241c3d1421e474","scrolled":true,"collapsed":true},"cell_type":"code","source":"PATH = Path('../input')\n# read training lables\ntrain_bb_df = pd.read_csv(PATH/'stage_1_train_labels.csv')\ntrain_bb_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"153bcac7c146abd2018f25d9d2c68dd8b67004e6","collapsed":true},"cell_type":"code","source":"!ls {PATH}/'stage_1_train_images'| wc -l","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"ec7735bf8d9f200d9489ae0c0ab60b0f510f412b"},"cell_type":"markdown","source":"row 4 shows, there is bouding box in image with given x & y. First 4 image don't have any bounding box\n### check if duplicate bounding box are present for any patient"},{"metadata":{"trusted":true,"_uuid":"3b98a272954161276884fd6a8c2605de9fa8991f","collapsed":true},"cell_type":"code","source":"train_bb_df['duplicate'] = train_bb_df.duplicated(['patientId'], keep=False)\n# see data\ntrain_bb_df[train_bb_df['duplicate']].head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"6dae0e268b80eab0409df5180e1c6a8de087ba72","collapsed":true},"cell_type":"code","source":"len(train_bb_df)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"56ebd9ec72029a47bc1ff98eb6de4b756d03615e","scrolled":false,"collapsed":true},"cell_type":"code","source":"detailed_df = pd.read_csv(PATH/'stage_1_detailed_class_info.csv')\n# detailed_df.head()\n# merge two df\nclass_df = train_bb_df.merge(detailed_df, on=\"patientId\")\n# len(class_df) # -> 35875 it is way more than original df.\n# class_df[class_df.duplicated()]\nclass_df.drop_duplicates(inplace=True)\nclass_df.head() # len is 28989. \ncsv_df = class_df.filter(['patientId', 'Target'], )\n# csv_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"91eaaefbc070e9e912c84c917b3f5ffa852415fa"},"cell_type":"markdown","source":"Loading all train images in memory causes memory overflow. Kernel will restart. \nWe creating dataset to read images, then apply transformation."},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"e2b2fbdfa1b9b1a570388551d03f3fcd95b37c32"},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"06fe4171d5f711a3d3d3abc8b8b4e3141678c343","collapsed":true},"cell_type":"code","source":"img_dir = PATH/'stage_1_train_images'\nsample = list(img_dir.iterdir())\n\nif TEST:\n    sample = sample[:SAMPLE_SIZE]\ntrain, test = train_test_split(sample)\nbatch_size=32\nsz=224\ntloc = Path('/tmp/pytorch')/str(sz)\ntloc.mkdir(parents=True, exist_ok=True)\n\ndef scale_to(x, ratio, targ): \n    '''Calculate dimension of an image during scaling with aspect ratio'''\n    return max(math.floor(x*ratio), targ)\n\ndef read_image_resize(sample, tsize=sz, tloc=tloc, ):\n    tloc.mkdir(parents=True, exist_ok=True)\n    for loc in tqdm(sample):\n        img_arr = pydicom.read_file(loc.as_posix()).pixel_array\n        img_arr = np.stack([img_arr] * 3, axis=2)\n        img_arr = img_arr/img_arr.max()\n        img_arr = (255*img_arr).clip(0, 255).astype(np.uint8)\n        img_arr = Image.fromarray(img_arr)#.convert('RGB') # model expects 3 channel image\n        r,c = img_arr.size\n        ratio = tsize/min(r,c)\n        sz = (scale_to(r, ratio, tsize), scale_to(c, ratio, tsize))\n        img_arr = img_arr.resize(sz, Image.LINEAR)\n        filepath = tloc / loc.name\n#         np.save(filepath, img_arr, )\n        img_arr.save((tloc/loc.stem).as_posix()+'.png')\n\n# read_image_resize()\n# try:\n#     if len(list(tloc.iterdir())) < SAMPLE_SIZE:\n#         read_image_resize()\n# except FileNotFoundError:\n#     read_image_resize()\n\ndef resize_image(loc, tsize=256, tloc=tloc):\n    img_arr = pydicom.read_file(loc.as_posix()).pixel_array\n    img_arr = np.stack([img_arr] * 3, axis=2)\n    img_arr = img_arr/img_arr.max()\n    img_arr = (255*img_arr).clip(0, 255).astype(np.uint8)\n    img_arr = Image.fromarray(img_arr)#.convert('RGB') # model expects 3 channel image\n    r,c = img_arr.size\n    ratio = tsize/min(r,c)\n    sz = (scale_to(r, ratio, tsize), scale_to(c, ratio, tsize))\n    img_arr = img_arr.resize(sz, Image.LINEAR)\n    filepath = tloc / loc.name\n#         np.save(filepath, img_arr, )\n    img_arr.save((tloc/loc.stem).as_posix()+'.png')\n    \npool = Pool()                         # Create a multiprocessing Pool\npool.map(resize_image, tqdm(sample))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"c0e48f29df43ceea3b4dff0f3a4ed8e5559da1fe","collapsed":true},"cell_type":"code","source":"!ls {tloc} | wc -l","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"04d6963b59aec391ec051af33d8ba5d19d1b99cf","collapsed":true},"cell_type":"code","source":"class CDataset(Dataset):\n    def __init__(self, ds, img_dir, class_df, transform=None, ext=None): \n        self.ds = ds\n        self.img_dir = img_dir\n        self.class_df = class_df\n        self.ext = ext or '.dcm'\n        self.transform = transforms.Compose(transform) if transform else None\n        \n    def __len__(self): \n        return len(self.ds)\n    \n    def read_dicom_image(self, pid):\n#         pid = pid +'.dcm.npy'\n#         return Image.fromarray(np.load(tloc/pid))\n        pid = pid +'.png'\n        return Image.open(tloc/pid)\n    \n    def get1item(self, i):\n        patientId = self.ds[i].name.split('.')[0]\n        img = self.read_dicom_image(patientId)\n        if self.transform:\n            img = self.transform(img)\n        kls = self.class_df[self.class_df['patientId'] == patientId]\n        return img, kls.iloc[0].Target\n#         row = kls.iloc[0]\n#         dim = []\n#         for i in ['x', 'y', 'width', 'height']:\n#             try:\n#                 val = str(int(getattr(row, i)))\n#             except ValueError:\n#                 val = '-'\n#             dim.append(val)\n#         return img,dim\n    \n    def __getitem__(self, idx):\n        return self.get1item(idx)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"57df580cddb34df670cf0a970ceedebedfa34cd7","collapsed":true},"cell_type":"code","source":"\ntransform = [\n#     transforms.RandomHorizontalFlip(), \n#     transforms.TenCrop(224), \n#     transforms.Lambda(lambda crops: torch.stack([transforms.ToTensor()(crop) for crop in crops])),\n    \n    transforms.ToTensor(),\n#   transforms.Normalize([0.485, 0.456, 0.406],[0.229, 0.224, 0.225])\n]\ntrain_ds = CDataset(train, tloc, class_df, transform=transform)\ntest_ds = CDataset(test, tloc, class_df, transform=transform)\n\ntrain_dl = DataLoader(train_ds, batch_size=batch_size,)\ntest_dl = DataLoader(test_ds, batch_size=batch_size)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"scrolled":true,"_uuid":"15795fa351c7bf5ce082bef11c8950ee10b31b85","collapsed":true},"cell_type":"code","source":"x,y = next(iter(train_dl))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"f85109b99572e4bdec0594c83d7a3b5aa3a2e271","collapsed":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"71b285cc2da2cbcdb5f5027f9c5e03f3e46cbca4","collapsed":true},"cell_type":"code","source":"use_gpu = torch.cuda.is_available()\ndataloaders = {'train': train_dl, 'val':test_dl}\n\ndef train_model(model, criterion, optimizer, scheduler, num_epochs=25):\n    since = time.time()\n    best_model_wts = copy.deepcopy(model.state_dict())\n    best_acc = 0.0\n    for epoch in range(num_epochs):\n        print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n        print('-' * 10)\n        # Each epoch has a training and validation phase\n        for phase in ['train', 'val']:\n            if phase == 'train':\n                scheduler.step()\n                model.train(True)  # Set model to training mode\n            else:\n                model.train(False)  # Set model to evaluate mode\n\n            running_loss = 0.0\n            running_corrects = 0\n            data_loader = dataloaders[phase]\n            start = time.time()\n            for data in tqdm(data_loader):\n                inputs, labels = data\n                if use_gpu:\n                    inputs = Variable(inputs.cuda(),requires_grad=True)\n                    labels = Variable(labels.cuda())\n                else:\n                    inputs, labels = Variable(inputs), Variable(labels)\n\n                optimizer.zero_grad()\n                outputs = model(inputs)\n                _, preds = torch.max(outputs.data, 1)\n                loss = criterion(outputs, labels)\n                if phase == 'train':\n                    loss.backward()\n                    optimizer.step()\n                running_loss += loss.data[0] * inputs.size(0)\n                running_corrects += torch.sum(preds == labels.data)\n\n            epoch_loss = running_loss / len(data_loader.dataset)\n            epoch_acc = running_corrects / len(data_loader.dataset)\n            epoch_time = time.time() - start\n            tqdm.write('{} Loss: {:.4f} Acc: {:.4f} in {:.0f}m {:.0f}s'.format(\n                phase, epoch_loss, epoch_acc, epoch_time // 60, epoch_time % 60))\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\n        tqdm.write('\\n')\n\n    time_elapsed = time.time() - since\n    print('Training complete in {:.0f}m {:.0f}s'.format(\n        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","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"9bcf0020aea5a3622cc61f441444182ed1214595","scrolled":true,"collapsed":true},"cell_type":"code","source":"device = torch.cuda.set_device(0)\nimport torch.nn.functional as F\nimport torch.backends.cudnn as cudnn\n\nclass Densenet(nn.Module):\n    def __init__(self, num_classes = 2):\n        super(Densenet,self).__init__()\n        original_model = torchvision.models.densenet121()\n        self.features = nn.Sequential(*list(original_model.children())[:-1])\n        num_ftrs = original_model.classifier.in_features\n        self.classifier = (nn.Linear(num_ftrs, num_classes))\n\n    def forward(self, x):\n        f = self.features(x)\n        f = F.relu(f, inplace=True)\n        f = F.avg_pool2d(f, kernel_size=7).view(f.size(0), -1)\n        y = self.classifier(f)\n        return y\n    \nmodel = Densenet()\n# model = torchvision.models.densenet121(pretrained=True)\n# # Freeze training for all layers\n# for param in model.parameters():\n#     param.require_grad = False\n    \nmodel.cuda()\n# net = torch.nn.DataParallel(net, device_ids=range(torch.cuda.device_count()))\ncudnn.benchmark = True\n    \nnum_ftrs = model.classifier.in_features\nprint(\"num_ftrs : \", num_ftrs)\nmodel.fc = nn.Linear(num_ftrs, 2)\ncriterion = nn.CrossEntropyLoss()#.cuda()\n\n# Observe that all parameters are being optimized\noptimizer_ft = optim.Adam(model.parameters())\n\n# Decay LR by a factor of 0.1 every 7 epochs\nexp_lr_scheduler = lr_scheduler.StepLR(optimizer_ft, step_size=7, gamma=0.1)\nsince = time.time()","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"f875cd84fab289f39640ad5ec088d90f65975b1d"},"cell_type":"markdown","source":"Lets train our model and check classification accuracy"},{"metadata":{"trusted":true,"_uuid":"7f2c0c0d9787c4ea7ce227f8df17eeb9699beb12","scrolled":false,"collapsed":true},"cell_type":"code","source":"model = train_model(model, criterion, optimizer_ft, exp_lr_scheduler, num_epochs=10)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true,"_uuid":"fbce099f733786ffeacd0e70916e610edbe0a1d1","collapsed":true},"cell_type":"code","source":"! nvidia-smi ","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"5f3938fbf35d269ff9b109a2f553998674fd857a"},"cell_type":"markdown","source":""},{"metadata":{"trusted":true,"collapsed":true,"_uuid":"0e867c91494258bf804b2d7ae3b195cf0ed005f7"},"cell_type":"code","source":"","execution_count":null,"outputs":[]}],"metadata":{"kernelspec":{"display_name":"Python 3","language":"python","name":"python3"},"language_info":{"name":"python","version":"3.6.4","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"}},"nbformat":4,"nbformat_minor":1}