{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":16880,"databundleVersionId":858837,"sourceType":"competition"},{"sourceId":924245,"sourceType":"datasetVersion","datasetId":464091}],"dockerImageVersionId":31090,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"!pip install -U --upgrade tensorflow","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:01:07.234145Z","iopub.execute_input":"2025-08-07T11:01:07.234436Z","iopub.status.idle":"2025-08-07T11:02:28.892365Z","shell.execute_reply.started":"2025-08-07T11:01:07.234348Z","shell.execute_reply":"2025-08-07T11:02:28.891692Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import sys\nimport sklearn\nimport tensorflow as tf\n\nimport cv2\nimport pandas as pd\nimport numpy as np\n\nimport plotly.graph_objs as go\nfrom plotly.offline import iplot\nfrom matplotlib import pyplot as plt","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:28.894767Z","iopub.execute_input":"2025-08-07T11:02:28.895007Z","iopub.status.idle":"2025-08-07T11:02:38.148059Z","shell.execute_reply.started":"2025-08-07T11:02:28.894984Z","shell.execute_reply":"2025-08-07T11:02:38.147372Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.test.is_gpu_available()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:38.151173Z","iopub.execute_input":"2025-08-07T11:02:38.151394Z","iopub.status.idle":"2025-08-07T11:02:39.702555Z","shell.execute_reply.started":"2025-08-07T11:02:38.151361Z","shell.execute_reply":"2025-08-07T11:02:39.701805Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\nplt.rc('font', size=14)\nplt.rc('axes', labelsize=14, titlesize=14)\nplt.rc('legend', fontsize=14)\nplt.rc('xtick', labelsize=10)\nplt.rc('ytick', labelsize=10)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.703582Z","iopub.execute_input":"2025-08-07T11:02:39.704333Z","iopub.status.idle":"2025-08-07T11:02:39.726081Z","shell.execute_reply.started":"2025-08-07T11:02:39.704284Z","shell.execute_reply":"2025-08-07T11:02:39.725553Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\n\ndef get_data():\n    return pd.read_csv('../input/deepfake-faces/metadata.csv')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.726713Z","iopub.execute_input":"2025-08-07T11:02:39.726892Z","iopub.status.idle":"2025-08-07T11:02:39.742894Z","shell.execute_reply.started":"2025-08-07T11:02:39.726877Z","shell.execute_reply":"2025-08-07T11:02:39.742338Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"meta=get_data()\nmeta.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.745201Z","iopub.execute_input":"2025-08-07T11:02:39.745454Z","iopub.status.idle":"2025-08-07T11:02:39.939660Z","shell.execute_reply.started":"2025-08-07T11:02:39.745430Z","shell.execute_reply":"2025-08-07T11:02:39.938886Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"meta.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.940523Z","iopub.execute_input":"2025-08-07T11:02:39.940861Z","iopub.status.idle":"2025-08-07T11:02:39.946167Z","shell.execute_reply.started":"2025-08-07T11:02:39.940833Z","shell.execute_reply":"2025-08-07T11:02:39.945429Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"len(meta[meta.label=='FAKE']),len(meta[meta.label=='REAL'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.947147Z","iopub.execute_input":"2025-08-07T11:02:39.947500Z","iopub.status.idle":"2025-08-07T11:02:39.988497Z","shell.execute_reply.started":"2025-08-07T11:02:39.947471Z","shell.execute_reply":"2025-08-07T11:02:39.987942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"real_df = meta[meta[\"label\"] == \"REAL\"]\nfake_df = meta[meta[\"label\"] == \"FAKE\"]\nsample_size = 8000\n\nreal_df = real_df.sample(sample_size, random_state=42)\nfake_df = fake_df.sample(sample_size, random_state=42)\n\nsample_meta = pd.concat([real_df, fake_df])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:39.989027Z","iopub.execute_input":"2025-08-07T11:02:39.989213Z","iopub.status.idle":"2025-08-07T11:02:40.016792Z","shell.execute_reply.started":"2025-08-07T11:02:39.989191Z","shell.execute_reply":"2025-08-07T11:02:40.016291Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nTrain_set, Test_set = train_test_split(sample_meta,test_size=0.2,random_state=42,stratify=sample_meta['label'])\nTrain_set, Val_set  = train_test_split(Train_set,test_size=0.3,random_state=42,stratify=Train_set['label'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:40.017357Z","iopub.execute_input":"2025-08-07T11:02:40.017593Z","iopub.status.idle":"2025-08-07T11:02:40.251618Z","shell.execute_reply.started":"2025-08-07T11:02:40.017578Z","shell.execute_reply":"2025-08-07T11:02:40.250775Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"Train_set.shape,Val_set.shape,Test_set.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:40.252507Z","iopub.execute_input":"2025-08-07T11:02:40.252785Z","iopub.status.idle":"2025-08-07T11:02:40.258259Z","shell.execute_reply.started":"2025-08-07T11:02:40.252762Z","shell.execute_reply":"2025-08-07T11:02:40.257458Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"y = dict()\n\ny[0] = []\ny[1] = []\n\nfor set_name in (np.array(Train_set['label']), np.array(Val_set['label']), np.array(Test_set['label'])):\n    y[0].append(np.sum(set_name == 'REAL'))\n    y[1].append(np.sum(set_name == 'FAKE'))\n\ntrace0 = go.Bar(\n    x=['Train Set', 'Validation Set', 'Test Set'],\n    y=y[0],\n    name='REAL',\n    marker=dict(color='#33cc33'),\n    opacity=0.7\n)\ntrace1 = go.Bar(\n    x=['Train Set', 'Validation Set', 'Test Set'],\n    y=y[1],\n    name='FAKE',\n    marker=dict(color='#ff3300'),\n    opacity=0.7\n)\n\ndata = [trace0, trace1]\nlayout = go.Layout(\n    title='Count of classes in each set',\n    xaxis={'title': 'Set'},\n    yaxis={'title': 'Count'}\n)\n\nfig = go.Figure(data, layout)\niplot(fig)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:40.259085Z","iopub.execute_input":"2025-08-07T11:02:40.259442Z","iopub.status.idle":"2025-08-07T11:02:42.183225Z","shell.execute_reply.started":"2025-08-07T11:02:40.259415Z","shell.execute_reply":"2025-08-07T11:02:42.182507Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"plt.figure(figsize=(15,15))\nfor cur,i in enumerate(Train_set.index[25:50]):\n    plt.subplot(5,5,cur+1)\n    plt.xticks([])\n    plt.yticks([])\n    plt.grid(False)\n    \n    plt.imshow(cv2.imread('../input/deepfake-faces/faces_224/'+Train_set.loc[i,'videoname'][:-4]+'.jpg'))\n    \n    if(Train_set.loc[i,'label']=='FAKE'):\n        plt.xlabel('FAKE Image')\n    else:\n        plt.xlabel('REAL Image')\n        \nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:42.184091Z","iopub.execute_input":"2025-08-07T11:02:42.184658Z","iopub.status.idle":"2025-08-07T11:02:44.053484Z","shell.execute_reply.started":"2025-08-07T11:02:42.184622Z","shell.execute_reply":"2025-08-07T11:02:44.052547Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Modelling**","metadata":{}},{"cell_type":"code","source":"def retreive_dataset(set_name):\n    images,labels=[],[]\n    for (img, imclass) in zip(set_name['videoname'], set_name['label']):\n        images.append(cv2.imread('../input/deepfake-faces/faces_224/'+img[:-4]+'.jpg'))\n        if(imclass=='FAKE'):\n            labels.append(1)\n        else:\n            labels.append(0)\n    \n    return np.array(images),np.array(labels)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:44.054717Z","iopub.execute_input":"2025-08-07T11:02:44.054971Z","iopub.status.idle":"2025-08-07T11:02:44.059594Z","shell.execute_reply.started":"2025-08-07T11:02:44.054953Z","shell.execute_reply":"2025-08-07T11:02:44.058937Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"X_train,y_train=retreive_dataset(Train_set)\nX_val,y_val=retreive_dataset(Val_set)\nX_test,y_test=retreive_dataset(Test_set)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:02:44.060893Z","iopub.execute_input":"2025-08-07T11:02:44.061076Z","iopub.status.idle":"2025-08-07T11:04:12.381873Z","shell.execute_reply.started":"2025-08-07T11:02:44.061062Z","shell.execute_reply":"2025-08-07T11:04:12.381196Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from functools import partial\n\ntf.random.set_seed(42) \nDefaultConv2D = partial(tf.keras.layers.Conv2D, kernel_size=3, padding=\"same\",\n                        activation=\"relu\", kernel_initializer=\"he_normal\")\n\nmodel = tf.keras.Sequential([\n    DefaultConv2D(filters=64, kernel_size=7, input_shape=[224, 224, 3]),\n    tf.keras.layers.MaxPool2D(),\n    DefaultConv2D(filters=128),\n    DefaultConv2D(filters=128),\n    tf.keras.layers.MaxPool2D(),\n    tf.keras.layers.Flatten(),\n    tf.keras.layers.Dense(units=128, activation=\"relu\",\n                          kernel_initializer=\"he_normal\"),\n    tf.keras.layers.Dropout(0.5),\n    tf.keras.layers.Dense(units=64, activation=\"relu\",\n                          kernel_initializer=\"he_normal\"),\n    tf.keras.layers.Dropout(0.5),\n    tf.keras.layers.Dense(units=1, activation=\"sigmoid\")\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:04:12.382814Z","iopub.execute_input":"2025-08-07T11:04:12.383600Z","iopub.status.idle":"2025-08-07T11:04:13.509610Z","shell.execute_reply.started":"2025-08-07T11:04:12.383573Z","shell.execute_reply":"2025-08-07T11:04:13.508807Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.compile(loss=\"binary_crossentropy\", optimizer=\"nadam\",\n              metrics=[\"accuracy\"])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:04:13.510507Z","iopub.execute_input":"2025-08-07T11:04:13.510799Z","iopub.status.idle":"2025-08-07T11:04:13.537927Z","shell.execute_reply.started":"2025-08-07T11:04:13.510775Z","shell.execute_reply":"2025-08-07T11:04:13.537305Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"history = model.fit(X_train, y_train, epochs=10,batch_size=64,\n                    validation_data=(X_val, y_val))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:04:13.538558Z","iopub.execute_input":"2025-08-07T11:04:13.538796Z","iopub.status.idle":"2025-08-07T11:12:38.862335Z","shell.execute_reply.started":"2025-08-07T11:04:13.538781Z","shell.execute_reply":"2025-08-07T11:12:38.861751Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"score = model.evaluate(X_test, y_test)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:38.863524Z","iopub.execute_input":"2025-08-07T11:12:38.863731Z","iopub.status.idle":"2025-08-07T11:12:49.946634Z","shell.execute_reply.started":"2025-08-07T11:12:38.863714Z","shell.execute_reply":"2025-08-07T11:12:49.946001Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot model performance\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs_range = range(1, len(history.epoch) + 1)\n\nplt.figure(figsize=(15,5))\n\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Train Set')\nplt.plot(epochs_range, val_acc, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.title('Model Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Train Set')\nplt.plot(epochs_range, val_loss, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('Model Loss')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:49.947787Z","iopub.execute_input":"2025-08-07T11:12:49.948053Z","iopub.status.idle":"2025-08-07T11:12:50.334731Z","shell.execute_reply.started":"2025-08-07T11:12:49.948029Z","shell.execute_reply":"2025-08-07T11:12:50.333927Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# **Pretrained Models for Transfer Learning**","metadata":{}},{"cell_type":"markdown","source":"i used Xception model for fine-tuning feel free to try the performance of other pretrained models.","metadata":{}},{"cell_type":"code","source":"train_set_raw=tf.data.Dataset.from_tensor_slices((X_train,y_train))\nvalid_set_raw=tf.data.Dataset.from_tensor_slices((X_val,y_val))\ntest_set_raw=tf.data.Dataset.from_tensor_slices((X_test,y_test))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:50.338943Z","iopub.execute_input":"2025-08-07T11:12:50.339167Z","iopub.status.idle":"2025-08-07T11:12:56.252821Z","shell.execute_reply.started":"2025-08-07T11:12:50.339151Z","shell.execute_reply":"2025-08-07T11:12:56.252024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.keras.backend.clear_session()  # extra code – resets layer name counter\n\nbatch_size = 32\npreprocess = tf.keras.applications.xception.preprocess_input\ntrain_set = train_set_raw.map(lambda X, y: (preprocess(tf.cast(X, tf.float32)), y))\ntrain_set = train_set.shuffle(1000, seed=42).batch(batch_size).prefetch(1)\nvalid_set = valid_set_raw.map(lambda X, y: (preprocess(tf.cast(X, tf.float32)), y)).batch(batch_size)\ntest_set = test_set_raw.map(lambda X, y: (preprocess(tf.cast(X, tf.float32)), y)).batch(batch_size)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:56.253660Z","iopub.execute_input":"2025-08-07T11:12:56.253914Z","iopub.status.idle":"2025-08-07T11:12:57.856942Z","shell.execute_reply.started":"2025-08-07T11:12:56.253887Z","shell.execute_reply":"2025-08-07T11:12:57.856339Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# extra code – displays the first 9 images in the first batch of valid_set\n\nplt.figure(figsize=(12, 12))\nfor X_batch, y_batch in valid_set.take(1):\n    for index in range(9):\n        plt.subplot(3, 3, index + 1)\n        plt.imshow((X_batch[index] + 1) / 2)  # rescale to 0–1 for imshow()\n        if(y_batch[index]==1):\n            classt='FAKE'\n        else:\n            classt='REAL'\n        plt.title(f\"Class: {classt}\")\n        plt.axis(\"off\")\n\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:57.857631Z","iopub.execute_input":"2025-08-07T11:12:57.857813Z","iopub.status.idle":"2025-08-07T11:12:59.288170Z","shell.execute_reply.started":"2025-08-07T11:12:57.857798Z","shell.execute_reply":"2025-08-07T11:12:59.287454Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"data_augmentation = tf.keras.Sequential([\n    tf.keras.layers.RandomFlip(mode=\"horizontal\", seed=42),\n    tf.keras.layers.RandomRotation(factor=0.05, seed=42),\n    tf.keras.layers.RandomContrast(factor=0.2, seed=42)\n])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:59.288890Z","iopub.execute_input":"2025-08-07T11:12:59.289104Z","iopub.status.idle":"2025-08-07T11:12:59.304123Z","shell.execute_reply.started":"2025-08-07T11:12:59.289087Z","shell.execute_reply":"2025-08-07T11:12:59.303408Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# extra code – displays the same first 9 images, after augmentation\n\nplt.figure(figsize=(12, 12))\nfor X_batch, y_batch in valid_set.take(1):\n    X_batch_augmented = data_augmentation(X_batch, training=True)\n    for index in range(9):\n        plt.subplot(3, 3, index + 1)\n        # We must rescale the images to the 0-1 range for imshow(), and also\n        # clip the result to that range, because data augmentation may\n        # make some values go out of bounds (e.g., RandomContrast in this case).\n        plt.imshow(np.clip((X_batch_augmented[index] + 1) / 2, 0, 1))\n        if(y_batch[index]==1):\n            classt='FAKE'\n        else:\n            classt='REAL'\n        plt.title(f\"Class: {classt}\")\n        plt.axis(\"off\")\n\nplt.show()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:12:59.304880Z","iopub.execute_input":"2025-08-07T11:12:59.305110Z","iopub.status.idle":"2025-08-07T11:13:02.200463Z","shell.execute_reply.started":"2025-08-07T11:12:59.305084Z","shell.execute_reply":"2025-08-07T11:13:02.199776Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"tf.random.set_seed(42)  # extra code – ensures reproducibility\nbase_model = tf.keras.applications.xception.Xception(weights=\"imagenet\",\n                                                     include_top=False)\navg = tf.keras.layers.GlobalAveragePooling2D()(base_model.output)\noutput = tf.keras.layers.Dense(1, activation=\"sigmoid\")(avg)\nmodel = tf.keras.Model(inputs=base_model.input, outputs=output)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:13:02.201459Z","iopub.execute_input":"2025-08-07T11:13:02.201735Z","iopub.status.idle":"2025-08-07T11:13:04.147037Z","shell.execute_reply.started":"2025-08-07T11:13:02.201713Z","shell.execute_reply":"2025-08-07T11:13:04.146155Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for layer in base_model.layers:\n    layer.trainable = False","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:13:04.147966Z","iopub.execute_input":"2025-08-07T11:13:04.148235Z","iopub.status.idle":"2025-08-07T11:13:04.153423Z","shell.execute_reply.started":"2025-08-07T11:13:04.148210Z","shell.execute_reply":"2025-08-07T11:13:04.152887Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"optimizer = tf.keras.optimizers.SGD(learning_rate=0.1, momentum=0.9)\nmodel.compile(loss=\"binary_crossentropy\", optimizer=optimizer,\n              metrics=[\"accuracy\"])\nhistory = model.fit(train_set, validation_data=valid_set, epochs=5)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:13:04.154146Z","iopub.execute_input":"2025-08-07T11:13:04.154492Z","iopub.status.idle":"2025-08-07T11:18:13.229161Z","shell.execute_reply.started":"2025-08-07T11:13:04.154466Z","shell.execute_reply":"2025-08-07T11:18:13.228599Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for indices in zip(range(33), range(33, 66), range(66, 99), range(99, 132)):\n    for idx in indices:\n        print(f\"{idx:3}: {base_model.layers[idx].name:22}\", end=\"\")\n    print()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:18:13.230009Z","iopub.execute_input":"2025-08-07T11:18:13.230249Z","iopub.status.idle":"2025-08-07T11:18:13.239217Z","shell.execute_reply.started":"2025-08-07T11:18:13.230233Z","shell.execute_reply":"2025-08-07T11:18:13.238438Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.evaluate(test_set)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:18:13.246967Z","iopub.execute_input":"2025-08-07T11:18:13.247635Z","iopub.status.idle":"2025-08-07T11:18:27.852799Z","shell.execute_reply.started":"2025-08-07T11:18:13.247613Z","shell.execute_reply":"2025-08-07T11:18:27.852174Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for layer in base_model.layers[56:]:\n    layer.trainable = True\n\noptimizer = tf.keras.optimizers.SGD(learning_rate=0.01, momentum=0.9)\nmodel.compile(loss=\"binary_crossentropy\", optimizer=optimizer,\n              metrics=[\"accuracy\"])\nhistory = model.fit(train_set, validation_data=valid_set, epochs=20)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T11:18:27.853670Z","iopub.execute_input":"2025-08-07T11:18:27.853942Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# plot model performance\nacc = history.history['accuracy']\nval_acc = history.history['val_accuracy']\nloss = history.history['loss']\nval_loss = history.history['val_loss']\nepochs_range = range(1, len(history.epoch) + 1)\n\nplt.figure(figsize=(15,5))\n\nplt.subplot(1, 2, 1)\nplt.plot(epochs_range, acc, label='Train Set')\nplt.plot(epochs_range, val_acc, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Accuracy')\nplt.title('Model Accuracy')\n\nplt.subplot(1, 2, 2)\nplt.plot(epochs_range, loss, label='Train Set')\nplt.plot(epochs_range, val_loss, label='Val Set')\nplt.legend(loc=\"best\")\nplt.xlabel('Epochs')\nplt.ylabel('Loss')\nplt.title('Model Loss')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:00:05.144502Z","iopub.execute_input":"2025-08-07T12:00:05.144800Z","iopub.status.idle":"2025-08-07T12:00:05.567252Z","shell.execute_reply.started":"2025-08-07T12:00:05.144778Z","shell.execute_reply":"2025-08-07T12:00:05.566544Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.evaluate(test_set)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:00:15.553977Z","iopub.execute_input":"2025-08-07T12:00:15.554241Z","iopub.status.idle":"2025-08-07T12:00:30.204164Z","shell.execute_reply.started":"2025-08-07T12:00:15.554223Z","shell.execute_reply":"2025-08-07T12:00:30.203461Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"model.save('xception_deepfake_image.h5')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:01:03.694849Z","iopub.execute_input":"2025-08-07T12:01:03.695467Z","iopub.status.idle":"2025-08-07T12:01:04.384518Z","shell.execute_reply.started":"2025-08-07T12:01:03.695445Z","shell.execute_reply":"2025-08-07T12:01:04.383589Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# try to interpret the trained model on how it finds a image FAKE","metadata":{}},{"cell_type":"code","source":"!pip install lime","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:01:16.240487Z","iopub.execute_input":"2025-08-07T12:01:16.241199Z","iopub.status.idle":"2025-08-07T12:01:19.689269Z","shell.execute_reply.started":"2025-08-07T12:01:16.241173Z","shell.execute_reply":"2025-08-07T12:01:19.688289Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from lime import lime_image\n\nexplainer = lime_image.LimeImageExplainer()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:01:22.246157Z","iopub.execute_input":"2025-08-07T12:01:22.246994Z","iopub.status.idle":"2025-08-07T12:01:22.251230Z","shell.execute_reply.started":"2025-08-07T12:01:22.246965Z","shell.execute_reply":"2025-08-07T12:01:22.250576Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from lime import lime_image\nfrom skimage.segmentation import mark_boundaries\nimport tensorflow as tf\nimport numpy as np\nimport matplotlib.pyplot as plt\n\ndef prediction_fn(images):\n    preprocessed_images = tf.keras.applications.xception.preprocess_input(images.astype('float32'))\n    return model.predict(preprocessed_images)\n\nexplainer = lime_image.LimeImageExplainer()\n\nplt.figure(figsize=(15, 10))\nfor i, (image_raw, label_raw) in enumerate(test_set_raw.take(6)):\n    \n    current_image_numpy = image_raw.numpy()\n    \n    explanation = explainer.explain_instance(\n        current_image_numpy,\n        prediction_fn, \n        top_labels=1, \n        hide_color=0, \n        num_samples=1000\n    )\n\n    temp, mask = explanation.get_image_and_mask(\n        explanation.top_labels[0], \n        positive_only=True,\n        num_features=10, \n        hide_rest=False\n    )\n    \n    plt.subplot(2, 3, i + 1)\n    plt.imshow(mark_boundaries(temp.astype('uint8'), mask))\n    \n    pred_val = model.predict(tf.expand_dims(tf.keras.applications.xception.preprocess_input(current_image_numpy), axis=0))[0][0]\n    pred_label = 'FAKE' if pred_val > 0.5 else 'REAL'\n    true_label = 'FAKE' if label_raw == 1 else 'REAL'\n    \n    plt.title(f\"Asli: {true_label}\\nPrediksi: {pred_label}\")\n    plt.axis('off')\n\nplt.tight_layout()\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:01:26.466054Z","iopub.execute_input":"2025-08-07T12:01:26.466945Z","iopub.status.idle":"2025-08-07T12:03:05.856118Z","shell.execute_reply.started":"2025-08-07T12:01:26.466917Z","shell.execute_reply":"2025-08-07T12:03:05.855081Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\nx_batch, y_batch = next(iter(test_set_raw.batch(32)))\n\ntest_data = x_batch[2] \n\nprint(\"Bentuk data yang dipilih:\")\nprint(test_data.shape)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:12.041287Z","iopub.execute_input":"2025-08-07T12:03:12.041617Z","iopub.status.idle":"2025-08-07T12:03:12.488994Z","shell.execute_reply.started":"2025-08-07T12:03:12.041593Z","shell.execute_reply":"2025-08-07T12:03:12.488268Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"explanation = explainer.explain_instance(test_data.numpy().astype('double'), prediction_fn,\n                                         top_labels=1, hide_color=0, num_samples=150)\nfrom skimage.segmentation import mark_boundaries\n\ntemp_1, mask_1 = explanation.get_image_and_mask(explanation.top_labels[0], positive_only=True, num_features=5, hide_rest=True)\ntemp_2, mask_2 = explanation.get_image_and_mask(explanation.top_labels[0], positive_only=False, num_features=10, hide_rest=False)\n\nfig, (ax1, ax2) = plt.subplots(1, 2, figsize=(15,15))\nax1.imshow(mark_boundaries(temp_1, mask_1))\nax2.imshow(mark_boundaries(temp_2, mask_2))\nax1.axis('off')\nax2.axis('off')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:17.345771Z","iopub.execute_input":"2025-08-07T12:03:17.346061Z","iopub.status.idle":"2025-08-07T12:03:21.439224Z","shell.execute_reply.started":"2025-08-07T12:03:17.346037Z","shell.execute_reply":"2025-08-07T12:03:21.438289Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# Deep Fake Video Classification","metadata":{}},{"cell_type":"code","source":"!pip install -U --upgrade tensorflow","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:26.779642Z","iopub.execute_input":"2025-08-07T12:03:26.779921Z","iopub.status.idle":"2025-08-07T12:03:30.572270Z","shell.execute_reply.started":"2025-08-07T12:03:26.779901Z","shell.execute_reply":"2025-08-07T12:03:30.571481Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install git+https://github.com/tensorflow/docs","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:34.968140Z","iopub.execute_input":"2025-08-07T12:03:34.969061Z","iopub.status.idle":"2025-08-07T12:03:42.264302Z","shell.execute_reply.started":"2025-08-07T12:03:34.969029Z","shell.execute_reply":"2025-08-07T12:03:42.263361Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from tensorflow_docs.vis import embed\nfrom tensorflow import keras\n#from imutils import paths\n\nimport matplotlib.pyplot as plt\nimport tensorflow as tf\nimport pandas as pd\nimport numpy as np\nimport imageio\nimport cv2\nimport os","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:44.494454Z","iopub.execute_input":"2025-08-07T12:03:44.495270Z","iopub.status.idle":"2025-08-07T12:03:44.500192Z","shell.execute_reply.started":"2025-08-07T12:03:44.495243Z","shell.execute_reply":"2025-08-07T12:03:44.499439Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"DATA_FOLDER = '../input/deepfake-detection-challenge'\nTRAIN_SAMPLE_FOLDER = 'train_sample_videos'\nTEST_FOLDER = 'test_videos'\n\nprint(f\"Train samples: {len(os.listdir(os.path.join(DATA_FOLDER, TRAIN_SAMPLE_FOLDER)))}\")\nprint(f\"Test samples: {len(os.listdir(os.path.join(DATA_FOLDER, TEST_FOLDER)))}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:03:52.838977Z","iopub.execute_input":"2025-08-07T12:03:52.839245Z","iopub.status.idle":"2025-08-07T12:03:52.845475Z","shell.execute_reply.started":"2025-08-07T12:03:52.839225Z","shell.execute_reply":"2025-08-07T12:03:52.844726Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_sample_metadata = pd.read_json('../input/deepfake-detection-challenge/train_sample_videos/metadata.json').T\ntrain_sample_metadata.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:04.084974Z","iopub.execute_input":"2025-08-07T12:04:04.085266Z","iopub.status.idle":"2025-08-07T12:04:04.159284Z","shell.execute_reply.started":"2025-08-07T12:04:04.085243Z","shell.execute_reply":"2025-08-07T12:04:04.158411Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_sample_metadata.groupby('label')['label'].count().plot(figsize=(15, 5), kind='bar', title='Distribution of Labels in the Training Set')\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:16.781051Z","iopub.execute_input":"2025-08-07T12:04:16.781843Z","iopub.status.idle":"2025-08-07T12:04:16.935878Z","shell.execute_reply.started":"2025-08-07T12:04:16.781815Z","shell.execute_reply":"2025-08-07T12:04:16.935198Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_sample_metadata.shape","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:23.377901Z","iopub.execute_input":"2025-08-07T12:04:23.378620Z","iopub.status.idle":"2025-08-07T12:04:23.384299Z","shell.execute_reply.started":"2025-08-07T12:04:23.378584Z","shell.execute_reply":"2025-08-07T12:04:23.383605Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"fake_train_sample_video = list(train_sample_metadata.loc[train_sample_metadata.label=='FAKE'].sample(3).index)\nfake_train_sample_video","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:26.530551Z","iopub.execute_input":"2025-08-07T12:04:26.530820Z","iopub.status.idle":"2025-08-07T12:04:26.537719Z","shell.execute_reply.started":"2025-08-07T12:04:26.530797Z","shell.execute_reply":"2025-08-07T12:04:26.536844Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_image_from_video(video_path):\n    '''\n    input: video_path - path for video\n    process:\n    1. perform a video capture from the video\n    2. read the image\n    3. display the image\n    '''\n    capture_image = cv2.VideoCapture(video_path) \n    ret, frame = capture_image.read()\n    fig = plt.figure(figsize=(10,10))\n    ax = fig.add_subplot(111)\n    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n    ax.imshow(frame)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:32.499520Z","iopub.execute_input":"2025-08-07T12:04:32.499782Z","iopub.status.idle":"2025-08-07T12:04:32.504782Z","shell.execute_reply.started":"2025-08-07T12:04:32.499764Z","shell.execute_reply":"2025-08-07T12:04:32.504024Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for video_file in fake_train_sample_video:\n    display_image_from_video(os.path.join(DATA_FOLDER, TRAIN_SAMPLE_FOLDER, video_file))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:38.592027Z","iopub.execute_input":"2025-08-07T12:04:38.592290Z","iopub.status.idle":"2025-08-07T12:04:40.560932Z","shell.execute_reply.started":"2025-08-07T12:04:38.592270Z","shell.execute_reply":"2025-08-07T12:04:40.560279Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Few Real Videos","metadata":{}},{"cell_type":"code","source":"real_train_sample_video = list(train_sample_metadata.loc[train_sample_metadata.label=='REAL'].sample(3).index)\nreal_train_sample_video","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:48.697942Z","iopub.execute_input":"2025-08-07T12:04:48.698224Z","iopub.status.idle":"2025-08-07T12:04:48.704943Z","shell.execute_reply.started":"2025-08-07T12:04:48.698201Z","shell.execute_reply":"2025-08-07T12:04:48.704294Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"for video_file in real_train_sample_video:\n    display_image_from_video(os.path.join(DATA_FOLDER, TRAIN_SAMPLE_FOLDER, video_file))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:04:52.239614Z","iopub.execute_input":"2025-08-07T12:04:52.239879Z","iopub.status.idle":"2025-08-07T12:04:54.312289Z","shell.execute_reply.started":"2025-08-07T12:04:52.239860Z","shell.execute_reply":"2025-08-07T12:04:54.311620Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_sample_metadata['original'].value_counts()[0:5]","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:00.909353Z","iopub.execute_input":"2025-08-07T12:05:00.910245Z","iopub.status.idle":"2025-08-07T12:05:00.917325Z","shell.execute_reply.started":"2025-08-07T12:05:00.910217Z","shell.execute_reply":"2025-08-07T12:05:00.916448Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def display_image_from_video_list(video_path_list, video_folder=TRAIN_SAMPLE_FOLDER):\n    '''\n    input: video_path_list - path for video\n    process:\n    0. for each video in the video path list\n        1. perform a video capture from the video\n        2. read the image\n        3. display the image\n    '''\n    plt.figure()\n    fig, ax = plt.subplots(2,3,figsize=(16,8))\n    # we only show images extracted from the first 6 videos\n    for i, video_file in enumerate(video_path_list[0:6]):\n        video_path = os.path.join(DATA_FOLDER, video_folder,video_file)\n        capture_image = cv2.VideoCapture(video_path) \n        ret, frame = capture_image.read()\n        frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n        ax[i//3, i%3].imshow(frame)\n        ax[i//3, i%3].set_title(f\"Video: {video_file}\")\n        ax[i//3, i%3].axis('on')","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:08.130065Z","iopub.execute_input":"2025-08-07T12:05:08.131005Z","iopub.status.idle":"2025-08-07T12:05:08.136715Z","shell.execute_reply.started":"2025-08-07T12:05:08.130974Z","shell.execute_reply":"2025-08-07T12:05:08.136064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"same_original_fake_train_sample_video = list(train_sample_metadata.loc[train_sample_metadata.original=='atvmxvwyns.mp4'].index)\ndisplay_image_from_video_list(same_original_fake_train_sample_video)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:15.210201Z","iopub.execute_input":"2025-08-07T12:05:15.210596Z","iopub.status.idle":"2025-08-07T12:05:18.856181Z","shell.execute_reply.started":"2025-08-07T12:05:15.210571Z","shell.execute_reply":"2025-08-07T12:05:18.855545Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Test video files","metadata":{}},{"cell_type":"code","source":"test_videos = pd.DataFrame(list(os.listdir(os.path.join(DATA_FOLDER, TEST_FOLDER))), columns=['video'])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:26.951114Z","iopub.execute_input":"2025-08-07T12:05:26.951807Z","iopub.status.idle":"2025-08-07T12:05:26.957158Z","shell.execute_reply.started":"2025-08-07T12:05:26.951782Z","shell.execute_reply":"2025-08-07T12:05:26.956441Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"test_videos.head()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:33.251273Z","iopub.execute_input":"2025-08-07T12:05:33.251592Z","iopub.status.idle":"2025-08-07T12:05:33.259444Z","shell.execute_reply.started":"2025-08-07T12:05:33.251569Z","shell.execute_reply":"2025-08-07T12:05:33.258548Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"display_image_from_video(os.path.join(DATA_FOLDER, TEST_FOLDER, test_videos.iloc[2].video))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:05:41.245558Z","iopub.execute_input":"2025-08-07T12:05:41.245830Z","iopub.status.idle":"2025-08-07T12:05:41.910772Z","shell.execute_reply.started":"2025-08-07T12:05:41.245808Z","shell.execute_reply":"2025-08-07T12:05:41.910100Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Play video files","metadata":{}},{"cell_type":"code","source":"fake_videos = list(train_sample_metadata.loc[train_sample_metadata.label=='FAKE'].index)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:08:05.421933Z","iopub.execute_input":"2025-08-07T12:08:05.422198Z","iopub.status.idle":"2025-08-07T12:08:05.427115Z","shell.execute_reply.started":"2025-08-07T12:08:05.422176Z","shell.execute_reply":"2025-08-07T12:08:05.426423Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from IPython.display import HTML\nfrom base64 import b64encode\n\ndef play_video(video_file, subset=TRAIN_SAMPLE_FOLDER):\n    '''\n    Display video\n    param: video_file - the name of the video file to display\n    param: subset - the folder where the video file is located (can be TRAIN_SAMPLE_FOLDER or TEST_Folder)\n    '''\n    video_url = open(os.path.join(DATA_FOLDER, subset,video_file),'rb').read()\n    data_url = \"data:video/mp4;base64,\" + b64encode(video_url).decode()\n    return HTML(\"\"\"<video width=500 controls><source src=\"%s\" type=\"video/mp4\"></video>\"\"\" % data_url)\n\nplay_video(fake_videos[10])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:08:10.058824Z","iopub.execute_input":"2025-08-07T12:08:10.059090Z","iopub.status.idle":"2025-08-07T12:08:10.222137Z","shell.execute_reply.started":"2025-08-07T12:08:10.059069Z","shell.execute_reply":"2025-08-07T12:08:10.221277Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"Modelling\n\nA CNN-RNN Architecture","metadata":{}},{"cell_type":"code","source":"IMG_SIZE = 224\nBATCH_SIZE = 64\nEPOCHS = 20\n\nMAX_SEQ_LENGTH = 20\nNUM_FEATURES = 2048","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:08:31.474833Z","iopub.execute_input":"2025-08-07T12:08:31.475110Z","iopub.status.idle":"2025-08-07T12:08:31.479742Z","shell.execute_reply.started":"2025-08-07T12:08:31.475087Z","shell.execute_reply":"2025-08-07T12:08:31.478894Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def crop_center_square(frame):\n    y, x = frame.shape[0:2]\n    min_dim = min(y, x)\n    start_x = (x // 2) - (min_dim // 2)\n    start_y = (y // 2) - (min_dim // 2)\n    return frame[start_y : start_y + min_dim, start_x : start_x + min_dim]\n\n\ndef load_video(path, max_frames=0, resize=(IMG_SIZE, IMG_SIZE)):\n    cap = cv2.VideoCapture(path)\n    frames = []\n    try:\n        while True:\n            ret, frame = cap.read()\n            if not ret:\n                break\n            frame = crop_center_square(frame)\n            frame = cv2.resize(frame, resize)\n            frame = frame[:, :, [2, 1, 0]]\n            frames.append(frame)\n\n            if len(frames) == max_frames:\n                break\n    finally:\n        cap.release()\n    return np.array(frames)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:08:41.464332Z","iopub.execute_input":"2025-08-07T12:08:41.464635Z","iopub.status.idle":"2025-08-07T12:08:41.470949Z","shell.execute_reply.started":"2025-08-07T12:08:41.464614Z","shell.execute_reply":"2025-08-07T12:08:41.470265Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def build_feature_extractor():\n    feature_extractor = keras.applications.InceptionV3(\n        weights=\"imagenet\",\n        include_top=False,\n        pooling=\"avg\",\n        input_shape=(IMG_SIZE, IMG_SIZE, 3),\n    )\n    preprocess_input = keras.applications.inception_v3.preprocess_input\n\n    inputs = keras.Input((IMG_SIZE, IMG_SIZE, 3))\n    preprocessed = preprocess_input(inputs)\n\n    outputs = feature_extractor(preprocessed)\n    return keras.Model(inputs, outputs, name=\"feature_extractor\")\n\n\nfeature_extractor = build_feature_extractor()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:08:51.076339Z","iopub.execute_input":"2025-08-07T12:08:51.076967Z","iopub.status.idle":"2025-08-07T12:08:52.762041Z","shell.execute_reply.started":"2025-08-07T12:08:51.076945Z","shell.execute_reply":"2025-08-07T12:08:52.761430Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_all_videos(df, root_dir):\n    num_samples = len(df)\n    video_paths = list(df.index)\n    labels = df[\"label\"].values\n    labels = np.array(labels=='FAKE').astype(np.int)\n\n    # `frame_masks` and `frame_features` are what we will feed to our sequence model.\n    # `frame_masks` will contain a bunch of booleans denoting if a timestep is\n    # masked with padding or not.\n    frame_masks = np.zeros(shape=(num_samples, MAX_SEQ_LENGTH), dtype=\"bool\")\n    frame_features = np.zeros(\n        shape=(num_samples, MAX_SEQ_LENGTH, NUM_FEATURES), dtype=\"float32\"\n    )\n\n    # For each video.\n    for idx, path in enumerate(video_paths):\n        # Gather all its frames and add a batch dimension.\n        frames = load_video(os.path.join(root_dir, path))\n        frames = frames[None, ...]\n\n        # Initialize placeholders to store the masks and features of the current video.\n        temp_frame_mask = np.zeros(shape=(1, MAX_SEQ_LENGTH,), dtype=\"bool\")\n        temp_frame_features = np.zeros(\n            shape=(1, MAX_SEQ_LENGTH, NUM_FEATURES), dtype=\"float32\"\n        )\n\n        # Extract features from the frames of the current video.\n        for i, batch in enumerate(frames):\n            video_length = batch.shape[0]\n            length = min(MAX_SEQ_LENGTH, video_length)\n            for j in range(length):\n                temp_frame_features[i, j, :] = feature_extractor.predict(\n                    batch[None, j, :]\n                )\n            temp_frame_mask[i, :length] = 1  # 1 = not masked, 0 = masked\n\n        frame_features[idx,] = temp_frame_features.squeeze()\n        frame_masks[idx,] = temp_frame_mask.squeeze()\n\n    return (frame_features, frame_masks), labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:24:14.710653Z","iopub.execute_input":"2025-08-07T12:24:14.711339Z","iopub.status.idle":"2025-08-07T12:24:14.718612Z","shell.execute_reply.started":"2025-08-07T12:24:14.711304Z","shell.execute_reply":"2025-08-07T12:24:14.717838Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_all_videos(df, root_dir):\n    import os\n    import numpy as np\n\n    max_frames = MAX_SEQ_LENGTH \n    feature_size = 2048\n\n    video_paths = list(df.index)\n    labels = df[\"label\"].values\n    labels = np.array(labels == 'FAKE').astype(int)\n\n    frame_features = np.zeros((len(video_paths), max_frames, feature_size), dtype=\"float32\")\n    frame_masks = np.zeros((len(video_paths), max_frames), dtype=\"bool\")\n\n    for idx, path in enumerate(video_paths):\n        frames = load_video(os.path.join(root_dir, path))\n        temp_frame_features = np.zeros((max_frames, feature_size), dtype=\"float32\")\n        temp_frame_mask = np.zeros((max_frames,), dtype=\"bool\")\n\n        length = min(len(frames), max_frames)\n        for i in range(length):\n            frame = frames[i]\n            batch = np.expand_dims(frame, axis=0)\n            temp_frame_features[i, :] = feature_extractor.predict(batch[None, :, :, :])\n            temp_frame_mask[i] = 1\n\n        frame_features[idx, :] = temp_frame_features.squeeze()\n        frame_masks[idx, :] = temp_frame_mask.squeeze()\n\n    return (frame_features, frame_masks), labels","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:31:29.828674Z","iopub.execute_input":"2025-08-07T12:31:29.829468Z","iopub.status.idle":"2025-08-07T12:31:29.836220Z","shell.execute_reply.started":"2025-08-07T12:31:29.829437Z","shell.execute_reply":"2025-08-07T12:31:29.835506Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"from sklearn.model_selection import train_test_split\n\nTrain_set, Test_set = train_test_split(train_sample_metadata,test_size=0.1,random_state=42,stratify=train_sample_metadata['label'])\n\nprint(Train_set.shape, Test_set.shape )","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:31:44.142192Z","iopub.execute_input":"2025-08-07T12:31:44.142771Z","iopub.status.idle":"2025-08-07T12:31:44.150732Z","shell.execute_reply.started":"2025-08-07T12:31:44.142749Z","shell.execute_reply":"2025-08-07T12:31:44.149760Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"train_data, train_labels = prepare_all_videos(Train_set, \"train\")\ntest_data, test_labels = prepare_all_videos(Test_set, \"test\")\n\nprint(f\"Frame features in train set: {train_data[0].shape}\")\nprint(f\"Frame masks in train set: {train_data[1].shape}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:31:51.602969Z","iopub.execute_input":"2025-08-07T12:31:51.603256Z","iopub.status.idle":"2025-08-07T12:31:51.683278Z","shell.execute_reply.started":"2025-08-07T12:31:51.603233Z","shell.execute_reply":"2025-08-07T12:31:51.682547Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"# sequence model","metadata":{}},{"cell_type":"code","source":"\nframe_features_input = keras.Input((MAX_SEQ_LENGTH, NUM_FEATURES))\nmask_input = keras.Input((MAX_SEQ_LENGTH,), dtype=\"bool\")\n\n\nx = keras.layers.GRU(16, return_sequences=True, recurrent_dropout=0.1)(\n    frame_features_input, mask=mask_input\n) \n\n\nx = keras.layers.GRU(8, recurrent_dropout=0.1)(x)\n\nx = keras.layers.Dropout(0.4)(x)\nx = keras.layers.Dense(8, activation=\"relu\")(x)\noutput = keras.layers.Dense(1, activation=\"sigmoid\")(x)\n\nmodel = keras.Model([frame_features_input, mask_input], output)\n\nmodel.compile(loss=\"binary_crossentropy\", optimizer=\"adam\", metrics=[\"accuracy\"])\nmodel.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:41:18.621959Z","iopub.execute_input":"2025-08-07T12:41:18.622253Z","iopub.status.idle":"2025-08-07T12:41:18.692958Z","shell.execute_reply.started":"2025-08-07T12:41:18.622231Z","shell.execute_reply":"2025-08-07T12:41:18.692416Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"checkpoint = keras.callbacks.ModelCheckpoint('/kaggle/working/xception_deepfake_image.weights.h5', save_weights_only=True, save_best_only=True)\nhistory = model.fit(\n        [train_data[0], train_data[1]],\n        train_labels,\n        validation_data=([test_data[0], test_data[1]],test_labels),\n        callbacks=[checkpoint],\n        epochs=EPOCHS,\n        batch_size=8\n    )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:41:27.364154Z","iopub.execute_input":"2025-08-07T12:41:27.364942Z","iopub.status.idle":"2025-08-07T12:42:56.139964Z","shell.execute_reply.started":"2025-08-07T12:41:27.364916Z","shell.execute_reply":"2025-08-07T12:42:56.139422Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def prepare_single_video(frames):\n    frames = frames[None, ...]\n    frame_mask = np.zeros(shape=(1, MAX_SEQ_LENGTH,), dtype=\"bool\")\n    frame_features = np.zeros(shape=(1, MAX_SEQ_LENGTH, NUM_FEATURES), dtype=\"float32\")\n\n    for i, batch in enumerate(frames):\n        video_length = batch.shape[0]\n        length = min(MAX_SEQ_LENGTH, video_length)\n        for j in range(length):\n            frame_features[i, j, :] = feature_extractor.predict(batch[None, j, :])\n        frame_mask[i, :length] = 1  # 1 = not masked, 0 = masked\n\n    return frame_features, frame_mask\n\ndef sequence_prediction(path):\n    frames = load_video(os.path.join(DATA_FOLDER, TEST_FOLDER,path))\n    frame_features, frame_mask = prepare_single_video(frames)\n    return model.predict([frame_features, frame_mask])[0]\n    \n# This utility is for visualization.\n# Referenced from:\n# https://www.tensorflow.org/hub/tutorials/action_recognition_with_tf_hub\ndef to_gif(images):\n    converted_images = images.astype(np.uint8)\n    imageio.mimsave(\"animation.gif\", converted_images, fps=10)\n    return embed.embed_file(\"animation.gif\")\n\n\ntest_video = np.random.choice(test_videos[\"video\"].values.tolist())\nprint(f\"Test video path: {test_video}\")\n\nif(sequence_prediction(test_video)>=0.5):\n    print(f'The predicted class of the video is FAKE')\nelse:\n    print(f'The predicted class of the video is REAL')\n\nplay_video(test_video,TEST_FOLDER)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-08-07T12:43:01.247106Z","iopub.execute_input":"2025-08-07T12:43:01.247369Z","iopub.status.idle":"2025-08-07T12:43:12.268492Z","shell.execute_reply.started":"2025-08-07T12:43:01.247349Z","shell.execute_reply":"2025-08-07T12:43:12.267449Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}