tune(instantid): raise IP-Adapter + landmark scale + strength for stronger identity

First img2img cert sweep: scene/lighting integration was excellent on both
single (tatsunari) and group (gemini_3) photos, but the regenerated faces
were "recognizable similar people" rather than the original individuals.
The cleaned face crop (which has already drifted from original through the
main controlnet 0.20 removal pass) was competing as a structural prior;
at the previous parameter settings InstantID's ArcFace branch couldn't
dominate it.

Push the identity signal:
- `ip_adapter_scale`: 0.8 -> 1.0 at load time (full IP-Adapter strength)
- `controlnet_conditioning_scale`: 0.8 -> 1.0 default (landmark anchor)
- `img2img_strength`: 0.55 -> 0.7 default (more denoise, less cleaned
  structure survives, more room for the diffusion to render ArcFace)

The cleaned image already passed the SynthID oracle, so the absolute floor
on strength is "any positive value" -- raising it only increases the
freedom of the diffusion to inject identity (SynthID-safety isn't reduced
by higher strength, because the noise injection only destroys more of the
input pixels).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Victor Kuznetsov
2026-06-08 20:54:41 -07:00
parent 8ed2d16a23
commit 7d8af7882a
@@ -287,9 +287,12 @@ def _get_pipeline() -> Any:
pipe.to(device)
# IP-Adapter weights that wire the ArcFace embedding into cross-attention.
ip_adapter_path = hf_hub_download(repo_id=_INSTANTID_REPO, filename=_INSTANTID_IP_ADAPTER)
# IP-Adapter scale (the weight on the ArcFace cross-attention branch) is
# set at load time, not at call time. 0.8 mirrors the upstream demo.
pipe.load_ip_adapter_instantid(ip_adapter_path, scale=0.8)
# IP-Adapter scale = weight on the ArcFace cross-attention. The upstream
# demo uses 0.8 for txt2img; for img2img-on-cleaned we push to 1.0 because
# the cleaned face crop is competing as identity prior and we want ArcFace
# to dominate (otherwise the regenerated face inherits the controlnet-
# drifted cleaned face, not the original identity).
pipe.load_ip_adapter_instantid(ip_adapter_path, scale=1.0)
# Diffusers 0.38 vs InstantID upstream compat patch: InstantID's __call__
# calls ``self.check_inputs(...)`` POSITIONALLY (signature from ~v0.29),
# but diffusers 0.38 added two new params (``ip_adapter_image``,
@@ -365,8 +368,8 @@ def restore_faces_instantid(
cleaned_bgr: NDArray[Any],
num_inference_steps: int = 30,
guidance_scale: float = 5.0,
controlnet_conditioning_scale: float = 0.8,
img2img_strength: float = 0.55,
controlnet_conditioning_scale: float = 1.0,
img2img_strength: float = 0.7,
seed: int | None = None,
detect_faces_fn: Any | None = None,
) -> NDArray[Any]: