{"cells":[{"metadata":{},"cell_type":"markdown","source":"[Next notebook](https://www.kaggle.com/keremt/04-generate-sequences)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"from fastai.vision.all import *","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"pd.options.display.max_columns = 100","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"datapath = Path(\"/kaggle/input/rsna-str-pulmonary-embolism-detection/\")\ntrain_df = pd.read_csv(datapath/'train.csv')\ntest_df = pd.read_csv(datapath/'test.csv')\nimagepath = Path(\"/kaggle/input/rsna-str-pe-detection-jpeg-256/\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.head(2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_qi = train_df.groupby(['StudyInstanceUID'])['pe_present_on_image'].agg('mean')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df.pe_present_on_image.mean()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"labels_dict = dict(zip(train_df['SOPInstanceUID'], train_df['pe_present_on_image']))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(labels_dict)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unique_pids = train_df.StudyInstanceUID.unique()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"n = len(unique_pids)\nnvalid = int(n*0.05); nvalid, n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"unique_pids = np.random.permutation(unique_pids)\ntrain_pids = unique_pids[nvalid:]\nvalid_pids = unique_pids[:nvalid]\nlen(train_pids), len(valid_pids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"os.makedirs(\"pids\", exist_ok=True)\npd.to_pickle(valid_pids, \"pids/train_pids.pkl\")\npd.to_pickle(valid_pids, \"pids/valid_pids.pkl\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files = get_image_files(imagepath)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Smart Sample\n\nWe don't have to use all the slices as input data per patient. We can simply sample every nth slice for each patient so that we have good enough variability within that patient and use that data for CNN feature training."},{"metadata":{"trusted":true},"cell_type":"code","source":"from fastai.medical.imaging import *","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"files_dict = defaultdict(list)\nfor o in files:\n    files_dict[o.parent.parent.name].append(o)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for k in files_dict:\n    files_dict[k] = sorted(files_dict[k], key=lambda o: int(o.name.split('_')[0]))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"plt.hist([len(files_dict[k]) for k in files_dict]);","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def sample_patient_slices(pid, num_slice_samples):\n    \"Use a fixed number of samples per patient for training speed up\"\n    files = array(files_dict[pid])\n    n = len(files)\n    if n > num_slice_samples:\n        idxs = [np.clip(int(i), 0, n-1) for i in np.linspace(0, n, num_slice_samples)]\n        return files[idxs]\n    else: return files","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_sampled_files = parallel(partial(sample_patient_slices, num_slice_samples=120), train_pids)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_files = []\nfor o in train_sampled_files: train_files += list(o)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"valid_files = []\nfor o in valid_pids: valid_files += files_dict[o]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train_files), len(valid_files)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"def aug_transforms(mult=1.0, do_flip=True, flip_vert=False, max_rotate=10., min_zoom=1., max_zoom=1.1,\n                   max_lighting=0.2, max_warp=0.2, p_affine=0.75, p_lighting=0.75, xtra_tfms=None, size=None,\n                   mode='bilinear', pad_mode=PadMode.Reflection, align_corners=True, batch=False, min_scale=1.):\n    \"Utility func to easily create a list of flip, rotate, zoom, warp, lighting transforms.\"\n    res,tkw = [],dict(size=size if min_scale==1. else None, mode=mode, pad_mode=pad_mode, batch=batch, align_corners=align_corners)\n    max_rotate,max_lighting,max_warp = array([max_rotate,max_lighting,max_warp])*mult\n    if do_flip: res.append(Dihedral(p=0.5, **tkw) if flip_vert else Flip(p=0.5, **tkw))\n    if max_warp:   res.append(Warp(magnitude=max_warp, p=p_affine, **tkw))\n    if max_rotate: res.append(Rotate(max_deg=max_rotate, p=p_affine, **tkw))\n    if min_zoom<1 or max_zoom>1: res.append(Zoom(min_zoom=min_zoom, max_zoom=max_zoom, p=p_affine, **tkw))\n    if max_lighting:\n        res.append(Brightness(max_lighting=max_lighting, p=p_lighting, batch=batch))\n        res.append(Contrast(max_lighting=max_lighting, p=p_lighting, batch=batch))\n    xtra_tfms = [RandomResizedCropGPU(size, min_scale=min_scale, ratio=(1,1))] + xtra_tfms\n    return res + L(xtra_tfms)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"wgtdict = {0:1, 1:10}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_label(o): return labels_dict[o.stem.split(\"_\")[1]]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class FlipUD(RandTransform):\n    def __init__(self, p=0.5): super().__init__(p=p)\n    def encodes(self, x:TensorImage): return x.flip(-2)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from time import time\ndef get_dls(train_files, valid_files, resize=256, size=224, bs=128):\n    \n    files = train_files + valid_files\n    trn_idxs = list(range(0, len(train_files)))\n    val_idxs = list(range(len(train_files), len(files)))\n    trn_wgts = [wgtdict[get_label(o)] for o in train_files]\n    print(f\"Collected idxs\")\n\n    tfms = [[PILImage.create, ToTensor, RandomResizedCrop(resize, min_scale=0.9)], \n            [get_label, Categorize()]]\n    dsets = Datasets(files, tfms=tfms, splits=(trn_idxs, val_idxs))\n    print(f\"Created dset\")\n\n    aug_tfms = aug_transforms(size=size, max_lighting=False, max_warp=False, flip_vert=False, min_scale=0.85,\n                              xtra_tfms=[RandomErasing(sh=0.2, min_aspect=0.15), FlipUD(p=0.3)])    \n    batch_tfms = [IntToFloatTensor] + aug_tfms\n    dls = dsets.dataloaders(bs=bs, after_batch=batch_tfms, dl_type=WeightedDL, dl_kwargs=[{\"wgts\":trn_wgts}, {}])\n    print(f\"DLs ready\")\n    return dls","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dls = get_dls(train_files, valid_files, resize=256, bs=128)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(dls.train.dataset), len(dls.valid.dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"dls.show_batch(max_n=16)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"opt_func = partial(ranger, **dict(sqrmom=0.99, mom=0.95, beta=0., eps=1e-4))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"loss_func = LabelSmoothingCrossEntropyFlat(eps=0.05)\nlearn = cnn_learner(dls, xresnet34, opt_func=opt_func, pretrained=True, loss_func=loss_func,\n                    metrics=[accuracy], cbs=[SaveModelCallback(\"accuracy\", fname=\"xresnet34-256\", every_epoch=True)])\nlearn.to_fp16();","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# learn.lr_find()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"learn.path = Path(\".\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"base_lr = 2e-3\nlr_mult = 100\nlearn.freeze()\nlearn.fit_flat_cos(1, slice(base_lr))\nbase_lr /= 2\nlearn.unfreeze()\nlearn.fit_flat_cos(4, slice(base_lr/lr_mult, base_lr))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"","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}