{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"from albumentations.pytorch import ToTensorV2\nimport albumentations as albu\n\nimport pandas as pd\nimport numpy as np\nimport os\nimport math\nfrom tqdm import tqdm\nimport cv2\nfrom PIL import Image\nimport random\n\nimport torch\nfrom torch import optim, nn\nfrom torch.optim import Adam\nfrom torchvision import models, transforms\nfrom torch.utils.data import Dataset, DataLoader\nfrom sklearn.model_selection import train_test_split\nfrom torch.cuda.amp import autocast, GradScaler\n\nimport sys\nsys.path.append('../input/pytorch-image-models/pytorch-image-models-master')\nimport timm\n\ndevice = torch.device('cuda:0' if torch.cuda.is_available() else \"cpu\")\n\n\ndef seed_torch(seed=42):\n    random.seed(seed)\n    os.environ['PYTHONHASHSEED'] = str(seed)\n    np.random.seed(seed)\n    torch.manual_seed(seed)\n    torch.cuda.manual_seed(seed)\n    torch.backends.cudnn.deterministic = True\n\nseed_torch(seed=42)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"target_cols=['ETT - Abnormal', 'ETT - Borderline', 'ETT - Normal',\n                 'NGT - Abnormal', 'NGT - Borderline', 'NGT - Incompletely Imaged', 'NGT - Normal', \n                 'CVC - Abnormal', 'CVC - Borderline', 'CVC - Normal',\n                 'Swan Ganz Catheter Present']\nTRAIN_PATH = '../input/ranzcr-clip-catheter-line-classification/train'\n\nclass CustomResNext(nn.Module):\n    def __init__(self, model_name='resnext50_32x4d', pretrained=False):\n        super().__init__()\n        self.model = timm.create_model(model_name, pretrained=pretrained)\n        n_features = self.model.fc.in_features\n        self.model.fc = nn.Linear(n_features, 11)\n\n    def forward(self, x):\n        x = self.model(x)\n        return x\n\n\nclass TrainDataset(Dataset):\n    def __init__(self, df, transform=None):\n        self.df = df\n        self.file_names = df['StudyInstanceUID'].values\n        self.labels = df[target_cols].values\n        self.transform = transform\n        \n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        file_name = self.file_names[idx]\n        file_path = f'{TRAIN_PATH}/{file_name}.jpg'\n        image = cv2.imread(file_path)\n        image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)\n        if self.transform:\n            augmented = self.transform(image=image)\n            image = augmented['image']\n            \n        label = torch.tensor(self.labels[idx]).float()\n        return image, label\n    \n\nsize = 512    \n\ndef get_transforms(data = ''):\n    if data == 'train':\n        return albu.Compose([\n                            albu.RandomResizedCrop(size, size, scale=(0.85, 1), p=1),\n                            albu.HorizontalFlip(p=0.5),\n                            #albu.ShiftScaleRotate(p=0.2),\n                            #albu.Cutout(max_h_size=int(size * 0.03), max_w_size=int(size * 0.03), num_holes=5, p=0.1),\n                            albu.Normalize(\n                                        mean=[0.485, 0.456, 0.406],\n                                        std=[0.229, 0.224, 0.225],\n                                    ),\n                            ToTensorV2()\n                        ])\n    elif data == 'valid':\n        return albu.Compose([\n                            albu.Resize(size, size),\n                            albu.Normalize(\n                                        mean=[0.485, 0.456, 0.406],\n                                        std=[0.229, 0.224, 0.225],\n                                    ),\n                            ToTensorV2()\n                        ])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class AverageMeter(object):\n    \"\"\"Computes and stores the average and current value\"\"\"\n    def __init__(self):\n        self.reset()\n\n    def reset(self):\n        self.val = 0\n        self.avg = 0\n        self.sum = 0\n        self.count = 0\n\n    def update(self, val, n=1):\n        self.val = val\n        self.sum += val * n\n        self.count += n\n        self.avg = self.sum / self.count\n\n\ndef asMinutes(s):\n    m = math.floor(s / 60)\n    s -= m * 60\n    return '%dm %ds' % (m, s)\n\n\ndef timeSince(since, percent):\n    now = time.time()\n    s = now - since\n    es = s / (percent)\n    rs = es - s\n    return '%s (remain %s)' % (asMinutes(s), asMinutes(rs))\n\n\ndef train_fn(train_loader, model, criterion, optimizer, epoch, scheduler, device):\n    scaler = GradScaler()\n    losses = AverageMeter()\n    scores = AverageMeter()\n\n    model.train()\n    global_step = 0\n    for step, (images, labels) in enumerate(train_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        batch_size = labels.size(0)\n        \n        with autocast():\n            y_preds = model(images)\n            loss = criterion(y_preds, labels)\n        \n        losses.update(loss.item(), batch_size)\n            \n        scaler.scale(loss).backward()\n        grad_norm = torch.nn.utils.clip_grad_norm_(model.parameters(), 1000)\n        \n        scaler.step(optimizer)\n        scaler.update()\n        optimizer.zero_grad()\n        global_step += 1\n        \n        if step % 100 == 0 or step == (len(train_loader) - 1):\n            print(f'Epoch: {epoch+1}  [{step} / {len(train_loader)}]')\n            print(f'Loss: {losses.val} {losses.avg}')\n\n        \n    return losses.avg\n\n\ndef valid_fn(valid_loader, model, criterion, device):\n    losses = AverageMeter()\n    scores = AverageMeter()\n    model.eval()\n    \n    preds = []\n    \n        \n    for step, (images, labels) in enumerate(valid_loader):\n        images = images.to(device)\n        labels = labels.to(device)\n        \n        batch_size = labels.size(0)\n        with torch.no_grad():\n            y_preds = model(images)\n            \n        loss = criterion(y_preds, labels)\n        losses.update(loss.item(), batch_size)\n                \n        preds.append(y_preds.sigmoid().to(\"cpu\").numpy())\n        \n        if step % 100 == 0 or step == (len(valid_loader)-1):\n            print(f'EVAL: {step} / {len(valid_loader)}')\n            print(f'Loss: {losses.val} {losses.avg}')\n        \n\n    predictions = np.concatenate(preds)\n    return losses.avg, predictions\n\n\n\ndef main():\n    \n    model = CustomResNext(\"resnext50_32x4d\", pretrained=True)\n    model.to(device)\n    criterion = torch.nn.BCEWithLogitsLoss()\n    optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-6, amsgrad=False)\n    #scheduler = torch.optim.lr_scheduler.StepLR(optimizer, step_size=7, gamma=0.15)\n    scheduler = torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=6, eta_min=1e-6, last_epoch=-1)\n    \n    my_df = pd.read_csv('../input/ranzcr-clip-catheter-line-classification/train.csv')\n    train_df, valid_df = train_test_split(my_df, random_state=42, test_size=0.15)\n    \n    train_dataset = TrainDataset(train_df, transform=get_transforms(data='train'))\n    valid_dataset = TrainDataset(valid_df, transform=get_transforms(data='valid'))\n    \n    train_loader = DataLoader(train_dataset,\n                             batch_size=32,\n                             num_workers=4,\n                             shuffle=True,\n                             drop_last=False,\n                             pin_memory=True)\n    \n    valid_loader = DataLoader(valid_dataset,\n                             batch_size=32,\n                             num_workers=4,\n                             shuffle=False,\n                             drop_last=False,\n                             pin_memory=True)\n    \n    \n    best_score = 0.\n    best_loss = np.inf\n    \n    for epoch in range(6):\n        print()\n        print(f'Start {epoch+1} EPOCH!!!')\n        avg_loss = train_fn(train_loader, model, criterion, optimizer, epoch, scheduler, device)\n        avg_val_loss, preds = valid_fn(valid_loader, model, criterion, device)\n        \n        if avg_val_loss < best_loss:\n            best_loss = avg_val_loss\n            torch.save(model, f'My_resnext50_fold0_best{epoch+1}.pth')\n        \n        scheduler.step()\n        \n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = main()","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":{"trusted":true},"cell_type":"code","source":"","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":{"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}