{"cells":[{"metadata":{},"cell_type":"markdown","source":"# Simple baseline binary Densenet169 classifier \n\nThis Kernel is a shameless copy from Public Kernels from the people who has already invested a lot of time in this comp and shared their great ideas . I am just trying to use that and setup some basic training pipeline.\n\n\n\nThanks to:  \n[@unkownhihi](https://www.kaggle.com/unkownhihi) for dataset and corresponding kernal: https://www.kaggle.com/unkownhihi/starter-kernel-with-cnn-model-ll-lb-0-69235\n[@humananalog](https://www.kaggle.com/humananalog) for inference kernal: https://www.kaggle.com/humananalog/inference-demo\n\nand ofcourse [https://www.kaggle.com/greatgamedota]\n https://www.kaggle.com/greatgamedota/xception-binary-classifier-inference\n\nSpecial Thanks to [https://www.kaggle.com/haqishen] for the gridmask implementation\n\n"},{"metadata":{"id":"YjwlB710mIH_","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"import pandas as pd\nimport numpy as np\nimport matplotlib.pyplot as plt\nimport cv2\nimport os\nfrom tqdm import tqdm,trange\nfrom sklearn.model_selection import train_test_split\nimport sklearn.metrics\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")\nimport re\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\nimport torch.utils.checkpoint as cp\nfrom collections import OrderedDict\nfrom torch import Tensor\nfrom torch.jit.annotations import List","execution_count":null,"outputs":[]},{"metadata":{"id":"AaU3SeKMz_qm","colab_type":"text"},"cell_type":"markdown","source":"# Setup Data"},{"metadata":{"trusted":true},"cell_type":"code","source":"df_trains = []\ndf_vals = []\nfor i in range(46):\n    df = pd.read_json(f'../input/deepfake/metadata{i}.json')\n    df_trains.append(df)\nfor i in range (47,49,1) :\n    df = pd.read_json(f'../input/deepfake/metadata{i}.json')\n    df_vals.append(df)\n    \nnums = list(range(len(df_trains)+1))\nLABELS = ['REAL','FAKE']\nval_nums=[47, 48, 49]    ","execution_count":null,"outputs":[]},{"metadata":{"id":"FSPvZdzbzKd5","colab_type":"code","outputId":"fe78b0b0-aab7-4dfd-d33c-0af316b60f04","colab":{"base_uri":"https://localhost:8080/"},"trusted":true},"cell_type":"code","source":"def get_path(num,x):\n    num=str(num)\n    if len(num)==2:\n        path='../input/deepfake/DeepFake'+num+'/DeepFake'+num+'/' + x.replace('.mp4', '') + '.jpg'\n    else:\n        path='../input/deepfake/DeepFake0'+num+'/DeepFake0'+num+'/' + x.replace('.mp4', '') + '.jpg'\n    if not os.path.exists(path):\n       raise Exception\n    return path\npaths=[]\ny=[]\nfor df_train,num in tqdm(zip(df_trains,nums),total=len(df_trains)):\n    images = list(df_train.columns.values)\n    for x in images:\n        try:\n            paths.append(get_path(num,x))\n            y.append(LABELS.index(df_train[x]['label']))\n        except Exception as err:\n            #print(err)\n            pass\n\nval_paths=[]\nval_y=[]\nfor df_val,num in tqdm(zip(df_vals,val_nums),total=len(df_vals)):\n    images = list(df_val.columns.values)\n    for x in images:\n        try:\n            val_paths.append(get_path(num,x))\n            val_y.append(LABELS.index(df_val[x]['label']))\n        except Exception as err:\n            #print(err)\n            pass","execution_count":null,"outputs":[]},{"metadata":{"id":"QXIIa5A-zfa3","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"def read_img(path):\n    return cv2.cvtColor(cv2.imread(path),cv2.COLOR_BGR2RGB)\n\ndef shuffle(X,y):\n    new_train=[]\n    for m,n in zip(X,y):\n        new_train.append([m,n])\n    random.shuffle(new_train)\n    X,y=[],[]\n    for x in new_train:\n        X.append(x[0])\n        y.append(x[1])\n    del new_train    \n    return X,y\n\nimport random\ndef get_random_sampling(paths, y, val_paths, val_y):\n  real=[]\n  fake=[]\n  for m,n in zip(paths,y):\n      if n==0:\n          real.append(m)\n      else:\n          fake.append(m)\n  # fake=random.sample(fake,len(real))\n  paths,y=[],[]\n  for x in real:\n      paths.append(x)\n      y.append(0)\n  for x in fake:\n      paths.append(x)\n      y.append(1)\n\n  real=[]\n  fake=[]\n  for m,n in zip(val_paths,val_y):\n      if n==0:\n          real.append(m)\n      else:\n          fake.append(m)\n  # fake=random.sample(fake,len(real))\n  val_paths,val_y=[],[]\n  for x in real:\n      val_paths.append(x)\n      val_y.append(0)\n  for x in fake:\n      val_paths.append(x)\n      val_y.append(1)\n\n  X=[]\n  for img in tqdm(paths):\n      X.append(read_img(img))\n  val_X=[]\n  for img in tqdm(val_paths):\n      val_X.append(read_img(img))\n\n\n  X, y = shuffle(X,y)\n  val_X, val_y = shuffle(val_X,val_y)\n\n  return X, val_X, y, val_y","execution_count":null,"outputs":[]},{"metadata":{"id":"HmvRDCqmaa_i","colab_type":"text"},"cell_type":"markdown","source":"# Dataset"},{"metadata":{"id":"7KNA5r-7afVp","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"from torch.utils.data import Dataset, DataLoader\nmean = [0.485, 0.456, 0.406]\nstd = [0.229, 0.224, 0.225]\n\nclass ImageDataset(Dataset):\n    def __init__(self, X, y, training=True, transform=None):\n        self.X = X\n        self.y = y\n        self.transform = transform\n        self.training = training\n\n    def __len__(self):\n        return len(self.X)\n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        \n        img = self.X[idx]\n\n        if self.transform is not None:\n          res = self.transform(image=img)\n          img = res['image']\n        \n        img = np.rollaxis(img, 2, 0)\n        # img = np.array(img).astype(np.float32) / 255.\n\n        labels = self.y[idx]\n        labels = np.array(labels).astype(np.float32)\n        return [img, labels]","execution_count":null,"outputs":[]},{"metadata":{"id":"-xvk_DhD1iUn","colab_type":"text"},"cell_type":"markdown","source":"## Model from Torchvision"},{"metadata":{"trusted":true},"cell_type":"code","source":"try:\n    from torch.hub import load_state_dict_from_url\nexcept ImportError:\n    from torch.utils.model_zoo import load_url as load_state_dict_from_url","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"__all__ = ['DenseNet', 'densenet121', 'densenet169', 'densenet201', 'densenet161']\n\nmodel_urls = {\n    'densenet121': 'https://download.pytorch.org/models/densenet121-a639ec97.pth',\n    'densenet169': 'https://download.pytorch.org/models/densenet169-b2777c0a.pth',\n    'densenet201': 'https://download.pytorch.org/models/densenet201-c1103571.pth',\n    'densenet161': 'https://download.pytorch.org/models/densenet161-8d451a50.pth',\n}","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class _DenseLayer(nn.Module):\n    def __init__(self, num_input_features, growth_rate, bn_size, drop_rate, memory_efficient=False):\n        super(_DenseLayer, self).__init__()\n        self.add_module('norm1', nn.BatchNorm2d(num_input_features)),\n        self.add_module('relu1', nn.ReLU(inplace=True)),\n        self.add_module('conv1', nn.Conv2d(num_input_features, bn_size *\n                                           growth_rate, kernel_size=1, stride=1,\n                                           bias=False)),\n        self.add_module('norm2', nn.BatchNorm2d(bn_size * growth_rate)),\n        self.add_module('relu2', nn.ReLU(inplace=True)),\n        self.add_module('conv2', nn.Conv2d(bn_size * growth_rate, growth_rate,\n                                           kernel_size=3, stride=1, padding=1,\n                                           bias=False)),\n        self.drop_rate = float(drop_rate)\n        self.memory_efficient = memory_efficient\n\n    def bn_function(self, inputs):\n        # type: (List[Tensor]) -> Tensor\n        concated_features = torch.cat(inputs, 1)\n        bottleneck_output = self.conv1(self.relu1(self.norm1(concated_features)))  # noqa: T484\n        return bottleneck_output\n\n    # todo: rewrite when torchscript supports any\n    def any_requires_grad(self, input):\n        # type: (List[Tensor]) -> bool\n        for tensor in input:\n            if tensor.requires_grad:\n                return True\n        return False\n\n    @torch.jit.unused  # noqa: T484\n    def call_checkpoint_bottleneck(self, input):\n        # type: (List[Tensor]) -> Tensor\n        def closure(*inputs):\n            return self.bn_function(*inputs)\n\n        return cp.checkpoint(closure, input)\n\n    @torch.jit._overload_method  # noqa: F811\n    def forward(self, input):\n        # type: (List[Tensor]) -> (Tensor)\n        pass\n\n    @torch.jit._overload_method  # noqa: F811\n    def forward(self, input):\n        # type: (Tensor) -> (Tensor)\n        pass\n\n    # torchscript does not yet support *args, so we overload method\n    # allowing it to take either a List[Tensor] or single Tensor\n    def forward(self, input):  # noqa: F811\n        if isinstance(input, Tensor):\n            prev_features = [input]\n        else:\n            prev_features = input\n\n        if self.memory_efficient and self.any_requires_grad(prev_features):\n            if torch.jit.is_scripting():\n                raise Exception(\"Memory Efficient not supported in JIT\")\n\n            bottleneck_output = self.call_checkpoint_bottleneck(prev_features)\n        else:\n            bottleneck_output = self.bn_function(prev_features)\n\n        new_features = self.conv2(self.relu2(self.norm2(bottleneck_output)))\n        if self.drop_rate > 0:\n            new_features = F.dropout(new_features, p=self.drop_rate,\n                                     training=self.training)\n        return new_features\n\n\nclass _DenseBlock(nn.ModuleDict):\n    _version = 2\n\n    def __init__(self, num_layers, num_input_features, bn_size, growth_rate, drop_rate, memory_efficient=False):\n        super(_DenseBlock, self).__init__()\n        for i in range(num_layers):\n            layer = _DenseLayer(\n                num_input_features + i * growth_rate,\n                growth_rate=growth_rate,\n                bn_size=bn_size,\n                drop_rate=drop_rate,\n                memory_efficient=memory_efficient,\n            )\n            self.add_module('denselayer%d' % (i + 1), layer)\n\n    def forward(self, init_features):\n        features = [init_features]\n        for name, layer in self.items():\n            new_features = layer(features)\n            features.append(new_features)\n        return torch.cat(features, 1)\n\n\nclass _Transition(nn.Sequential):\n    def __init__(self, num_input_features, num_output_features):\n        super(_Transition, self).__init__()\n        self.add_module('norm', nn.BatchNorm2d(num_input_features))\n        self.add_module('relu', nn.ReLU(inplace=True))\n        self.add_module('conv', nn.Conv2d(num_input_features, num_output_features,\n                                          kernel_size=1, stride=1, bias=False))\n        self.add_module('pool', nn.AvgPool2d(kernel_size=2, stride=2))\n\n\nclass DenseNet(nn.Module):\n    r\"\"\"Densenet-BC model class, based on\n    `\"Densely Connected Convolutional Networks\" <https://arxiv.org/pdf/1608.06993.pdf>`_\n    Args:\n        growth_rate (int) - how many filters to add each layer (`k` in paper)\n        block_config (list of 4 ints) - how many layers in each pooling block\n        num_init_features (int) - the number of filters to learn in the first convolution layer\n        bn_size (int) - multiplicative factor for number of bottle neck layers\n          (i.e. bn_size * k features in the bottleneck layer)\n        drop_rate (float) - dropout rate after each dense layer\n        num_classes (int) - number of classification classes\n        memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,\n          but slower. Default: *False*. See `\"paper\" <https://arxiv.org/pdf/1707.06990.pdf>`_\n    \"\"\"\n\n    def __init__(self, growth_rate=32, block_config=(6, 12, 24, 16),\n                 num_init_features=64, bn_size=4, drop_rate=0, num_classes=1000, memory_efficient=False):\n\n        super(DenseNet, self).__init__()\n\n        # First convolution\n        self.features = nn.Sequential(OrderedDict([\n            ('conv0', nn.Conv2d(3, num_init_features, kernel_size=7, stride=2,\n                                padding=3, bias=False)),\n            ('norm0', nn.BatchNorm2d(num_init_features)),\n            ('relu0', nn.ReLU(inplace=True)),\n            ('pool0', nn.MaxPool2d(kernel_size=3, stride=2, padding=1)),\n        ]))\n\n        # Each denseblock\n        num_features = num_init_features\n        for i, num_layers in enumerate(block_config):\n            block = _DenseBlock(\n                num_layers=num_layers,\n                num_input_features=num_features,\n                bn_size=bn_size,\n                growth_rate=growth_rate,\n                drop_rate=drop_rate,\n                memory_efficient=memory_efficient\n            )\n            self.features.add_module('denseblock%d' % (i + 1), block)\n            num_features = num_features + num_layers * growth_rate\n            if i != len(block_config) - 1:\n                trans = _Transition(num_input_features=num_features,\n                                    num_output_features=num_features // 2)\n                self.features.add_module('transition%d' % (i + 1), trans)\n                num_features = num_features // 2\n\n        # Final batch norm\n        self.features.add_module('norm5', nn.BatchNorm2d(num_features))\n\n        # Linear layer\n        self.classifier = nn.Linear(num_features, num_classes)\n\n        # Official init from torch repo.\n        for m in self.modules():\n            if isinstance(m, nn.Conv2d):\n                nn.init.kaiming_normal_(m.weight)\n            elif isinstance(m, nn.BatchNorm2d):\n                nn.init.constant_(m.weight, 1)\n                nn.init.constant_(m.bias, 0)\n            elif isinstance(m, nn.Linear):\n                nn.init.constant_(m.bias, 0)\n\n    def forward(self, x):\n        features = self.features(x)\n        out = F.relu(features, inplace=True)\n        out = F.adaptive_avg_pool2d(out, (1, 1))\n        out = torch.flatten(out, 1)\n        out = self.classifier(out)\n        return out","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def _load_state_dict(model, model_url, progress):\n    # '.'s are no longer allowed in module names, but previous _DenseLayer\n    # has keys 'norm.1', 'relu.1', 'conv.1', 'norm.2', 'relu.2', 'conv.2'.\n    # They are also in the checkpoints in model_urls. This pattern is used\n    # to find such keys.\n    pattern = re.compile(\n        r'^(.*denselayer\\d+\\.(?:norm|relu|conv))\\.((?:[12])\\.(?:weight|bias|running_mean|running_var))$')\n\n    state_dict = load_state_dict_from_url(model_url, progress=progress)\n    for key in list(state_dict.keys()):\n        res = pattern.match(key)\n        if res:\n            new_key = res.group(1) + res.group(2)\n            state_dict[new_key] = state_dict[key]\n            del state_dict[key]\n    model.load_state_dict(state_dict)\n\n\ndef _densenet(arch, growth_rate, block_config, num_init_features, pretrained, progress,\n              **kwargs):\n    model = DenseNet(growth_rate, block_config, num_init_features, **kwargs)\n    if pretrained:\n        _load_state_dict(model, model_urls[arch], progress)\n    return model","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def densenet169(pretrained=False, progress=True, **kwargs):\n    r\"\"\"Densenet-169 model from\n    `\"Densely Connected Convolutional Networks\" <https://arxiv.org/pdf/1608.06993.pdf>`_\n    Args:\n        pretrained (bool): If True, returns a model pre-trained on ImageNet\n        progress (bool): If True, displays a progress bar of the download to stderr\n        memory_efficient (bool) - If True, uses checkpointing. Much more memory efficient,\n          but slower. Default: *False*. See `\"paper\" <https://arxiv.org/pdf/1707.06990.pdf>`_\n    \"\"\"\n    return _densenet('densenet169', 32, (6, 12, 32, 32), 64, pretrained, progress,\n                     **kwargs)\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Create base Model for our purpose\nmodel = densenet169(pretrained =True)","execution_count":null,"outputs":[]},{"metadata":{"id":"dcIJUiPx1DgP","colab_type":"code","outputId":"d8024ba7-ca65-4aed-c2c8-042a5274fdf4","colab":{"base_uri":"https://localhost:8080/","height":52},"trusted":true},"cell_type":"code","source":"## Remove the head from the model because we dont need to do 1000 class classification like imagenet\nmodel = nn.Sequential(*list(model.children())[:-1]) # Remove original output layer","execution_count":null,"outputs":[]},{"metadata":{"id":"jGr9EuSX1ZYI","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"## make the final pool adaptive\nmodel[0].final_pool = nn.Sequential(nn.AdaptiveAvgPool2d((1,1)))","execution_count":null,"outputs":[]},{"metadata":{"id":"EEVBeVoW1cJX","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"## Create then head that we need . Copied from the wise people before me .\nclass Head(torch.nn.Module):\n  def __init__(self, in_f, out_f):\n    super(Head, self).__init__()\n    \n    self.f = nn.Flatten()\n    self.l = nn.Linear(in_f, 512)\n    self.d = nn.Dropout(0.75)\n    self.o = nn.Linear(512, out_f)\n    self.b1 = nn.BatchNorm1d(in_f)\n    self.b2 = nn.BatchNorm1d(512)\n    self.r = nn.ReLU()\n\n  def forward(self, x):\n    x = self.f(x)\n    x = self.b1(x)\n    x = self.d(x)\n\n    x = self.l(x)\n    x = self.r(x)\n    x = self.b2(x)\n    x = self.d(x)\n\n    out = self.o(x)\n    return out","execution_count":null,"outputs":[]},{"metadata":{"id":"FRyOSBXy1wim","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"## Create the final model\nclass FCN(torch.nn.Module):\n  def __init__(self, base, in_f):\n    super(FCN, self).__init__()\n    self.base = base\n    self.h1 = Head(in_f, 1)\n  \n  def forward(self, x):\n    x = self.base(x)\n    return self.h1(x)\n\nmodel = FCN(model, 1664)","execution_count":null,"outputs":[]},{"metadata":{"id":"pZv7D2KQ2YBk","colab_type":"text"},"cell_type":"markdown","source":"# Train Functions"},{"metadata":{"id":"Jc3QTjqj2XkJ","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"## This is our loss\ndef criterion1(pred1, targets):\n  l1 = F.binary_cross_entropy(F.sigmoid(pred1), targets)\n  return l1\n\n## This is training pipeline \ndef train_model(epoch, optimizer, scheduler=None, history=None):\n    model.train()\n    total_loss = 0\n    \n    t = tqdm(train_loader)\n    for i, (img_batch, y_batch) in enumerate(t):\n        img_batch = img_batch.cuda().float()\n        y_batch = y_batch.cuda().float()\n\n        optimizer.zero_grad()\n\n        out = model(img_batch)\n        loss = criterion1(out, y_batch)\n\n        total_loss += loss.item()\n        t.set_description(f'Epoch {epoch+1}/{n_epochs}, LR: %6f, Loss: %.4f'%(optimizer.state_dict()['param_groups'][0]['lr'],total_loss/(i+1)))\n\n        if history is not None:\n          history.loc[epoch + i / len(X), 'train_loss'] = loss.item()#.cpu().numpy()\n          history.loc[epoch + i / len(X), 'lr'] = optimizer.state_dict()['param_groups'][0]['lr']\n\n        loss.backward()\n        optimizer.step()\n        if scheduler is not None:\n          scheduler.step()\n\ndef evaluate_model(epoch, scheduler=None, history=None):\n    model.eval()\n    loss = 0\n    pred = []\n    real = []\n    with torch.no_grad():\n        for img_batch, y_batch in val_loader:\n            img_batch = img_batch.cuda().float()\n            y_batch = y_batch.cuda().float()\n\n            o1 = model(img_batch)\n            l1 = criterion1(o1, y_batch)\n            loss += l1\n            \n            for j in o1:\n              pred.append(F.sigmoid(j))\n            for i in y_batch:\n              real.append(i.data.cpu())\n    \n    pred = [p.data.cpu().numpy() for p in pred]\n    pred2 = pred\n    pred = [np.round(p) for p in pred]\n    pred = np.array(pred)\n    acc = sklearn.metrics.recall_score(real, pred, average='macro')\n\n    real = [r.item() for r in real]\n    pred2 = np.array(pred2).clip(0.1, 0.9)\n    kaggle = sklearn.metrics.log_loss(real, pred2)\n\n    loss /= len(val_loader)\n    \n    if history is not None:\n        history.loc[epoch, 'dev_loss'] = loss.cpu().numpy()\n    \n    if scheduler is not None:\n      scheduler.step(loss)\n\n    print(f'Dev loss: %.4f, Acc: %.6f, Kaggle: %.6f'%(loss,acc,kaggle))\n    \n    return loss","execution_count":null,"outputs":[]},{"metadata":{"id":"XAhEFXSVKsyr","colab_type":"text"},"cell_type":"markdown","source":"# Dataloaders"},{"metadata":{"id":"n25nfarz8Gfi","colab_type":"code","outputId":"9961d38f-8461-4535-ef15-2a3d06ae64cd","colab":{"base_uri":"https://localhost:8080/","height":141},"trusted":true},"cell_type":"code","source":"## Create train , test split\nX, val_X, y, val_y = get_random_sampling(paths, y, val_paths, val_y)\n\nprint('There are '+str(y.count(1))+' fake train samples')\nprint('There are '+str(y.count(0))+' real train samples')\nprint('There are '+str(val_y.count(1))+' fake val samples')\nprint('There are '+str(val_y.count(0))+' real val samples')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## Needed this library for some out of the box augmentations\nimport albumentations\nfrom albumentations.core.transforms_interface import DualTransform\nfrom albumentations.augmentations import functional as F1\nfrom albumentations.augmentations.transforms import ShiftScaleRotate, HorizontalFlip, Normalize, RandomBrightnessContrast,RandomBrightness,RandomGridShuffle","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"## The author details are there along with the function\nclass GridMask(DualTransform):\n    \"\"\"GridMask augmentation for image classification and object detection.\n    \n    Author: Qishen Ha\n    Email: haqishen@gmail.com\n    2020/01/29\n\n    Args:\n        num_grid (int): number of grid in a row or column.\n        fill_value (int, float, lisf of int, list of float): value for dropped pixels.\n        rotate ((int, int) or int): range from which a random angle is picked. If rotate is a single int\n            an angle is picked from (-rotate, rotate). Default: (-90, 90)\n        mode (int):\n            0 - cropout a quarter of the square of each grid (left top)\n            1 - reserve a quarter of the square of each grid (left top)\n            2 - cropout 2 quarter of the square of each grid (left top & right bottom)\n\n    Targets:\n        image, mask\n\n    Image types:\n        uint8, float32\n\n    Reference:\n    |  https://arxiv.org/abs/2001.04086\n    |  https://github.com/akuxcw/GridMask\n    \"\"\"\n\n    def __init__(self, num_grid=3, fill_value=0, rotate=0, mode=0, always_apply=False, p=0.5):\n        super(GridMask, self).__init__(always_apply, p)\n        if isinstance(num_grid, int):\n            num_grid = (num_grid, num_grid)\n        if isinstance(rotate, int):\n            rotate = (-rotate, rotate)\n        self.num_grid = num_grid\n        self.fill_value = fill_value\n        self.rotate = rotate\n        self.mode = mode\n        self.masks = None\n        self.rand_h_max = []\n        self.rand_w_max = []\n\n    def init_masks(self, height, width):\n        if self.masks is None:\n            self.masks = []\n            n_masks = self.num_grid[1] - self.num_grid[0] + 1\n            for n, n_g in enumerate(range(self.num_grid[0], self.num_grid[1] + 1, 1)):\n                grid_h = height / n_g\n                grid_w = width / n_g\n                this_mask = np.ones((int((n_g + 1) * grid_h), int((n_g + 1) * grid_w))).astype(np.uint8)\n                for i in range(n_g + 1):\n                    for j in range(n_g + 1):\n                        this_mask[\n                             int(i * grid_h) : int(i * grid_h + grid_h / 2),\n                             int(j * grid_w) : int(j * grid_w + grid_w / 2)\n                        ] = self.fill_value\n                        if self.mode == 2:\n                            this_mask[\n                                 int(i * grid_h + grid_h / 2) : int(i * grid_h + grid_h),\n                                 int(j * grid_w + grid_w / 2) : int(j * grid_w + grid_w)\n                            ] = self.fill_value\n                \n                if self.mode == 1:\n                    this_mask = 1 - this_mask\n\n                self.masks.append(this_mask)\n                self.rand_h_max.append(grid_h)\n                self.rand_w_max.append(grid_w)\n\n    def apply(self, image, mask, rand_h, rand_w, angle, **params):\n        h, w = image.shape[:2]\n        mask = F1.rotate(mask, angle) if self.rotate[1] > 0 else mask\n        mask = mask[:,:,np.newaxis] if image.ndim == 3 else mask\n        image *= mask[rand_h:rand_h+h, rand_w:rand_w+w].astype(image.dtype)\n        return image\n\n    def get_params_dependent_on_targets(self, params):\n        img = params['image']\n        height, width = img.shape[:2]\n        self.init_masks(height, width)\n\n        mid = np.random.randint(len(self.masks))\n        mask = self.masks[mid]\n        rand_h = np.random.randint(self.rand_h_max[mid])\n        rand_w = np.random.randint(self.rand_w_max[mid])\n        angle = np.random.randint(self.rotate[0], self.rotate[1]) if self.rotate[1] > 0 else 0\n\n        return {'mask': mask, 'rand_h': rand_h, 'rand_w': rand_w, 'angle': angle}\n\n    @property\n    def targets_as_params(self):\n        return ['image']\n\n    def get_transform_init_args_names(self):\n        return ('num_grid', 'fill_value', 'rotate', 'mode')","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"batch_size= 16\nclass_sample_count = np.array([len(np.where(y==t)[0]) for t in np.unique(y)])\nweight = 1. / class_sample_count\nsamples_weight = np.array([weight[t] for t in y])\nsamples_weight = torch.from_numpy(samples_weight)\nsampler = torch.utils.data.sampler.WeightedRandomSampler(samples_weight.type('torch.DoubleTensor'), len(samples_weight))","execution_count":null,"outputs":[]},{"metadata":{"id":"kfCLL0pt9Vh-","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"## Create the transformation we need \ntrain_transform = albumentations.Compose([\n                                          ShiftScaleRotate(p=0.3, scale_limit=0.25, border_mode=1),\n                                          HorizontalFlip(p=0.2),\n                                          albumentations.RandomCrop(150,150),\n                                          #A.RandomBrightness(limit=0.3, always_apply=False, p=0.3),\n                                         # albumentations.RandomGridShuffle(grid=(2, 1), always_apply=False, p=0.4),\n                                          RandomBrightnessContrast(p=0.5, brightness_limit=0.1, contrast_limit=0.1),\n                                          albumentations.OneOf([\n                                            GridMask(num_grid=(1,3),rotate=15),\n                                            GridMask(num_grid=(2,4), mode=0),\n                                            GridMask(num_grid=3, mode=2),\n                                          ], p=0.5),\n                                          Normalize()\n])\nval_transform = albumentations.Compose([\n                                        albumentations.RandomCrop(150,150),  \n                                        Normalize()\n])\n\ntrain_dataset = ImageDataset(X, y, transform=train_transform)\nval_dataset = ImageDataset(val_X, val_y, transform=val_transform)\n\ntrain_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False, num_workers=4,sampler= sampler,pin_memory=True)\nval_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, num_workers=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import gc\ngc.collect()","execution_count":null,"outputs":[]},{"metadata":{"id":"P0Z_BWFJ-E5A","colab_type":"code","outputId":"db70092d-f2b0-4e17-fdfe-ffbb32bd9630","colab":{"base_uri":"https://localhost:8080/","height":499},"trusted":true},"cell_type":"code","source":"nrow, ncol = 5, 6\nfig, axes = plt.subplots(nrow, ncol, figsize=(20, 8))\naxes = axes.flatten()\nfor i, ax in enumerate(axes):\n    image, label = train_dataset[i]\n    image = np.rollaxis(image, 0, 3)\n    image = image*std + mean\n    image = np.clip(image, 0., 1.)\n    ax.imshow(image)\n    ax.set_title(f'label: {label}')","execution_count":null,"outputs":[]},{"metadata":{"id":"zbaUUqLIKwst","colab_type":"text"},"cell_type":"markdown","source":"# Train"},{"metadata":{"id":"RJmdT2spBEU1","colab_type":"code","outputId":"bd51ed41-f0b2-49ec-8fa1-7c890243b78d","colab":{"base_uri":"https://localhost:8080/","height":405},"trusted":true},"cell_type":"code","source":"import gc\n\nhistory = pd.DataFrame()\nhistory2 = pd.DataFrame()\n\ntorch.cuda.empty_cache()\ngc.collect()\n\nbest = 1e10\nn_epochs = 5\nbatch_size = batch_size\n\nmodel = model.cuda()\n\noptimizer = torch.optim.AdamW(model.parameters(), lr=1e-4,weight_decay=1e-5)\n\nscheduler = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, patience=2, mode='min', factor=0.1, verbose=True, min_lr=1e-5)\n\nfor epoch in range(n_epochs):\n    torch.cuda.empty_cache()\n    gc.collect()\n\n    train_model(epoch, optimizer, scheduler=None, history=None)\n    \n    loss = evaluate_model(epoch, scheduler=scheduler, history=history2)\n    \n    if loss < best:\n      best = loss\n      print(f'Saving best model...')\n      torch.save(model.state_dict(), f'model.pth')","execution_count":null,"outputs":[]},{"metadata":{"id":"vtSjo9DYtoEL","colab_type":"code","colab":{},"trusted":true},"cell_type":"code","source":"history2.plot()","execution_count":null,"outputs":[]}],"metadata":{"colab":{"name":"Deepfake_Detection.ipynb","provenance":[],"collapsed_sections":["AaU3SeKMz_qm","XsefoEdR1gHt"],"machine_shape":"hm"},"kernelspec":{"name":"python3","display_name":"Python 3"},"accelerator":"GPU"},"nbformat":4,"nbformat_minor":4}