File size: 8,573 Bytes
b497448
36fde01
 
7763ce9
b497448
36fde01
 
 
7763ce9
36fde01
 
 
7763ce9
36fde01
 
 
7763ce9
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
---
license: other
base_model: black-forest-labs/FLUX.1-dev
tags: [flux, lora, style, character-design, concept-art, comfyui]
---

# art-lora-flux1-dev

Style LoRA for **FLUX.1-dev**. Trained on 19 curated painterly character-design references.

**Trigger:** `sk3tchref`

Hand-painted character concept art β€” broad flat brush shapes, hard-edged colour blocking,
minimal blending, muted olive / charcoal / cream / tan palette, flat off-white background
with a thin shadow smear, stylized elongated proportions.

![samples](samples/_grids/grid2000.jpg)

---

## Repo contents

| Path | What it is |
|---|---|
| `sk3tchref.safetensors` | **Final weights (step 2000) β€” use this one** |
| `sk3tchref-step000005/1000/1500/2000.safetensors` | Intermediate checkpoints |
| `workflow.json` | ComfyUI workflow β€” drag onto the canvas |
| `workflow_api.json` | Same graph in API format, for `POST /prompt` |
| `dataset/` | All 19 training images **and** their caption files |
| `samples/` | Outputs per checkpoint + comparison grids |

Style LoRAs overfit, so the best checkpoint is not always the last. All of them are here
so you can compare β€” see `samples/_grids/`.

---

## 1. Download the models

Everything below goes into your ComfyUI `models/` tree. Total ~34 GB.

```bash
cd /workspace/ComfyUI      # adjust to your ComfyUI root
mkdir -p models/diffusion_models models/text_encoders models/vae models/loras
```

### Transformer β€” FLUX.1-dev, 23.8 GB

The official repo **`black-forest-labs/FLUX.1-dev` is gated**: you must accept the licence
on the model page and use a read token. Same for `FLUX.1-schnell`.

```bash
# Option A β€” official, gated. Accept the licence first at
#   https://huggingface.co/black-forest-labs/FLUX.1-dev
# then create a READ token at https://huggingface.co/settings/tokens
export HF_TOKEN=hf_xxxxxxxxxxxxxxxxxxxx

wget --header="Authorization: Bearer $HF_TOKEN" \
  -O models/diffusion_models/flux1-dev.safetensors \
  "https://huggingface.co/black-forest-labs/FLUX.1-dev/resolve/main/flux1-dev.safetensors"
```

```bash
# Option B β€” Comfy-Org mirror. Identical weights, no token needed at time of writing.
wget -O models/diffusion_models/flux1-dev.safetensors \
  "https://huggingface.co/Comfy-Org/flux1-dev/resolve/main/flux1-dev.safetensors"
```

Option B is what this LoRA was trained against. Mirrors can be gated or removed without
notice β€” if Option B starts returning `401`, fall back to Option A.

### Text encoders β€” 10 GB

```bash
wget -O models/text_encoders/t5xxl_fp16.safetensors \
  "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/t5xxl_fp16.safetensors"

wget -O models/text_encoders/clip_l.safetensors \
  "https://huggingface.co/comfyanonymous/flux_text_encoders/resolve/main/clip_l.safetensors"
```

### VAE β€” 335 MB

```bash
# ungated mirror (black-forest-labs/FLUX.1-schnell is gated and returns 401)
wget -O models/vae/ae.safetensors \
  "https://huggingface.co/ffxvs/vae-flux/resolve/main/ae.safetensors"
```

### This LoRA

```bash
wget -O models/loras/sk3tchref.safetensors \
  "https://huggingface.co/kirusanth08/art-lora-flux1-dev/resolve/main/sk3tchref.safetensors"

# intermediate checkpoints, if you want to compare
for S in 00000500 00001000 00001500 00002000; do
  wget -O "models/loras/sk3tchref-step$S.safetensors" \
    "https://huggingface.co/kirusanth08/art-lora-flux1-dev/resolve/main/sk3tchref-step$S.safetensors"
done
```

If the repo is private, add `--header="Authorization: Bearer $HF_TOKEN"` to those too.

### Verify

A truncated download does not error β€” it fails later at load time with
`'NoneType' object has no attribute 'Params'`. Check the sizes:

```bash
ls -l models/diffusion_models/flux1-dev.safetensors   # 23802932552
ls -l models/text_encoders/t5xxl_fp16.safetensors     #  9787841024
ls -l models/text_encoders/clip_l.safetensors         #   246144152
ls -l models/vae/ae.safetensors                       #   335304388
```

---

## 2. Run it

```bash
wget -O workflow.json \
  "https://huggingface.co/kirusanth08/art-lora-flux1-dev/resolve/main/workflow.json"
```

