基于 CLIP 的视频 Deepfake 检测,结合 FCG(Face-Centric Guidance)与 STA(Spatio-Temporal Adapter)。
参考论文:
- FCG: arXiv:2404.05583 — Face-Centric Guidance for Video Deepfake Detection
- STA: arXiv:2408.17065 — Spatio-Temporal Adapter
当前对比了三版 STA+FCG:
v1:原始STA+FCGv2:修复 focal loss + cosine LR +ffg_weight=1.5v3:在v2基础上加入 cross-attention STA
| 模型 | FFPP AUC | CDF AUC | DFo AUC | WDF AUC | DFD(.avi) AUC | 备注 |
|---|---|---|---|---|---|---|
v1 |
98.3% | 94.6% | 98.1% | 79.8% | 93.8% | 原始 STA+FCG |
v2 |
98.0% | 94.7% | 98.3% | 80.1% | 93.5% | 当前最均衡推荐 |
v3 |
97.6% | 95.2% | 98.3% | 80.5% | 94.8% | CDF / WDF / DFD AUC 最优 |
结论:
- 如果只看
FFPP,v1最好 - 如果看外部数据集
CDF / WDF / DFD的 AUC,v3最强 - 如果看跨数据集的整体均衡性,
v2 / v3明显优于v1 - 若只保留一个默认版本,推荐
v2 - 若强调
CDF / WDF / DFD外部泛化,保留v3 official FCG weights在DFD(.avi)上为AUC=92.9%,低于当前三版 STA+FCG
当前主要 checkpoint:
v1:lightning_logs/sta_ffg_l14_10f3s/version_1/checkpoints/epoch=15-step=27264.ckptv2:lightning_logs/sta_ffg_l14_10f3s_v2/version_0/checkpoints/epoch=18-step=32376.ckptv3:lightning_logs/sta_ffg_l14_10f3s_v3/version_0/checkpoints/epoch=19-step=34080.ckptofficial:checkpoint/weights.ckpt
说明:
DFD原始.mp4推理在 2026-04-27 被机器侧 CUDA/NVML 异常阻塞;最终通过“先裁脸为.avi再单卡串行推理”完成稳定评测WDF使用本地deepfake_in_the_wild/*_test/*.tar.gz转为mp4后评测
本阶段已经完成:
FFPP / CDF / DFo / WDF / DFD(.avi) / DF40 Protocol-2六组评测official FCG weights与三版STA+FCG的对齐比较DFD从原始.mp4切换到裁脸.avi的稳定评测链路
DFD 最终不再直接使用原始 .mp4,而是先做关键点提取与人脸裁剪,再通过 datasets/dfd_avi/ wrapper 评测。
可用样本数:
REAL:360 / 363FAKE:3017 / 3068
合计评测样本:3377
| 模型 | accuracy@0.5 | ROC-AUC | best_accuracy | best_thr |
|---|---|---|---|---|
official |
81.9% | 92.9% | 91.7% | 0.312824 |
v1 |
85.3% | 93.8% | 92.3% | 0.211049 |
v2 |
83.7% | 93.5% | 92.5% | 0.213017 |
v3 |
83.6% | 94.8% | 93.1% | 0.212390 |
结论:
official在DFD(.avi)上并不占优v1在固定阈值0.5下 accuracy 最好v3在AUC和best_accuracy上最好,说明排序能力与阈值可调性更强
对应日志:
official:lightning_logs/infer_official_dfd_avi_safe.logv1:lightning_logs/infer_v1_dfd_avi_safe.logv2:lightning_logs/infer_v2_dfd_avi_safe.logv3:lightning_logs/infer_v3_dfd_avi_safe.log
同一套 DF40 Protocol-2 已全部跑完,四套模型都在同一机器、同一套流程下完成。mobileswap 过程中所有模型都遇到相同的 video_reader 解码 warning,但没有中断,结果正常落盘。
| 模型 | 平均 accuracy@0.5 | 平均 AUC | 结论 |
|---|---|---|---|
official |
93.5% | 99.2% | 跨操作泛化最强 |
v1 |
88.1% | 94.8% | 我们三版中最接近 official |
v3 |
88.6% | 93.7% | 次优,较稳 |
v2 |
86.0% | 91.8% | 最弱 |
| 操作 | v1 |
v2 |
v3 |
official |
|---|---|---|---|---|
blendface |
0.924 | 0.896 | 0.918 | 0.990 |
e4s |
0.963 | 0.939 | 0.957 | 1.000 |
facedancer |
0.974 | 0.931 | 0.958 | 0.990 |
fsgan |
0.955 | 0.925 | 0.948 | 0.995 |
inswap |
0.946 | 0.908 | 0.919 | 0.988 |
mobileswap |
0.935 | 0.922 | 0.941 | 0.990 |
simswap |
0.927 | 0.899 | 0.913 | 0.984 |
uniface |
0.962 | 0.924 | 0.939 | 0.997 |
| 操作 | v1 |
v2 |
v3 |
official |
|---|---|---|---|---|
blendface |
0.854 | 0.833 | 0.854 | 0.958 |
e4s |
0.907 | 0.837 | 0.907 | 0.953 |
facedancer |
0.938 | 0.938 | 0.938 | 0.917 |
fsgan |
0.875 | 0.875 | 0.896 | 0.938 |
inswap |
0.864 | 0.886 | 0.886 | 0.909 |
mobileswap |
0.860 | 0.847 | 0.881 | 0.932 |
simswap |
0.833 | 0.833 | 0.833 | 0.917 |
uniface |
0.917 | 0.833 | 0.896 | 0.958 |
结论:
official在DF40 Protocol-2上显著强于当前三版STA+FCG- 这不是简单的“训练坏了”,而是 跨 manipulation 泛化能力 的差距
FFPP域内时我们的 checkpoint 并不弱,但到了DF40 Protocol-2这种跨操作评测,official FCG的可迁移性明显更强- 最可能的原因依次是:模型结构差异、训练 recipe 差异、以及对
FFPP域内 cue 的过拟合
对应 report 文件:
v1:archive/reports/report_0428T160741.jsonv2:archive/reports/report_0428T161022.jsonv3:archive/reports/report_0428T153604.jsonofficial:archive/reports/report_0428T161244.json
main.py:训练入口(训练结束后自动对 test datamodule 执行 inference)inference.py:独立评测入口,输出 AUC / accuracy,结果写入archive/reports/demo.py:单视频可视化推理(输出带检测框和分数的视频)setup_dataset.py:整理 FFPP 下载目录并生成 splitfaceforensics_download_v4.py:FFPP 下载脚本
cd /home/yangboyuan/DFD-FCG-main
source /home/yangboyuan/miniconda3/etc/profile.d/conda.sh
conda env create -f environment.yml
conda activate dfd-fcg当前关键版本:
- Python 3.10
- torch 2.2.1 + cu121
- torchvision 0.17.1
- torchaudio 2.2.1
- av 16.1.0
其余依赖由 pip_requirements.txt 补全。
预处理流程依赖 face_alignment 权重下载,当前仓库约定:
export TORCH_HOME="$(pwd)/.torch_cache"这样权重会落在仓库本地,避免使用 ~/.cache/torch 导致的跨机器不一致或坏缓存问题。
main.py 的主流程:
- 构建
ODLightningCLI与ODTrainer datamodule.affine_model(model)将模型 transform 注入数据管线- 根据
ckpt_mode处理断点继续或微调加载 trainer.fit(...)- 训练结束后自动调用
inference_driver(...)对最佳 checkpoint 评测
重点:
- 默认将训练配置保存为
setting.yaml - 默认 early-stop / checkpoint 监控指标为
valid/FFPP/auc
inference.py 接收三个位置参数:
python inference.py <model_cfg_path> <data_cfg_path> <ckpt_path>评测时会:
- 通过
trainer.predict收集视频级概率 - 汇总为 Accuracy、ROC-AUC
- 额外搜索 best threshold 并输出 best_accuracy
- 在配置目录写入
report_*.json与stats_*.pickle
python -m demo "checkpoint/setting.yaml" "checkpoint/weights.ckpt" "resources/videos/000_003.mp4" --out_path="pred.avi"依赖同名路径下的预处理产物:
frame_data/*.picklecropped/videos/*.avi
输出带检测框、类别(REAL/FAKE)和分数的视频文件。
训练/评测优先读取:
datasets/ffpp/<TYPE>/c23/cropped/videos/*.avi
若 cropped/videos 不存在,则回退到:
datasets/ffpp/<TYPE>/c23/videos/*
其中 <TYPE> 典型为:real, DF, F2F, FS, NT, FSh
split 文件:
datasets/ffpp/csv_files/train.jsondatasets/ffpp/csv_files/val.jsondatasets/ffpp/csv_files/test.json
export TORCH_HOME="$(pwd)/.torch_cache"
bash preprocess_ffpp.sh该脚本对 real/DF/F2F/FS/NT 依次执行:
src.preprocess.fetch_landmark_bbox(关键点提取,~27s/视频)src.preprocess.crop_main_face(150×150 裁脸,输出 .avi)
关键输出:
datasets/ffpp/<TYPE>/c23/frame_data/*.pickle(关键点和 bbox)datasets/ffpp/<TYPE>/c23/cropped/videos/*.avi(裁脸后视频)
CDF 和 DFo 预处理步骤相同,以 CDF FAKE 为例(支持 --split-num 分片并行):
export TORCH_HOME="$(pwd)/.torch_cache"
# Step 1: 关键点提取(耗时,推荐多卡并行,part-num 从 1 开始)
CUDA_VISIBLE_DEVICES=0 python -m src.preprocess.fetch_landmark_bbox \
--root-dir="datasets/cdf/FAKE" \
--video-dir="videos" \
--fdata-dir="frame_data" \
--glob-exp="*.mp4" \
--split-num=4 --part-num=1 &
CUDA_VISIBLE_DEVICES=1 python -m src.preprocess.fetch_landmark_bbox \
--root-dir="datasets/cdf/FAKE" \
--video-dir="videos" \
--fdata-dir="frame_data" \
--glob-exp="*.mp4" \
--split-num=4 --part-num=2 &
# ... 以此类推 part-num=3,4
wait
# Step 2: 人脸裁剪(CPU 并行)
python -m src.preprocess.crop_main_face \
--root-dir="datasets/cdf/FAKE" \
--video-dir="videos" \
--fdata-dir="frame_data" \
--crop-dir="cropped" \
--glob-exp="*.mp4" \
--workers=8REAL 同理,--root-dir="datasets/cdf/REAL"。
预处理完成后,创建评测用的符号链接目录(规避路径约定差异):
mkdir -p datasets/cdf_avi/REAL datasets/cdf_avi/FAKE
ln -s "$(pwd)/datasets/cdf/REAL/cropped/videos" datasets/cdf_avi/REAL/videos
ln -s "$(pwd)/datasets/cdf/FAKE/cropped/videos" datasets/cdf_avi/FAKE/videos
cp -r datasets/cdf/csv_files datasets/cdf_avi/DFo 同理,目录为 datasets/dfo_avi/。
DFD 在当前机器上直接对原始 .mp4 做多卡推理不稳定,推荐固定流程:
fetch_landmark_bboxcrop_main_face- 建
datasets/dfd_avi/wrapper - 单卡串行推理
关键点提取与裁脸:
export TORCH_HOME="$(pwd)/.torch_cache"
# REAL
python -m src.preprocess.fetch_landmark_bbox \
--root-dir datasets/dfd_eval/real \
--video-dir videos \
--fdata-dir frame_data \
--glob-exp "*.mp4" \
--split-num 1 \
--part-num 1 \
--batch 8 \
--max-res 800
python -m src.preprocess.crop_main_face \
--root-dir datasets/dfd_eval/real \
--video-dir videos \
--fdata-dir frame_data \
--crop-dir cropped \
--glob-exp "*.mp4" \
--workers 8
# FAKE(三分片 landmark,再统一裁脸)
CUDA_VISIBLE_DEVICES=1 python -m src.preprocess.fetch_landmark_bbox \
--root-dir datasets/dfd_eval/fake \
--video-dir videos \
--fdata-dir frame_data \
--glob-exp "*.mp4" \
--split-num 3 \
--part-num 1 \
--batch 8 \
--max-res 800 &
CUDA_VISIBLE_DEVICES=3 python -m src.preprocess.fetch_landmark_bbox \
--root-dir datasets/dfd_eval/fake \
--video-dir videos \
--fdata-dir frame_data \
--glob-exp "*.mp4" \
--split-num 3 \
--part-num 2 \
--batch 8 \
--max-res 800 &
CUDA_VISIBLE_DEVICES=5 python -m src.preprocess.fetch_landmark_bbox \
--root-dir datasets/dfd_eval/fake \
--video-dir videos \
--fdata-dir frame_data \
--glob-exp "*.mp4" \
--split-num 3 \
--part-num 3 \
--batch 8 \
--max-res 800 &
wait
python -m src.preprocess.crop_main_face \
--root-dir datasets/dfd_eval/fake \
--video-dir videos \
--fdata-dir frame_data \
--crop-dir cropped \
--glob-exp "*.mp4" \
--workers 8wrapper 目录:
mkdir -p datasets/dfd_avi/real datasets/dfd_avi/fake
ln -sfn "$(pwd)/datasets/dfd_eval/real/cropped/videos" datasets/dfd_avi/real/videos
ln -sfn "$(pwd)/datasets/dfd_eval/fake/cropped/videos" datasets/dfd_avi/fake/videos下载 FFPP:
python faceforensics_download_v4.py datasets/ffpp -d original -c c23 -t videos --server EU2
python setup_dataset.py其他数据集:
bash scripts/tools/download/download_ffpp_extras.sh # FSh
python scripts/tools/download/prepare_celebdf_v2_as_cdf.py # CDF
python scripts/tools/download/prepare_deeperforensics_as_dfo.py # DFo
python scripts/tools/download/download_wdf_from_hf.py # WDF(从 HF 下载)详细说明见 scripts/tools/download/README.md。
WDF 当前支持两种入口:
- 直接从 Hugging Face 下载并转视频
- 读取本地
deepfake_in_the_wild/*_test/*.tar.gz,转为:datasets/wdf/real/videos/*.mp4datasets/wdf/fake/videos/*.mp4
本地 tar 转视频:
python scripts/tools/download/download_wdf_from_hf.py \
--source_root datasets/deepfake_in_the_wild \
--out_dir datasets/wdf \
--split testDFD 当前通过 wrapper 目录评测:
datasets/dfd_eval/real/videos -> datasets/hf_dfd_git/DFD_original sequencesdatasets/dfd_eval/fake/videos -> datasets/hf_dfd_git/DFD_manipulated_sequences/DFD_manipulated_sequences
对应 datamodule:
src.dataset.dfd_eval.DFDDataModule
configs/base.yaml:trainer 基础参数(precision、epochs、grad clip 等),early_stop / checkpoint / lr_monitor 默认设置
configs/data.yaml:主训练与验证数据拼接配置(多数据集验证入口 CDF/FSh 等)
| 配置文件 | 模型 | 说明 |
|---|---|---|
configs/clip/L14/fcg.yaml |
FFGSynoVideoLearner |
FCG 官方配置复现 |
configs/clip/L14/sta.yaml |
StAFFGVideoLearner |
STA 实验配置 |
configs/comparison/sta_ffg_l14_10f3s.yaml |
StAFFGVideoLearner |
当前最佳:STA+FCG,10帧/3s |
| 配置文件 | 说明 |
|---|---|
configs/infer/inference_ffpp_10f.yaml |
FFPP 评测(10帧) |
configs/infer/inference_cdf_avi.yaml |
CDF 评测(预处理 .avi) |
configs/infer/inference_dfo_avi.yaml |
DFo 评测(预处理 .avi) |
configs/infer/inference_cdf_avi_safe.yaml |
CDF 低内存评测 |
configs/infer/inference_dfo_avi_safe.yaml |
DFo 低内存评测 |
configs/infer/inference_wdf_safe.yaml |
WDF 评测 |
configs/infer/inference_dfd_safe.yaml |
DFD 保守评测 |
configs/infer/inference_dfd_fast.yaml |
DFD 加速评测 |
configs/infer/inference_dfd_ultrasafe.yaml |
DFD 超保守排障配置 |
configs/infer/inference_dfd_avi_safe.yaml |
DFD 裁脸 .avi 单卡稳定评测 |
configs/infer/official_ffg.yaml |
FCG 官方权重评测 |
configs/infer/ours_full.yaml |
本项目完整评测 |
scripts/tools/dataset/process_and_merge.pyscripts/tools/dataset/process_new_data.pyscripts/tools/dataset/cleanup_processed.pyscripts/tools/dataset/monitor_preprocess_progress.py:监控预处理进度
scripts/tools/splits/generate_splits_v2.py:生成数据集 split CSVscripts/tools/splits/create_dfo_csv.py:生成 DFo test split CSVscripts/tools/splits/fix_splits.py
scripts/tools/inference/run_inference.pyscripts/tools/inference/run_inference_simple.py
scripts/tools/download/download_ffpp_extras.sh:下载 FShscripts/tools/download/prepare_celebdf_v2_as_cdf.py:整理 CelebDF-v2scripts/tools/download/prepare_deeperforensics_as_dfo.py:整理 DeeperForensicsscripts/tools/download/download_wdf_from_hf.py:从 HuggingFace 下载 WDF
python main.py --config configs/comparison/sta_ffg_l14_10f3s.yaml训练日志保存至 lightning_logs/sta_ffg_l14_10f3s/version_1/,包含 setting.yaml(完整超参记录)。
python main.py --config configs/comparison/sta_ffg_l14_10f3s.yaml \
--trainer.limit_train_batches=1 \
--trainer.limit_val_batches=0 \
--trainer.max_epochs=1# FFPP
python inference.py \
"lightning_logs/sta_ffg_l14_10f3s/version_1/setting.yaml" \
"configs/infer/inference_ffpp_10f.yaml" \
"lightning_logs/sta_ffg_l14_10f3s/version_1/checkpoints/epoch=15-step=27264.ckpt"
# CDF(需先完成 4.3 节预处理 + cdf_avi 符号链接)
python inference.py \
"lightning_logs/sta_ffg_l14_10f3s/version_1/setting.yaml" \
"configs/infer/inference_cdf_avi.yaml" \
"lightning_logs/sta_ffg_l14_10f3s/version_1/checkpoints/epoch=15-step=27264.ckpt"
# DFo(同上,需 dfo_avi 符号链接)
python inference.py \
"lightning_logs/sta_ffg_l14_10f3s/version_1/setting.yaml" \
"configs/infer/inference_dfo_avi.yaml" \
"lightning_logs/sta_ffg_l14_10f3s/version_1/checkpoints/epoch=15-step=27264.ckpt"
# WDF
python inference.py \
"lightning_logs/sta_ffg_l14_10f3s_v2/version_0/setting.yaml" \
"configs/infer/inference_wdf_safe.yaml" \
"lightning_logs/sta_ffg_l14_10f3s_v2/version_0/checkpoints/epoch=18-step=32376.ckpt"
# DFD(推荐 `.avi` 版本,需先完成 4.6 节预处理)
python inference.py \
"lightning_logs/sta_ffg_l14_10f3s_v2/version_0/setting.yaml" \
"configs/infer/inference_dfd_avi_safe.yaml" \
"lightning_logs/sta_ffg_l14_10f3s_v2/version_0/checkpoints/epoch=18-step=32376.ckpt"
# DFD official FCG
python inference.py \
"configs/infer/official_ffg.yaml" \
"configs/infer/inference_dfd_avi_safe.yaml" \
"checkpoint/weights.ckpt"python -m demo "checkpoint/setting.yaml" "checkpoint/weights.ckpt" "resources/videos/000_003.mp4" --out_path="pred.avi"现象:unexpected EOF / Read timed out
建议:
- 确保设置
export TORCH_HOME=$(pwd)/.torch_cache - 使用已下载好的
.torch_cache直接拷贝到仓库根目录
通常是 split 与本地子集不一致(quick-start 子集常见)。可使用 split 工具重新生成或过滤。
inference.py 内部使用 trainer.predict(),默认会将每个 batch 的完整输出(包含注意力张量)累积在内存中,对 CDF(5639 视频)和 DFo 等大数据集易触发 OOM。
解决方案:在 inference_driver 调用处添加 monkeypatch,推理时跳过大张量的收集(仅在不需要可视化时使用):
# 在 inference.py 调用 inference_driver 之前插入
import src.model.clip.sta_learner as _sta
_orig_predict = _sta.StAFFGVideoLearner.predict_step
def _light_predict(self, batch, batch_idx, dataloader_idx=0):
result = _orig_predict(self, batch, batch_idx, dataloader_idx)
result.pop("clips", None)
result.pop("visual_tensors", None)
return result
_sta.StAFFGVideoLearner.predict_step = _light_predictDFD 使用外部 .mp4 数据时,在当前机器上曾出现:
CUDA error: unknown errorCUDA error: unspecified launch failureCan't initialize NVMLNo supported gpu backend found!
其中 2026-04-27 的 DFD 阻塞定位为运行环境问题,不是 DFDDataModule 的标签逻辑错误。最终稳定方案不是继续硬跑原始 .mp4,而是:
- 先做 landmark
- 再裁脸为
.avi - 最后使用
configs/infer/inference_dfd_avi_safe.yaml - 固定单卡串行推理
额外说明:
- 裁脸阶段允许少量坏样本被跳过;本次最终保留
REAL=360、FAKE=3017 - 这比反复在原始
.mp4上多卡并发重试更稳,也更可复现
若再次出现,按以下顺序排查:
- 先确认
torch.cuda.is_available()是否为True - 避开异常卡(本次排查期间
GPU4曾出现Unknown Error) - 优先切回
.avi流程与configs/infer/inference_dfd_avi_safe.yaml - 若仍失败,再尝试
configs/infer/inference_dfd_ultrasafe.yaml - 若仍失败,再切回 CPU / 重启机器 / 重载驱动后复测
正确命令是:
nvidia-smi