{"cells":[{"metadata":{},"cell_type":"markdown","source":"# version 3:\n1.update datasets\n\n2.sampler\n\n3.fix label bug"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nimport glob\nimport cv2\nimport os\nfrom matplotlib import pyplot as plt\nimport os\nimport cv2\nimport numpy as np\nimport pandas as pd\nfrom torch.utils.data import TensorDataset, DataLoader,Dataset\nimport albumentations as albu\nfrom skimage.color import gray2rgb\nimport functools\nimport torch\nfrom tqdm.auto import tqdm","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"train_csv_path = '../input/rsna-str-pulmonary-embolism-detection/train.csv'\njpeg_dir = '../input/rsna-str-pe-detection-jpeg-256/train-jpegs'","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df = pd.read_csv(train_csv_path)\ntrain_df.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"row = train_df.iloc[100]\nimg = cv2.imread(glob.glob(f\"{jpeg_dir}/{row[0]}/{row[1]}/*{row[2]}.jpg\")[0])\nplt.figure(figsize=[12,6])\nplt.subplot(131)\nplt.imshow(img[:,:,0],cmap='gray')\nplt.subplot(132)\nplt.imshow(img[:,:,1],cmap='gray')\nplt.subplot(133)\nplt.imshow(img[:,:,2],cmap='gray')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def get_training_augmentation(y=256,x=256):\n    train_transform = [albu.RandomBrightnessContrast(p=0.3),\n                           albu.VerticalFlip(p=0.5),\n                           albu.HorizontalFlip(p=0.5),\n                           albu.Downscale(p=1.0,scale_min=0.35,scale_max=0.75,),\n                           albu.Resize(y, x)]\n    return albu.Compose(train_transform)\n\n\nformatted_settings = {\n            'input_size': [3, 224, 224],\n            'input_range': [0, 1],\n            'mean': [0.485, 0.456, 0.406],\n            'std': [0.229, 0.224, 0.225],}\ndef preprocess_input(\n    x, mean=None, std=None, input_space=\"RGB\", input_range=None, **kwargs\n):\n\n    if input_space == \"BGR\":\n        x = x[..., ::-1].copy()\n\n    if input_range is not None:\n        if x.max() > 1 and input_range[1] == 1:\n            x = x / 255.0\n\n    if mean is not None:\n        mean = np.array(mean)\n        x = x - mean\n\n    if std is not None:\n        std = np.array(std)\n        x = x / std\n\n    return x\n\ndef get_preprocessing(preprocessing_fn):\n    _transform = [\n        albu.Lambda(image=preprocessing_fn),\n        albu.Lambda(image=to_tensor, mask=to_tensor),\n    ]\n    return albu.Compose(_transform)\n\ndef get_validation_augmentation(y=256,x=256):\n    \"\"\"Add paddings to make image shape divisible by 32\"\"\"\n    test_transform = [albu.Resize(y, x)]\n    return albu.Compose(test_transform)\n\ndef to_tensor(x, **kwargs):\n    \"\"\"\n    Convert image or mask.\n    \"\"\"\n    return x.transpose(2, 0, 1).astype('float32')\n\nclass CTDataset2D(Dataset):\n    def __init__(self,df,transforms = albu.Compose([albu.HorizontalFlip()]),preprocessing=None,size=256,mode='val'):\n        self.df_main = df.values\n        if mode=='val':\n            self.df = self.df_main\n        else:\n            self.update_train_df()\n            \n        self.transforms = transforms\n        self.preprocessing = preprocessing\n        self.size=size\n\n\n    def __getitem__(self, idx):\n        row = self.df[idx]\n        img = cv2.imread(glob.glob(f\"{jpeg_dir}/{row[0]}/{row[1]}/*{row[2]}.jpg\")[0])\n        label = row[3:].astype(int)\n        label[2:] = label[2:] if label[0]==1 else 0\n        if self.transforms:\n            img = self.transforms(image=img)['image']\n        if self.preprocessing:\n            img = self.preprocessing(image=img)['image']\n        return img,torch.from_numpy(label.reshape(-1))\n\n    def __len__(self):\n        return len(self.df)\n    \n    def update_train_df(self):\n        df0 = self.df_main[self.df_main[:,3]==0]\n        df1 = self.df_main[self.df_main[:,3]==1]\n        np.random.shuffle(df0)\n        self.df = np.concatenate([df0[:len(df1)],df1],axis=0)\n        \n\ndef norm(img):\n    img-=img.min()\n    return img/img.max()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"StudyInstanceUID = list(set(train_df['StudyInstanceUID']))\nprint(len(StudyInstanceUID))\nt_df = train_df[train_df['StudyInstanceUID'].isin(StudyInstanceUID[0:6500])]\nv_df = train_df[train_df['StudyInstanceUID'].isin(StudyInstanceUID[6500:])]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class config:\n    model_name=\"resnet18\"\n    batch_size = 128\n    WORKERS = 4\n    classes =14\n    resume = False\n    epochs = 10\n    MODEL_PATH = 'log/cpt'\n    if not os.path.exists(MODEL_PATH):\n        os.makedirs(MODEL_PATH)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocessing_fn = functools.partial(preprocess_input, **formatted_settings)\ntrain_dataset = CTDataset2D(t_df,\n                            transforms=get_training_augmentation(),\n                            preprocessing=get_preprocessing(preprocessing_fn),mode='train')\nval_dataset = CTDataset2D(v_df,\n                            transforms=get_validation_augmentation(),\n                            preprocessing=get_preprocessing(preprocessing_fn))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train = DataLoader(train_dataset, batch_size=config.batch_size, shuffle=True, num_workers=config.WORKERS, pin_memory=True)\nval = DataLoader(val_dataset, batch_size=config.batch_size*2, shuffle=False, num_workers=config.WORKERS, pin_memory=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"x,y = train_dataset[-400]\nx.shape,len(y),y,len(train_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torchvision.models as models\nmodel = models.resnet18(pretrained=True)\nmodel.fc = torch.nn.Linear(in_features=512, out_features=config.classes, bias=True)\nmodel = model.cuda()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(),lr=5e-4,weight_decay= 0.00001)\nscheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer,T_max= 300,eta_min= 0.000001)\nloss_fn = torch.nn.BCEWithLogitsLoss()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from torch.optim.lr_scheduler import ReduceLROnPlateau\nclass trainer:\n    def __init__(self,loss_fn,model,optimizer,scheduler):\n        self.loss_fn = loss_fn\n        self.model = model\n        self.optimizer = optimizer\n        self.scheduler = scheduler\n\n        \n    def batch_train(self, batch_imgs, batch_labels, batch_idx):\n        batch_imgs, batch_labels = batch_imgs.cuda().float(), batch_labels.cuda().float()\n        predicted = self.model(batch_imgs)\n        loss = self.loss_fn(predicted.float(), batch_labels)\n        loss.backward()\n        self.optimizer.step()\n        self.optimizer.zero_grad()\n        return loss.item(), predicted\n    \n    def batch_valid(self, batch_imgs,get_fet):\n        self.model.eval()\n        batch_imgs = batch_imgs.cuda()\n        with torch.no_grad():\n            predicted = self.model(batch_imgs)\n        predicted = torch.sigmoid(predicted)\n        return predicted\n    \n    def train_epoch(self, loader):\n        self.model.train()\n        tqdm_loader = tqdm(loader)\n        current_loss_mean = 0\n        for batch_idx, (imgs,labels) in enumerate(tqdm_loader):\n            loss, predicted = self.batch_train(imgs, labels, batch_idx)\n            current_loss_mean = (current_loss_mean * batch_idx + loss) / (batch_idx + 1)\n            tqdm_loader.set_description('loss: {:.4} lr:{:.6}'.format(\n                    current_loss_mean, self.optimizer.param_groups[0]['lr']))\n            self.scheduler.step(batch_idx)\n        return current_loss_mean\n    \n    def valid_epoch(self, loader,name=\"valid\"):\n        self.model.eval()\n        tqdm_loader = tqdm(loader)\n        current_loss_mean = 0\n        for batch_idx, (imgs,labels) in enumerate(tqdm_loader):\n            with torch.no_grad():\n                batch_imgs = imgs.cuda().float()\n                batch_labels = labels.cuda()\n                predicted = self.model(batch_imgs)\n                loss = self.loss_fn(predicted.float(),batch_labels.float()).item()\n                current_loss_mean = (current_loss_mean * batch_idx + loss) / (batch_idx + 1)\n        score = 1-current_loss_mean\n        print('metric {}'.format(score))\n        return score\n    \n    def run(self,train_loder,val_loder):\n        best_score = -100000\n        for e in range(config.epochs):\n            print(\"----------Epoch {}-----------\".format(e))\n            current_loss_mean = self.train_epoch(train_loder)\n            train_loder.dataset.update_train_df()\n            score = self.valid_epoch(val_loder)\n            if best_score < score:\n                best_score = score\n                torch.save(self.model.state_dict(),config.MODEL_PATH+\"/{}_best.pth\".format(config.model_name))\n\n    def batch_valid_tta(self, batch_imgs):\n        batch_imgs = batch_imgs.cuda()\n        predicted = model(batch_imgs)\n        tta_flip = [[-1],[-2]]\n        for axis in tta_flip:\n            predicted += torch.flip(model(torch.flip(batch_imgs, axis)), axis)\n        predicted = predicted/(1+len(tta_flip))\n        predicted = torch.sigmoid(predicted)\n        return predicted.cpu().numpy()\n            \n    def load_best_model(self):\n        if os.path.exists(config.MODEL_PATH+\"/{}_best.pth\".format(config.model_name)):\n            self.model.load_state_dict(torch.load(config.MODEL_PATH+\"/{}_best.pth\".format(config.model_name)))\n        \n    def predict(self,imgs_tensor,get_fet = False):\n        self.model.train()\n        with torch.no_grad():\n            return self.batch_valid(imgs_tensor,get_fet=get_fet)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Trainer = trainer(loss_fn,model,optimizer,scheduler)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"Trainer.run(train,val)","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}