{"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 albumentations==0.5.2\nfrom efficientnet_pytorch import EfficientNet\nfrom albumentations.pytorch import ToTensorV2\nfrom albumentations import (\n    Compose, HorizontalFlip, CLAHE, HueSaturationValue,\n    RandomBrightness, RandomContrast, RandomGamma, OneOf, Resize,\n    ToFloat, ShiftScaleRotate, GridDistortion, ElasticTransform, JpegCompression, HueSaturationValue,\n    RGBShift, RandomBrightness, RandomContrast, Blur, MotionBlur, MedianBlur, GaussNoise, CenterCrop,\n    IAAAdditiveGaussianNoise, GaussNoise, OpticalDistortion, RandomSizedCrop, VerticalFlip\n)\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":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2021-12-05T03:22:23.056395Z","iopub.execute_input":"2021-12-05T03:22:23.056674Z","iopub.status.idle":"2021-12-05T03:22:37.734412Z","shell.execute_reply.started":"2021-12-05T03:22:23.056641Z","shell.execute_reply":"2021-12-05T03:22:37.733583Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 随机数\nseed = 42\nprint(f'setting everything to seed {seed}')\nrandom.seed(seed)\nos.environ['PYTHONHASHSEED'] = str(seed)\nnp.random.seed(seed)\ntorch.manual_seed(seed)\ntorch.cuda.manual_seed(seed)\ntorch.backends.cudnn.deterministic = True","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:37.738072Z","iopub.execute_input":"2021-12-05T03:22:37.738293Z","iopub.status.idle":"2021-12-05T03:22:37.746414Z","shell.execute_reply.started":"2021-12-05T03:22:37.738266Z","shell.execute_reply":"2021-12-05T03:22:37.745534Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 创建train 和 test\ndata_dir = '../input/alaska2-image-steganalysis'\nsample_size = 75000\nval_size = int(sample_size*0.25)\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    train_fn.extend(train_filenames[val_size:])\n    train_labels.extend(np.zeros(len(train_filenames[val_size:],))+label)\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), \"wrong labels\"\nassert len(val_labels) == len(val_fn), \"wrong labels\"\n\n# 验证\ntrain_df = pd.DataFrame({'ImageFileName': train_fn, 'Label': train_labels}, columns=['ImageFileName', 'Label'])\ntrain_df['Label'] = train_df['Label'].astype(int)\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)\ntrain_df.Label.hist()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:37.748375Z","iopub.execute_input":"2021-12-05T03:22:37.749003Z","iopub.status.idle":"2021-12-05T03:22:39.157178Z","shell.execute_reply.started":"2021-12-05T03:22:37.748963Z","shell.execute_reply":"2021-12-05T03:22:39.156451Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Pytorch 数据集构建\nclass Alaska2Dataset(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 = Compose([\n    Resize(img_size, img_size, p=1),\n    VerticalFlip(p=0.5),\n    HorizontalFlip(p=0.5),\n    JpegCompression(quality_lower=75, quality_upper=100,p=0.5),\n    ToFloat(max_value=255),\n    ToTensorV2()\n], p=1)\n\n\nAUGMENTATIONS_TEST = Compose([\n    Resize(img_size, img_size, p=1),\n    ToFloat(max_value=255),\n    ToTensorV2()\n], p=1)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:39.158591Z","iopub.execute_input":"2021-12-05T03:22:39.158893Z","iopub.status.idle":"2021-12-05T03:22:39.167921Z","shell.execute_reply.started":"2021-12-05T03:22:39.15885Z","shell.execute_reply":"2021-12-05T03:22:39.166971Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# test 数据集 不做图像增强\ntemp_df = train_df.sample(64).reset_index(drop=True)\ntrain_dataset = Alaska2Dataset(temp_df, augmentations=AUGMENTATIONS_TEST)\nbatch_size = 64\nnum_workers = 0\n\ntemp_loader = torch.utils.data.DataLoader(train_dataset,\n                                          batch_size=batch_size,\n                                          num_workers=num_workers, shuffle=False)\n\n\nimages, labels = next(iter(temp_loader))\nimages = images['image'].permute(0, 2, 3, 1)\nmax_images = 64\ngrid_width = 16\ngrid_height = int(max_images / grid_width)\nfig, axs = plt.subplots(grid_height, grid_width,figsize=(grid_width+1, grid_height+1))\n\nfor i, (im, label) in enumerate(zip(images, labels)):\n    ax = axs[int(i / grid_width), i % grid_width]\n    ax.imshow(im.squeeze())\n    ax.set_title(str(label.item()))\n    ax.axis('off')\n\nplt.suptitle(\"0: COVER, 1: JMiPOD, 2: JUNIWARD, 3:UERD\")\nplt.show()\ndel images\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:39.171087Z","iopub.execute_input":"2021-12-05T03:22:39.171763Z","iopub.status.idle":"2021-12-05T03:22:45.267139Z","shell.execute_reply.started":"2021-12-05T03:22:39.171711Z","shell.execute_reply":"2021-12-05T03:22:45.266423Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# train 数据集 进行图像增强\ntrain_dataset = Alaska2Dataset(temp_df, augmentations=AUGMENTATIONS_TRAIN)\nbatch_size = 64\nnum_workers = 0\n\ntemp_loader = torch.utils.data.DataLoader(train_dataset,\n                                          batch_size=batch_size,\n                                          num_workers=num_workers, shuffle=False)\n\n\nimages, labels = next(iter(temp_loader))\nimages = images['image'].permute(0, 2, 3, 1)\nmax_images = 64\ngrid_width = 16\ngrid_height = int(max_images / grid_width)\nfig, axs = plt.subplots(grid_height, grid_width,\n                        figsize=(grid_width+1, grid_height+1))\n\nfor i, (im, label) in enumerate(zip(images, labels)):\n    ax = axs[int(i / grid_width), i % grid_width]\n    ax.imshow(im.squeeze())\n    ax.set_title(str(label.item()))\n    ax.axis('off')\n\nplt.suptitle(\"0: No Hidden Message, 1: JMiPOD, 2: JUNIWARD, 3:UERD\")\nplt.show()\ndel images, temp_df\ngc.collect()","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:45.268505Z","iopub.execute_input":"2021-12-05T03:22:45.268906Z","iopub.status.idle":"2021-12-05T03:22:51.116163Z","shell.execute_reply.started":"2021-12-05T03:22:45.268872Z","shell.execute_reply":"2021-12-05T03:22:51.115551Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# 搭建 网络 efficient b0\nclass Net(nn.Module):\n    def __init__(self):\n        super().__init__()\n        self.model = EfficientNet.from_pretrained('efficientnet-b0')\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":"2021-12-05T03:22:51.117295Z","iopub.execute_input":"2021-12-05T03:22:51.119777Z","iopub.status.idle":"2021-12-05T03:22:51.126377Z","shell.execute_reply.started":"2021-12-05T03:22:51.119736Z","shell.execute_reply":"2021-12-05T03:22:51.12555Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"batch_size = 8\nnum_workers = 8\n\n# 构建数据集\ntrain_dataset = Alaska2Dataset(train_df, augmentations=AUGMENTATIONS_TRAIN)\nvalid_dataset = Alaska2Dataset(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)\n\ndevice = 'cuda'\nmodel = Net().to(device)\nmodel.load_state_dict(torch.load('../input/alaska/epoch_13_val_loss_6.67_auc_0.819.pth'))\noptimizer = torch.optim.AdamW(model.parameters(), lr=1e-4)","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:22:51.127758Z","iopub.execute_input":"2021-12-05T03:22:51.128312Z","iopub.status.idle":"2021-12-05T03:22:51.337452Z","shell.execute_reply.started":"2021-12-05T03:22:51.128267Z","shell.execute_reply":"2021-12-05T03:22:51.336724Z"},"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":"2021-12-05T03:22:51.339105Z","iopub.execute_input":"2021-12-05T03:22:51.339592Z","iopub.status.idle":"2021-12-05T03:22:51.349238Z","shell.execute_reply.started":"2021-12-05T03:22:51.339545Z","shell.execute_reply":"2021-12-05T03:22:51.348385Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"criterion = torch.nn.CrossEntropyLoss()\nnum_epochs = 0\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":"2021-12-05T03:22:51.350326Z","iopub.execute_input":"2021-12-05T03:22:51.351987Z","iopub.status.idle":"2021-12-05T03:23:58.080751Z","shell.execute_reply.started":"2021-12-05T03:22:51.351959Z","shell.execute_reply":"2021-12-05T03:23:58.079525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"plt.figure(figsize=(15,7))\nplt.plot(train_loss, c='r')\nplt.plot(val_loss, c='b')\nplt.legend(['train_loss', 'val_loss'])\nplt.title('Loss Plot')","metadata":{"execution":{"iopub.status.busy":"2021-12-05T03:23:58.08241Z","iopub.status.idle":"2021-12-05T03:23:58.082865Z","shell.execute_reply.started":"2021-12-05T03:23:58.08262Z","shell.execute_reply":"2021-12-05T03:23:58.082656Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"markdown","source":"# 进行测试","metadata":{}},{"cell_type":"code","source":"# 构建测试集数据\nclass Alaska2TestDataset(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\n\ntest_filenames = sorted(glob(f\"{data_dir}/Test/*.jpg\"))\ntest_df = pd.DataFrame({'ImageFileName': list(test_filenames)}, columns=['ImageFileName'])\n\nbatch_size = 16\nnum_workers = 4\ntest_dataset = Alaska2TestDataset(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":"2021-12-05T03:23:58.084805Z","iopub.status.idle":"2021-12-05T03:23:58.085231Z","shell.execute_reply.started":"2021-12-05T03:23:58.08499Z","shell.execute_reply":"2021-12-05T03:23:58.085012Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model.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:]\n# new_preds[labels != 0] = [temp[i, val] for i, val in enumerate(temp.argmax(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":"2021-12-05T03:23:58.08661Z","iopub.status.idle":"2021-12-05T03:23:58.087061Z","shell.execute_reply.started":"2021-12-05T03:23:58.086814Z","shell.execute_reply":"2021-12-05T03:23:58.086836Z"},"trusted":true},"execution_count":null,"outputs":[]}]}