dinov3-deepfake-detection / scripts /make_report_figures.py
ManhQuangAI's picture
Upload folder using huggingface_hub
e23cf4c verified
Raw History Blame Contribute Delete
7.72 kB
"""Sinh các figure cho coursework report (PDF LaTeX) từ các file JSON kết quả.
Không load model / không cần GPU — chỉ đọc JSON và vẽ matplotlib (nhẹ, không lo tràn RAM).
Output: report/figures/*.png
"""
import json
import os
import matplotlib
matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
REPORT_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "report")
FIG_DIR = os.path.join(REPORT_DIR, "figures")
os.makedirs(FIG_DIR, exist_ok=True)
plt.rcParams.update({
"font.size": 10,
"axes.labelsize": 10,
"axes.titlesize": 11,
"legend.fontsize": 9,
"xtick.labelsize": 9,
"ytick.labelsize": 9,
"figure.dpi": 200,
"savefig.dpi": 200,
"savefig.bbox": "tight",
})
VIT_COLOR = "#1f77b4" # blue
CNN_COLOR = "#d62728" # red
GRAY = "#7f7f7f"
def load(path):
with open(path) as f:
return json.load(f)
# ---------------------------------------------------------------------------
# Figure 1: Fine-tune loss + val accuracy (ViT) — từ finetune_insight_report.json
# ---------------------------------------------------------------------------
def fig_finetune_loss():
d = load(os.path.join(REPORT_DIR, "..", "outputs", "results", "finetune_insight_report.json"))
hist = d["history"]
epochs = [h["epoch"] for h in hist]
train_loss = [h["train_loss"] for h in hist]
val_acc = [h["accuracy"] * 100 for h in hist]
val_f1 = [h["f1"] * 100 for h in hist]
fig, ax1 = plt.subplots(figsize=(6.2, 3.8))
ax1.plot(epochs, train_loss, "o-", color=VIT_COLOR, label="Train loss")
ax1.set_xlabel("Epoch")
ax1.set_ylabel("Train loss", color=VIT_COLOR)
ax1.tick_params(axis="y", labelcolor=VIT_COLOR)
ax1.set_xticks(epochs)
ax2 = ax1.twinx()
ax2.plot(epochs, val_acc, "s--", color=CNN_COLOR, label="Val accuracy")
ax2.plot(epochs, val_f1, "^--", color=GRAY, label="Val F1")
ax2.set_ylabel("Validation (%)", color=CNN_COLOR)
ax2.tick_params(axis="y", labelcolor=CNN_COLOR)
ax2.set_ylim(85, 100)
lines = ax1.get_lines() + ax2.get_lines()
ax1.legend(lines, [l.get_label() for l in lines], loc="center right", frameon=False)
ax1.set_title("Fine-tuning DINOv3 ViT-S/16 (5 epochs)")
fig.tight_layout()
out = os.path.join(FIG_DIR, "finetune_loss.png")
fig.savefig(out)
plt.close(fig)
print("Wrote", out)
# ---------------------------------------------------------------------------
# Figure 2: Linear-probe ViT vs CNN (DeepFakeFace) — comparison_report_v2.json
# ---------------------------------------------------------------------------
def fig_linprobe():
d = load(os.path.join(REPORT_DIR, "..", "outputs", "results", "comparison_report_v2.json"))
vit = d["models"]["vit"]["metrics"]
cnn = d["models"]["cnn"]["metrics"]
metrics = ["accuracy", "precision", "recall", "f1", "roc_auc"]
labels = ["Accuracy", "Precision", "Recall", "F1", "ROC-AUC"]
vit_vals = [vit[m] * 100 for m in metrics]
cnn_vals = [cnn[m] * 100 for m in metrics]
x = np.arange(len(metrics))
w = 0.36
fig, ax = plt.subplots(figsize=(6.2, 3.6))
b1 = ax.bar(x - w / 2, vit_vals, w, label="ViT-S/16 (Plus)", color=VIT_COLOR)
b2 = ax.bar(x + w / 2, cnn_vals, w, label="ConvNeXt-Tiny", color=CNN_COLOR)
ax.set_xticks(x)
ax.set_xticklabels(labels)
ax.set_ylabel("Score (%)")
ax.set_ylim(0, 100)
ax.legend(frameon=False, loc="lower right")
for bars in (b1, b2):
for b in bars:
ax.annotate(f"{b.get_height():.1f}", (b.get_x() + b.get_width() / 2, b.get_height()),
ha="center", va="bottom", fontsize=7.5)
ax.set_title("Linear probe on DeepFakeFace (identity-disjoint test)")
fig.tight_layout()
out = os.path.join(FIG_DIR, "linprobe_comparison.png")
fig.savefig(out)
plt.close(fig)
print("Wrote", out)
# ---------------------------------------------------------------------------
# Figure 3: DeepfakeTIMIT detection rate — deepfaketimit_report.json
# ---------------------------------------------------------------------------
def fig_timit():
d = load(os.path.join(REPORT_DIR, "..", "outputs", "benchmark", "deepfaketimit_report.json"))
vit = d["vit"]
cnn = d["cnn"]
groups = ["Overall", "HQ (128px)", "LQ (64px)"]
vit_vals = [vit["detection_rate"] * 100, vit["hq_detection_rate"] * 100, vit["lq_detection_rate"] * 100]
cnn_vals = [cnn["detection_rate"] * 100, cnn["hq_detection_rate"] * 100, cnn["lq_detection_rate"] * 100]
x = np.arange(len(groups))
w = 0.36
fig, ax = plt.subplots(figsize=(5.6, 3.4))
b1 = ax.bar(x - w / 2, vit_vals, w, label="ViT-S/16 (Plus)", color=VIT_COLOR)
b2 = ax.bar(x + w / 2, cnn_vals, w, label="ConvNeXt-Tiny", color=CNN_COLOR)
ax.set_xticks(x)
ax.set_xticklabels(groups)
ax.set_ylabel("Detection rate (%)")
ax.set_ylim(0, 105)
ax.legend(frameon=False, loc="lower left")
for bars in (b1, b2):
for b in bars:
ax.annotate(f"{b.get_height():.1f}", (b.get_x() + b.get_width() / 2, b.get_height()),
ha="center", va="bottom", fontsize=8)
ax.set_title("DeepfakeTIMIT (all frames fake)")
fig.tight_layout()
out = os.path.join(FIG_DIR, "timit_detection.png")
fig.savefig(out)
plt.close(fig)
print("Wrote", out)
# ---------------------------------------------------------------------------
# Figure 4: Confidence histogram p(fake) — DeepfakeTIMIT
# ---------------------------------------------------------------------------
def fig_timit_hist():
d = load(os.path.join(REPORT_DIR, "..", "outputs", "benchmark", "deepfaketimit_report.json"))
vit = np.array(d["vit"]["prob_fake"])
cnn = np.array(d["cnn"]["prob_fake"])
bins = np.linspace(0, 1, 21)
fig, axes = plt.subplots(1, 2, figsize=(6.4, 2.9), sharey=True)
axes[0].hist(vit, bins=bins, color=VIT_COLOR, alpha=0.85)
axes[0].set_title("ViT-S/16 (Plus)")
axes[0].set_xlabel("Predicted p(fake)")
axes[1].hist(cnn, bins=bins, color=CNN_COLOR, alpha=0.85)
axes[1].set_title("ConvNeXt-Tiny")
axes[1].set_xlabel("Predicted p(fake)")
axes[0].set_ylabel("Number of frames")
for ax in axes:
ax.axvline(0.5, color="k", ls="--", lw=0.8)
fig.suptitle("Confidence distribution on DeepfakeTIMIT (640 fake frames)", fontsize=10)
fig.tight_layout()
out = os.path.join(FIG_DIR, "timit_prob_hist.png")
fig.savefig(out)
plt.close(fig)
print("Wrote", out)
# ---------------------------------------------------------------------------
# Figure 5: Confusion matrix — fine-tune test result
# ---------------------------------------------------------------------------
def fig_finetune_cm():
d = load(os.path.join(REPORT_DIR, "..", "outputs", "results", "finetune_insight_report.json"))
cm = np.array(d["test"]["confusion_matrix"]) # [[tn, fp], [fn, tp]]
fig, ax = plt.subplots(figsize=(3.4, 3.0))
im = ax.imshow(cm, cmap="Blues")
ax.set_xticks([0, 1]); ax.set_xticklabels(["Pred Real", "Pred Fake"])
ax.set_yticks([0, 1]); ax.set_yticklabels(["Real", "Fake"])
for i in range(2):
for j in range(2):
ax.text(j, i, f"{cm[i, j]}", ha="center", va="center",
color="white" if cm[i, j] > cm.max() / 2 else "black", fontsize=12)
ax.set_title("Fine-tuned ViT test set (n=11920)")
fig.tight_layout()
out = os.path.join(FIG_DIR, "finetune_cm.png")
fig.savefig(out)
plt.close(fig)
print("Wrote", out)
if __name__ == "__main__":
fig_finetune_loss()
fig_linprobe()
fig_timit()
fig_timit_hist()
fig_finetune_cm()
print("Done.")