{"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":"!pip install -q efficientnet_pytorch\n!pip install -q albumentations==0.5.2","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:53:59.433323Z","iopub.execute_input":"2022-03-26T19:53:59.434199Z","iopub.status.idle":"2022-03-26T19:54:14.307569Z","shell.execute_reply.started":"2022-03-26T19:53:59.434085Z","shell.execute_reply":"2022-03-26T19:54:14.306642Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"from efficientnet_pytorch import EfficientNet\nfrom albumentations.pytorch import ToTensorV2\nimport albumentations as A\nimport os\nimport torch\nimport pandas as pd\nimport numpy as np\nimport random\nimport torch.nn as nn\nimport matplotlib.pyplot as plt\nfrom glob import glob\nimport torchvision\nfrom torch.utils.data import Dataset\nimport time\nfrom tqdm.notebook import tqdm\n#from tqdm import tqdm\nfrom sklearn import metrics\nimport cv2\nimport gc\nimport torch.nn.functional as F","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:54:16.831141Z","iopub.execute_input":"2022-03-26T19:54:16.831809Z","iopub.status.idle":"2022-03-26T19:54:18.100027Z","shell.execute_reply.started":"2022-03-26T19:54:16.831769Z","shell.execute_reply":"2022-03-26T19:54:18.099289Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"SEED = 42\ndef seed_everything(seed):\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    torch.backends.cudnn.benchmark = True\nseed_everything(SEED)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:54:21.730669Z","iopub.execute_input":"2022-03-26T19:54:21.731236Z","iopub.status.idle":"2022-03-26T19:54:21.73826Z","shell.execute_reply.started":"2022-03-26T19:54:21.731195Z","shell.execute_reply":"2022-03-26T19:54:21.737475Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"data_dir = '../input/alaska2-image-steganalysis'\nsample_size = 5000\nval_size = int(sample_size*0.2)\n\ntrain_fn, val_fn = [], []\ntrain_labels, val_labels = [], []\n\nfolder_names = ['Cover/','JMiPOD/', 'JUNIWARD/', 'UERD/'] # label 1 2 3\nfor label, folder in enumerate(folder_names):\n    train_filenames = sorted(glob(f\"{data_dir}/{folder}/*.jpg\"))[:sample_size]\n    #np.random.shuffle(train_filenames) #можно потом включить для перемешивания\n    \n    train_fn.extend(train_filenames[val_size:])\n    train_labels.extend(np.zeros(len(train_filenames[val_size:],))+label)\n    \n    val_fn.extend(train_filenames[:val_size])\n    val_labels.extend(np.zeros(len(train_filenames[:val_size],))+label)\n\nassert len(train_labels) == len(train_fn), \"неверное заполнение labels\"\nassert len(val_labels) == len(val_fn), \"неверное заполнение labels\"\n\ntrain_df = pd.DataFrame({'ImageFileName': train_fn, 'Label': train_labels}, columns=['ImageFileName', 'Label'])\ntrain_df['Label'] = train_df['Label'].astype(int)\n\nval_df = pd.DataFrame({'ImageFileName': val_fn, 'Label': val_labels}, columns=['ImageFileName', 'Label'])\nval_df['Label'] = val_df['Label'].astype(int)\n\nprint(train_df)\nprint(val_df)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:54:26.974971Z","iopub.execute_input":"2022-03-26T19:54:26.975497Z","iopub.status.idle":"2022-03-26T19:54:28.065866Z","shell.execute_reply.started":"2022-03-26T19:54:26.975452Z","shell.execute_reply":"2022-03-26T19:54:28.065117Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class Alaska2_Dataset(Dataset):\n\n    def __init__(self, df, augmentations=None):\n\n        self.data = df\n        self.augment = augmentations\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        fn, label = self.data.loc[idx]\n        im = cv2.imread(fn)[:, :, ::-1]\n        if self.augment:\n            im = self.augment(image=im)\n        return im, label\n\n\nimg_size = 512\nAUGMENTATIONS_TRAIN = A.Compose([\n    A.Resize(img_size, img_size, p=1.0),\n    A.VerticalFlip(p=0.5),\n    A.HorizontalFlip(p=0.5),\n    A.JpegCompression(quality_lower=75, quality_upper=100, p=0.5),\n    A.ToFloat(max_value=255),\n    ToTensorV2()\n], p=1.0)\n\n\nAUGMENTATIONS_TEST = A.Compose([\n    A.Resize(img_size, img_size, p=1.0),\n    A.ToFloat(max_value=255),\n    ToTensorV2()\n], p=1.0)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:54:35.66087Z","iopub.execute_input":"2022-03-26T19:54:35.661491Z","iopub.status.idle":"2022-03-26T19:54:35.670696Z","shell.execute_reply.started":"2022-03-26T19:54:35.661426Z","shell.execute_reply":"2022-03-26T19:54:35.66976Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = Alaska2_Dataset(train_df, augmentations=AUGMENTATIONS_TRAIN)\nvalid_dataset = Alaska2_Dataset(val_df, augmentations=AUGMENTATIONS_TEST)\n\ntrain_loader = torch.utils.data.DataLoader(train_dataset,\n                                           batch_size=batch_size,\n                                           num_workers=num_workers,\n                                           shuffle=True)\n\nvalid_loader = torch.utils.data.DataLoader(valid_dataset,\n                                           batch_size=batch_size*2,\n                                           num_workers=num_workers,\n                                           shuffle=False)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:54:40.809894Z","iopub.execute_input":"2022-03-26T19:54:40.810156Z","iopub.status.idle":"2022-03-26T19:54:40.961512Z","shell.execute_reply.started":"2022-03-26T19:54:40.810126Z","shell.execute_reply":"2022-03-26T19:54:40.960274Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"image, label = valid_dataset[0]\nimage = image.get('image').permute(1,2,0).cpu().numpy()\nplt.imshow(image)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"class Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = EfficientNet.from_pretrained('efficientnet-b1')\n        self.dense_output = nn.Linear(1280, 4)\n\n    def forward(self, x):\n        feat = self.model.extract_features(x)\n        feat = F.avg_pool2d(feat, feat.size()[2:]).reshape(-1, 1280)\n        return self.dense_output(feat)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:55:02.314492Z","iopub.execute_input":"2022-03-26T19:55:02.315044Z","iopub.status.idle":"2022-03-26T19:55:02.320402Z","shell.execute_reply.started":"2022-03-26T19:55:02.315003Z","shell.execute_reply":"2022-03-26T19:55:02.319638Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"","metadata":{}},{"cell_type":"code","source":"batch_size = 4 \nnum_workers = 2 \n\ntrain_loader = torch.utils.data.DataLoader(train_dataset,\n                                           batch_size=batch_size,\n                                           num_workers=num_workers,\n                                           shuffle=True)\n\nvalid_loader = torch.utils.data.DataLoader(valid_dataset,\n                                           batch_size=batch_size*2,\n                                           num_workers=num_workers,\n                                           shuffle=False)\n\ndevice = 'cuda'\nmodel = Net().to(device)\n\noptimizer = torch.optim.AdamW(model.parameters(), lr=0.001)\ncriterion = torch.nn.CrossEntropyLoss() ","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:55:31.592536Z","iopub.execute_input":"2022-03-26T19:55:31.593193Z","iopub.status.idle":"2022-03-26T19:55:35.42945Z","shell.execute_reply.started":"2022-03-26T19:55:31.593155Z","shell.execute_reply":"2022-03-26T19:55:35.428685Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def alaska_weighted_auc(y_true, y_valid):\n    tpr_thresholds = [0.0, 0.4, 1.0]\n    weights = [2, 1]\n\n    fpr, tpr, thresholds = metrics.roc_curve(y_true, y_valid, pos_label=1)\n\n    # size of subsets\n    areas = np.array(tpr_thresholds[1:]) - np.array(tpr_thresholds[:-1])\n\n    # The total area is normalized by the sum of weights such that the final weighted AUC is between 0 and 1.\n    normalization = np.dot(areas, weights)\n\n    competition_metric = 0\n    for idx, weight in enumerate(weights):\n        y_min = tpr_thresholds[idx]\n        y_max = tpr_thresholds[idx + 1]\n        mask = (y_min < tpr) & (tpr < y_max)\n        # pdb.set_trace()\n\n        x_padding = np.linspace(fpr[mask][-1], 1, 100)\n\n        x = np.concatenate([fpr[mask], x_padding])\n        y = np.concatenate([tpr[mask], [y_max] * len(x_padding)])\n        y = y - y_min  # normalize such that curve starts at y=0\n        score = metrics.auc(x, y)\n        submetric = score * weight\n        best_subscore = (y_max - y_min) * weight\n        competition_metric += submetric\n\n    return competition_metric / normalization","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:55:38.485264Z","iopub.execute_input":"2022-03-26T19:55:38.48554Z","iopub.status.idle":"2022-03-26T19:55:38.494801Z","shell.execute_reply.started":"2022-03-26T19:55:38.485508Z","shell.execute_reply":"2022-03-26T19:55:38.493496Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"Пример обучения","metadata":{}},{"cell_type":"code","source":"num_epochs = 5\ntrain_loss, val_loss = [], []\n\nfor epoch in range(num_epochs):\n    print('Epoch {}/{}'.format(epoch, num_epochs - 1))\n    print('-' * 10)\n    model.train()\n    running_loss = 0\n    tk0 = tqdm(train_loader, total=int(len(train_loader)))\n    for im, labels in tk0:\n        inputs = im[\"image\"].to(device, dtype=torch.float)\n        labels = labels.to(device, dtype=torch.long)\n        optimizer.zero_grad()\n        outputs = model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        running_loss += loss.item()\n        tk0.set_postfix(loss=(loss.item()))\n\n    epoch_loss = running_loss / (len(train_loader)/batch_size)\n    train_loss.append(epoch_loss)\n    print('Training Loss: {:.8f}'.format(epoch_loss))\n\n    tk1 = tqdm(valid_loader, total=int(len(valid_loader)))\n    model.eval()\n    running_loss = 0\n    y, preds = [], []\n    with torch.no_grad():\n        for (im, labels) in tk1:\n            inputs = im[\"image\"].to(device, dtype=torch.float)\n            labels = labels.to(device, dtype=torch.long)\n            outputs = model(inputs)\n            loss = criterion(outputs, labels)\n            y.extend(labels.cpu().numpy().astype(int))\n            preds.extend(F.softmax(outputs, 1).cpu().numpy())\n            running_loss += loss.item()\n            tk1.set_postfix(loss=(loss.item()))\n\n        epoch_loss = running_loss / (len(valid_loader)/batch_size)\n        val_loss.append(epoch_loss)\n        preds = np.array(preds)\n\n        labels = preds.argmax(1)\n        acc = (labels == y).mean()*100\n        new_preds = np.zeros((len(preds),))\n        temp = preds[labels != 0, 1:]\n        new_preds[labels != 0] = temp.sum(1)\n        new_preds[labels == 0] = preds[labels == 0, 0]\n        y = np.array(y)\n        y[y != 0] = 1\n        auc_score = alaska_weighted_auc(y, new_preds)\n        print(f'Val Loss: {epoch_loss:.3}, Weighted AUC:{auc_score:.3}, Acc: {acc:.3}')\n\n    torch.save(model.state_dict(),f\"epoch_{epoch+4}_val_loss_{epoch_loss:.3}_auc_{auc_score:.3}.pth\")","metadata":{"execution":{"iopub.status.busy":"2022-03-26T19:55:41.913617Z","iopub.execute_input":"2022-03-26T19:55:41.913978Z","iopub.status.idle":"2022-03-26T21:05:51.799352Z","shell.execute_reply.started":"2022-03-26T19:55:41.913933Z","shell.execute_reply":"2022-03-26T21:05:51.798514Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# собираем тестовые картинки\n\nclass Alaska2_TestDataset(Dataset):\n\n    def __init__(self, df, augmentations=None):\n\n        self.data = df\n        self.augment = augmentations\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        fn = self.data.loc[idx][0]\n        im = cv2.imread(fn)[:, :, ::-1]\n\n        if self.augment:\n            im = self.augment(image=im)\n\n        return im\n    \nAUGMENTATIONS_TEST = A.Compose([\n    A.Resize(img_size, img_size, p=1.0),\n    A.ToFloat(max_value=255),\n    ToTensorV2()\n], p=1.0)\n        \n\ndata_dir = '../input/alaska2-image-steganalysis'\n\ntest_filenames = sorted(glob(f\"{data_dir}/Test/*.jpg\"))\ntest_df = pd.DataFrame({'ImageFileName': list(test_filenames)}, columns=['ImageFileName'])\n\nbatch_size = 4 # гиперпараметр\nnum_workers = 2 # гиперпараметр\ntest_dataset = Alaska2_TestDataset(test_df, augmentations=AUGMENTATIONS_TEST)\ntest_loader = torch.utils.data.DataLoader(test_dataset,\n                                          batch_size=batch_size,\n                                          num_workers=num_workers,\n                                          shuffle=False,\n                                          drop_last=False)","metadata":{"execution":{"iopub.status.busy":"2022-03-26T21:07:12.682036Z","iopub.execute_input":"2022-03-26T21:07:12.682285Z","iopub.status.idle":"2022-03-26T21:07:12.715118Z","shell.execute_reply.started":"2022-03-26T21:07:12.682253Z","shell.execute_reply":"2022-03-26T21:07:12.714467Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# получение результата на обученной модели\n\nmodel.eval()\n\npreds = []\ntk0 = tqdm(test_loader)\nwith torch.no_grad():\n    for i, im in enumerate(tk0):\n        inputs = im[\"image\"].to(device)\n        # flip vertical\n        im = inputs.flip(2)\n        outputs = model(im)\n        # fliplr\n        im = inputs.flip(3)\n        outputs = (0.25*outputs + 0.25*model(im))\n        outputs = (outputs + 0.5*model(inputs))        \n        preds.extend(F.softmax(outputs, 1).cpu().numpy())\n\npreds = np.array(preds)\nlabels = preds.argmax(1)\nnew_preds = np.zeros((len(preds),))\ntemp = preds[labels != 0, 1:]\nnew_preds[labels != 0] = temp.sum(1)\nnew_preds[labels == 0] = preds[labels == 0, 0]\n\ntest_df['Id'] = test_df['ImageFileName'].apply(lambda x: x.split(os.sep)[-1])\ntest_df['Label'] = new_preds\n\ntest_df = test_df.drop('ImageFileName', axis=1)\ntest_df.to_csv('submission.csv', index=False)\nprint(test_df.head())","metadata":{"execution":{"iopub.status.busy":"2022-03-26T21:07:20.078255Z","iopub.execute_input":"2022-03-26T21:07:20.078527Z","iopub.status.idle":"2022-03-26T21:09:39.414359Z","shell.execute_reply.started":"2022-03-26T21:07:20.078494Z","shell.execute_reply":"2022-03-26T21:09:39.413601Z"},"trusted":true},"execution_count":null,"outputs":[]}]}