Skip to content

딥페이크 탐지 어플리케이션 (Deepfake Detection Service)

공식 구현체가 없는 최신 논문 아키텍처를 직접 분석 및 구현하고, 고부하 AI 모델의 병목을 해결하기 위해 FastAPI와 TaskIQ 기반의 비동기 추론 파이프라인을 구축한 프로젝트입니다.


1. Project Overview (프로젝트 개요)

  • 기간: 2026.01.28 ~ 2026.02.27 (부트캠프 최종 프로젝트 | 5명)
  • 역할: AI 모델 구현, 백엔드 비동기 태스크 큐 설계 및 구현, 개발 환경(uv 워크스페이스) 구축 및 최적화
  • 핵심 기술 스택:
    • AI & Model: PyTorch, PyTorch Lightning, Transformers (SigLIP), ONNX Runtime GPU, WandB
    • Backend: FastAPI, TaskIQ, Redis, SQLModel (ORM), PostgreSQL, Boto3 (S3)
    • DevOps & Tooling: uv (Workspace), Git, Docker
  • Github: https://github.com/AICV-Deepfaker/deepfaker_detection

🌐 비동기 추론 아키텍처 파이프라인 (Architecture Pipeline)

고부하 AI 모델 추론 시 서버 병목을 방지하고 사용자 경험을 극대화하기 위해 설계한 비동기 추론 아키텍처입니다.

sequenceDiagram
    autonumber
    actor User as 사용자 (App)
    participant API as FastAPI 백엔드
    participant DB as PostgreSQL (SQLModel)
    participant Broker as TaskIQ Broker (Redis)
    participant Worker as TaskIQ Worker
    participant S3 as AWS S3 Storage
    participant ORT as ONNX Runtime (GPU)

    User->>API: 비디오 업로드 요청
    API->>S3: 비디오 파일 업로드
    S3-->>API: S3 파일 경로 반환
    API->>DB: 비디오 메타데이터 저장 (상태: PENDING)
    API->>Broker: 비동기 추론 태스크 요청 (video_id)
    API-->>User: 202 ACCEPTED 반환 (즉시 응답)

    Note over Worker, ORT: 백그라운드 비동기 추론 시작
    Broker->>Worker: 태스크 할당 (predict_deepfake_fast)
    Worker->>DB: 비디오 상태 업데이트 (PROCESSING)
    Worker->>S3: S3에서 비디오 다운로드 (임시 디렉토리)
    Worker->>ORT: 비디오 프레임 추출 및 ONNX 추론 실행
    ORT-->>Worker: 탐지 확률 반환 (REAL/FAKE)
    Worker->>DB: 추론 결과 및 리포트 저장 (상태: COMPLETED)
    Worker->>Broker: Redis Pub/Sub 채널로 완료 알림 발행
    Broker-->>User: 실시간 푸시 알림 (추론 완료 및 결과 조회 가능)

2. Repository Structure (레포지토리 구조)

직접 설계하고 구축한 모노레포 워크스페이스 구조와 핵심 기여 모듈(★)입니다.

deepfaker_detection/ (★ uv 워크스페이스 모노레포)
├── pyproject.toml          # ★ uv 워크스페이스 및 공통 의존성 설정
├── uv.lock                 # ★ 전체 워크스페이스 통합 락 파일
├── ddp_backend/            # ★ FastAPI 백엔드 서비스
│   ├── core/
│   │   ├── database.py     # SQLModel DB 세션 및 커넥션 풀 설정
│   │   ├── tk_broker.py    # TaskIQ Redis 브로커 설정
│   │   └── s3.py           # Boto3 기반 S3 업로드/다운로드 유틸리티
│   ├── detectors/          # ★ AI 추론 엔진 래퍼
│   │   └── visual/
│   │       ├── base.py     # ★ BaseVideoDetector 추상 클래스
│   │       └── unite.py    # ★ UNITE ONNX 추론 및 CUDA VRAM 최적화 구현
│   ├── models/             # ★ SQLModel 기반 DB 테이블 정의
│   │   ├── models.py       # Result, FastReport, DeepReport 테이블
│   │   └── user.py         # User 테이블 및 OAuth2 스키마
│   ├── routers/            # ★ FastAPI API 엔드포인트
│   │   └── detection.py    # ★ 비동기 태스크 트리거 및 다형성 리포트 응답 라우터
│   └── task/               # ★ TaskIQ 비동기 작업 정의
│       └── detection.py    # ★ 비동기 추론 태스크 (S3 다운로드 -> 추론 -> DB 저장)
└── unite_detection/        # ★ [Submodule] UNITE 모델 학습 및 ONNX 내보내기 엔진
    ├── pyproject.toml      # ★ CPU/GPU/Flash-Attn 환경 분기 및 의존성 설정
    └── src/unite_detection/
        ├── dataset/        # ★ Celeb-DF, SAIL-VOS 등 커스텀 데이터셋 로더
        ├── lit_modules/    # ★ PyTorch Lightning 모듈 및 콜백
        │   ├── datamodule.py
        │   ├── unite_classifier.py  # ★ LightningModule (체크포인트 경량화 포함)
        │   └── visualization_callback.py # ★ W&B 연동 자동 시각화 콜백
        ├── losses/         # ★ 커스텀 손실 함수
        │   └── ad_loss.py  # ★ 논문 구현체 보완 (Differentiable AD Loss)
        ├── models/         # ★ 신경망 아키텍처 구현
        │   ├── unite_model.py # ★ UNITE 메인 모델 (SigLIP + Temporal ViT)
        │   └── vit_encoder.py # ★ Temporal ViT Encoder
        └── train.py        # 학습 엔트리포인트

