{"cells":[{"metadata":{},"cell_type":"markdown","source":"## credits\nThe following kernels inspired, setting up the baseline framework,  \nhttps://www.kaggle.com/greatgamedota/xception-classifier-w-ffhq-training-lb-537/data  \nhttps://www.kaggle.com/humananalog/inference-demo"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"import os, sys, time\nimport cv2\nimport numpy as np\nimport pandas as pd\n\nimport torch\nimport torch.nn as nn\nimport torch.nn.functional as F\n\n%matplotlib inline\nimport matplotlib.pyplot as plt\n\nfrom tqdm import tqdm,trange\nfrom sklearn.model_selection import train_test_split\nimport sklearn.metrics\n\nimport warnings\nwarnings.filterwarnings(\"ignore\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"df_train0 = pd.read_json('../input/deepfake-detection-challenge/metadata0.json')","execution_count":null,"outputs":[]},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"test_dir = \"/kaggle/input/deepfake-detection-challenge/test_videos/\"\ntest_videos = sorted([x for x in os.listdir(test_dir) if x[-4:] == \".mp4\"])\nlen(test_videos)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"print(\"PyTorch version:\", torch.__version__)\nprint(\"CUDA version:\", torch.version.cuda)\nprint(\"cuDNN version:\", torch.backends.cudnn.version())","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"gpu = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\ngpu","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import sys\nsys.path.insert(0, \"/kaggle/input/blazeface-pytorch\")\nsys.path.insert(0, \"/kaggle/input/deepfakes-inference-demo\")","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from blazeface import BlazeFace\nfacedet = BlazeFace().to(gpu)\nfacedet.load_weights(\"/kaggle/input/blazeface-pytorch/blazeface.pth\")\nfacedet.load_anchors(\"/kaggle/input/blazeface-pytorch/anchors.npy\")\n_ = facedet.train(False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from helpers.read_video_1 import VideoReader\nfrom helpers.face_extract_1 import FaceExtractor\n\nframes_per_video = 20\n\nvideo_reader = VideoReader()\nvideo_read_fn = lambda x: video_reader.read_frames(x, num_frames=frames_per_video)\nface_extractor = FaceExtractor(video_read_fn, facedet)\n\n\nfrom torchvision.transforms import Normalize\nmean = [0.485, 0.456, 0.406]\nstd = [0.229, 0.224, 0.225]\nnormalize_transform = Normalize(mean, std)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"def isotropically_resize_image(img, size, resample=cv2.INTER_AREA):\n    h, w = img.shape[:2]\n    if w > h:\n        h = h * size // w\n        w = size\n    else:\n        w = w * size // h\n        h = size\n\n    resized = cv2.resize(img, (w, h), interpolation=resample)\n    return resized\n\n\ndef make_square_image(img):\n    h, w = img.shape[:2]\n    size = max(h, w)\n    t = 0\n    b = size - h\n    l = 0\n    r = size - w\n    return cv2.copyMakeBorder(img, t, b, l, r, cv2.BORDER_CONSTANT, value=0)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"import torch.nn as nn\nimport torchvision.models as models\n\nclass MyResNeXt(models.resnet.ResNet):\n    def __init__(self, training=True):\n        super(MyResNeXt, self).__init__(block=models.resnet.Bottleneck,\n                                        layers=[3, 4, 6, 3], \n                                        groups=32, \n                                        width_per_group=4)\n        self.fc = nn.Linear(2048, 1)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# ##SCRATCH-PAD\n# import os\n# test_dir = \"/kaggle/input/deepfake-detection-challenge/test_videos/\"\n# test_videos = sorted([x for x in os.listdir(test_dir) if x[-4:] == \".mp4\"])\n# def show(faces,no_of_frames=5):\n#     from matplotlib import pyplot as plt\n#     %matplotlib inline\n#     for i in range(no_of_frames):\n#         plt.imshow(faces[i]['faces'][0], interpolation='nearest')\n#         plt.show()\n# for file in test_videos[:10]:\n#     video_path = os.path.join(test_dir,file)\n#     faces = face_extractor.process_video(video_path)\n#     face_extractor.keep_only_beimport torch.nn as nn\n#import torchvision.models as modelsst_face(faces)\n#     show(faces)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"## Prediction loop"},{"metadata":{"trusted":true},"cell_type":"code","source":"def predict_on_video(video_path, batch_size):\n    try:\n        # Find the faces for N frames in the video.\n        faces = face_extractor.process_video(video_path)\n\n        # Only look at one face per frame.\n        face_extractor.keep_only_best_face(faces)\n        \n        if len(faces) > 0:\n            # NOTE: When running on the CPU, the batch size must be fixed\n            # or else memory usage will blow up. (Bug in PyTorch?)\n            x = np.zeros((batch_size, input_size, input_size, 3), dtype=np.uint8)\n\n            # If we found any faces, prepare them for the model.\n            n = 0\n            for frame_data in faces:\n                for face in frame_data[\"faces\"]:\n                    # Resize to the model's required input size.\n                    # We keep the aspect ratio intact and add zero-padding if necessary.                    \n                    resized_face = isotropically_resize_image(face, input_size)\n                    resized_face = make_square_image(resized_face)\n\n                    if n < batch_size:\n                        x[n] = resized_face\n                        n += 1\n                    else:\n                        print(\"WARNING: have %d faces but batch size is %d\" % (n, batch_size))\n                    \n                    # Test time augmentation: horizontal flips.\n                    # TODO: not sure yet if this helps or not\n#                     x[n] = cv2.flip(resized_face, 1)\n#                     n += 1\n\n            if n > 0:\n                x = torch.tensor(x, device=gpu).float()\n\n                # Preprocess the images.\n                x = x.permute((0, 3, 1, 2))\n\n                for i in range(len(x)):\n                    x[i] = normalize_transform(x[i] / 255.)\n\n                # Make a prediction, then take the average.\n                with torch.no_grad():\n                    y_pred = model(x)\n                    y_pred = torch.sigmoid(y_pred.squeeze())\n                    return y_pred[:n].mean().item()\n\n    except Exception as e:\n        print(\"Prediction error on video %s: %s\" % (video_path, str(e)))\n\n    return 0.5","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from concurrent.futures import ThreadPoolExecutor\n\ndef predict_on_video_set(videos, num_workers):\n    def process_file(i):\n        filename = videos[i]\n        y_pred = predict_on_video(os.path.join(test_dir, filename), batch_size=frames_per_video)\n        return y_pred\n\n    with ThreadPoolExecutor(max_workers=num_workers) as ex:\n        predictions = ex.map(process_file, range(len(videos)))\n\n    return list(predictions)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"input_size = 224\ncheckpoint = torch.load(\"/kaggle/input/deepfakes-inference-demo/resnext.pth\", map_location=gpu)\n\nmodel = MyResNeXt().to(gpu)\nmodel.load_state_dict(checkpoint)\n_ = model.eval()\n\ndel checkpoint\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\npredictions_resnext = predict_on_video_set(test_videos, num_workers=4)\nsubmission_df_resnext = pd.DataFrame({\"filename\": test_videos, \"label\": predictions_resnext})\nplt.hist(submission_df_resnext['label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#SPEED-TEST FOR RESNEXT\nstart_time = time.time()\nspeedtest_videos = test_videos[:5]\npredictions = predict_on_video_set(speedtest_videos, num_workers=4)\nelapsed = time.time() - start_time\nprint(\"Elapsed %f sec. Average per video: %f sec.\" % (elapsed, elapsed / len(speedtest_videos)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"# Xception model"},{"metadata":{"trusted":true},"cell_type":"code","source":"!pip install ../input/deepfake-xception-trained-model/pytorchcv-0.0.55-py2.py3-none-any.whl --quiet","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"class Head(nn.Module):\n    def __init__(self, in_f, out_f):\n        super().__init__()\n\n        self.f = nn.Flatten()\n        self.l = nn.Linear(in_f, 512)\n        self.b1 = nn.BatchNorm1d(in_f)\n        self.d = nn.Dropout(0.25)#CHANGED HERE!!!!!!!!!!!!!!!0.5--->0.25\n        self.o = nn.Linear(512, out_f)\n        self.b2 = nn.BatchNorm1d(512)\n        self.r = nn.ReLU()\n\n    def forward(self, x):\n        x = self.f(x)\n        \n        x = self.b1(x)\n        x = self.d(x)\n\n        x = self.l(x)\n        x = self.r(x)\n        \n        x = self.b2(x)\n        x = self.d(x)\n\n        out = self.o(x)\n        return out\n\nclass FCN(nn.Module):\n    def __init__(self, base, in_f):\n        super().__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)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"from pytorchcv.model_provider import get_model\nmodel = get_model(\"xception\", pretrained=False)\nmodel = nn.Sequential(*list(model.children())[:-1]) #remove the last layer-->create Sequential model from the rest\nmodel[0].final_block.pool = nn.Sequential(nn.AdaptiveAvgPool2d((1,1)))# modifying the pooling layer","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"input_size = 150\ncheckpoint = torch.load('../input/mymodels/model_niz.pth', map_location=gpu)\n\nmodel = FCN(model, 2048).to(gpu)\nmodel.load_state_dict(checkpoint) \n_ = model.eval()\n\ndel checkpoint\n","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"\npredictions_xception = predict_on_video_set(test_videos, num_workers=4)\nsubmission_df_xception = pd.DataFrame({\"filename\": test_videos, \"label\": predictions_xception})\nplt.hist(submission_df_xception['label'])","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"#SPEED TEST\nstart_time = time.time()\nspeedtest_videos = test_videos[:5]\npredictions = predict_on_video_set(speedtest_videos, num_workers=4)\nelapsed = time.time() - start_time\nprint(\"Elapsed %f sec. Average per video: %f sec.\" % (elapsed, elapsed / len(speedtest_videos)))","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"### Speed test  \nThe leaderboard submission must finish within 9 hours. With 4000 test videos, that is `9*60*60/4000 = 8.1` seconds per video. So if the average time per video is greater than ~8 seconds, the kernel will be too slow!"},{"metadata":{},"cell_type":"markdown","source":"## Make the submission"},{"metadata":{"trusted":true},"cell_type":"code","source":"final_predictions = 0.5 * (np.array(predictions_resnext) + np.array(predictions_xception))\nsubmission_df = pd.DataFrame({'filename': test_videos, \"label\": final_predictions})\nplt.hist(submission_df['label'])#AFTER AVERAGING RESNEXT & XCEPTION","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for x,y in zip(final_predictions,test_videos):\n    submission_df.loc[submission_df['filename']==y,'label']=min([max([0.1,x]),0.9])\nplt.hist(submission_df['label'])#AFTER AVERAGING--->APPROXIMATING","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"submission_df.to_csv(\"submission.csv\", index=False)\n","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}