Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 23 additions & 8 deletions App/schemas/explain_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,29 @@


class ExplainImageRequest(BaseModel):
branch_level: Literal["low","high"] = Field("high", description="브랜치 레벨\nlow: 국소 위조 흔적 포착\nhigh: 전역적 위조 흔적 포착")
explainer_type: str = Field("eigengradcam", description = ("선택 가능한 XAI 기법. low: [hirescam, gradcamelementwise, layercam], ""high: [eigengradcam, gradcamplusplus, xgradcam]"))
display_type: Literal["heatmap", "bbox"] = Field("heatmap", description="시각화 형태. heatmap: 전체 분포, bbox: 위조 의심 영역 사각형")
category: Literal[0, 1] = Field(1, description="판단 클래스 인덱스 (0: Real / 1: Fake)")
overlay_ratio: float = Field(0.5, ge=0.0, le=1.0, description = "Heatmap 투명도 (0: 히트맵만 강조, 1: 원본 이미지 위주)")
threshold: float = Field(0.5, ge=0.5, le=1.0, description="contour/bbox 이진화 임계값 (0.0~1.0)")
aug_smooth: bool = Field(False, description = "TTA(Test Time Augmentation) 적용 여부. 히트맵을 더 객체 중심적으로 정렬")
eigen_smooth: bool = Field(False, description = "PCA 기반 노이즈 제거. 지배적인 패턴만 남김")
branch_level: Literal["low","high"] = Field("high",
description="브랜치 레벨\nlow: 국소 위조 흔적 포착\nhigh: 전역적 위조 흔적 포착")

explainer_type: str = Field("eigengradcam",
description = ("선택 가능한 XAI 기법. low: [hirescam, gradcamelementwise, layercam], ""high: [eigengradcam, gradcamplusplus, xgradcam]"))

display_type: Literal["heatmap", "bbox", "heatmap_bbox"] = Field("heatmap",
description="시각화 형태. heatmap: 전체 분포, bbox: 위조 의심 영역 사각형, heatmap_bbox: 위조 의심 사각형 내부에 블러 처리된 히트맵을 중첩")

category: Literal[0, 1] = Field(1,
description="판단 클래스 인덱스 (0: Real / 1: Fake)")

overlay_ratio: float = Field(0.5, ge=0.0, le=1.0,
description = "Heatmap 투명도 (0: 히트맵만 강조, 1: 원본 이미지 위주)")

threshold: float = Field(0.5, ge=0.5, le=1.0,
description="contour/bbox 이진화 임계값 (0.0~1.0)")

aug_smooth: bool = Field(False,
description = "TTA(Test Time Augmentation) 적용 여부. 히트맵을 더 객체 중심적으로 정렬")

eigen_smooth: bool = Field(False,
description = "PCA 기반 노이즈 제거. 지배적인 패턴만 남김")

