{"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":"none","dataSources":[{"sourceId":16880,"databundleVersionId":858837,"sourceType":"competition"}],"dockerImageVersionId":29844,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"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,"execution":{"iopub.status.busy":"2025-03-01T14:03:52.980821Z","iopub.execute_input":"2025-03-01T14:03:52.981230Z","iopub.status.idle":"2025-03-01T14:03:55.368666Z","shell.execute_reply.started":"2025-03-01T14:03:52.981161Z","shell.execute_reply":"2025-03-01T14:03:55.367683Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport cv2\nimport torch\nimport numpy as np\nimport pandas as pd\nimport torchvision.transforms as transforms\n\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models\nfrom torch import nn, optim\nfrom PIL import Image\ndata_path = \"/kaggle/input/deepfake-detection-challenge/train_sample_videos\"\nmetadata_path = os.path.join(data_path, \"metadata.json\")\nprint(\"Các file có sẵn:\")\nprint(os.listdir(data_path)[:10])  # Hiển thị 10 file đầu tiên\nimport json\n\nwith open(metadata_path, \"r\") as f:\n    metadata = json.load(f)\n\n# Chuyển metadata thành DataFrame\ndf = pd.DataFrame(metadata).T\ndf = df.reset_index().rename(columns={'index': 'filename'})\n\n# Hiển thị dữ liệu\nprint(df.head())\ndef extract_frames(video_path, num_frames=5):\n    cap = cv2.VideoCapture(video_path)\n    frames = []\n    \n    total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    frame_indices = np.linspace(0, total_frames - 1, num_frames, dtype=int)\n\n    for idx in frame_indices:\n        cap.set(cv2.CAP_PROP_POS_FRAMES, idx)\n        ret, frame = cap.read()\n        if ret:\n            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # Chuyển ảnh sang RGB\n            frame = Image.fromarray(frame)\n            frames.append(frame)\n\n    cap.release()\n    return frames\nsample_video = os.path.join(data_path, df.iloc[0][\"filename\"])\nsample_frames = extract_frames(sample_video, num_frames=5)\n\nimport matplotlib.pyplot as plt\n\n# Hiển thị ảnh đầu tiên trong danh sách khung hình\nplt.imshow(sample_frames[0])\nplt.axis(\"off\")  # Ẩn trục\nplt.show()\ntransform = transforms.Compose([\n    transforms.Resize((128, 128)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.5], std=[0.5])\n])\nclass DeepfakeDataset(Dataset):\n    def __init__(self, df, data_path, num_frames=5, transform=None):\n        self.df = df\n        self.data_path = data_path\n        self.num_frames = num_frames\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.df)\n\n    def __getitem__(self, idx):\n        video_name = self.df.iloc[idx][\"filename\"]\n        label = 1 if self.df.iloc[idx][\"label\"] == \"FAKE\" else 0\n        video_path = os.path.join(self.data_path, video_name)\n\n        frames = extract_frames(video_path, num_frames=self.num_frames)\n        \n        if self.transform:\n            frames = [self.transform(frame) for frame in frames]\n\n        return torch.stack(frames), torch.tensor(label, dtype=torch.long)\ndataset = DeepfakeDataset(df, data_path, transform=transform)\ndataloader = DataLoader(dataset, batch_size=8, shuffle=True)\n\n# Kiểm tra batch đầu tiên\nfor images, labels in dataloader:\n    print(\"Batch size:\", images.shape)  # [batch, num_frames, 3, 128, 128]\n    print(\"Label:\", labels)\n    break\nclass Discriminator(nn.Module):\n    def __init__(self):\n        super(Discriminator, self).__init__()\n        self.model = nn.Sequential(\n            nn.Conv2d(3, 64, kernel_size=4, stride=2, padding=1),\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(64, 128, kernel_size=4, stride=2, padding=1),\n            nn.BatchNorm2d(128),\n            nn.LeakyReLU(0.2),\n            nn.Conv2d(128, 256, kernel_size=4, stride=2, padding=1),\n            nn.BatchNorm2d(256),\n            nn.LeakyReLU(0.2),\n            nn.Flatten(),\n            nn.Linear(256 * 16 * 16, 1),\n            nn.Sigmoid()\n        )\n\n    def forward(self, x):\n        return self.model(x)\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\ndiscriminator = Discriminator().to(device)\ncriterion = nn.BCELoss()\noptimizer = optim.Adam(discriminator.parameters(), lr=0.0002, betas=(0.5, 0.999))\nnum_epochs = 5\n\nfor epoch in range(num_epochs):\n    total_loss = 0\n\n    for images, labels in dataloader:\n        images = images[:, 0, :, :, :].to(device)  # Chỉ lấy frame đầu tiên\n        labels = labels.float().to(device)\n\n        optimizer.zero_grad()\n        outputs = discriminator(images).squeeze()\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n\n        total_loss += loss.item()\n\n    print(f\"Epoch [{epoch+1}/{num_epochs}], Loss: {total_loss/len(dataloader):.4f}\") ","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T14:03:55.374887Z","iopub.execute_input":"2025-03-01T14:03:55.375219Z","iopub.status.idle":"2025-03-01T15:30:39.507861Z","shell.execute_reply.started":"2025-03-01T14:03:55.375170Z","shell.execute_reply":"2025-03-01T15:30:39.506589Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import matplotlib.pyplot as plt\n\ndef predict(image):\n    image = transform(image).unsqueeze(0).to(device)\n    output = discriminator(image).item()\n    return \"FAKE\" if output > 0.5 else \"REAL\"\n\n# Lấy video test\ntest_video = os.path.join(data_path, df.iloc[5][\"filename\"])\ntest_frames = extract_frames(test_video, num_frames=1)\n\n# Kiểm tra nếu có frame thì dự đoán và hiển thị ảnh\nif len(test_frames) > 0:\n    prediction = predict(test_frames[0])\n    print(\"Kết quả dự đoán:\", prediction)\n\n    # Hiển thị ảnh\n    plt.imshow(test_frames[0])\n    plt.axis(\"off\")  # Ẩn trục\n    plt.title(f\"Dự đoán: {prediction}\")  # Hiển thị nhãn dự đoán trên ảnh\n    plt.show()\nelse:\n    print(\"Lỗi: Không lấy được frame từ video.\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T15:30:39.509924Z","iopub.execute_input":"2025-03-01T15:30:39.510304Z","iopub.status.idle":"2025-03-01T15:30:39.923066Z","shell.execute_reply.started":"2025-03-01T15:30:39.510240Z","shell.execute_reply":"2025-03-01T15:30:39.921933Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"#Lấy nhãn thực tế của video test\nactual_label = df[df[\"filename\"] == os.path.basename(test_video)][\"label\"].values[0]\n\n# So sánh với kết quả dự đoán\nprint(f\"Kết quả dự đoán: {prediction}\")\nprint(f\"Nhãn thực tế: {actual_label}\")\n\n# Hiển thị ảnh kèm theo nhãn thực tế\nplt.imshow(test_frames[0])\nplt.axis(\"off\")  \nplt.title(f\"Dự đoán: {prediction} | Thực tế: {actual_label}\")\nplt.show()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T15:30:39.924483Z","iopub.execute_input":"2025-03-01T15:30:39.924876Z","iopub.status.idle":"2025-03-01T15:30:40.197406Z","shell.execute_reply.started":"2025-03-01T15:30:39.924810Z","shell.execute_reply":"2025-03-01T15:30:40.196551Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"correct = 0\ntotal = 0\n\nwith torch.no_grad():  # Không tính gradient khi kiểm tra\n    for images, labels in dataloader:\n        images = images[:, 0, :, :, :].to(device)  # Chỉ lấy frame đầu tiên\n        labels = labels.to(device)\n\n        outputs = discriminator(images).squeeze()\n        predictions = (outputs > 0.5).long()\n\n        correct += (predictions == labels).sum().item()\n        total += labels.size(0)\n\naccuracy = correct / total * 100\nprint(f\"Độ chính xác trên tập validation: {accuracy:.2f}%\")\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-03-01T15:31:35.508031Z","iopub.execute_input":"2025-03-01T15:31:35.508473Z","iopub.status.idle":"2025-03-01T15:48:59.727986Z","shell.execute_reply.started":"2025-03-01T15:31:35.508405Z","shell.execute_reply":"2025-03-01T15:48:59.726890Z"}},"outputs":[],"execution_count":null}]}