Skip to content

Commit d508b7a

Browse files
committed
docs: update CLAUDE.md with GGUF support, device split, hal9000 working config
1 parent 176f29e commit d508b7a

1 file changed

Lines changed: 85 additions & 17 deletions

File tree

CLAUDE.md

Lines changed: 85 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ pub trait InferenceEngine: Send + Sync {
8686
8. **VAE decoding**`flux::autoencoder::AutoEncoder::decode()` converts latents to pixels
8787
9. **Image encoding** — Tensor → RGB → PNG/JPEG bytes via the `image` crate
8888

89+
**Device split** — T5 and CLIP encoders load on **CPU** (9.2GB combined), while the FLUX transformer and VAE load on **GPU**. This is required because FLUX dev BF16 (23GB) + T5 (9.2GB) exceeds 24GB VRAM.
90+
91+
**GGUF quantized models** — the engine auto-detects `.gguf` extension on `MOLD_TRANSFORMER_PATH` and uses `candle_transformers::quantized_var_builder` + `flux::quantized_model::Flux`. GGUF quantized models (Q4_1 = 7GB, Q8_0 = 12GB) leave plenty of VRAM for activations. When quantized, state tensors use F32; when BF16, they use BF16.
92+
93+
**FluxTransformer enum** wraps either `flux::model::Flux` (BF16) or `flux::quantized_model::Flux` (GGUF quantized). Both implement `flux::WithForward` so the same `denoise()` call works for both.
94+
8995
Model loading is **lazy** (on first generation request) and uses **mmap** for safetensors files.
9096

9197
Feature flags: `cuda` (CUDA backend), `metal` (Metal backend).
@@ -181,47 +187,94 @@ The client sends a `GenerateRequest` via HTTP POST to `/api/generate` and receiv
181187

182188
## Deployment to hal9000
183189

184-
Model files on hal9000 (already downloaded):
190+
### Hardware
191+
- NixOS, RTX 4090 (24GB VRAM)
192+
- SSH: `jamesbrink@hal9000.home.urandom.io`
193+
- If direct TCP fails: `ssh -J bender.tail1f4f9.ts.net jamesbrink@10.70.100.206`
194+
195+
### Model files on hal9000 (already on disk)
185196
```
186-
Transformer: /home/jamesbrink/AI/models/unet/flux1-dev.safetensors
197+
# GGUF quantized (recommended — fits in 24GB with room for activations)
198+
flux1-schnell-Q8_0.gguf /home/jamesbrink/AI/models/unet/flux1-schnell-Q8_0.gguf (12GB) ← ACTIVE
199+
flux1-dev-Q8_0.gguf /home/jamesbrink/AI/models/unet/flux1-dev-Q8_0.gguf (12GB)
200+
flux1-dev-Q4_1.gguf /home/jamesbrink/AI/models/unet/flux1-dev-Q4_1.gguf (7GB)
201+
202+
# BF16 safetensors (23GB — causes CUDA OOM during denoising, avoid)
203+
flux1-dev.safetensors /home/jamesbrink/AI/models/unet/flux1-dev.safetensors (23GB)
204+
205+
# Shared components (used regardless of transformer choice)
187206
VAE: /home/jamesbrink/AI/models/vae/ae.safetensors
188207
T5 encoder: /home/jamesbrink/AI/models/text_encoders/t5xxl_fp16.safetensors
189208
CLIP-L: /home/jamesbrink/AI/models/clip/clip_l.safetensors
209+
T5 tokenizer: /home/jamesbrink/AI/models/tokenizers/t5-v1_1-xxl.tokenizer.json
210+
CLIP tokenizer: /home/jamesbrink/AI/models/tokenizers/clip-vit-large-patch14.tokenizer.json
211+
```
212+
213+
### Building with CUDA (Nix devshell)
214+
215+
The `flake.nix` provides a devshell with all CUDA 12.8 dependencies:
216+
217+
```bash
218+
# On hal9000:
219+
cd /home/jamesbrink/mold
220+
git pull
221+
nix develop --command cargo build --release -p mold-server --features cuda
222+
```
223+
224+
### Systemd user service
225+
226+
The server runs as a systemd user service on hal9000:
227+
228+
```bash
229+
# Check status
230+
systemctl --user is-active mold-server
231+
journalctl --user -u mold-server -f
232+
233+
# Restart
234+
systemctl --user restart mold-server
235+
236+
# Service file location
237+
~/.config/systemd/user/mold-server.service
190238
```
191239

192-
### First-time setup
240+
The service is configured with all required env vars including `LD_LIBRARY_PATH=/run/opengl-driver/lib` for CUDA driver access.
241+
242+
### First-time tokenizer setup
193243

194244
```bash
195-
# On hal9000: download tokenizer files
196245
ssh jamesbrink@hal9000.home.urandom.io
197246
bash /home/jamesbrink/mold/scripts/fetch-tokenizers.sh
198247
```
199248

200-
### Deploy
249+
### Deploy from local
201250

202251
```bash
203-
# From the mold project root on your local machine:
252+
# From the mold project root:
204253
./scripts/deploy.sh
205254
```
206255

207-
This will:
208-
1. rsync source to hal9000
209-
2. Build with CUDA on hal9000
210-
3. Stop any running mold-server
211-
4. Start mold-server with model paths configured via env vars
212-
213-
### Test after deploy
256+
### Test
214257

215258
```bash
216-
MOLD_HOST=http://hal9000.home.urandom.io:7680 mold generate "a rusty robot on a beach"
259+
# Direct HTTP test
260+
curl -X POST http://hal9000.home.urandom.io:7680/api/generate \
261+
-H "Content-Type: application/json" \
262+
-d '{"prompt":"a cat on Mars","model":"flux-schnell","width":512,"height":512,"steps":4,"batch_size":1,"output_format":"png"}' \
263+
-o output.png
264+
265+
# Or via ProxyJump if local TCP is broken:
266+
ssh -J bender.tail1f4f9.ts.net jamesbrink@10.70.100.206 \
267+
'curl -X POST http://localhost:7680/api/generate ...'
217268
```
218269

219270
## Known Models
220271

221-
| Name | HuggingFace Repo | Size |
272+
| Name | HuggingFace Repo | Recommended File |
222273
|------|-----------------|------|
223-
| `flux-schnell` | `black-forest-labs/FLUX.1-schnell` | ~23.8 GB |
224-
| `flux-dev` | `black-forest-labs/FLUX.1-dev` | ~23.8 GB |
274+
| `flux-schnell` | `black-forest-labs/FLUX.1-schnell` | `flux1-schnell-Q8_0.gguf` (12GB) |
275+
| `flux-dev` | `black-forest-labs/FLUX.1-dev` | `flux1-dev-Q4_1.gguf` (7GB) or `flux1-dev-Q8_0.gguf` (12GB) |
276+
277+
> **Note:** The full BF16 safetensors FLUX dev (23GB) fills all 24GB VRAM and causes CUDA OOM during the denoising activation pass. Always use GGUF quantized models on the RTX 4090.
225278
226279
Model registry is defined in `mold-inference/src/model_registry.rs`.
227280

@@ -297,3 +350,18 @@ cargo test -p mold-core # Test specific crate
297350
7. **mmap for safetensors**: Model weights are memory-mapped rather than read into memory, allowing the OS to manage paging efficiently.
298351

299352
8. **Env var + config file model paths**: Supports both deployment-friendly env vars and local config file paths. Env vars take precedence over config.
353+
354+
9. **GGUF over BF16 safetensors for 24GB VRAM**: The full BF16 FLUX dev model (23GB) fills all VRAM, leaving nothing for activations. GGUF Q8_0 (12GB) or Q4_1 (7GB) leave plenty of room. Engine auto-detects `.gguf` extension.
355+
356+
10. **T5/CLIP on CPU**: Text encoders load on CPU to keep ~9.2GB off the GPU. Embeddings are moved to GPU after encoding. This is required for the FLUX transformer to fit in VRAM alongside activations.
357+
358+
11. **Nix devshell for CUDA**: `flake.nix` provides a devshell with CUDA 12.8 packages (`cuda_nvcc`, `cuda_cudart`, `libcublas`, `cuda_nvrtc`, `libcurand`) and `CUDA_COMPUTE_CAP=89` for the RTX 4090. Build with `nix develop --command cargo build --release -p mold-server --features cuda`.
359+
360+
## Confirmed Working Configuration (hal9000, 2026-03-12)
361+
362+
```
363+
Model: flux-schnell Q8_0 GGUF
364+
VRAM used: ~12GB (transformer) + ~300MB (VAE) = ~12.3GB / 24GB
365+
Generation: 512×512, 4 steps, ~36s first run (model load included)
366+
GPU: RTX 4090 (CUDA 12.8, driver 580.119.02)
367+
```

0 commit comments

Comments
 (0)