Drag `workflow.json` onto the ComfyUI canvas. It wires up:

```
UNETLoader (flux1-dev, fp8_e4m3fn)
  └─ LoraLoaderModelOnly (sk3tchref.safetensors, strength 1.0)
       └─ KSampler ── VAEDecode ── SaveImage
DualCLIPLoader (clip_l + t5xxl_fp16, type "flux")
  └─ CLIPTextEncode ─┬─ FluxGuidance 3.0 ──→ positive
                     └─ ConditioningZeroOut ─→ negative
```

`workflow_api.json` is the same graph for `POST /prompt`.

### Settings that matter

**`cfg` must stay at `1.0`.** Flux dev is CFG-distilled β€” raising it destroys the image,
and negative prompts do nothing, which is why the negative branch is just a zeroed-out
copy of the positive. `FluxGuidance` (~3.0) is the real prompt-adherence knob.

Sampler `euler`, scheduler `beta`, 28 steps, 832Γ—1216.

### Prompt template

```
sk3tchref, a full body character illustration of <SUBJECT>, hand-painted character
concept art, broad flat brush shapes, hard-edged colour blocking, muted desaturated
palette, flat off-white background, thin grey shadow smear under the feet
```

The trigger must come first.

### Strength guide

| Strength | Result |
|---|---|
| 0.6 | Too weak β€” the base model's smooth prior shows through |
| 0.8 | Works |
| **1.0** | **Recommended β€” strongest read, no subject bleed** |
| 1.1+ | Training subjects and poses start reappearing |

See `samples/final/sweep.jpg`.

---

## 3. How it was trained

kohya `sd-scripts` (`sd3` branch), `flux_train_network.py`, on an RTX 5090 32 GB.
~1.75 s/it, ~1 hour for 2000 steps.

```bash
accelerate launch --num_processes 1 --mixed_precision bf16 \
  --num_cpu_threads_per_process 8 flux_train_network.py \
  --pretrained_model_name_or_path $M/diffusion_models/flux1-dev.safetensors \
  --clip_l $M/text_encoders/clip_l.safetensors \
  --t5xxl $M/text_encoders/t5xxl_fp16.safetensors \
  --ae $M/vae/ae.safetensors \
  --dataset_config dataset.toml \
  --output_dir ./out --output_name sk3tchref \
  --save_model_as safetensors --save_precision bf16 \
  --network_module networks.lora_flux --network_dim 24 --network_alpha 24 \
  --network_train_unet_only \
  --optimizer_type adamw8bit --learning_rate 1e-4 \
  --lr_scheduler constant_with_warmup --lr_warmup_steps 40 \
  --max_train_steps 2000 --save_every_n_steps 500 \
  --gradient_checkpointing --mixed_precision bf16 --fp8_base --sdpa --highvram \
  --cache_latents_to_disk --cache_text_encoder_outputs --cache_text_encoder_outputs_to_disk \
  --max_data_loader_n_workers 2 --persistent_data_loader_workers --seed 42 \
  --timestep_sampling shift --discrete_flow_shift 3.1582 \
  --model_prediction_type raw --guidance_scale 1.0 --loss_type l2
```

Dataset config: aspect-ratio bucketing at 1024 base, `min_bucket_reso 512`,
`max_bucket_reso 1536`, `keep_tokens = 1`, `shuffle_caption = false`.

---

## 4. The captioning method

This is the part that decides whether a style LoRA works.

Captions describe **content only** β€” who the character is, what they wear, what they do:

```
sk3tchref, two views, front and back, of a heavy-set older man with a grey beard in an
olive green jacket, cream shirt and dark green trousers, holding a bottle
```

Note what is *absent*: no "painterly", no "flat colour blocking", no "muted palette", no
"white background". Everything constant across the set and missing from the captions
collapses onto the single token they all share β€” `sk3tchref`.

Write style words into the captions and the style scatters across those common words
instead, producing a LoRA that is weak, hard to trigger, and unresponsive to strength.
`keep_tokens = 1` pins the trigger at the front so shuffling never displaces it.

Every caption in `dataset/` was written by looking at the image.

---

## Why a LoRA and not `--sref`

Reference-image conditioning was tested first and does not work for style transfer:

| Approach | Result |
|---|---|
| Redux / IPAdapter | Encodes the reference into **content** tokens. Below ~0.2 strength nothing transfers; above it the reference's *subject* appears β€” its hat, its props, its character. No setting yields brushwork without subject bleed. |
| Flux.2 Klein / Kontext edit-refs | Trained to **preserve** reference content; "style only" fights the objective. |
| Prompt engineering alone | Yields Flux's own house style. Sweeping guidance moves composition, not paint. |

Conditioning transfers content. Prompting transfers the base model's prior. Only weight
updates transfer style.