@model_validator(mode="after")
def validate_explainer_for_branch(self) -> "ExplainImageRequest":
Expand Down
6 changes: 4 additions & 2 deletions App/services/explain_svc.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,12 @@ def _run_visualization(explainer: CAMExplainer, image_path: str, explain_req_dic
if explain_req_dict["display_type"] == "heatmap":
return explainer.display_heatmap_on_image(image_path, image_weight=explain_req_dict["overlay_ratio"], threshold=explain_req_dict["threshold"],
category=explain_req_dict["category"], aug_smooth=explain_req_dict["aug_smooth"], eigen_smooth=explain_req_dict["eigen_smooth"])
else:
elif explain_req_dict["display_type"] == "bbox":
return explainer.display_bbox_on_image(image_path, threshold=explain_req_dict["threshold"],
category=explain_req_dict["category"], aug_smooth=explain_req_dict["aug_smooth"], eigen_smooth=explain_req_dict["eigen_smooth"])

else: # display_type == "heatmap_bbox"
return explainer.display_heatmap_bbox_on_image(image_path, threshold=explain_req_dict["threshold"],
category=explain_req_dict["category"], aug_smooth=explain_req_dict["aug_smooth"], eigen_smooth=explain_req_dict["eigen_smooth"])
# 딥페이크 이미지 위조 흔적 시각화 처리
@celery_app.task(name="process_explain_image_task")
def process_explain_image_task(user_email: str,
Expand Down
Binary file removed Images/deepfake-xai/서양인_가짜_1.JPG
Binary file not shown.
Binary file removed Images/deepfake.JPG
Binary file not shown.
Binary file removed Images/ff_compare.png
Binary file not shown.
Binary file removed Images/model_architecture.JPG
Binary file not shown.
Binary file removed Images/ms_eff_gcvit.JPG
Binary file not shown.
Binary file removed Images/multi_scale.JPG
Binary file not shown.
149 changes: 131 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</p>

<p align="center">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/deepfake2.png" alt="DeepGuard Banner" width="800" height="400">
<img src="docs/samples/deepfake_thumbnails.png" alt="DeepGuard Banner" width="800" height="400">
</p>

<p align="center">
Expand Down Expand Up @@ -143,7 +143,7 @@ Multi Scale Efficient Global Context Vision Transformer is an optimized multi-sc


<p align="center">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/ms_eff_gcvit.JPG" width="100%" height="700">
<img src="docs/architectures/ms_eff_gcvit.JPG" width="100%" height="700">
</p>

We utilizes two distinct types of self-attention to capture both long-range and short-range information across feature maps.
Expand All @@ -154,7 +154,7 @@ We utilizes two distinct types of self-attention to capture both long-range and


<p align="center">
<img src=https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/window_attention.JPG width="100%" height="300">
<img src=docs/architectures/window_attention.JPG width="100%" height="300">
</p>

## 🧬 Model Zoo
Expand Down Expand Up @@ -310,35 +310,148 @@ print(f"Deepfake Probability: {result:.4f}")

## 🎨 DeepFake AI Explainability

Deepfake detection requires high reliability and interpretability. DeepGuard integrates a robust Explainable AI (XAI) Toolkit to visualize the decision-making process of our hybrid models
Deepfake detection is only as trustworthy as its explanations. DeepGuard integrates a production-ready XAI Toolkit that visualizes where and why the model flags a face as manipulated — turning a black-box score into actionable forensic evidence.

⭐ Validated on hybrid CNN-ViT architectures, specifically `MS-EffViT` and `MS-EffGCViT`.
⭐ Dual-Branch Analysis: `Low-Level Branch`(focus on local forgery region), `High-Level Branch`(focus on global forgery region)
⭐ Dual-Branch Analysis: Dual-branch design mirrors the model's own multi-scale reasoning

### Deepfake Detection: XAI Methods by Multi-Scale Branch
### 🧠 How Dual-Branch XAI Works

| Branch | Method | 🎯 What it does |
<p align="center">
<img src="docs/architectures/dual_branch.gif" width="70%" height="300">
</p>


| Branch | Feature Map | Focus | Best For |
| ------ | ----------- | ----- | -------- |
| ![](https://img.shields.io/badge/Low_level-blue?style=flat-square) | High Resolution | Local Forgery artifacts | Skin texture, boundary blending, compression traces |
| ![](https://img.shields.io/badge/High_level-red?style=flat-square) | Low Resolution | Global Semantic Structure | Lighting inconsistency, facial geometry, Shadow artifacts |

### 📐 XAI Methods

Each method is assigned to the branch where it performs best empirically.

| Branch | Method | 🎯 Core Idea |
| :--- | :--- | :--- |
| ![](https://img.shields.io/badge/Low_level-blue?style=flat-square) | **HiResCAM** | Like GradCAM but element-wise multiply the activations with the gradients; provably guaranteed faithfulness for certain models |
| ![](https://img.shields.io/badge/Low_level-blue?style=flat-square) | **GradCAMElementWise** | Like GradCAM but element-wise multiply the activations with the gradients then apply a ReLU operation before summing |
| ![](https://img.shields.io/badge/Low_level-blue?style=flat-square) | **LayerCAM** | Spatially weight the activations by positive gradients. Works better especially in lower layers |
| **`low level`** | **HiResCAM** | Like GradCAM but element-wise multiply the activations with the gradients; provably guaranteed faithfulness for certain models |
| **`low level`** | **GradCAMElementWise** | Like GradCAM but element-wise multiply the activations with the gradients then apply a ReLU operation before summing |
| **`low level`** | **LayerCAM** | Spatially weight the activations by positive gradients. Works better especially in lower layers |
| --- | --- | --- | --- |
| ![](https://img.shields.io/badge/High_level-red?style=flat-square) | **EigenGradCAM** | Like EigenCAM but with class discrimination: First principle component of Activations*Grad. Looks like GradCAM, but cleaner |
| ![](https://img.shields.io/badge/High_level-red?style=flat-square) | **GradCAM++** | Like GradCAM but uses second order gradients |
| ![](https://img.shields.io/badge/High_level-red?style=flat-square) | **XGradCAM** | Like GradCAM but scale the gradients by the normalized activations |
| **`high level`** | **EigenGradCAM** | Like EigenCAM but with class discrimination: First principle component of Activations*Grad. Looks like GradCAM, but cleaner |
| **`high level`** | **GradCAM++** | Like GradCAM but uses second order gradients |
| **`high level`** | **XGradCAM** | Like GradCAM but scale the gradients by the normalized activations |

- **`aug_smooth`** applies TTA (horizontal flips) before averaging CAMs → smoother, more object-aligned maps
- **`eigen_smooth`** applies PCA noise reduction → retains dominant forgery pattern only

### 💡 DeepFake XAI Usage

### Multi Scale Efficient Vision Transformer
**Low-Level Branch — Local Artifact Detection**

```python
from explainability import HiResCAMExplainer, GradCAMElementWiseExplainer, LayerCAMExplainer

explainer = HiResCAMExplainer(
model_name = "ms_eff_gcvit_b0", # or ms_eff_vit_b0, ms_eff_gcvit_b5, ms_eff_vit_b5
dataset = "celeb_df_v2", # or ff++, kodf
branch_level = "low",
)
```

**High-Level Branch — Global Semantic Detection**
```python
from explainability import EigenGradCAMExplainer, GradCAMPlusPlusExplainer, XGradCAMExplainer

explainer = EigenGradCAMExplainer(
model_name = "ms_eff_gcvit_b0",
dataset = "celeb_df_v2",
branch_level = "high",
)
```

### 🎨 Visualization Modes

<p align="center">
<img src="docs/xai-results/xai_demo.gif" width="80%" height=300>
</p>

**1. Heatmap — Continuous activation distribution**

```python
result = explainer.display_heatmap_on_image(
img_path = "path/to/image.jpg",
category = 1, # 0: Real, 1: Fake
threshold = 0.5, # binarization cutoff (0.5~1.0), or "auto" for Otsu
image_weight = 0.5, # 0.0: heatmap only ← → 1.0: original only
aug_smooth = False, # TTA smoothing (not supported on 'pro' models)
eigen_smooth = False, # PCA noise reduction
)
```

**2. Bounding Box — Discrete forgery region localization**

```python
result = explainer.display_bbox_on_image(
img_path = "path/to/image.jpg",
category = 1,
threshold = 0.5,
thickness = 1,
aug_smooth = False,
eigen_smooth = False,
)
```

**3. Heatmap + BBox — Full overlay (recommended for reporting)**
```python
result = explainer.display_heatmap_bbox_on_image(
img_path = "path/to/image.jpg",
category = 1,
threshold = 0.5,
image_weight = 0.5,
aug_smooth = False,
eigen_smooth = False,
)
```

### 📊 Visual Results

<p align="center">
<table>
<tr>
<td><img src="/docs/architectures/low_branch.gif" width="100%"></td>
<td width="20%"></td>
<td><img src="/docs/architectures/high_branch.gif" width="100%"></td>
</tr>
</table>
</p>

#### MS-EFF-VIT — Low-Level Branch

| Model | Branch-Level | Image | HiresCam | GradCamElementwise | LayerCam |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **⚡ ms-eff-vit-b0** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="Images/deepfake-xai/서양인_가짜_1.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_low_hirescam.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_low_gradcamelementwise.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_low_layercam.JPG" width="100"> |
| **⚡ ms-eff-vit-b5** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="Images/deepfake-xai/서양인_가짜_1.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_low_hirescam.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_low_gradcamelementwise.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_low_layercam.JPG" width="100"> |
| **⚡ ms-eff-vit-b0** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_low_hirescam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_low_gradcamelementwise.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_low_layercam.JPG" width="100"> |
| **🔥 ms-eff-vit-b5** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_low_hirescam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_low_gradcamelementwise.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_low_layercam.JPG" width="100"> |

#### MS-Eff-ViT — High-Level Branch

| Model | Branch-Level | Image | EigenGradCam | GradCamPlusPlus | XGradCam |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **⚡ ms-eff-vit-b0** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="Images/deepfake-xai/서양인_가짜_1.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_high_eigengradcam.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_high_gradcamplusplus.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b0_high_xgradcam.JPG" width="100"> |
| **🔥 ms-eff-vit-b5** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="Images/deepfake-xai/서양인_가짜_1.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_high_eigengradcam.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_high_gradcamplusplus.JPG" width="100"> | <img src="Images/deepfake-xai/ms_eff_vit_b5_high_xgradcam.JPG" width="100"> |
| **⚡ ms-eff-vit-b0** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_high_eigengradcam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_high_gradcamplusplus.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b0_high_xgradcam.JPG" width="100"> |
| **🔥 ms-eff-vit-b5** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_high_eigengradcam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_high_gradcamplusplus.JPG" width="100"> | <img src="docs/xai-results/ms_eff_vit_b5_high_xgradcam.JPG" width="100"> |

#### MS-EFF-GCVIT — Low-Level Branch

| Model | Branch-Level | Image | HiresCam | GradCamElementwise | LayerCam |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **⚡ ms-eff-gcvit-b0** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_low_hirescam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_low_gradcamelementwise.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_low_layercam.JPG" width="100"> |
| **🔥 ms-eff-gcvit-b5** | ![](https://img.shields.io/badge/Low_level_Branch-blue?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_low_hirescam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_low_gradcamelementwise.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_low_layercam.JPG" width="100"> |

#### MS-Eff-GCViT — High-Level Branch

| Model | Branch-Level | Image | EigenGradCam | GradCamPlusPlus | XGradCam |
| :--- | :---: | :---: | :---: | :---: | :---: |
| **⚡ ms-eff-gcvit-b0** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_high_eigengradcam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_high_gradcamplusplus.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b0_high_xgradcam.JPG" width="100"> |
| **🔥 ms-eff-gcvit-b5** | ![](https://img.shields.io/badge/High_level_Branch-red?style=flat-square) | <img src="docs/samples/images/western/western_fake_1.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_high_eigengradcam.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_high_gradcamplusplus.JPG" width="100"> | <img src="docs/xai-results/ms_eff_gcvit_b5_high_xgradcam.JPG" width="100"> |


## 📊 Metrics and Evaluation for DeepFake XAI
Expand Down
6 changes: 3 additions & 3 deletions README_KR.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Deepfakes Detection (딥페이크 탐지)

<p align="center">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/deepfake2.png" alt="DeepGuard Banner" width="800" height="400">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/docs/samples/deepfake_thumbnails.png" alt="DeepGuard Banner" width="800" height="400">
</p>

<p align="center">
Expand Down Expand Up @@ -135,7 +135,7 @@ DATA_ROOT/


<p align="center">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/ms_eff_gcvit.JPG" width="100%" height="700">
<img src="https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/docs/architectures/ms_eff_gcvit.JPG" width="100%" height="700">
</p>

특징 맵 전체에 걸쳐 장거리(Long-range) 및 단거리(Short-range) 정보를 모두 캡처하기 위해 두 가지 유형의 셀프 어텐션을 활용합니다.
Expand All @@ -144,7 +144,7 @@ DATA_ROOT/
- **Global Window Attention**: Swin Transformer와 달리, 이 모듈은 로컬 윈도우의 Key, Value와 상호작용하는 글로벌 쿼리(Global-queries)를 사용합니다. 이를 통해 각 로컬 영역이 전역 컨텍스트를 수용하게 함으로써 장거리 의존성을 효과적으로 파악하고 전체 공간 구조에 대한 포괄적인 이해를 제공합니다.

<p align="center">
<img src=https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/Images/window_attention.JPG width="100%" height="300">
<img src=https://raw.githubusercontent.com/HanMoonSub/DeepGuard/main/docs/architectures/window_attention.JPG width="100%" height="300">
</p>

## 🧬 모델 주(Model Zoo)
Expand Down
Loading
Loading