FardoX commited on
Commit
f03b346
·
verified ·
1 Parent(s): 6100d15

mede CPU (o veredito se INVERTE: Q4_K_M ganha 1,46-1,51x) e documenta `sasori draw`

Browse files
Files changed (1) hide show
  1. README.md +85 -8
README.md CHANGED
@@ -92,6 +92,44 @@ decode da VAE). Os três braços rodam **no mesmo pod, ao mesmo tempo**, cada um
92
  > permanente. Com o modelo carregado uma vez e 5 repetições, a comparação correta é a tabela acima:
93
  > **empate com o FP16**, e vantagem sobre o `Q4_K_M`. O número anterior estava errado e foi retirado.
94
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
  ### Fidelidade — CLIP-score pareado (ViT-L/14, N=16 pares: 8 prompts × 2 seeds)
96
 
97
  | braço | CLIP-score | retenção vs FP16 | Wilcoxon p | placar par-a-par (FP/braço) |
@@ -121,11 +159,12 @@ rubber ducks" sai correta e o fotorrealismo se mantém; o que muda é a trajetó
121
  degradação.
122
  - **CLIP-score não é FID.** Mede alinhamento imagem-texto pareado, não fidelidade perceptual da
123
  distribuição. Nenhum FID de Fréchet foi computado.
124
- - **Escopo da medição:** 1 modelo, 1 GPU (A100-80 PCIe), 4 steps, euler, VAE `small-decoder`.
125
- Velocidade: 768² e 1024², 5 repetições em regime permanente. Fidelidade: 1024², 2 seeds,
126
- 8 prompts, 1 CLIP (ViT-L/14), N=16 pares. Não medido: CPU, ARM, outros samplers, FID, e a
127
- fidelidade da **edição** (a edição por imagem de referência funciona foi exercitada no webapp
128
- interno — mas não foi avaliada quantitativamente).
 
129
 
130
  ## Como rodar
131
 
@@ -158,13 +197,51 @@ stable-diffusion.cpp/build/bin/sd-cli \
158
  Use a flag só se o modelo não couber na sua GPU.
159
  - **VRAM necessária** (TQ3P, 1024², sem offload): **14,7 GB** com o text encoder também em TQ3P (7,1 GB o DiT + 7,5 GB o TE + 0,1 GB a VAE), ou 22,9 GB mantendo o text encoder em BF16.
160
  - **CPU**: o kernel TQ{K}P usa `_mm256_maddubs_epi16` (AVX2) e é um mpGEMM direto — o trit
161
- multiplica sem dequantizar. Passe `-t <núcleos>`. **Não medido neste run**; medições
162
- anteriores do projeto (outro modelo) colocam o TQ2P empatado com o Q4_K_M em CPU e o TQ3P
163
- atrás de ambos — a vantagem de ~1,5× sobre o `Q4_K_M` acima é de **GPU**, não extrapole.
164
  - **Servir com o modelo quente:** `sd-server` mantém os pesos carregados; via `sd-cli` cada
165
  imagem paga load + setup outra vez (o que também distorce medição de velocidade — veja a
166
  nota de correção acima). Para uso repetido, use o servidor.
167
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
168
  ### Ternarizar você mesmo (e o que aprendi sobre paralelizar isso)
169
 
