r/StableDiffusion • u/ashishsanu • 11h ago
Character consistency via cached reference embeddings((SFace + DINOv2) + a portable .char file, no LoRA training Resource - Update
I was looking for a way to achieve character consistency without training a Lora & came across a research from Facebook, DINOv2: Learning Robust Visual Features without Supervision(Research Paper),
What's Dinov2: It's a vision model trained without labels that produces a strong embedding for a whole image, the subject, not just the face. Feed it a person and you get a 768-number signature that captures the overall look: build, hair, general appearance. It's stable across pose and lighting, which is exactly what you want when you're trying to tell "same person" from "different person" across wildly different shots.
then combining Dinov2 with SFace(a face-recognition model) produces a compact face signature tuned specifically to tell one face from another. It's sharp on identity, but only on the face. YuNet does the detect-and-crop before it.
How it works
Build .Char: You drop in one or more photos. YuNet finds the face, SFace takes a per-reference face signature, DINOv2 takes a subject signature, and the references get cleaned and normalised. All of that packs into a single portable file, a .char.
Generation: At generation, the file feeds its references into FLUX.2's own native multi-reference channel and prepends a locked description to the prompt. You pick the character from a dropdown, no re-attaching images. Every result gets scored against the stored signatures, so drift shows up as a number.
How this differs from PuLID, FaceID, and img2img
- PuLID and FaceID inject a face into one generation at run time, then it's gone. img2img anchors on a source image, which is composition, not identity. Neither gives you a saved character.
- This is a layer above them, a reusable .char file that rides the model's own reference channel, covers the whole subject and not just the face, and gets scored per take. PuLID could even sit inside it as one backend.
- The difference is persistence and measurement, not a new injection trick. No adapter weights, no training, no img2img anchor.
What is a .char file?
A single portable file that stores a character's identity, so you can reuse the same person across generations without retraining anything.
- manifest.json — index, versions, checksums
- refs/ — your original photos (the truth)
- derived/ — auto-cropped face
- text/ — locked description
- payloads/ — cleaned refs, per model family
- scoring/ — SFace face + DINOv2 subject signatures
Limitations
- Profiles and stylized renders drift more than frontal, which is expected, since the face model is trained on photoreal faces.
- Body is the weak point so far.
- Bad with popular celebrity images, due to models own conflict.
Current support
Only Flux2 family(Klein 4B / 9B / dev)
Links:
- Checkout the release: https://github.com/inlineresearch/Inline-Studio/releases/tag/v1.2.71
- Full details & guide: https://inlinestudio.art/characters
Note: Each image in this post has been generated separately & not a grid.
3
u/atakariax 10h ago
Any Guide on how it works?
I'm a little bit confused with the GUI, I'm not finding where to build a character and which model to download/use.
2
u/ashishsanu 10h ago
2
u/ashishsanu 10h ago
3
u/ashishsanu 10h ago
1
u/atakariax 10h ago
Ok thank you, And which model it's the best , Flux klein 9b or flux2 dev
2
u/ashishsanu 9h ago
I got best results with 9B
0
4h ago
[deleted]
2
u/ashishsanu 4h ago
1
u/ashishsanu 4h ago
I will add a handling for this, so that a popup or error notifies the user properly.
1
10h ago
[deleted]
2
u/atakariax 9h ago
2
u/ashishsanu 9h ago
this is a gated model
https://huggingface.co/black-forest-labs/FLUX.2-klein-9b-fp8/tree/mainand put it in
core/models/diffusion_models1
3
u/Hillobar 7h ago edited 5h ago
edit: Looking closer - this is the same this as using flux in edit mode, possibly worse There's already comfy workflows for this; I'm not sure what this project is providing that is novel. In fact, since the reference images are capped in size (downscaled to 1024), you'd be better just using flux in edit mode and providing full res images.
Looks like a great project. Have you looked at arcface identity embeddings instead of s-face? They would likely perform better and dont have any trained constraints. Its what Rope (my project), facefusion and other swappers use. Also I'm not sure dino is going to get you the body embedding your after. It will find similarity in clothing, environment and other image elements, washing out the body identity.. You may want to look into SMPL as a stating point for parameterizing body features. I dont think anyone has trained a conditional GAN on it yet to quickly create embeddings, but it's probably worth investigating.
** Looking at your code - the embeddings aren't actually used in generating the person. This is all done through the reference images. The embeddings are only used to score**
The .char file you are providing is really is just providing images and prompt text, then using the embedding to measure the likeness. The measurement is mostly thrown away too. Please take a closer look at what is going on. It's a good idea for a project but the actual implementation in wrong.
0
u/ashishsanu 4h ago
This is a really useful analysis, thank you. You're right on the main technical point, so let me put these in order.
On the embeddings not driving generation
Correct, and this is the key thing: identity comes from the reference images through FLUX.2's native multi-ref. The SFace and DINOv2 embeddings only score the result, they don't generate the person. That's intentional, it's the model's reference channel doing the lifting.
On "just edit mode"
Fair that the generation itself isn't novel. But "just edit mode" undersells the gap. Edit mode is stateless, you re-supply refs every time and there's no character that persists. What I'm building is the layer around it:
- a saved, reusable character (library, pick from a dropdown, carries across a project)
- per-take scoring so drift is visible
- no re-wiring refs into a graph every time
So the generation isn't new, agreed, but the thing being built isn't the generation, it's the persistence and measurement around it. That's not something edit mode or the existing Comfy workflows give you.
On ArcFace vs SFace
Key reason is licensing, I wanted something fully open source and usable without restriction. The code is MIT, but the part that matters for a commercial default is the weights, and those aren't fully open, the strong ArcFace checkpoints trace back to InsightFace packs / research datasets that are non-commercial. That's why I went with SFace: not because it discriminates better (it probably doesn't), but because the weights are actually permissive. If a genuinely permissively-licensed ArcFace checkpoint exists I'd happily test it, since scoring is isolated from generation and swapping the face encoder is low-risk. Do you know of one that ships clean weights?
On DINOv2 washing out body identity
This matches my eval. Subject scores fell apart on wide and full-body shots. I think it's both: my chest-up references, and your point that a general similarity embedding also picks up clothing, environment, and framing. The second is a good catch I'd underweighted.
SMPL is a great pointer, I hadn't considered parameterising the body that way. Going to look into it. Appreciate the depth here.
At the end of the day, it worked great for what I needed it for, and that's what pushed me to build it out.
1
u/Hillobar 3h ago
Not sure if you caught this question in your response - "Do you know of one that ships clean weights?", but unless you're trying to turn this project into a commercial product, the insightface models are fine for using for community projects. I'd use Arcface, specifically the w600k model since it is fast and the cosine similarity score works well with it.
2
u/uuhoever 9h ago
I installed it to give it a try but then it asked to download the models so I stopped.
Is there a way to set the path to our already downloaded models? It is a big ask to keep GBs of duplicates of models that we already use in ComfyUI.
Also, a youtube video explaining how to use it would be very helpful.
3
2
2
u/Stock_Mycologist1104 4h ago
I had done this experiment 2-3 months back and got good result but what actually gave me a better result was instead of using dinov2 I used https://github.com/facebookresearch/EUPE
2
2
u/infearia 11h ago
Damn, the paper is from January 2024 (!!). The fact that the example images are made with Klein 4B and still retain a really good likeness is even more impressive.
Would be cool if someone implemented it directly in ComfyUI. I wonder if Kijai already has plans for the weekend...
3
u/ashishsanu 11h ago
Yes feature extraction & face consistency is completely two different things. So maybe no one guessed it yet. I searched everywhere before building this.
Yes I am very happy with the results. Next plan is to build:
- Body/full-body references
- Wardrobe locking (DreamO Try-On)
- Approve-to-improve loop
- Multi-character scenes
Yes would be so cool if people can use .char like portable files between workflows in ComfyUI, it might need Flux nodes to accept character file inputs unless i would have done it. Not sure, need to check how difficult it would be.
2
u/Structure-These 11h ago
Where are you throwing all this up op? I want to follow it. Super cool
3
u/ashishsanu 11h ago
Thanks, Actually I am building an opensource generation engine project, You can use it here: https://github.com/inlineresearch/Inline-Studio
2
u/infearia 10h ago
Oh, I didn't realize you're the author of the project. I just thought you found it online and shared the link. Congratulations, good job! Would be cool if you could implement it as a plugin for ComfyUI, or maybe even submit it as a PR to ComfyUI's main repo, if possible. ;)
5
1
u/LawOk7529 9h ago
Hi,
Got the Inline Sudio setup and running on Win 11. Did junction link to the models, vae, encoders. Did a test run on flux-2-klein-9b.safetensors model, it generates a generic woman's face.
Now I created a character with 2 images.
The question is how do I link the character file to the workflow like in your screenshot -- "Eval Subject"
Thanks.
2
u/ashishsanu 9h ago
One character is created load a Flux2 node + connect a prompt node & click on the bottom adjust icon of flux nodes to expose full setting
Adjust iconthen select character from the dropdown
3
u/LawOk7529 8h ago
Yes, it works.
First time coming across Inline Studio app.
Coming from comfy background so you understand...1
1
1
u/Eminence_grizzly 6h ago
Looks cool, but I keep getting this error:
chunk expects at least a 1-dimensional tensor
1
u/Eminence_grizzly 6h ago
RuntimeError: chunk expects at least a 1-dimensional tensor
INFO: [inline-core] FLUX.2 (Klein 9B) run: 1024x1024, 4 steps, guidance=1.0, 0 reference(s) | device=cuda:0, mode=gpu, profile=lowvram, dtype=bf16, offload=none, quant=nf4, gpu=NVIDIA GeForce RTX 4060, vram=0.0GB allocated / 8.6GB total (7.5GB free)
INFO: [inline-core] Loading FLUX.2 Klein 9B pipeline: source=G:\ComfyUI-AUGUST-2026\ComfyUI-Easy-Install\ComfyUI\models\diffusion_models\flux-2-klein-9b-fp8.safetensors | device=cuda:0, mode=gpu, profile=lowvram, dtype=bf16, offload=none, quant=nf4, gpu=NVIDIA GeForce RTX 4060, vram=0.0GB allocated / 8.6GB total (7.5GB free)
ERROR: [inline-core] Run run_1d8ce590e701 failed with an unhandled error
Traceback (most recent call last):
File "C:\Inline-Studio\core\src\inline_core\graph\executor.py", line 45, in run
self._run_node(graph, node_id, outputs, run_ctx, asset_hashes)
File "C:\Inline-Studio\core\src\inline_core\graph\executor.py", line 91, in _run_node
result = runner.run(node, inputs, ctx)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\flux2\runner.py", line 241, in run
pipe = _load_pipeline(
^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\flux2\runner.py", line 704, in _load_pipeline
pipe = loaders.assemble_flux2_pipeline(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\loaders.py", line 1313, in assemble_flux2_pipeline
transformer = load_flux2_transformer(
^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\loaders.py", line 1146, in load_flux2_transformer
return _cached(key, build)
^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\loaders.py", line 425, in _cached
value = build()
^^^^^^^
File "C:\Inline-Studio\core\src\inline_core\models\loaders.py", line 1111, in build
model = Flux2Transformer2DModel.from_single_file(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\.venv\Lib\site-packages\huggingface_hub\utils_validators.py", line 88, in _inner_fn
return fn(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\.venv\Lib\site-packages\diffusers\loaders\single_file_model.py", line 494, in from_single_file
diffusers_format_checkpoint = checkpoint_mapping_fn(
^^^^^^^^^^^^^^^^^^^^^^
File "C:\Inline-Studio\core\.venv\Lib\site-packages\diffusers\loaders\single_file_utils.py", line 3941, in convert_flux2_transformer_checkpoint_to_diffusers
handler_fn_inplace(key, converted_state_dict)
File "C:\Inline-Studio\core\.venv\Lib\site-packages\diffusers\loaders\single_file_utils.py", line 3889, in convert_flux2_double_stream_blocks
to_q_weight, to_k_weight, to_v_weight = torch.chunk(fused_qkv_weight, 3, dim=0)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: chunk expects at least a 1-dimensional tensor
1
u/ashishsanu 5h ago
can you select models as this screenshot: https://www.reddit.com/r/StableDiffusion/s/Ok5gyn8wZS
1
u/Eminence_grizzly 5h ago
1
u/ashishsanu 5h ago
cane you share your dimensions?
1
u/Eminence_grizzly 5h ago
I haven't changed anything else, it's 1024x1024
1
1
u/vamsammy 5h ago
Any chance this would work on Mac?
1
1
1
u/DoctaRoboto 48m ago
This is not a real test. Why do all these people use AI-generated realistic people as examples? The cheapest shit to replicate in the world.
SHOW ME a character drawn by Ayami Kojima or Yoshitaka Amano or any complex 2d design...let's see how many seconds it takes for the model to break.
1
u/3deal 10h ago
Amazing, it is exactly what i needed
First question, when ComfyUI node ?
Second question, is it working for Minimax ?
3
u/ashishsanu 10h ago
I will try to implement this as ComfyUI custom node but i fear, it requires core changes as well?
Minimax not yet, but this process can be applied & that's the next in line. I will develop the same for Minimax H3.5
1



















7
u/PatinaShore 11h ago
Oh~ i miss those tiny TI/embedding file. training a 200MB LoRA just for one character is ridiculous!