{"cells":[{"metadata":{},"cell_type":"markdown","source":"<a id=\"toc\"></a>\n# Table of Contents\n1. [Introduction](#introduction)\n1. [Configure hyper-parameters](#configure_hyper_parameters)\n1. [Import libraries](#import_libraries)\n1. [Define useful classes](#define_useful_classes)\n1. [Get all train directories](#get_all_train_directories)\n1. [Construct DataFrame for training data](#construct_dataframe_for_training_data)\n1. [Split training data](#split_training_data)\n1. [Create datasets and dataloaders](#create_datasets_and_dataloaders)\n1. [Test the dataloaders](#test_the_dataloaders)\n1. [Conclusion](#conclusion)"},{"metadata":{},"cell_type":"markdown","source":"<a id=\"introduction\"></a>\n# Introduction\nIn this kernel, I'll provide a simple example to demonstrate how to load data from multiple Kaggle datasets and feed all of these to a PyTorch Dataset. The custom Dataset created in this kernel is just a demo, you can modify it or create a new one to fit your own purpose.\n\nAll the datasets used in this demo was listed in this dicussion -> [*Other useful datasets*](https://www.kaggle.com/c/deepfake-detection-challenge/discussion/128954).\n\n---\n[Back to Table of Contents](#toc)"},{"metadata":{},"cell_type":"markdown","source":"<a id=\"configure_hyper_parameters\"></a>\n# Configure hyper-parameters\n[Back to Table of Contents](#toc)"},{"metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true},"cell_type":"code","source":"INPUT_DIR = '/kaggle/input/'\n\nTEST_SIZE = 0.3\nRANDOM_STATE = 128\n\nBATCH_SIZE = 8\nNUM_WORKERS = 0","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"import_libraries\"></a>\n# Import libraries\n[Back to Table of Contents](#toc)"},{"metadata":{"_uuid":"d629ff2d2480ee46fbb7e2d37f6b5fab8052498a","_cell_guid":"79c7e3d0-c299-4dcb-8224-4455121ee9b0","trusted":true},"cell_type":"code","source":"import torch\nfrom torch.utils.data import Dataset, DataLoader\nfrom albumentations import Normalize, Compose\nimport numpy as np\nimport pandas as pd\nimport cv2\nfrom tqdm.notebook import tqdm\nfrom sklearn.model_selection import train_test_split\nimport os\nimport glob","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"define_useful_classes\"></a>\n# Define useful classes\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"class RandomFaceDataset(Dataset):\n    def __init__(self, img_dirs, labels, preprocess=None):\n        '''\n        Parameters:\n            img_dirs: The directories that contain face images.\n                Each directory coresponding to a video in the original training data.\n            labels: Corresponding labels {'FAKE': 1, 'REAL', 0} of videos\n            \n        '''\n        self.img_dirs = img_dirs\n        self.labels = labels\n        self.preprocess = preprocess\n\n    def __len__(self):\n        return len(self.img_dirs)\n    \n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n\n        img_dir = self.img_dirs[idx]\n        label = self.labels[idx]\n        face_paths = glob.glob(f'{img_dir}/*.png')\n\n        sample = face_paths[np.random.choice(len(face_paths))]\n        \n        face = cv2.imread(sample, 1)\n        face = cv2.cvtColor(face, cv2.COLOR_BGR2RGB)\n\n        if self.preprocess is not None:\n            augmented = self.preprocess(image=face)\n            face = augmented['image']\n        \n        return {'face': face, 'label': np.array([label], dtype=float)}","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"get_all_train_directories\"></a>\n# Get all train directories\nReturn all directories that match a specific pattern\n\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_train_dirs = glob.glob(INPUT_DIR + 'deepfake-detection-faces-*')\nfor i, train_dir in enumerate(all_train_dirs):\n    print('[{:02}]'.format(i), train_dir)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"construct_dataframe_for_training_data\"></a>\n# Construct DataFrame for training data\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"all_dataframes = []\nfor train_dir in all_train_dirs:\n    df = pd.read_csv(os.path.join(train_dir, 'metadata.csv'))\n    df['path'] = df['filename'].apply(lambda x: os.path.join(train_dir, x.split('.')[0]))\n    all_dataframes.append(df)\n\ntrain_df = pd.concat(all_dataframes, ignore_index=True, sort=False)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"# Remove videos that don't have any face\ntrain_df = train_df[train_df['path'].map(lambda x: os.path.exists(x))]","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{"_kg_hide-output":true,"trusted":true},"cell_type":"code","source":"train_df['label'].replace({'FAKE': 1, 'REAL': 0}, inplace=True)","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"train_df","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"label_count = train_df.groupby('label').count()['filename']\nprint(label_count)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"split_training_data\"></a>\n# Split training data\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"X = train_df['path'].to_numpy()\ny = train_df['label'].to_numpy()","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"X_train, X_val, y_train, y_val = train_test_split(X, y, test_size=TEST_SIZE, random_state=RANDOM_STATE, stratify=y)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"create_datasets_and_dataloaders\"></a>\n# Create datasets and dataloaders\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"preprocess = Compose([\n    Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225], p=1)\n])\n\ntrain_dataset = RandomFaceDataset(\n    img_dirs=X_train,\n    labels=y_train,\n    preprocess=preprocess\n)\nval_dataset = RandomFaceDataset(\n    img_dirs=X_val,\n    labels=y_val,\n    preprocess=preprocess\n)\n\ntrain_dataloader = DataLoader(\n    train_dataset,\n    batch_size=BATCH_SIZE,\n    shuffle=True,\n    num_workers=NUM_WORKERS\n)\nval_dataloader = DataLoader(\n    val_dataset,\n    batch_size=BATCH_SIZE,\n    shuffle=False,\n    num_workers=NUM_WORKERS\n)","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"test_the_dataloaders\"></a>\n# Test the dataloaders\n[Back to Table of Contents](#toc)"},{"metadata":{"trusted":true},"cell_type":"code","source":"for batch in tqdm(train_dataloader):\n    face_batch = batch['face']\n    label_batch = batch['label']\n    \n    print(type(face_batch), face_batch.shape)\n    print(type(label_batch), label_batch.shape)\n\n    break","execution_count":null,"outputs":[]},{"metadata":{"trusted":true},"cell_type":"code","source":"for batch in tqdm(val_dataloader):\n    face_batch = batch['face']\n    label_batch = batch['label']\n    \n    print(type(face_batch), face_batch.shape)\n    print(type(label_batch), label_batch.shape)\n\n    break","execution_count":null,"outputs":[]},{"metadata":{},"cell_type":"markdown","source":"<a id=\"conclusion\"></a>\n# Conclusion\nIt's quite easy to load a bunch of datasets into a Kaggle kernel, isn't it?\nNext, let feed these faces and labels to your hungry classifier to see whether it can learn something from these FAKE and REAL faces :3\n\nI'll daily update the list of preprocessed datasets in this discussion topic -> [*Other useful datasets*](https://www.kaggle.com/c/deepfake-detection-challenge/discussion/128954).\n\nDo we truly get better classifiers when we have more data? Let's try =]]\n\n---\n[Back to Table of Contents](#toc)"}],"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}