mirror of
https://github.com/wiltodelta/remove-ai-watermarks.git
synced 2026-07-18 05:37:19 +02:00
refactor(face-restore): rollback PhotoMaker, restore GFPGAN on the CLEANED image
After 7 cascading upstream-compat fixes (insightface dep, peft dep, pm_version, device, etc.), the PhotoMaker V1 cert sweep still hit a CFG batch-dim mismatch inside the denoising loop. The upstream PhotoMaker `pipeline.py` is forked from diffusers v0.29.1 and our env runs 0.38; SDXL prompt-encoder handling changed significantly between those versions, so making PhotoMaker work end-to-end needs a proper fork or a diffusers downgrade — both expensive. Not worth shipping today. Pivot: restore `face_restore.py` (GFPGAN) with a single-line fix that makes it SynthID-safe by construction. The previous design ran GFPGAN.enhance on the ORIGINAL watermarked image and was oracle-confirmed to re-add SynthID via the weight-0.5 pixel blend. The fix is to run GFPGAN on the diffusion-CLEANED image — whatever pixels GFPGAN derives from are already SynthID-free, so the partial blend cannot transport the watermark. Identity fidelity is lower than a true identity-as-embedding stack would deliver, but it ships and works. Changes: - `src/remove_ai_watermarks/face_restore.py` restored from pre-wipe state with one line changed: `restorer.enhance(cleaned_bgr, ...)` instead of `restorer.enhance(original_bgr, ...)`. `original_bgr` is kept as an unused positional argument for API stability. - `src/remove_ai_watermarks/photomaker_restore.py` and its tests REMOVED. The research note (`docs/synthid-robust-identity-research.md`) keeps a "status notice" documenting why PhotoMaker is parked for now and what the path back in would look like. - `pyproject.toml` `restore` extra restored (gfpgan/facexlib/basicsr + scipy<1.18 + numba<0.60 pins + the basicsr setuptools<69 build pin), plus `photomaker` extra (with its einops/insightface/peft pile) and the `[tool.hatch.metadata] allow-direct-references = true` block REMOVED. - `InvisibleEngine._restore_faces_photomaker` removed; `_restore_faces` restored. The `--restore-faces` CLI flag and its plumbing through cmd_* signatures are unchanged. - CLAUDE.md, README.md, docs/synthid.md, docs/controlnet-removal-pipeline- research.md updated to describe the shipped GFPGAN-on-cleaned design and to reference PhotoMaker only as the parked alternative. ruff + strict pyright(src/) clean; 578 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+24
-42
@@ -76,42 +76,22 @@ lama = [
|
||||
"onnxruntime>=1.16.0",
|
||||
"huggingface-hub>=0.20.0",
|
||||
]
|
||||
# Optional PhotoMaker-V2 face-identity restoration (commercial-safe end-to-end:
|
||||
# PhotoMaker-V2 weights Apache-2.0 + OpenCLIP-ViT-H/14 MIT, NO InsightFace). Carries
|
||||
# identity in a SEMANTIC EMBEDDING and generates fresh face pixels conditioned on it
|
||||
# -- so the pixel watermark is not transported. Empirically validated 2026-06-04: the
|
||||
# OpenCLIP embedding changes by cosine 0.002 under SynthID-magnitude pixel noise (an
|
||||
# order of magnitude less than JPEG90 drift, which SynthID survives). Replaces the
|
||||
# removed `restore` (GFPGAN) extra, which ran on the watermarked ORIGINAL and was
|
||||
# oracle-confirmed to re-introduce SynthID. See
|
||||
# docs/synthid-robust-identity-research.md and
|
||||
# src/remove_ai_watermarks/photomaker_restore.py. Weights (~3 GB SDXL + ~1 GB
|
||||
# PhotoMaker-V2 adapter) download on first use; never bundled. Kept OUT of `all`
|
||||
# (heavy + model download), same as `esrgan`.
|
||||
photomaker = [
|
||||
"photomaker @ git+https://github.com/TencentARC/PhotoMaker.git",
|
||||
"huggingface-hub>=0.20.0",
|
||||
# Upstream PhotoMaker imports `einops` but doesn't declare it in its install_requires
|
||||
# (verified 2026-06-04: cert sweep failed with "No module named 'einops'").
|
||||
"einops>=0.7.0",
|
||||
# `insightface` is the upstream PyPI package's CODE (MIT). PhotoMaker's package
|
||||
# __init__.py unconditionally `from .insightface_package import FaceAnalysis2`,
|
||||
# so just IMPORTING the V1 pipeline class requires `insightface` to be importable
|
||||
# -- we never actually call `FaceAnalysis()` (which is what would trigger the
|
||||
# non-commercial model-pack download), so the legal status of the *models* does
|
||||
# not bind us. The code itself is MIT. See `photomaker_restore.py` for the V1-only
|
||||
# call path. Without this dep the cert sweep fails with
|
||||
# "No module named 'insightface'" (caught empirically 2026-06-04).
|
||||
"insightface>=0.7.3",
|
||||
# `insightface` pulls onnxruntime as a runtime dep for the FaceAnalysis class. We
|
||||
# never instantiate that class, but the import has to resolve, so we pin it
|
||||
# explicitly (already pinned by the `lama` extra; pinned here too so this extra is
|
||||
# self-contained without depending on `lama`).
|
||||
"onnxruntime>=1.16.0",
|
||||
# `peft` is required by diffusers' `pipe.fuse_lora()` (PhotoMaker adapter ships
|
||||
# LoRA weights for the SDXL UNet). Without it the load chain raises
|
||||
# "PEFT backend is required for this method." (caught empirically 2026-06-04).
|
||||
"peft>=0.10.0",
|
||||
# Optional GFPGAN face-polish post-pass (commercial-safe: GFPGAN Apache-2.0 +
|
||||
# RetinaFace MIT). Polishes face detail in the DIFFUSION-CLEANED image (not the
|
||||
# original) using GFPGAN's StyleGAN2 prior, so SynthID is NOT re-introduced -- the
|
||||
# input pixels GFPGAN derives from are already SynthID-free. This is the shipped path
|
||||
# because the alternative we wanted (PhotoMaker-V1 identity-as-embedding) has
|
||||
# significant upstream / diffusers-version compatibility issues; see
|
||||
# `src/remove_ai_watermarks/face_restore.py` and
|
||||
# `docs/synthid-robust-identity-research.md`. gfpgan/basicsr/facexlib are an OLD
|
||||
# ecosystem and pin numpy<2: scipy<1.18 (>=1.18 uses np.long, gone in numpy 1.24-1.26)
|
||||
# and numba<0.60. Kept OUT of `all` (heavy + model download).
|
||||
restore = [
|
||||
"gfpgan>=1.3.8",
|
||||
"facexlib>=0.3.0",
|
||||
"basicsr>=1.4.2",
|
||||
"scipy<1.18",
|
||||
"numba<0.60",
|
||||
]
|
||||
# Optional pre-diffusion super-resolution for small inputs (Real-ESRGAN). Loaded via
|
||||
# spandrel (MIT) -- a pure model-loader with NO basicsr dependency (it pulls only
|
||||
@@ -141,6 +121,14 @@ all = ["remove-ai-watermarks[gpu,detect,trustmark,lama,dev]"]
|
||||
[tool.uv]
|
||||
prerelease = "allow"
|
||||
|
||||
# basicsr 1.4.2 (pulled by the `restore` GFPGAN extra) ships sdist-only and its
|
||||
# setup.py get_version() reads basicsr/version.py in a way that newer setuptools
|
||||
# (>= 69) breaks with ``KeyError: '__version__'`` under isolated PEP 517 builds.
|
||||
# Pin an old setuptools as its build dependency so the sdist builds; this is
|
||||
# scoped to basicsr and does not affect the rest of the resolution.
|
||||
[tool.uv.extra-build-dependencies]
|
||||
basicsr = ["setuptools<69"]
|
||||
|
||||
# PyTorch Intel-GPU (XPU) wheel index. ``explicit = true`` keeps it inert for
|
||||
# the default CPU/CUDA install: uv consults it only when a torch install
|
||||
# explicitly targets it (see the ``gpu`` extra comment), so it does not alter
|
||||
@@ -171,12 +159,6 @@ Repository = "https://github.com/wiltodelta/remove-ai-watermarks"
|
||||
requires = ["hatchling<1.31"]
|
||||
build-backend = "hatchling.build"
|
||||
|
||||
# Allow the `photomaker` extra to reference its upstream git URL directly (the
|
||||
# TencentARC/PhotoMaker package is not on PyPI). Apache-2.0; weights download on
|
||||
# first use, so this only adds the Python wrapper.
|
||||
[tool.hatch.metadata]
|
||||
allow-direct-references = true
|
||||
|
||||
[tool.hatch.build.targets.wheel]
|
||||
packages = ["src/remove_ai_watermarks"]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user