3. Key Contributions & Code Highlights (핵심 기여 및 코드 하이라이트)

① Modern Python Tooling: uv 워크스페이스 환경 구축

  • 도전 과제: 로컬 개발 환경(Mac/Windows)과 학습 서버(Linux GPU) 간의 PyTorch CUDA 버전 및 flash-attn 빌드 의존성 충돌로 인해 환경 구축 시 잦은 오류 발생.
  • 해결 방안: 현대적인 Python 패키지 매니저인 uv 워크스페이스를 도입하여 모노레포 내의 여러 패키지를 통합 관리하고, 환경별 의존성을 명확히 분리.
  • 코드 하이라이트 (pyproject.toml - 루트):
    [tool.uv]
    # flash-attn 빌드 시 PyTorch가 격리되지 않고 먼저 참조되도록 설정 (빌드 실패 방지)
    build-constraint-dependencies = ["setuptools<82.0.0"]
    no-build-isolation-package = ["flash-attn"]
    override-dependencies = [
      "torch>=2.10.0",
      "torchvision>=0.25.0",
      "torchcodec==0.10.0",
    ]
    
    [tool.uv.workspace]
    members = ["Wavelet-CLIP", "ddp_backend", "unite_detection", "STT"]
    
    [tool.uv.sources]
    # Linux 환경에서만 PyTorch CUDA 12.8 인덱스를 타겟팅하도록 설정
    torch = [
      { index = "pytorch-cu128", marker = "sys_platform == 'linux'" },
    ]
    torchvision = [
      { index = "pytorch-cu128", marker = "sys_platform == 'linux'" },
    ]
    unite-detection = { workspace = true, editable = true }
    

② Paper-to-Code: UNITE 모델 직접 구현 및 수식 보완

  • 도전 과제: 공식 코드가 없는 최신 논문(UNITE)을 분석하여 모델을 직접 구현해야 했음. 특히 논문의 핵심인 Attention-based Anomaly Detection Loss (ADLoss) 수식 중 클래스 센터 $C$가 연산 그래프에서 분리(detached)되어 있어 PyTorch에서 역전파(Backpropagation)가 불가능한 수학적 한계 발견.
  • 해결 방안:
    • SigLIP 이미지 인코더를 Frozen 백본으로 두고, 프레임 간 관계를 학습하는 Temporal Positional EncodingTemporal ViT Encoder를 직접 설계.
    • ad_loss.py에서 역전파가 불가능한 센터 $C$ 대신, 미분 가능한 배치 클래스 평균 $P$를 사용하여 클래스 간 손실(Between-class loss)을 계산하도록 수식을 보완하여 학습이 정상적으로 진행되도록 개선.
  • 코드 하이라이트 (unite_detection/src/unite_detection/losses/ad_loss.py):
    # 1. 센터 업데이트 (현재 배치 정보를 활용해 이동 평균 업데이트 - Gradient 분리)
    if self.training:
        for c in range(self.config.arch.num_cls):
            mask: Bool[Tensor, "batch"] = labels == c
            if mask.any():
                valid_cls += 1
                batch_class_mean: Float[Tensor, "head frame"] = P_norm[mask].mean(dim=0)
                with torch.no_grad():
                    # C[c]는 역전파가 되지 않는 버퍼로 업데이트
                    self.C[c] = (1 - self.config.eta) * self.C[c] + self.config.eta * batch_class_mean.detach()
    
                # [수식 보완] 논문에서는 C와 C 사이의 거리를 계산하라고 되어 있으나,
                # C는 gradient가 흐르지 않으므로 미분 가능한 batch_class_mean(P)을 사용하여 Loss 계산!
                dist_matrix: Float[Tensor, "head head"] = torch.cdist(batch_class_mean, batch_class_mean, p=2)
                # ... 이후 loss_between 계산 진행
    

