{"cells":[{"metadata":{"trusted":true},"cell_type":"code","source":"! git clone https://github.com/dwgoon/jpegio\n# Once downloaded install the package\n!pip install jpegio/.\nimport jpegio as jio","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"This notebook is a small noob attempt to implement the model shown in the following paper:\nhttps://arxiv.org/ftp/arxiv/papers/1704/1704.08378.pdf\n\nWith few changes on the way since I am still almost a novice in this field","execution_count":null},{"metadata":{"trusted":true},"cell_type":"code","source":"import jpegio as jpio\nimport matplotlib.pyplot as plt\nimport matplotlib.image as mpimg\nimport cv2","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torchvision\nfrom torchvision import transforms,datasets\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\n'''for dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))'''\n\n# You can write up to 5GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import os \nimport cv2\nimport numpy as np\nfrom tqdm.notebook import tqdm\nimport sys\n\nREBUILD_DATA= True","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\ndevice","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Image preprocessing modules\ntrain_transform = transforms.Compose([\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomVerticalFlip(p=0.5),\n    transforms.Resize(512, 512),\n    transforms.ToTensor()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# For updating learning rate\ndef update_lr(optimizer, lr):    \n    for param_group in optimizer.param_groups:\n        param_group['lr'] = lr","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"BASE_PATH = \"/kaggle/input/alaska2-image-steganalysis\"\ntrain_imageids = pd.Series(os.listdir(BASE_PATH + '/Cover')).sort_values(ascending=True).reset_index(drop=True)\ntest_imageids = pd.Series(os.listdir(BASE_PATH + '/Test')).sort_values(ascending=True).reset_index(drop=True)\nsub = pd.read_csv('/kaggle/input/alaska2-image-steganalysis/sample_submission.csv')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_transform=transforms.Compose([\n    transforms.Resize(512, 512),\n    transforms.ToTensor()])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(test_imageids.head(3))\ntrain_imageids.head()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#https://www.kaggle.com/xhlulu/alaska2-efficientnet-on-tpus\ndef append_path(pre):\n    return np.vectorize(lambda file: os.path.join(BASE_PATH, pre, file))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_filenames = np.array(os.listdir(\"/kaggle/input/alaska2-image-steganalysis/Cover/\"))\nprint(len(train_filenames))\ntrain_filenames","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#https://www.kaggle.com/xhlulu/alaska2-efficientnet-on-tpus\nnp.random.seed(0)\npositives = train_filenames.copy()\nnegatives = train_filenames.copy()\nnp.random.shuffle(positives)\nnp.random.shuffle(negatives)\n\njmipod = append_path('JMiPOD')(positives[:10000])\njuniward = append_path('JUNIWARD')(positives[10000:20000])\nuerd = append_path('UERD')(positives[20000:30000])\n\npos_paths = np.concatenate([jmipod, juniward, uerd])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"test_paths = append_path('Test')(sub.Id.values)\nneg_paths = append_path('Cover')(negatives[:30000])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_paths = np.concatenate([pos_paths, neg_paths])\ntrain_labels = np.array([1] * len(pos_paths) + [0] * len(neg_paths))\nprint(train_paths)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from sklearn.model_selection import train_test_split","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#https://www.kaggle.com/xhlulu/alaska2-efficientnet-on-tpus\ntrain_paths, valid_paths, train_labels, valid_labels = train_test_split(\n    train_paths, train_labels, test_size=0.15, random_state=2020)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(len(train_paths))\nprint(len(valid_paths))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"l=np.array([train_paths,train_labels])\ntraindataset = pd.DataFrame({ 'images': list(train_paths), 'label': train_labels},columns=['images','label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"traindataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"val_l=np.array([valid_paths,valid_labels])\nvaliddataset=dataset = pd.DataFrame({ 'images': list(valid_paths), 'label': valid_labels},columns=['images','label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"validdataset","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from PIL import Image, ImageFile\nfrom tqdm import tqdm_notebook as tqdm\nimport scipy                        # for cosine similarity\nfrom scipy import fftpack","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# add image augmen tation\nclass train_images(torch.utils.data.Dataset):\n\n    def __init__(self, csv_file):\n\n        self.data = csv_file\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        #print(idx)\n        img_name =  self.data.loc[idx][0]\n        jpegStruct = jpio.read(img_name)\n        image=np.zeros([512, 512, 3])\n        for j in range(3):\n            image[:,:,j]=jpegStruct.coef_arrays[j]\n        #image = Image.open(img_name)\n        label = self.data.loc[idx][1] #torch.tensor(self.data.loc[idx, 'label'])\n       \n\n# ## https://pytorch.org/docs/stable/torchvision/transforms.html\n# transforms.Compose([\n# transforms.CenterCrop(10),\n# transforms.ToTensor(),\n# ])\n        \n#         return {'image': transforms.ToTensor()(image), # ORIG\n        return {'image': image,\n            'label': label\n            }\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_dataset = train_images(traindataset)\nvalid_dataset = train_images(validdataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(type(train_dataset))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"len(train_dataset)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size = 32\nepochs = 2\nlearning_rate = 0.001","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_loader = torch.utils.data.DataLoader(train_dataset, batch_size = batch_size, shuffle=True, num_workers=4)\nvalid_loader = torch.utils.data.DataLoader(valid_dataset, batch_size = batch_size, shuffle=True, num_workers=4)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def conv3x3(in_channels, out_channels, stride=1, padding = 0):\n    return nn.Conv2d(in_channels, out_channels, kernel_size=3, \n                     stride=stride, padding = padding, bias=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class IdentityBlock(nn.Module):\n    def __init__(self, in_channels, out_channels, stride):\n        super().__init__()\n        self.expansion=1\n        self.conv1 = conv3x3(in_channels, in_channels, stride=1, padding = 1)\n        self.bn1 = nn.BatchNorm2d(in_channels)\n        self.relu = nn.ReLU(inplace=False)\n        \n        self.pad = 1\n        if stride!=1:\n            self.expansion=2\n            \n        self.conv2 = conv3x3(in_channels, out_channels ,stride, padding = self.pad)\n        self.bn2 = nn.BatchNorm2d(out_channels)\n        \n    def forward(self, x,):\n        residual = x\n        out = self.conv1(x)\n        out = self.bn1(out)\n        out = self.relu(out)\n        out = self.conv2(out)\n        out = self.bn2(out)\n        \n        if self.expansion==2:\n            residual = self.conv2(residual)\n            residual = self.bn2(residual)\n            \n        out += residual\n        out = self.relu(out)\n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class ResNet(nn.Module):\n    def __init__(self, block, dct_input_channel,  num_classes=2):\n        super(ResNet, self).__init__()\n        \n        self.in_channels = 24\n        self.conv1 = conv3x3(dct_input_channel, int(self.in_channels/2), padding = 1)\n        self.bn1 = nn.BatchNorm2d(int(self.in_channels/2))\n        self.relu = nn.ReLU(inplace=False)\n        self.conv2 = conv3x3(int(self.in_channels/2), self.in_channels, stride =2)\n        self.bn2 = nn.BatchNorm2d(self.in_channels)\n        \n        self.conv= conv3x3(dct_input_channel, self.in_channels, stride = 2)\n        \n        self.layer1 = self.make_layer(block, self.in_channels*2) #in_channels = 24 \n        self.layer2 = self.make_layer(block, self.in_channels*2)\n        self.layer3 = self.make_layer(block, self.in_channels*2)\n        self.layer4 = self.make_layer(block, self.in_channels*2)\n        \n        self.avg_pool = nn.AvgPool2d(16)\n        self.fc = nn.Linear(self.in_channels , num_classes)\n        \n    def make_layer(self, block, out_channels):\n        layers = []\n        layers.append(block(self.in_channels, self.in_channels , stride =1))\n        layers.append(block(self.in_channels, out_channels , stride =2))\n        self.in_channels=out_channels\n        return nn.Sequential(*layers)\n    \n    def forward(self, x):\n        residual= self.relu(self.bn2(self.conv(x)))\n        out = self.relu(self.bn1(self.conv1(x)))\n        out = self.relu(self.bn2(self.conv2(out)))\n        out+=residual\n        \n        out = self.layer1(out)\n        out = self.layer2(out)\n        out = self.layer3(out)\n        out = self.layer4(out)\n        out = self.avg_pool(out)\n        out = out.view(out.size(0), -1)\n        out = self.fc(out)\n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model = ResNet(IdentityBlock, 3).to(device)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"criterion = nn.CrossEntropyLoss()\noptimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)\n\nprint(model)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"epoch_loss = 0\ntotal_step = len(train_loader)\ncurr_lr = learning_rate\nfor epoch in range(epochs):\n\n    tk0 = tqdm(train_loader, total=int(len(train_loader)))\n    counter = 0\n    for bi, d in enumerate(tk0):\n            inputs = d[\"image\"]\n            labels = d[\"label\"].view(-1, 1)\n    \n            inputs = inputs.to(device, dtype=torch.float)\n            labels = labels.to(device, dtype=torch.long)\n            #labels = labels.squeeze(1)\n        \n            inputs = inputs.view(-1,3,512,512)\n            #print(inputs.shape)\n            \n            # Forward pass\n            outputs = model(inputs)\n            loss  = criterion(outputs, torch.max(labels, 1)[1])\n\n            # Backward and optimize\n            optimizer.zero_grad()\n            loss.backward()\n            optimizer.step()\n            epoch_loss =epoch_loss + loss.item()\n            \n    epoch_loss = epoch_loss / (len(train_loader)/batch_size)\n    print (\"Epoch [{}/{}] Loss: {:.4f}\".format(epoch+1, epochs, epoch_loss))\n\n    # Decay learning rate\n    curr_lr /= 3\n    update_lr(optimizer, curr_lr)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"model.eval()\nwith torch.no_grad():\n    correct = 0\n    total = 0\n    tk0 = tqdm(valid_loader, total=int(len(valid_loader)))\n    counter = 0\n    for bi, d in enumerate(tk0):\n            inputs = d[\"image\"]\n            labels = d[\"label\"].view(-1, 1)\n    \n            inputs = inputs.to(device, dtype=torch.float)\n            labels = labels.to(device, dtype=torch.long)\n            inputs = inputs.view(-1,3,512,512)\n   \n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n    \n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n            for i,val in enumerate(predicted):\n                print(val)\n    print(\"correct\",correct)\n    print(\"total\", total)\n    print('Accuracy of the model on the test images: {} %'.format(100 * correct / total))","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"torch.save(model.state_dict(), 'resnet.ckpt')","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}