170
  ```bash
 
92
  > permanente. Com o modelo carregado uma vez e 5 repetições, a comparação correta é a tabela acima:
93
  > **empate com o FP16**, e vantagem sobre o `Q4_K_M`. O número anterior estava errado e foi retirado.
94
 
95
+ ### Velocidade em CPU — o veredito se INVERTE
96
+
97
+ EPYC 4564P (16 vCPU, AVX2/AVX512), 124 GB de RAM (folgada de propósito: mede o **teto**, sem
98
+ `--mmap` nem releitura de disco), 4 steps, `-t 16`, executado via `sasori draw`.
99
+
100
+ **512²**
101
+
102
+ | braço | encode do prompt | sampling | **s/it** | VAE decode | total por imagem |
103
+ |---|---|---|---|---|---|
104
+ | TQ3P (DiT K3 + TE K3) | 17,51 s | 259,43 s | **64,86** | 9,43 s | ~4,8 min |
105
+ | Q4_K_M + Q8_0 | 12,81 s | 171,32 s | **42,83** | 9,46 s | ~3,2 min |
106
+
107
+ **1024²**
108
+
109
+ | braço | encode do prompt | sampling | **s/it** | VAE decode | total por imagem |
110
+ |---|---|---|---|---|---|
111
+ | TQ3P (DiT K3 + TE K3) | 17,19 s | 833,03 s | **208,26** | 35,89 s | ~14,8 min |
112
+ | Q4_K_M + Q8_0 | 12,17 s | 570,16 s | **142,54** | 36,90 s | ~10,3 min |
113
+
114
+ **Em CPU o `Q4_K_M` é 1,51× (512²) / 1,46× (1024²) MAIS RÁPIDO que o TQ3P — o inverso quase exato
115
+ da GPU** (onde o TQ3P era 1,52× mais rápido). A simetria não é coincidência: em CPU o denoise é limitado por **bytes
116
+ lidos por peso**, e o K3 a 6,1875 bpw lê ~37 % mais que o `Q4_K_M` a ~4,5 bpw; na GPU o gargalo é
117
+ o caminho de kernel, e ali o TQ3P entra pelo `dequant → cuBLAS`. O text encoder ternário paga o
118
+ mesmo preço (17,5 s vs 12,8 s no encode do prompt). Isto reproduz e reforça o que o projeto já
119
+ havia medido no SD3.5-Medium em CPU (TQ3P 24,0 vs Q4_K_M 18,9 s/it).
120
+
121
+ **Recomendação honesta, por hardware:**
122
+
123
+ | onde você roda | escolha | por quê |
124
+ |---|---|---|
125
+ | **GPU** | **TQ3P (este repo)** | 1,52× mais rápido que o `Q4_K_M`, empata com o FP16, 2,44× menos bytes que o FP16 |
126
+ | **CPU** | **`Q4_K_M`** ([unsloth](https://huggingface.co/unsloth/FLUX.2-klein-9B-GGUF)) | 1,51× mais rápido que este artefato; ternário não é o formato certo aí |
127
+
128
+ E, em qualquer hardware, **CPU não é um caminho confortável para o 9B**: no melhor caso (RAM
129
+ folgada, sem `--mmap`) são ~3–5 min por imagem a 512² e **10–15 min a 1024²**. Numa máquina de
130
+ 16 GB, onde o pacote de 14,3 GB só entra com `--mmap`, é pior que isso. Para CPU o alvo razoável é
131
+ o **klein-4B**, 2,3× menor e com licença Apache-2.0.
132
+
133
  ### Fidelidade — CLIP-score pareado (ViT-L/14, N=16 pares: 8 prompts × 2 seeds)
134
 
135
  | braço | CLIP-score | retenção vs FP16 | Wilcoxon p | placar par-a-par (FP/braço) |
 
159
  degradação.
160
  - **CLIP-score não é FID.** Mede alinhamento imagem-texto pareado, não fidelidade perceptual da
161
  distribuição. Nenhum FID de Fréchet foi computado.
162
+ - **Escopo da medição:** 1 modelo, 4 steps, euler, VAE `small-decoder`. **GPU** (A100-80 PCIe):
163
+ 768² e 1024², 5 repetições em regime permanente. **CPU** (EPYC 4564P, 16 vCPU): 512², 1 execução
164
+ por braço, RAM folgada. Fidelidade: 1024² na GPU, 2 seeds, 8 prompts, 1 CLIP (ViT-L/14), N=16
165
+ pares. Não medido: ARM, outros samplers, FID, o regime com `--mmap` sob RAM apertada, e a
166
+ fidelidade da **edição** (ela funciona — foi exercitada no webapp interno — mas não foi avaliada
167
+ quantitativamente).
168
 
169
  ## Como rodar
170
 
 
197
  Use a flag só se o modelo não couber na sua GPU.
198
  - **VRAM necessária** (TQ3P, 1024², sem offload): **14,7 GB** com o text encoder também em TQ3P (7,1 GB o DiT + 7,5 GB o TE + 0,1 GB a VAE), ou 22,9 GB mantendo o text encoder em BF16.
199
  - **CPU**: o kernel TQ{K}P usa `_mm256_maddubs_epi16` (AVX2) e é um mpGEMM direto — o trit
200
+ multiplica sem dequantizar. Passe `-t <núcleos>`. **Medido** (ver a seção de CPU acima): aqui o
201
+ `Q4_K_M` ganha por 1,51×; a vantagem de ~1,5× do TQ3P é **exclusivamente de GPU**.
 
202
  - **Servir com o modelo quente:** `sd-server` mantém os pesos carregados; via `sd-cli` cada
203
  imagem paga load + setup outra vez (o que também distorce medição de velocidade — veja a
204
  nota de correção acima). Para uso repetido, use o servidor.
205
 
206
+ ### `sasori draw` — deixa a ferramenta escolher as flags de memória
207
+
208
+ O `stable-diffusion.cpp` tem várias flags de residência de peso (`--mmap`, `--offload-to-cpu`,
209
+ `--clip-on-cpu`, `--vae-on-cpu`, `--stream-layers`, `--max-vram`) e saber **qual usar em qual
210
+ tamanho** é chato. O formato TQ{K}P decide quantos *bytes* um peso custa; quem decide o que fica
211
+ residente e quando é o runtime — então o sasori calcula o encaixe e escolhe:
212
+
213
+ ```bash
214
+ python3 -m sasori draw flux-2-klein-9b-TQ3P.gguf \
215
+ --llm text_encoder/Qwen3-8B-TQ3P.gguf \
216
+ --vae vae/full_encoder_small_decoder.safetensors \
217
+ -p "a lovely cat sitting on a wooden table, soft window light" \
218
+ --sd-cpp <path do stable-diffusion.cpp buildado> -o cat.png
219
+
220
+ # editar (kontext-style): o prompt passa a ser a INSTRUÇÃO
221
+ python3 -m sasori draw ... -r foto.png -p "troque o fundo por uma praia ao amanhecer"
222
+
223
+ # ver a contabilidade e o comando sem rodar nada
224
+ python3 -m sasori draw ... --dry-run
225
+ ```
226
+
227
+ Ele soma os pesos em disco + os buffers de compute que a resolução implica (coeficientes medidos:
228
+ VAE **4,76 KB/px**, denoiser **1,36 KB/px**, dobrando com imagem de referência), compara com a VRAM
229
+ livre / a RAM disponível de verdade, e **imprime cada flag com o motivo**. Numa GPU pequena adiciona
230
+ `--offload-to-cpu` + `--clip-on-cpu`; em CPU sem RAM suficiente adiciona `--mmap` **avisando que
231
+ aquilo "cabe" ao custo de reler os pesos do disco a cada step** — em vez de apresentar isso como um
232
+ encaixe limpo. Exemplo real, numa máquina de 16 GB:
233
+
234
+ ```
235
+ [sasori draw] pesos 14.18 GB + buffers ~6.12 GB (1024x1024) = 20.30 GB
236
+ [sasori draw] ⚠ pesos+buffers 20.3 GB > RAM disponivel 11.1 GB -> --mmap: CABE, mas cada step pode
237
+ reler do DISCO o que for despejado (14.2 GB de pesos). Menor resolucao ou um modelo
238
+ menor e mais rapido que este modo.
239
+ ```
240
+
241
+ **A VAE é o maior consumidor de buffer e não depende do tamanho do denoiser** (a mesma VAE serve o
242
+ 4B e o 9B): 4 994 MB a 1024² contra ~1 250 MB a 512². Baixar a resolução é a alavanca de memória
243
+ mais forte que você tem.
244
+
245
  ### Ternarizar você mesmo (e o que aprendi sobre paralelizar isso)
246
 
247
  ```bash