|
|
| Each core returns the probability that the input is fake. The unified script combines |
| them as a weighted sum: |
|
|
| ``` |
| final_fakeness = 0.5Β·lipsync + 0.4Β·audio + 0.1Β·video |
| ``` |
|
|
| (weights are renormalised over whichever cores actually produced a score). |
|
|
| --- |
|
|
| ## How it routes input |
|
|
| ``` |
| βββββββββββββ audio file ββββββββββββΊ audio core βββΊ final = audio score |
| INPUT βββ€ |
| βββββββββββββ video file βββ¬β extract wav ββΊ audio core β |
| ββββββββββββββββΊ video core βββΊ weighted final |
| ββββββββββββββββΊ lipsync core β |
| ``` |
|
|
| Audio-only input only the audio core runs; the final score *is* the audio score. |
| Video input audio is extracted with `ffmpeg` and sent to the audio core; the video |
| file goes to the video and lipsync cores. |
|
|
|
|
|
|
|
|
| ## Requirements |
|
|
| Linux `ffmpeg` / `ffprobe`** on `PATH` |
| (the scripts default to `/usr/bin/ffmpeg`, `/usr/bin/ffprobe`). |
| Three isolated Python environments, since the cores have mutually incompatible |
| dependencies, so they cannot share one environment: |
|
|
| | core | interpreter (default) | key pins | |
| |------|-----------------------|----------| |
| | audio | `/opt/dfdetect-envs/audio/bin/python` | torch 2.6.0, transformers 4.44.0, **scikit-learn 1.3.2**, scipy 1.13.1, joblib 1.4.2, librosa, soundfile | |
| | video | `/opt/dfdetect-envs/video/bin/python` | torch 2.2.2, torchvision 0.17.2, transformers 4.51.2, numpy 1.26.4, opencv-python 4.11.0.86 | |
| | lipsync | `/opt/conda/envs/avh/bin/python` | local fairseq + avhubert, dlib, skvideo, python_speech_features, numpy 1.25 | |
|
|
| Put the environments on LOCAL disk (e.g. `/opt`) |
|
|
|
|
| ### Recreating the environments |
|
|
| ```bash |
| # audio |
| python -m venv /opt/dfdetect-envs/audio |
| /opt/dfdetect-envs/audio/bin/python -m pip install -U pip wheel |
| /opt/dfdetect-envs/audio/bin/python -m pip install \ |
| torch==2.6.0 torchvision==0.21.0 transformers==4.44.0 \ |
| scikit-learn==1.3.2 scipy==1.13.1 joblib==1.4.2 \ |
| librosa soundfile accelerate "huggingface_hub<0.26" pandas numpy |
| |
| # video |
| python -m venv /opt/dfdetect-envs/video |
| /opt/dfdetect-envs/video/bin/python -m pip install -U pip wheel |
| /opt/dfdetect-envs/video/bin/python -m pip install \ |
| torch==2.2.2 torchvision==0.17.2 transformers==4.51.2 numpy==1.26.4 \ |
| opencv-python==4.11.0.86 huggingface-hub safetensors accelerate pillow scipy pandas |
| |
| # lipsync β a conda env (Python 3.10) named `avh` |
| conda create -n avh python=3.10 -y |
| /opt/conda/envs/avh/bin/python -m pip install -U pip wheel |
| /opt/conda/envs/avh/bin/python -m pip install -r avh-align_core/requirements.txt |
| |
| ``` |
|
|
| > The vendored `avh-align_core/fairseq/` is the *importable package only* (no `setup.py`), |
| > so it works via `sys.path` at runtime but is **not pip-installable** β that is why the |
| > recipe above installs fairseq from source. |
| |
| |
| |
| ## Inference β `detect.py` |
| |
| ```bash |
| python detect.py INPUT_FILE # text report |
| python detect.py INPUT_FILE --json # machine-readable JSON |
| |
| ``` |
| |
| |
| |
| --- |
| |
| ## Retraining |
| |
| Each script reuses the matching core's frozen feature extractor (so the feature space |
| stays identical to inference) and retrains only the lightweight head. They auto-relaunch |
| into the correct environment, so just run them with any Python. |
| |
| ### Label conventions (important β audio is inverted!) |
| |
| | script | metadata columns | label meaning | |
| |--------|------------------|---------------| |
| | `retrain_audio.py` | `file_path,label` | **`1` = real, `0` = fake** | |
| | `retrain_video.py` | `file_path,label` | **`1` = fake, `0` = real** | |
| | `retrain_lipsync.py` | `file_path` (or `path`) | **real videos only** (no label β unsupervised alingment network) | |
| |
| |
| |
| python retrain_audio.py --metadata audio_meta.csv |
| |
| |
| python retrain_video.py --metadata video_meta.csv --epochs 40 |
| |
| |
| python retrain_lipsync.py --metadata real_videos.csv --epochs 10 --skip-existing |
| |
| |
| Each script has `--help` for all options (epochs, lr, batch size, `--out`, etc.). |
| |
| ### Using a retrained model |
| |
| Point `detect.py` at it β the weights are swapped in after the core loads: |
| |
| ```bash |
| python detect.py clip.mp4 \ |
| --audio-model retrained_models/audio/logreg_retrained.joblib \ |
| --video-model retrained_models/video/cnn_retrained.pt \ |
| --lipsync-model retrained_models/lipsync/fusion_retrained.pt |
| ``` |
| |
| --- |
| |
| ## Troubleshooting |
| |
| A core reports `FAILED β its score is dropped and the remaining cores are |
| reweighted; rerun with `--verbose` to see that core's traceback (e.g. lipsync needs a |
| detectable face; very short clips may yield no segments). |
| No GPU / busy GPU β cores fall back to CPU (much slower). The box is shared, so |
| throughput depends on how many of the GPUs are free. |
| |