Chroma support (pruned Flux model) - #696
Conversation
stduhpf
commented
May 30, 2025
stduhpf
commented
May 30, 2025
Ok, running the Vulkan build with preview on, I can say there's something very wrong going on. Sometimes (very rarely, I got this like twice in a hundred tests) the output looks correct after the first step, then it turns to noise, then a full black image (Probably NaN/inf). About half of the time it looks like noise from the first step already and then turns black after a few steps. The rest of the time it starts off with a black image and stays like that. It's extremely inconsistent. Edit: it seems inconsistent on CPU too, but it works more often |
stduhpf
commented
May 30, 2025
Ran it on cuda. edit: worth noting is that I do have d20f77f |
stduhpf
commented
May 30, 2025
@Green-Sky Is it the same broken image everytime you run it with the same settings, or is it inconsistent too? |
rmatif
commented
May 30, 2025
@stduhpf Ran it on CUDA too and I got this, it's inconsistent too, I ran it 10 times and I got same thing each time |
Green-Sky
commented
May 30, 2025
stduhpf
commented
May 30, 2025
Yeah that's odd. Why would it vary? It's supposed to be deterministic |
I tried compiling it with ubsan and asan, but and thats the first thing that happens. looks like an upstream issue. also we should update ggml <.< Oh and using cpu backend, it crashes with Details |
Green-Sky
commented
May 30, 2025
Thank you for trying that @Green-Sky . I believe it's working now. Vulkan backend, 16 steps with cfg (cfg_scale =4), so 32 forward passes without anything breaking: |
stduhpf
commented
May 30, 2025
Ok it's very important to keep the distilled guidance scale to 0. For some reason the model still accepts it as an input, but it completely breaks apart if it's not zero (I double checked it with ComfyUI, it's not an issue with my code). Maybe I should just force it to zero for chroma to keep things simple? |
Green-Sky
commented
May 30, 2025
Go for it. Down the line we should put recommended/forced values into the gguf file. |
The q4_k is hurting it somewhat, as expected.
edit: I used v33 |
Keeping the v32:
Which begs the question: should we condsider making the convert tool "smarter", like it is in llama.cpp, with different quant types depending on the role of each tensor? |
Green-Sky
commented
May 31, 2025
We should. I find this model with current sd.cpp quantization incredibly hard to prompt too, but that is probably the token padding / masking. This is supposed to be q5_k quality, normal flux looks way better, even flux light looks better. |
kgigitdev
commented
Jun 1, 2025
Hi @stduhpf and @Green-Sky , Apologies for the question, but is this branch intended to work solely with vanilla master and master's version of ggml? I've been maintaining a little script for personal use that merges specific branches from here and there to get a more up-to-date build, and no matter what I do I can't get this branch to work, either on its own or with other branches. Here's the extract from my script that shows the current state of what I have generally been merging in (with a few of them commented out, as you can see, but I've included them anyway since they do work in some other combinations): BRANCHES="zhouwg/sync_with_latest_ggml"
BRANCHES="${BRANCHES} wbruna/fix_sdxl_lora"
BRANCHES="${BRANCHES} stduhpf/sdxl-embd"
BRANCHES="${BRANCHES} stduhpf/tiled-vae-encode"
BRANCHES="${BRANCHES} stduhpf/imatrix"
BRANCHES="${BRANCHES} stduhpf/lcppT5"
BRANCHES="${BRANCHES} stduhpf/unchained"
BRANCHES="${BRANCHES} stduhpf/dt"# BRANCHES="${BRANCHES} stduhpf/diffusers"
BRANCHES="${BRANCHES} stduhpf/override-te"
BRANCHES="${BRANCHES} stduhpf/concat-controls"# BRANCHES="${BRANCHES} stduhpf/ip2p"
BRANCHES="${BRANCHES} ImKyra/master"# BRANCHES="${BRANCHES} Green-Sky/large_file_hardening"# BRANCHES="${BRANCHES} rmatif/sigmas"Now, I already suspected that this branch would probably not work directly in my script, since you said, "I had to update GGML to get bf16 to work on vulkan", and that probably conflicts with Now, Chroma being a Flux derivative, I should also mention that for a while now I've not been able to get Flux to work either; the problems are generally of the form: A gajillion of these: [ERROR] model.cpp:1938 - tensor 'first_stage_model.decoder.conv_in.bias' not in model fileor a gajillion of these (with the [INFO ] model.cpp:1897 - unknown tensor 'model.diffusion_model.model.diffusion_model.double_blocks.0.img_attn.norm.key_norm.scale | f8_e4m3 | 1 [128, 1, 1, 1, 1]'in model file(the doubled prefix probably indicating that something has automatically prefixed followed by: [ERROR] stable-diffusion.cpp:441 - load tensors from model loader failedFrom looking at And that's the point where I give up, since I don't know enough about the expected naming of the tensors. Which also brings us to the elephant in the room that you're all too polite to talk about :-) : vis-a-vis #686 , given that I'm probably not the only one with the above problems, I'm sure that nobody would take offence if a temporary (friendly, and prominently attributed) fork were created to contain suitably-approved merged and conflict-resolved branches from all the developers who have pending PRs, as well as lots of useful work that is currently being duplicated across lots of forks. |
Green-Sky
commented
Jun 1, 2025
@kgigitdev I feel you. For my use case I depend on the webserver api.
This does not seem to be in this pr.
If we ended up doing this, I would ask @ggerganov to host that project at the ggml org. |
kgigitdev
commented
Jun 1, 2025
Hi @Green-Sky , Thanks for your swift answer.
Gosh, yes, I hadn't even thought of that option. I think I had subconsciously assumed that stable-diffusion.cpp was only ever on the periphery of the llama.cpp people, because llama == serious work whereas stable diffusion == frippery and frivolity. |
stduhpf
commented
Jun 1, 2025
That probably means the VAE is missing, or that the tensors from the VAE can't be found because their names are not the ones expected.
Yes, the doubled prefix means the tensor names are already prefixed in the model file you're using, which means you should use |
wbruna
commented
Jun 2, 2025
FWIW, I've been working on an option for sd.cpp to choose the quant by tensor pattern, a la llama.cpp's overridetensors: e128cfa . The conversion itself already works; could be useful for testing. |
wbruna
commented
Jun 18, 2025
@LostRuins , may I suggest targeting the bleedingedge release for Koboldcpp? Apart from Chroma support, it also includes many pending fixes for sd.cpp (like that VAE tile initialization bug), and both Koboldcpp and sd-server would benefit from any fixes needed for running with a persistent model in memory. |
LostRuins
commented
Jun 19, 2025
Yes I have merged the VAE tile fix, what else is there? I don't see any |
wbruna
commented
Jun 19, 2025
From the top of my head there is also #484 and #681 (apart from stuff that you probably fixed directly on Koboldcpp already, like #658).
https://github.com/stduhpf/stable-diffusion.cpp/commits/bleedingedge/ , with several tagged releases. |
LostRuins
commented
Jun 19, 2025
681 isnt needed for kobo because kobo doesn't load ckpt or diffusers models, only gguf and safetensors. I'd rather not rebase off a significantly different codebase as it'll require a bunch of testing to ensure everything works and I might have to deal with possible regressions. Instead if there are any critical or important issues I can patch those in manually. |
wbruna
commented
Jun 19, 2025
I gave an example on LostRuins/koboldcpp#1603, to avoid more unrelated discussions on this PR.
Fair enough. |
LostRuins
commented
Jun 20, 2025
Alright I added the tiling fix |
| // TODO: not hardcoded? | ||
| const int single_blocks_count = 38; | ||
| const int double_blocks_count = 19; |
There was a problem hiding this comment.
Looks like I'll have to implement this todo:
https://huggingface.co/lodestones/flux-ultra-lite
There was a problem hiding this comment.
tensor 'model.diffusion_model.distilled_guidance_layer.in_proj.weight' has wrong shape in model file: got [32, 5120, 1, 1], expected [64, 5120, 1, 1]
That's odd. Is it using a different VAE?
There was a problem hiding this comment.
Hmm looks like it's not quite the same architecture as chroma. There a similarities, but somehow the "time_in" "vector_in" and "guidance_in" are back, as well as the modulation for double blocks only. And the distilled_guidance_layer doesn't have the same input shape...
There was a problem hiding this comment.
Gotta wait for more info then.
There was a problem hiding this comment.
My current guess is that it's using the double blocks from flux lite and the single blocks from Chroma.
There was a problem hiding this comment.
Nice. Hoping your earlier commits get merged by leejet soon.
leejet
commented
Jun 29, 2025
Thank you for your contribution! |
Green-Sky
commented
Jul 17, 2025
ggml-org/llama.cpp#14735 |
LostRuins
commented
Aug 9, 2025
stduhpf
commented
Aug 9, 2025
Not really, I didn't quite understand what they meant by that. Results seem to somewhat match what we get with similar settings in comfyUI, so I think we're good. |
By the way, are any of you able to use Chroma with flash attention? Normal renders work fine, but |
Green-Sky
commented
Aug 9, 2025
Yes, it is up there in the thread somewhere. Somehow when we do flash attention with the mask (which you can turn off for worse results), something goes wrong. |
| if (mask->ne[1] < GGML_PAD(q->ne[1], GGML_KQ_MASK_PAD)) { | ||
| LOG_DEBUG("mask dims %ld, %ld, %ld, %ld\n", mask->ne[0], mask->ne[1], mask->ne[2], mask->ne[3]); | ||
| LOG_DEBUG("needs padding, padding from %ld to %ld\n", mask->ne[1], GGML_PAD(q->ne[1], GGML_KQ_MASK_PAD)); | ||
| mask = ggml_pad(ctx, mask, 0, GGML_PAD(q->ne[1], GGML_KQ_MASK_PAD) - mask->ne[1], 0, 0); |
There was a problem hiding this comment.
Actually, now that I think of it. We should not pad with zeros, but with infs (or was it -inf).
There was a problem hiding this comment.
Ah yes, -inf. (-HUGE_VALF if I remember correctly)
There was a problem hiding this comment.
Not that it matters too much, since we are not hitting this code path anyway.
Test run with v50 (final) flash-heun (recommends 10steps, cfg 1). prompt1:
The simple schedule is important. I tested this previously against flux, and it made no real difference, but not here. I think the quantization is more detrimental to this model than other flux models. You can somewhat recover the artifacts with more steps like usual. Also this is a short prompt. The quality increases with prompt length with this model. Tests done with mostly defaults otherwise, no flash attention. Simple schedule from #675 |
EDIT: Simple schedule does seem marginally better. Maybe it should be enforced? |
I think that's the point? It's a undistilled, general purpose base model that could be fine-tuned further for better results just like sd1.5. |
We don't even default to
Yep, the focus was to dedistill and learn missing stuff, mostly nsfw I guess. edit: also ran it ![]() |
FeiTianXi
commented
Nov 9, 2025
When using the Chroma model to generate images for character consistency, the custom Collector (Advanced) prompts an error! AttributeError: 'Chroma' object has no attribute 'time_in'. |






























https://huggingface.co/lodestones/Chroma
Chroma is a Flux model with modulation layers pruned off, which makes it fit in a lower memory footprint. Unlike Flux, it doesn't use Clip-L, only t5-xxl.
Usage
Advanced usage
The following environment variables can be set to change the behavior:
--guidance 0arg seems to break inference)(closes#690)