--- license: apache-2.0 base_model: OpenMOSS-Team/MOSS-Image-SFT base_model_relation: adapter library_name: diffusion-single-file pipeline_tag: text-to-image tags: - comfyui - lora - moss-image - text-to-image --- # MOSS-Image SFT DeBand The MOSS-Image **SFT** model often draws faint, evenly spaced **vertical color stripes** across smooth areas like skies, fog, backdrops and walls. This repo has two **banding-fix LoRAs** that remove them while keeping the image close to what SFT would have made, plus **preset workflows** that pair the fix with community speed LoRAs for 10–14 step (or 4–8 step) generation. ## TL;DR **Just want one file that works?** [MOSS-Image-SFT-DeBand-int8](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand-int8) has the fix (and the Fast preset) merged into ready-to-run 5.4 GB int8 models. No LoRAs or custom nodes. 1. Download the main fix, [`moss_image_sft_banding_fix_L37-41_bf16.safetensors`](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/moss_image_sft_banding_fix_L37-41_bf16.safetensors), into `ComfyUI/models/loras/`. 2. In your MOSS-Image workflow, add **LoraLoaderModelOnly** after the SFT model (`moss_image_sft_bf16.safetensors` from [Comfy-Org/MOSS-Image](https://huggingface.co/Comfy-Org/MOSS-Image)) and set it to **1.0**. No custom nodes needed. 3. Still seeing stripes? That happens most on smooth skies and gradients, and on wide images (1536 px and up). Add a second LoraLoaderModelOnly with the extra fix, [`moss_image_sft_banding_fix_L32-36_extra_bf16.safetensors`](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/moss_image_sft_banding_fix_L32-36_extra_bf16.safetensors), also at **1.0**. That's the **Quality+** preset. 4. **Or** drag [`workflows/moss_banding_fix_presets.json`](workflows/moss_banding_fix_presets.json) into ComfyUI and pick a preset: **Quality** (25 steps), **Quality+** (both fixes), **Balanced** (14 steps), **Fast** / **Fast alt** (10 steps). The files each preset needs are listed [below](#preset-workflows-in-detail). 5. Want 4–8 steps? [`workflows/moss_banding_fix_presets_rapid_moss.json`](workflows/moss_banding_fix_presets_rapid_moss.json) adds the **Turbo** presets. It needs two custom nodes; see the setup below. Keep Turbo near 1 MP (e.g. 1024×1024); bigger sizes tile. How it works: each LoRA is an exact weight difference that turns some of SFT's transformer layers back into the Base model's weights. The main fix covers the **last five layers (37–41)**, the extra fix covers **32–36**, and everything else is untouched. How those layers were found is [further down](#how-the-layers-were-found), with the full write-up in [ANALYSIS.md](ANALYSIS.md). ## Examples **Before / after:** same prompt and seed, 768×1024. The bottom row removes brightness and boosts color 5×, which makes the stripes easy to see. ![Fog forest before and after](images/before_after_fog.jpg)
More before/after: anime pier and goose ![Anime pier before and after](images/before_after_anime.jpg) ![Goose before and after](images/before_after_goose.jpg)
**Every preset on the five test prompts:** the exact output of the preset workflow at 768×1024, seed 11. Each label gives the banding score (about 1.0 = clean) and how close the image stays to plain SFT. The color view shows the stripes. ![All presets, fog forest](images/presets_fog_forest_photo.jpg) ![All presets, fog forest, color view](images/presets_fog_forest_color.jpg)
Fjord sky: the hardest one; only Quality+ fully cleans the sky ![All presets, fjord sky](images/presets_fjord_sky_photo.jpg) ![All presets, fjord sky, color view](images/presets_fjord_sky_color.jpg)
Goose at the checkout ![All presets, goose](images/presets_goose_photo.jpg) ![All presets, goose, color view](images/presets_goose_color.jpg)
Oil still life ![All presets, oil still life](images/presets_oil_still_life_photo.jpg) ![All presets, oil still life, color view](images/presets_oil_still_life_color.jpg)
Perfume bottle ![All presets, perfume bottle](images/presets_product_glass_photo.jpg) ![All presets, perfume bottle, color view](images/presets_product_glass_color.jpg)
**The workflow's default prompt:** a cozy anime illustration of a woman in a penguin sweater with a penguin mug, on a window seat over an icy bay. This is what the preset workflows produce out of the box (1024×1024, every preset). This scene doesn't band much even on plain SFT, so it shows the look and speed of each preset. ![All presets on the default prompt](images/presets_default_prompt.jpg) **A busy cinematic scene, 1280×720:** text, crowds, reflections, steam and neon hold up with the fix and with the speed LoRAs. ![Cinematic neon street across setups](images/cinematic_neon_presets.jpg)
More scenes: ballroom, viking ship, anime pier, and a layout check These were made while tuning the presets, so some speed-LoRA strengths and step counts differ from the final presets. Every label names the exact setup. ![Cinematic ballroom across setups](images/cinematic_ballroom_setups.jpg) ![Cinematic viking ship across setups](images/cinematic_viking_setups.jpg) ![Anime pier across setups](images/anime_pier_setups.jpg) **Layout check:** the prompt places four objects in four boxes, plus a card reading "LAYOUT OK". Every setup put all four objects in their boxes and got the text right, so the fix and speed LoRAs don't hurt prompt following. ![Layout check across setups](images/layout_check_setups.jpg)
## Results Same prompt, seed (11) and settings in every column, 768×1024. Each cell is **banding · SFT similarity**. - **Banding** measures the stripe at the exact width SFT draws it, relative to nearby patterns. About **1.0 means no stripe**; plain SFT scores about 2. Fine grain and real vertical patterns (pleats, tree trunks) also raise it, so compare within a column. - **SFT similarity** is SSIM against the plain SFT image. Higher keeps more of the SFT look. | Setup | Fog forest | Fjord sky | Goose | Oil still life | Perfume bottle | **Mean** | |---|---|---|---|---|---|---| | Off (plain SFT) | 2.33 | 2.21 | 2.16 | 1.96 | 1.53 | **2.04** | | Quality | 1.28 · 86% | 1.74 · 90% | 1.21 · 69% | 1.43 · 89% | 1.29 · 93% | **1.39 · 86%** | | Quality+ | 1.10 · 74% | 0.93 · 84% | 1.28 · 54% | 1.17 · 80% | 1.00 · 88% | **1.09 · 76%** | | Balanced | 1.22 · 62% | 1.42 · 82% | 1.00 · 45% | 1.09 · 64% | 1.53 · 80% | **1.25 · 66%** | | Fast | 1.26 · 58% | 1.29 · 77% | 1.05 · 38% | 0.91 · 58% | 1.18 · 81% | **1.14 · 62%** | | Fast alt | 1.22 · 57% | 1.49 · 78% | 1.00 · 39% | 0.95 · 57% | 1.21 · 81% | **1.17 · 62%** | | Turbo | 1.04 · 42% | 1.30 · 44% | 1.59 · 32% | 1.15 · 31% | 1.29 · 73% | **1.27 · 45%** | | Turbo max | 1.17 · 32% | 2.41 · 65% | 2.15 · 30% | 1.27 · 23% | 0.99 · 71% | **1.60 · 44%** | | Kijai 21–49 @ −0.5 | 1.70 · 81% | 1.74 · 88% | 1.24 · 51% | 1.46 · 85% | 1.32 · 91% | **1.49 · 79%** | | Base model | 1.13 · 59% | 1.19 · 78% | 1.17 · 45% | 0.92 · 61% | 1.20 · 82% | **1.12 · 65%** | How to read it: - **Quality** keeps the most of SFT (86%) and removes most of the banding. **Quality+** is the cleanest (about as clean as Base) but changes the image more. - **Balanced / Fast / Fast alt** are clean too, but at 10–14 steps they change more of the image. - **Turbo / Turbo max** redraw the scene (30–70% similarity). Turbo max's high scores on the fjord and goose come mostly from fine grain the 4-step adapter adds, not SFT's stripes; check its color views above. Settings: ER-SDE, CFG 3, Temporal Score Rescaling and skip-layer guidance (layers 22, 24) on, int8 Qwen3.5-9B text encoder. These are the preset workflow's own settings; the Turbo presets use the rapid-moss sampler. ### Image size: when does banding go away? It doesn't, really. SFT draws fine stripes at 768 and 1024 px wide. At **1536 and 2048 px wide it draws wider, wavy stripes instead**. These are center crops of the color view at 1:1 pixels, height 1024, seed 11: ![Fjord sky across widths](images/widthsweep_fjord_sky.jpg)
Fog forest across widths ![Fog forest across widths](images/widthsweep_fog_forest.jpg)
| Width | Plain SFT | Quality | Quality+ | |---|---|---|---| | 768 | strong stripes | fainter; still visible on the fjord sky | clean | | 1024 | strong stripes | faint | clean | | 1280 | clean on both prompts | clean | clean | | 1536 | wide wavy stripes | fog clean; fjord sky still striped | fog clean; fjord sky very faint | | 2048 | wide wavy stripes | fog clean; faint waves on the fjord sky | clean | So: **use Quality+ for wide images or big smooth skies.** 1280 wide was clean for every setup here, but that's two prompts and one seed. The wavy stripes at 1536+ are wider than the ones the banding score looks for, so this table is by eye. ## Preset workflows in detail Two ready-made ComfyUI workflows are in [`workflows/`](workflows). Pick a **Preset** from the dropdown at the top; it sets every LoRA strength and the step count for you. | Preset | What it does | Steps | |---|---|---| | **Quality** | SFT + main banding fix (layers 37–41) | 25 | | **Quality+** | SFT + main fix + extra fix (layers 32–36). Cleanest, slightly different look | 25 | | **Balanced** | main fix + lodestones 8-step DMD LoRA at 0.28 | 14 | | **Fast** | main fix + lodestones 8-step DMD LoRA at 0.35 | 10 | | **Fast alt** | main fix + darask0 4-step LoRA at 0.35 | 10 | | **Off** | plain SFT, to compare | 25 | | **Turbo** *(rapid-moss workflow only)* | lodestones 8-step adapter + main fix, its own sampler | 8 | | **Turbo max** *(rapid-moss workflow only)* | darask0 4-step adapter + main fix, its own sampler (about 3 s per image on an RTX 5090) | 4 | | **Turbo hi-res (experimental)** *(rapid-moss workflow only)* | Turbo max at ~1 MP, latent upscale to your size, then 3 Fast steps at 0.5 denoise | 4 + 3 | The speed and Turbo presets use only the main fix. For wide images with smooth skies, Quality+ is the safe choice. **Turbo presets need a size near 1 MP** (1024×1024, 1216×832, 832×1216, 1344×768, 768×1344): the rapid-moss adapters were trained there and step through fixed timesteps. At bigger sizes the image breaks into a grid of repeated tiny subjects, and short prompts make it worse, so write detailed prompts. For bigger images use **Fast** or **Balanced**: at 1664×1136 they take about 11 s and 16 s on an RTX 5090 and hold up fine. **Turbo hi-res is experimental.** It is about twice as fast as Fast at big sizes (about 6 s at 1664×1136), but these settings don't hold up every time: detailed photo areas such as foliage get a canvas-like texture, and Turbo's odd choices (extra props, sloppy distant figures, misspelled text) carry over into the final image. It's usually not worth it, but it isn't fully tuned either; the stage-2 steps, denoise and upscale method are a starting point if you want to experiment. ### `moss_banding_fix_presets.json`: stock ComfyUI, no custom nodes Put these files in your ComfyUI `models` folder (each link downloads the file directly): | Save as | Into folder | Download | |---|---|---| | `moss_image_sft_bf16.safetensors` | `diffusion_models` | [Comfy-Org](https://huggingface.co/Comfy-Org/MOSS-Image/resolve/main/diffusion_models/moss_image_sft_bf16.safetensors) | | `qwen3.5_9b_int8_convrot.safetensors` | `text_encoders` | [Comfy-Org](https://huggingface.co/Comfy-Org/MOSS-Image/resolve/main/text_encoders/qwen3.5_9b_int8_convrot.safetensors) | | `flux2-vae.safetensors` | `vae` | [Comfy-Org](https://huggingface.co/Comfy-Org/MOSS-Image/resolve/main/vae/flux2-vae.safetensors) | | `moss_image_sft_banding_fix_L37-41_bf16.safetensors` | `loras` | [this repo](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/moss_image_sft_banding_fix_L37-41_bf16.safetensors) | | `moss_image_sft_banding_fix_L32-36_extra_bf16.safetensors` | `loras` | [this repo](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/moss_image_sft_banding_fix_L32-36_extra_bf16.safetensors) | | `lodestones_moss_sft_8step_dmd_lora_latest.safetensors` | `loras` | [`lora_latest.safetensors` from lodestones](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd/resolve/main/lora_latest.safetensors), **renamed** | | `darask0_moss_sft_4step_dmad_lora.safetensors` | `loras` | [`lora.safetensors` from darask0](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/lora.safetensors), **renamed** | The two speed LoRAs are both called `lora.safetensors` upstream, so rename them as shown. A LoRA at strength 0 is skipped, but ComfyUI still checks that every file exists. If you don't want a speed LoRA, delete its node and don't pick its preset. ### `moss_banding_fix_presets_rapid_moss.json`: adds the Turbo presets Everything above, plus: - **Custom nodes**, each folder copied into `ComfyUI/custom_nodes/`: - OpenMOSS's [`moss-image`](https://github.com/OpenMOSS/MOSS-Image/tree/main/comfyui/moss-image) (the `comfyui/moss-image` folder of their GitHub repo); - darask0's [`rapid-moss`](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/tree/main/comfyui/rapid-moss) (the `comfyui/rapid-moss` folder of their Hugging Face repo). - **[`moss_image_sft_bf16_split_qkv.safetensors`](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/split_qkv/moss_image_sft_bf16_split_qkv.safetensors)** (10.2 GB, this repo) → `models/diffusion_models`. The rapid-moss adapters patch q, k and v separately, so they need the SFT model with q/k/v stored apart. This file is the official [OpenMOSS-Team/MOSS-Image-SFT](https://huggingface.co/OpenMOSS-Team/MOSS-Image-SFT) transformer as a single file, with the same 463 tensors. The Comfy-Org file fuses q/k/v; with it, the rapid-moss adapters produce noise or a black image without raising an error. - **[`moss_image_sft_banding_fix_L37-41_bf16_splitqkv.safetensors`](https://huggingface.co/MATLOWAI/MOSS-Image-SFT-DeBand/resolve/main/moss_image_sft_banding_fix_L37-41_bf16_splitqkv.safetensors)** (this repo) → `models/loras`. The same main fix, laid out for the split model. - **Adapter folders**, each holding three files with exactly these names: | Folder | `lora.safetensors` | `time_embedding.safetensors` | `dataspace.safetensors` | |---|---|---|---| | `models/rapid_moss/lodestones-8step-latest/` | [lodestones' `lora_latest.safetensors`](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd/resolve/main/lora_latest.safetensors), **renamed** to `lora.safetensors` | [download](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd/resolve/main/time_embedding.safetensors) | [download](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd/resolve/main/dataspace.safetensors) | | `models/rapid_moss/rapid-moss-4step/` | [darask0's `lora.safetensors`](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/lora.safetensors) | [download](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/time_embedding.safetensors) | [download](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora/resolve/main/dataspace.safetensors) | Only the branch for the chosen preset runs, so the normal presets don't load the split model. ## Compared with Kijai's LoRA and the Base model [Kijai/MOSS-image_experimental](https://huggingface.co/Kijai/MOSS-image_experimental) has the SFT-difference LoRAs this work builds on, and its README has the original −0.5 banding recipe: - [`moss_image_sft_lora_blocks_21_to_49_rank_512_bf16`](https://huggingface.co/Kijai/MOSS-image_experimental/blob/main/loras/moss_image_sft_lora_blocks_21_to_49_rank_512_bf16.safetensors): Kijai's banding fix, applied to SFT at −0.5. It's the "Kijai 21–49 @ −0.5" row in the [results table](#results) and the bottom-right image in the grids below. - [`moss_image_sft_lora_rank_256_bf16`](https://huggingface.co/Kijai/MOSS-image_experimental/blob/main/loras/moss_image_sft_lora_rank_256_bf16.safetensors) and [`moss_image_sft_lora_rank_512_bf16`](https://huggingface.co/Kijai/MOSS-image_experimental/blob/main/loras/moss_image_sft_lora_rank_512_bf16.safetensors): the full SFT difference as a LoRA, for applying the SFT look to the Base model at whatever strength you want. At +1 the rank-512 version reproduces SFT's banding as well. The two fixes take different routes. Kijai's subtracts half of the SFT change across layers 3, 4 and 21–41; the main fix here fully reverts only layers 37–41. On these images the main fix bands less or the same and keeps more of the SFT image every time. Pick by eye: each grid shows Full SFT (top left), Base (top right), the main fix (bottom left) and Kijai's LoRA (bottom right).
Perfume bottle: fix 1.29 vs Kijai 1.32 ![Perfume bottle](images/product_glass_768x1024_photo.png)
Fjord sky: tie, 1.74 each. Neither cleans this sky; Base and Quality+ do. ![Fjord sky](images/fjord_sky_768x1024_photo.png)
Goose, 768×1024: fix 1.21 vs Kijai 1.24 ![Goose at 768x1024](images/goose_768x1024_photo.png)
Fog forest: fix 1.28 vs Kijai 1.70 ![Fog forest](images/fog_forest_768x1024_photo.png)
Oil still life: fix 1.43 vs Kijai 1.46 ![Oil still life](images/oil_still_life_768x1024_photo.png)
Goose, 1024×1024: fix 1.07 vs Kijai 1.24 ![Goose at 1024x1024](images/goose_1024_photo.png)
Color views: brightness removed and color boosted 5×, where the stripes are easy to see ![Perfume bottle, color view](images/product_glass_768x1024_color.png) ![Fjord sky, color view](images/fjord_sky_768x1024_color.png) ![Goose 768x1024, color view](images/goose_768x1024_color.png) ![Fog forest, color view](images/fog_forest_768x1024_color.png) ![Oil still life, color view](images/oil_still_life_768x1024_color.png) ![Goose 1024x1024, color view](images/goose_1024_color.png)
## How the layers were found 1. **Block swaps with exact weights.** Copying the Base model's weights into SFT for one block range at a time showed that removing SFT's changes in layers 21–41 fixes the banding, while reverting layers 0–20 alone does not. Within that range, attention (qkv, o) and MLP (ffn_up_gate, ffn_down) weights all contribute; the norms don't. 2. **An activation probe.** Running the residual stream at every layer and step through the model's own output head showed the stripe frequency. In SFT it starts in the top layers (37–41) and then builds up across sampling steps, because each step's striped output feeds the next. 3. **Bakeoff.** Reverting layers 37–41 for every step was the best trade-off across five prompts. It removed more banding than a late-step-only revert and changed the image less than Kijai's LoRA. Adding 32–36 cleans the stubborn cases (the fjord sky, wide images) at the cost of more change, so it ships as the separate extra fix. ![Stripe energy by layer and sampling step](analysis/probe_2_heatmaps.png) *The stripe frequency inside the model, by layer (vertical) and sampling step (horizontal). In Full SFT (left) it builds up from about step 7 and spreads through every layer; it never starts with the fix or in Base.* The full write-up, with the ablation charts, probe figures, step-window tests, open questions and the tools to reproduce it all, is in **[ANALYSIS.md](ANALYSIS.md)**. It uses an earlier banding score with a different scale (plain SFT about 20–120, lower is better); the ordering of setups is the same. ## Limitations - **Image size matters.** At 768 px wide the main fix still leaves faint stripes on smooth skies, and at 1536 px and up SFT switches to wider stripes the main fix doesn't always catch. Quality+ handled every size tested. See [Image size](#image-size-when-does-banding-go-away). - **Small test set.** Five prompts at one seed for the presets, two prompts for the size sweep. Seeds swing the banding score a lot, so treat small differences in the table as noise. - **The banding score is a guide, not ground truth.** Fine grain and real vertical patterns raise it. When in doubt, check the color views. - **Not pixel-identical to an exact layer swap.** ComfyUI's LoRA loader rounds the merged weights slightly differently, which changes fine details the way a nearby seed would. On average it scores the same. - **ComfyUI format.** The files use ComfyUI's full-difference (`.diff`) LoRA keys and have only been tested in ComfyUI. ## Files | File | Size | Contents | |---|---|---| | `moss_image_sft_banding_fix_L37-41_bf16.safetensors` | 1.13 GB | Main fix: Base minus SFT weights for layers 37–41 (40 tensors, bf16, full rank) | | `moss_image_sft_banding_fix_L32-36_extra_bf16.safetensors` | 1.13 GB | Extra fix for layers 32–36; stack it with the main fix for Quality+ | | `moss_image_sft_banding_fix_L37-41_bf16_splitqkv.safetensors` | 1.13 GB | The main fix with q/k/v split, for the split model (rapid-moss workflow) | | `split_qkv/moss_image_sft_bf16_split_qkv.safetensors` | 10.2 GB | The official MOSS-Image-SFT transformer as one file with q/k/v separate (rapid-moss workflow only) | | `workflows/*.json` | | The two preset workflows; `*_api.json` are API-format copies for scripting | SHA-256: - main fix `01329abd340dd9cf55677381a11558fe5307c7fd648f1988b441172fbbd86fd5` - extra 32–36 `7f6e43c7566b0c04ad9772cf3efdf9da973b65e242d1a384b17e8db91a6337cd` - main fix, split q/k/v `34b29f56c168f33a50624a5b9728cae4026db43b88b46b381a739926921bc882` - split SFT model `0e5803a087c07cb4c7d8010a2d44153494a053706337edc7f76b455e9900b3a6` ## Credits - [OpenMOSS](https://huggingface.co/OpenMOSS-Team) for MOSS-Image Base and SFT (Apache-2.0), and [Comfy-Org](https://huggingface.co/Comfy-Org/MOSS-Image) for the ComfyUI repack. - [lodestones](https://huggingface.co/lodestones/MOSS-Image-SFT-8-steps-dmd) and [darask0](https://huggingface.co/darask0/MOSS-Image_4-step_adapter_lora) for the 8-step DMD and 4-step adapters used in the speed and Turbo presets. - [Kijai](https://huggingface.co/Kijai/MOSS-image_experimental) for the SFT-difference LoRAs, and a big thanks for pointing me in the right direction: Kijai's note that the SFT causes the banding in the later blocks, fixable with negative strength, is where this investigation started.