{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":104308,"databundleVersionId":12660285,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":12239128,"sourceType":"datasetVersion","datasetId":7711609},{"sourceId":12239252,"sourceType":"datasetVersion","datasetId":7711701},{"sourceId":12239752,"sourceType":"datasetVersion","datasetId":7712072},{"sourceId":12240307,"sourceType":"datasetVersion","datasetId":7712449}],"dockerImageVersionId":31040,"isInternetEnabled":false,"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\n# import os\n# for 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-06-23T11:01:52.038557Z","iopub.execute_input":"2025-06-23T11:01:52.039054Z","iopub.status.idle":"2025-06-23T11:01:52.654434Z","shell.execute_reply.started":"2025-06-23T11:01:52.039014Z","shell.execute_reply":"2025-06-23T11:01:52.653320Z"}},"outputs":[],"execution_count":null},{"cell_type":"markdown","source":"마지막 cell\nif __name__ == \"__main__\":\n    main()\n\n주석 해제 후 실행해주시면 됩니다.\n\n\n\n\n\nTEST_DIR   = \"/kaggle/input/Deepfake_Detection_and_Generation_Challenge_Blue_Team/test_sample_videos\"\n테스트 비디오 해당 부분 수정 후 실행해주시면 됩니다","metadata":{}},{"cell_type":"code","source":"#!/usr/bin/env python\n# -*- coding: utf-8 -*-\nimport os, json, subprocess\nfrom pathlib import Path\nfrom collections import Counter\n\nimport cv2, dlib, torch\nimport numpy as np\nfrom PIL import Image\nfrom skimage import transform as trans\nfrom torchvision import transforms\nfrom tqdm.auto import tqdm\nimport timm\nimport torch.nn as nn\n\n# ───────────────────────────── parameters ─────────────────────────────\nMODEL_PATH = \"/kaggle/input/pth-inception/model_epoch08.pt\"\nTEST_DIR   = \"/kaggle/input/Deepfake_Detection_and_Generation_Challenge_Blue_Team/test_sample_videos\"\nOUT_CSV    = \"/kaggle/working/submission.csv\"\nIMG_SIZE   = 128\nMAX_FRAMES = 32\nDEVICE     = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n\n\ntransform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor()\n])\nmajority = lambda xs: Counter(xs).most_common(1)[0][0] if xs else 0\n\n\nIDX5 = [37, 44, 30, 49, 55]\nREF5 = np.array([\n    [30.2946, 51.6963], [65.5318, 51.5014],\n    [48.0252, 71.7366], [33.5493, 92.3655], [62.7299, 92.2041]\n], np.float32)\nREF5[:,0] += 8.0\nREF5 *= IMG_SIZE / 112.0\n\ndetector = dlib.get_frontal_face_detector()\npredictor = dlib.shape_predictor(\n    \"/kaggle/input/face-landmarks-81/shape_predictor_81_face_landmarks.dat\"\n)\n\ndef extract_aligned(img):\n    rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)\n    mean_b = np.mean(rgb)\n    if mean_b < 50:\n        yuv = cv2.cvtColor(rgb, cv2.COLOR_RGB2YUV)\n        yuv[:, :, 0] = cv2.equalizeHist(yuv[:, :, 0])\n        rgb = cv2.cvtColor(yuv, cv2.COLOR_YUV2RGB)\n        inv_gamma = 1.0 / 1.1\n        table = np.array([(i/255.0)**inv_gamma * 255 for i in range(256)], dtype='uint8')\n        rgb = cv2.LUT(rgb, table)\n    faces = detector(rgb, 1)\n    if not faces:\n        return None\n    rect = max(faces, key=lambda r: r.width()*r.height())\n    shp  = predictor(rgb, rect)\n    kp = np.float32([[shp.part(i).x, shp.part(i).y] for i in IDX5])\n    scale = 1.3\n    dst = REF5.copy()\n    m = IMG_SIZE * (scale - 1) / 2\n    dst[:,0] += m\n    dst[:,1] += m\n    tform = trans.SimilarityTransform()\n    tform.estimate(kp, dst)\n    warped = cv2.warpAffine(\n        rgb,\n        tform.params[:2],\n        (int(IMG_SIZE*scale), int(IMG_SIZE*scale))\n    )\n    return cv2.resize(warped, (IMG_SIZE, IMG_SIZE))\n\ndef get_frames(vp: Path, max_frames=MAX_FRAMES):\n    cap = cv2.VideoCapture(str(vp))\n    if not cap.isOpened():\n        return []\n    total = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))\n    idxs = np.linspace(0, total-1, max_frames, dtype=int)\n    aligned, raw = [], []\n    for fid in idxs:\n        cap.set(cv2.CAP_PROP_POS_FRAMES, int(fid))\n        ret, frame = cap.read()\n        if not ret: continue\n        raw.append(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))\n        a = extract_aligned(frame)\n        if a is not None:\n            aligned.append(a)\n    cap.release()\n    return aligned if aligned else raw\n\n\n\nclass GradReverse(torch.autograd.Function):\n    @staticmethod\n    def forward(ctx, x, lmbda):\n        ctx.lmbda = lmbda\n        return x.view_as(x)\n    @staticmethod\n    def backward(ctx, grad):\n        return -ctx.lmbda * grad, None\n\nclass DANN(nn.Module):\n    def __init__(self, num_domains, num_comp):\n        super().__init__()\n        self.backbone = timm.create_model(\n            \"inception_resnet_v2\", pretrained=False, features_only=True\n        )\n        self.pool = nn.AdaptiveAvgPool2d(1)\n        dim = self.backbone.feature_info[-1][\"num_chs\"]\n        self.cls_head  = nn.Linear(dim, 2)\n        self.dom_head  = nn.Linear(dim, num_domains)\n        self.comp_head = nn.Linear(dim, num_comp)\n    def forward(self, x, lmbda=1.0):\n        f = self.backbone(x)[-1]\n        f = self.pool(f).view(f.size(0), -1)\n        y_cls = self.cls_head(f)\n        f_rev = GradReverse.apply(f, lmbda)\n        y_dom = self.dom_head(f_rev)\n        y_comp = self.comp_head(f_rev)\n        return y_cls, y_dom, y_comp\n\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-23T11:02:53.373729Z","iopub.execute_input":"2025-06-23T11:02:53.374103Z","iopub.status.idle":"2025-06-23T11:02:54.114825Z","shell.execute_reply.started":"2025-06-23T11:02:53.374077Z","shell.execute_reply":"2025-06-23T11:02:54.113065Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"\ndef main():\n    from pathlib import Path\n    # Ensure TEST_DIR is Path\n    test_dir = Path(TEST_DIR)\n\n    NUM_DOMAINS = 7  # 학습 시 동일 설정\n    NUM_COMP    = 2\n    device = DEVICE\n\n    model = DANN(NUM_DOMAINS, NUM_COMP).to(device)\n    state = torch.load(MODEL_PATH, map_location=device)\n    model.load_state_dict(state)\n    model.eval()\n    print(\"모델 가중치 로드 완료\")\n\n    results = []\n    for vp in tqdm(sorted(test_dir.glob(\"*.mp4\")), desc=\"Inference\"):\n        frames = get_frames(vp)\n        if not frames:\n            results.append({\"ID\": f\"{vp.stem}.mp4\", \"label\": 1})\n            continue\n        batch = torch.stack([transform(Image.fromarray(f)) for f in frames]).to(device)\n        with torch.no_grad():\n            logits, _, _ = model(batch, lmbda=0.0)\n            preds = logits.argmax(1).cpu().tolist()\n        results.append({\"ID\": f\"{vp.stem}.mp4\", \"label\": majority(preds)})\n\n    import pandas as pd\n    pd.DataFrame(results).to_csv(OUT_CSV, index=False)\n    print(f\"제출 파일 저장 → {OUT_CSV}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-06-23T11:02:56.278811Z","iopub.execute_input":"2025-06-23T11:02:56.279157Z","iopub.status.idle":"2025-06-23T11:02:56.288011Z","shell.execute_reply.started":"2025-06-23T11:02:56.279133Z","shell.execute_reply":"2025-06-23T11:02:56.286637Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"if __name__ == \"__main__\":\n    main()","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}