③ PyTorch Lightning 기반 학습 파이프라인 최적화

  • 도전 과제: 대용량 Frozen 백본(SigLIP)이 체크포인트마다 중복 저장되어 디스크 공간을 기가바이트 단위로 낭비하고, 체크포인트 저장 속도가 매우 느려짐.
  • 해결 방안: on_save_checkpoint를 오버라이드하여 학습 대상이 아닌 Frozen 파라미터(vis_encoder)를 체크포인트 저장 대상에서 제외하는 최적화 적용.
  • 코드 하이라이트 (unite_detection/src/unite_detection/lit_modules/unite_classifier.py):
    @override
    def on_save_checkpoint(self, checkpoint):
        """체크포인트 저장 시 Frozen 파라미터(Backbone)를 제외하여 용량을 획기적으로 줄입니다."""
        state_dict = checkpoint["state_dict"]
    
        # 저장하지 않을 키 필터링 (vis_encoder 관련 키들 제거)
        keys_to_remove = [k for k in state_dict if "model.vis_encoder" in k]
        for k in keys_to_remove:
            del state_dict[k]
    
        print(f"[Optimizer] Removed {len(keys_to_remove)} frozen backbone keys from checkpoint.")
    

④ ONNX Runtime & CUDA VRAM 최적화

  • 도전 과제: GPU 서버에서 다중 비동기 추론 세션 실행 시 CUDA 메모리 단편화(Fragmentation)로 인해 VRAM 여유가 있음에도 cublasCreate 실패 및 서버 크래시 발생.
  • 해결 방안: ONNX Runtime의 세션 옵션 및 CUDA Execution Provider 설정을 정밀하게 튜닝하고, 추론 직전 PyTorch 캐시를 강제로 비우는 방어적 코드 작성.
  • 코드 하이라이트 (ddp_backend/detectors/visual/unite.py):
    @override
    def load_model(self):
        import torch
        sess_options = ort.SessionOptions()
        sess_options.enable_mem_pattern = False
        sess_options.enable_cpu_mem_arena = False
    
        if ort.get_device() == "GPU":
            cuda_provider_options = {
                "device_id": 0,
                "arena_extend_strategy": "kSameAsRequested", # 필요한 만큼만 VRAM 할당 (기본값은 큰 블록 선점)
                "initial_chunk_size_bytes": 1 * 1024 * 1024,   # 초기 아레나 크기를 1MB로 최소화해 cublasCreate 실패 방지
                "gpu_mem_limit": 14 * 1024 * 1024 * 1024,      # ORT가 사용 가능한 최대 VRAM 제한 (14 GB)
                "cudnn_conv_algo_search": "DEFAULT",
                "do_copy_in_default_stream": True,
            }
            # PyTorch 캐시 해제 후 ORT 세션 초기화 (단편화된 VRAM 확보)
            torch.cuda.empty_cache()
            providers = [("CUDAExecutionProvider", cuda_provider_options), "CPUExecutionProvider"]
        else:
            providers = ["CPUExecutionProvider"]
    
        self.session = ort.InferenceSession(
            self.config.model_path,
            sess_options=sess_options,
            providers=providers,
        )
    

4. Troubleshooting Stories (트러블슈팅 경험)

🚨 [Data Leakage] Validation 성능은 비정상적으로 높은데 Test 성능은 낮은 현상

  • 문제 현상: 모델 학습 시 Validation Accuracy가 98% 이상으로 비정상적으로 높게 나왔으나, 실제 Test 데이터셋에서는 성능이 70% 수준으로 급격히 하락하는 과적합/일반화 실패 현상 발생.
  • 원인 분석:
    • 데이터셋을 Train/Validation으로 나눌 때 무작위(Random Split)로 분할함.
    • 그러나 비디오 데이터 특성상 하나의 영상에서 여러 프레임(32프레임 단위)을 추출하여 학습 데이터로 사용하기 때문에, 영상 단위로 분할하지 않으면 동일한 비디오에서 나온 매우 유사한 프레임들이 Train과 Validation에 동시에 들어가게 되는 데이터 누수(Data Leakage)가 발생함이 원인이었음.
  • 해결 방안: 데이터셋 분할 방식을 프레임 레벨 무작위 분할에서 비디오 ID 기준 그룹 분할(Video-level Split)로 전면 수정함. 수정 후 Validation 지표가 Test 지표와 유사한 수준(약 82%)으로 조정되었으며, 데이터 누수 없는 신뢰할 수 있는 평가 파이프라인을 확보함.

🚨 [Git] Rebase 중 발생한 대형 커밋 소실 복구

  • 문제 현상: 충돌(Conflict)이 발생한 브랜치를 Rebase하는 도중, 실수로 하루 동안 작업한 대규모 커밋이 날아가 버리는 상황 발생.
  • 해결 방안: Git의 커밋 이력 추적 도구인 git reflog를 실행하여 잃어버린 커밋의 해시값을 찾아내고, git reset --hard로 헤드를 복구한 뒤, 충돌이 발생한 커밋을 체리피킹(git cherry-pick)하여 안전하게 작업을 복구함. 이 경험을 통해 Git의 내부 동작 원리와 복구 메커니즘을 깊이 이해하게 됨.