{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.6.6","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"}],"dockerImageVersionId":29845,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# This Python 3 environment comes with many helpful analytics libraries installed\n# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python\n# For example, here's several helpful packages to load\n\nimport numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\n\n# Input data files are available in the read-only \"../input/\" directory\n# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory\n\nimport os\nfor dirname, _, filenames in os.walk('/kaggle/input'):\n    for filename in filenames:\n        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"_kg_hide-input":false},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport random\nimport shutil\nimport numpy as np\nimport pandas as pd\n\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\n\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import DataLoader\nfrom torchvision import transforms, models\nfrom torchvision.datasets import ImageFolder","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:12:14.263720Z","iopub.execute_input":"2024-12-28T22:12:14.264069Z","iopub.status.idle":"2024-12-28T22:12:14.269230Z","shell.execute_reply.started":"2024-12-28T22:12:14.264014Z","shell.execute_reply":"2024-12-28T22:12:14.268355Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"dataset_path = '/kaggle/input/deepfake-detection-challenge'\ntrain_videos_path = os.path.join(dataset_path, 'train_sample_videos')\ntest_videos_path = os.path.join(dataset_path, 'test_videos')\n\nprint(f\"train samples: {len(os.listdir(os.path.join(dataset_path, train_videos_path)))}\")\nprint(f\"test samples: {len(os.listdir(os.path.join(dataset_path, test_videos_path)))}\")\n\n\ntrain_sample_metadata = pd.read_json('/kaggle/input/deepfake-detection-challenge/train_sample_videos/metadata.json').T\ntrain_sample_metadata.head()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T19:33:13.446026Z","iopub.execute_input":"2024-12-28T19:33:13.446352Z","iopub.status.idle":"2024-12-28T19:33:14.025025Z","shell.execute_reply.started":"2024-12-28T19:33:13.446294Z","shell.execute_reply":"2024-12-28T19:33:14.024267Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\n\noutput_dir = '/kaggle/working/frames'\nos.makedirs(output_dir, exist_ok=True)\n\nreal_folder = os.path.join(output_dir, 'REAL')\nfake_folder = os.path.join(output_dir, 'Fake')\nos.makedirs(real_folder, exist_ok = True)\nos.makedirs(fake_folder, exist_ok = True)\n\n# Define the dataset path\nVIDEO_DATASET_PATH = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos\"  # Path containing deepfake videos\n\n\n\n\n# Function to extract frames from videos\ndef extract_frames(video_path, output_dir, frame_rate=30):\n    \"\"\"\n    video_path: مسار ملف الفيديو\n    output_dir: المجلد الذي ستحفظ فيه الصور\n    frame_rate: حفظ إطار واحد كل frame_rate إطار\n    \"\"\"\n    cap = cv2.VideoCapture(video_path)\n    frame_idx = 0\n\n    while cap.isOpened():\n        ret, frame = cap.read()\n        if not ret:\n            break\n        # حفظ إطار كل (frame_rate) إطار\n        if int(cap.get(cv2.CAP_PROP_POS_FRAMES)) % frame_rate == 0:\n            frame_name = f\"{os.path.basename(video_path)}_frame_{frame_idx}.jpg\"\n            frame_path = os.path.join(output_dir, frame_name)\n            # تحويل BGR إلى RGB قبل الحفظ (اختياري)\n            frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)\n            cv2.imwrite(frame_path, frame_rgb)\n            frame_idx += 1\n\n    cap.release()\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T21:39:41.583576Z","iopub.execute_input":"2024-12-28T21:39:41.583878Z","iopub.status.idle":"2024-12-28T21:39:41.591728Z","shell.execute_reply.started":"2024-12-28T21:39:41.583842Z","shell.execute_reply":"2024-12-28T21:39:41.591054Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"###############################################\n# 6) استخراج الإطارات من كل فيديو للمجلدات   #\n###############################################\nVIDEO_DATASET_PATH = train_videos_path  # للمزيد من الوضوح\n\nfor video_name, data in train_sample_metadata.iterrows():\n    label = data['label']  # REAL أو FAKE\n    video_path = os.path.join(VIDEO_DATASET_PATH, video_name)\n    \n    if label == 'REAL':\n        extract_frames(video_path, real_folder)\n    else:\n        extract_frames(video_path, fake_folder)\n\nprint(\"Frame extraction completed.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T21:39:58.313834Z","iopub.execute_input":"2024-12-28T21:39:58.314100Z","iopub.status.idle":"2024-12-28T21:42:21.538803Z","shell.execute_reply.started":"2024-12-28T21:39:58.314063Z","shell.execute_reply":"2024-12-28T21:42:21.537361Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"def split_data(source_dir, train_dir, val_dir, test_dir, train_ratio=0.7, val_ratio=0.1):\n    \"\"\"\n    تقسيم الإطارات المستخرجة إلى مجلدات train / val / test\n    مع الحفاظ على بنية المجلد (REAL, Fake)\n    \"\"\"\n    for category in [\"REAL\", \"Fake\"]:\n        category_path = os.path.join(source_dir, category)\n        if not os.path.isdir(category_path):\n            continue\n\n        images = [os.path.join(category_path, img) for img in os.listdir(category_path)]\n        \n        # تقسيم أولي إلى (Train, Test) ثم إعادة تقسيم الـTrain إلى (Train, Val)\n        train_images, test_images = train_test_split(images, test_size=(1 - train_ratio), random_state=42)\n        train_images, val_images  = train_test_split(train_images, test_size=val_ratio / train_ratio, random_state=42)\n\n        # نسخ الملفات إلى المجلدات النهائية\n        for img_set, out_dir in zip([train_images, val_images, test_images],\n                                    [train_dir, val_dir, test_dir]):\n            cat_out_dir = os.path.join(out_dir, category)\n            os.makedirs(cat_out_dir, exist_ok=True)\n            for img_path in img_set:\n                shutil.copy(img_path, cat_out_dir)\n\n\n# إنشاء المجلدات الفرعية (Train, Val, Test)\nBASE_SPLIT_DIR = \"/kaggle/working/dataset_split\"\nTRAIN_DIR = os.path.join(BASE_SPLIT_DIR, \"train\")\nVAL_DIR   = os.path.join(BASE_SPLIT_DIR, \"val\")\nTEST_DIR  = os.path.join(BASE_SPLIT_DIR, \"test\")\n\nos.makedirs(TRAIN_DIR, exist_ok=True)\nos.makedirs(VAL_DIR, exist_ok=True)\nos.makedirs(TEST_DIR, exist_ok=True)\n\n# استدعاء الدالّة\nsplit_data(\n    source_dir = output_dir,\n    train_dir  = TRAIN_DIR,\n    val_dir    = VAL_DIR,\n    test_dir   = TEST_DIR,\n    train_ratio=0.7,\n    val_ratio = 0.1\n)\n\nprint(\"Data splitting completed.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T21:42:24.232889Z","iopub.execute_input":"2024-12-28T21:42:24.233213Z","iopub.status.idle":"2024-12-28T21:42:25.964939Z","shell.execute_reply.started":"2024-12-28T21:42:24.233149Z","shell.execute_reply":"2024-12-28T21:42:25.964113Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"##############################################################\n# 8) إنشاء الـ Datasets و DataLoaders باستخدام ImageFolder #\n##############################################################\n# التحويلات (Transforms) الأساسية\ntrain_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(p=0.5),  # مثال لإضافة Augmentation\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std =[0.229, 0.224, 0.225])\n])\n\nval_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std =[0.229, 0.224, 0.225])\n])\n\ntest_transform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406],\n                         std =[0.229, 0.224, 0.225])\n])\n\n# إنشاء الـ Datasets\ntrain_dataset = ImageFolder(root=TRAIN_DIR, transform=train_transform)\nval_dataset   = ImageFolder(root=VAL_DIR,   transform=val_transform)\ntest_dataset  = ImageFolder(root=TEST_DIR,  transform=test_transform)\n\n# أحجام دفعية (Batch Size)\nbatch_size = 32\n\n# إنشاء الـ DataLoaders\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True,  num_workers=2)\nval_loader   = DataLoader(val_dataset,   batch_size=batch_size, shuffle=False, num_workers=2)\ntest_loader  = DataLoader(test_dataset,  batch_size=batch_size, shuffle=False, num_workers=2)\n\n# عرض عدد الصور في كل قسم\nprint(f\"Train Dataset: {len(train_dataset)} images\")\nprint(f\"Val Dataset  : {len(val_dataset)} images\")\nprint(f\"Test Dataset : {len(test_dataset)} images\")\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:12:22.247580Z","iopub.execute_input":"2024-12-28T22:12:22.247878Z","iopub.status.idle":"2024-12-28T22:12:22.272111Z","shell.execute_reply.started":"2024-12-28T22:12:22.247829Z","shell.execute_reply":"2024-12-28T22:12:22.271500Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"############################################\n# 9) إنشاء نموذج ResNet50 مُحدَّث الرأس  #\n############################################\ndef create_model_resnet50(num_classes=2):\n    model = models.resnet50(pretrained=True)\n    # تجميد جميع الطبقات الأساسية (اختياري)\n    # for param in model.parameters():\n    #     param.requires_grad = False\n\n    in_features = model.fc.in_features\n    # تعيين عدد الإخراج بمقدار عدد الأصناف (2)\n    model.fc = nn.Linear(in_features, num_classes)\n    return model\n\nmodel = create_model_resnet50(num_classes=2)\nmodel = model.to(device)\n\n# اختيار الخسارة والمُحسّن (Optimizer)\ncriterion = nn.CrossEntropyLoss()           \noptimizer = optim.Adam(model.parameters(), lr=1e-4)  # يمكن تغيير الـLR وتجربته\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:12:26.688741Z","iopub.execute_input":"2024-12-28T22:12:26.689001Z","iopub.status.idle":"2024-12-28T22:12:27.275575Z","shell.execute_reply.started":"2024-12-28T22:12:26.688965Z","shell.execute_reply":"2024-12-28T22:12:27.275008Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#######################################\n# 10) توابع التدريب والتقييم (Val)    #\n#######################################\ndef train_one_epoch(model, dataloader, optimizer, criterion):\n    model.train()\n    running_loss = 0.0\n    correct = 0\n    total   = 0\n\n    for images, labels in dataloader:\n        images, labels = images.to(device), labels.to(device)\n\n        # تصفير تراكم الـGradient\n        optimizer.zero_grad()\n\n        # تمرير البيانات داخل النموذج\n        outputs = model(images)  # مخرجات حجمها [Batch, 2]\n        loss    = criterion(outputs, labels)\n\n        # Backpropagation\n        loss.backward()\n        optimizer.step()\n\n        # حساب الخسارة\n        running_loss += loss.item() * images.size(0)\n\n        # حساب عدد العينات المصنفة صحيحًا\n        _, preds = torch.max(outputs, dim=1)\n        correct += (preds == labels).sum().item()\n        total   += labels.size(0)\n\n    epoch_loss = running_loss / total\n    epoch_acc  = correct / total\n    return epoch_loss, epoch_acc\n\ndef validate(model, dataloader, criterion):\n    model.eval()\n    running_loss = 0.0\n    correct = 0\n    total   = 0\n\n    with torch.no_grad():\n        for images, labels in dataloader:\n            images, labels = images.to(device), labels.to(device)\n            outputs = model(images)\n            loss    = criterion(outputs, labels)\n\n            running_loss += loss.item() * images.size(0)\n            _, preds = torch.max(outputs, dim=1)\n            correct += (preds == labels).sum().item()\n            total   += labels.size(0)\n\n    val_loss = running_loss / total\n    val_acc  = correct / total\n    return val_loss, val_acc\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:12:29.856110Z","iopub.execute_input":"2024-12-28T22:12:29.856415Z","iopub.status.idle":"2024-12-28T22:12:29.866055Z","shell.execute_reply.started":"2024-12-28T22:12:29.856342Z","shell.execute_reply":"2024-12-28T22:12:29.865336Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"############################################\n# 11) حلقة التدريب الأساسية (Training Loop)\n############################################\nnum_epochs = 5  # عدّل حسب رغبتك\nfor epoch in range(num_epochs):\n    train_loss, train_acc = train_one_epoch(model, train_loader, optimizer, criterion)\n    val_loss, val_acc = validate(model, val_loader, criterion)\n\n    print(f\"Epoch [{epoch+1}/{num_epochs}] \"\n          f\"- Train Loss: {train_loss:.4f}, Train Acc: {train_acc:.4f} \"\n          f\"- Val Loss: {val_loss:.4f}, Val Acc: {val_acc:.4f}\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:12:33.805740Z","iopub.execute_input":"2024-12-28T22:12:33.805996Z","iopub.status.idle":"2024-12-28T22:17:27.433160Z","shell.execute_reply.started":"2024-12-28T22:12:33.805960Z","shell.execute_reply":"2024-12-28T22:17:27.432164Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"################################\n# 12) التقييم على بيانات الاختبار\n################################\nmodel.eval()\nall_labels = []\nall_preds  = []\n\nwith torch.no_grad():\n    for images, labels in test_loader:\n        images = images.to(device)\n        labels = labels.to(device)\n\n        outputs = model(images)\n        _, preds = torch.max(outputs, 1)\n\n        all_preds.extend(preds.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\naccuracy  = accuracy_score(all_labels, all_preds)\nprecision = precision_score(all_labels, all_preds, average='macro')\nrecall    = recall_score(all_labels, all_preds, average='macro')\nf1        = f1_score(all_labels, all_preds, average='macro')\ncm        = confusion_matrix(all_labels, all_preds)\n\nprint(\"\\n===== Test Metrics =====\")\nprint(f\"Accuracy : {accuracy:.4f}\")\nprint(f\"Precision: {precision:.4f}\")\nprint(f\"Recall   : {recall:.4f}\")\nprint(f\"F1-Score : {f1:.4f}\")\nprint(\"Confusion Matrix:\")\nprint(cm)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2024-12-28T22:17:40.579128Z","iopub.execute_input":"2024-12-28T22:17:40.579428Z","iopub.status.idle":"2024-12-28T22:18:03.552486Z","shell.execute_reply.started":"2024-12-28T22:17:40.579382Z","shell.execute_reply":"2024-12-28T22:18:03.551556Z"}},"outputs":[],"execution_count":null}]}