docs: the 2026-09-17 frank-medium shape -- 36:29, 327680 pool, vision

AGENTS.md topology row and section, and the runbook: the pool is 327680
positions (163840 per conversation over two slots), the split is 36:29 -- one
layer past the 34:31 balance at this context, on purpose, for headroom on the
drafter card (fit 29.19/26.04, measured 28.40/26.66 GiB at load, 3.46/5.20
headroom) -- and vision is on via the explicit --mmproj flag, because this
build has no autoload (the first deploy came up text-only and 500'd image
requests). The rope caveat is written down where the cap lives: the GGUF has
no scaling keys, so the top 65k of the pool extrapolates on the base rope.
This commit is contained in:
Frank
2026-09-17 02:08:14 -07:00
parent 4b7de59dc8
commit 0a25351caa
2 changed files with 57 additions and 11 deletions
+5 -4
View File
@@ -24,7 +24,7 @@ merge absorbed the former `vllmScripts` repo, history preserved).
| Target | Service | Runtime | Model | Port | | Target | Service | Runtime | Model | Port |
|--------|---------|---------|-------|------| |--------|---------|---------|-------|------|
| Dankserver | `frank-medium` | mainline llama.cpp master fb27a525 (root systemd unit, gfx1201 HIP build) | ajgazin Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP UD-Q8_K_XL + z-lab Qwen3.8-27B-DFlash2 Q8_0 drafter, 2x Radeon AI PRO R9700 in ONE layer-split process (35:30), 262144 ctx over 2 slots, batch 6144x512, text only | 7770 | | Dankserver | `frank-medium` | mainline llama.cpp master fb27a525 (root systemd unit, gfx1201 HIP build) | ajgazin Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP UD-Q8_K_XL + z-lab Qwen3.8-27B-DFlash2 Q8_0 drafter, 2x Radeon AI PRO R9700 in ONE layer-split process (36:29), 327680 ctx over 2 slots of 163840, batch 6144x512, vision (BF16 mmproj) | 7770 |
| Dankclaw | `frank-large` | halogen-flash-server 0.5.8 (rootless Quadlet) | peonist-ai Qwen3.8-Flash-Next w4b `.hgn` on the gfx1151 iGPU (Strix Halo LPDDR), 200192 ctx per conversation over one 400384-position KV pool / 2 slots, text only | 7770 | | Dankclaw | `frank-large` | halogen-flash-server 0.5.8 (rootless Quadlet) | peonist-ai Qwen3.8-Flash-Next w4b `.hgn` on the gfx1151 iGPU (Strix Halo LPDDR), 200192 ctx per conversation over one 400384-position KV pool / 2 slots, text only | 7770 |
| Dankclaw | `frank-small` | mainline llama.cpp master 37b53fd (root systemd unit) | ISTA-DASLab Qwen3.8-27B-GSQ-RCO IQ3_S (`-mtp` + BF16 mmproj) on the RTX 3090, 131072 ctx / 1 slot, MTP speculative decoding, the fleet's vision endpoint | 7771 | | Dankclaw | `frank-small` | mainline llama.cpp master 37b53fd (root systemd unit) | ISTA-DASLab Qwen3.8-27B-GSQ-RCO IQ3_S (`-mtp` + BF16 mmproj) on the RTX 3090, 131072 ctx / 1 slot, MTP speculative decoding, the fleet's vision endpoint | 7771 |
@@ -321,9 +321,10 @@ systemd unit `scripts/frank-medium.service`) serving
`ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP-GGUF` at **UD-Q8_K_XL** `ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP-GGUF` at **UD-Q8_K_XL**
(29.29 GiB) with the **z-lab DFlash2** `Q8_0` drafter chained to the (29.29 GiB) with the **z-lab DFlash2** `Q8_0` drafter chained to the
draftless **ngram-mod** matcher, in **one process across both R9700s**, draftless **ngram-mod** matcher, in **one process across both R9700s**,
`--split-mode layer` at a **35:30 tensor split** (the balance point for the `--split-mode layer` at a **36:29 tensor split** (one layer past the 34:31
deployed batch: the drafter rides ROCm1, so it takes fewer target layers), balance point at this context, moved to buy headroom on the drafter card:
262144 ctx over **2 slots** of 131072, batch 6144x512, text only. DSpark was ROCm1 carries the drafter, its KV and the output layers), 327680 ctx over
**2 slots** of 163840, batch 6144x512, vision via the BF16 mmproj. DSpark was
put up in the drafter's place the same day and reverted: it declares no sliding put up in the drafter's place the same day and reverted: it declares no sliding
window, so its draft KV spanned the whole context (5.0 GiB) and cost ROCm1 four window, so its draft KV spanned the whole context (5.0 GiB) and cost ROCm1 four
layers of the split. layers of the split.
@@ -1,7 +1,7 @@
--- ---
type: configuration type: configuration
title: frank-medium llama.cpp Runbook (DFlash2 drafter) title: frank-medium llama.cpp Runbook (DFlash2 drafter)
description: The ACTIVE frank-medium deployment since 2026-09-16 — mainline llama.cpp on Dankserver serving ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP at UD-Q8_K_XL with the z-lab Qwen3.8-27B-DFlash2 Q8_0 drafter, as ONE layer-split process across both Radeon AI PRO R9700 cards at a 35:30 split, 262144 ctx over two slots. description: The ACTIVE frank-medium deployment since 2026-09-16 — mainline llama.cpp on Dankserver serving ajgazin/Swift-Qwen3.8-27B-Uncensored-Dynamic-MTP at UD-Q8_K_XL with the z-lab Qwen3.8-27B-DFlash2 Q8_0 drafter, as ONE layer-split process across both Radeon AI PRO R9700 cards at a 36:29 split, a 327680-position KV pool (163840 per conversation over two slots), vision via the BF16 mmproj.
tags: tags:
- frank-medium - frank-medium
- dankserver - dankserver
@@ -12,7 +12,7 @@ tags:
- gfx1201 - gfx1201
- r9700 - r9700
- layer-split - layer-split
timestamp: 2026-09-16 timestamp: 2026-09-17
--- ---
# frank-medium — llama.cpp (DFlash2 drafter) # frank-medium — llama.cpp (DFlash2 drafter)
@@ -144,9 +144,9 @@ Deployed flags:
| Flag | Value | Why | | Flag | Value | Why |
|---|---|---| |---|---|---|
| `--split-mode` / `--device` / `--tensor-split` | `layer` / `ROCm0,ROCm1` / `35,30` | both cards, one model, no collective; the split is skewed because ROCm1 carries the drafter, and it is one LAYER of granularity — 0.43 GiB on a DeltaNet boundary, 1.43 GiB on an attention one | | `--split-mode` / `--device` / `--tensor-split` | `layer` / `ROCm0,ROCm1` / `36,29` | both cards, one model, no collective; the split is skewed because ROCm1 carries the drafter, and it is one LAYER of granularity — 0.43 GiB on a DeltaNet boundary, 1.43 GiB on an attention one. Since 2026-09-17 it is one layer PAST the balance point at the 327680 pool, on purpose: the move bought headroom on the drafter card (see below) |
| `--gpu-layers` / `--fit` | `999` / `off` | everything on the cards; auto-fit must not resize a context we set | | `--gpu-layers` / `--fit` | `999` / `off` | everything on the cards; auto-fit must not resize a context we set |
| `--ctx-size` / `--parallel` | `262144` / `2` | the model's whole window over two slots of 131072; `--parallel` **divides** the context | | `--ctx-size` / `--parallel` | `327680` / `2` | the pool over two slots of 163840; `--parallel` **divides** the context. 1.25x the trained 262144 window, and the GGUF has no rope scaling — see the 2026-09-17 section |
| `--batch-size` / `--ubatch-size` | `6144` / `512` | measured: ubatch 512 is the prefill optimum *and* the cheapest point on the curve; the logical batch is throughput- and VRAM-neutral. See [[frank-medium-batch-ubatch]] | | `--batch-size` / `--ubatch-size` | `6144` / `512` | measured: ubatch 512 is the prefill optimum *and* the cheapest point on the curve; the logical batch is throughput- and VRAM-neutral. See [[frank-medium-batch-ubatch]] |
| `--ctx-checkpoints` / `--cache-ram` | `0` / `8192` | no per-slot KV snapshots (the build's default); the RAM-side prompt cache is capped at 8 GiB | | `--ctx-checkpoints` / `--cache-ram` | `0` / `8192` | no per-slot KV snapshots (the build's default); the RAM-side prompt cache is capped at 8 GiB |
| `--flash-attn` / cache types | `on` / `f16` K and V | an agentic checkpoint is the wrong place to spend KV precision | | `--flash-attn` / cache types | `on` / `f16` K and V | an agentic checkpoint is the wrong place to spend KV precision |
@@ -154,7 +154,7 @@ Deployed flags:
| `--spec-draft-device` | `ROCm1` | the drafter rides the card that ends up holding the target's last layers | | `--spec-draft-device` | `ROCm1` | the drafter rides the card that ends up holding the target's last layers |
| `--temp` / `--top-p` / `--top-k` | `0.7` / `0.95` / `20` | the values the vLLM predecessor served on this endpoint | | `--temp` / `--top-p` / `--top-k` | `0.7` / `0.95` / `20` | the values the vLLM predecessor served on this endpoint |
| `--reasoning-format` / `--reasoning-budget` | `deepseek` / `-1` | trace into `reasoning_content`, unlimited | | `--reasoning-format` / `--reasoning-budget` | `deepseek` / `-1` | trace into `reasoning_content`, unlimited |
| `--no-mmproj` | — | text only | | `--mmproj` | `mmproj-BF16.gguf` (888 MiB, beside the target) | vision enabled since 2026-09-17; this build has NO autoload, so the flag is explicit and the serve script refuses to start without the file |
## The DSpark excursion (2026-09-16, tried and reverted) ## The DSpark excursion (2026-09-16, tried and reverted)
@@ -260,6 +260,51 @@ larger, so the question is closed rather than pending.
> 39:26 itself was only *loaded* at the deployed batch, not exercised), and it > 39:26 itself was only *loaded* at the deployed batch, not exercised), and it
> is **not** an OOM: no amount of headroom would prevent it. > is **not** an OOM: no amount of headroom would prevent it.
## 2026-09-17: the pool grows to 327680, the split moves to 36:29, vision comes on
The window grew from 262144 to a **327680-position pool** (163840 per
conversation over the two slots), the split moved one layer to ROCm0
(35:30 → 36:29), and the **BF16 mmproj** (888 MiB) came on.
**Why 36:29, not the balance.** At this context the fit model puts the balance
point at 34:31 (0.11 GiB gap). The operator moved a layer to ROCm0 to buy
headroom on ROCm1 — the card that carries the drafter, its KV, the output
layers and the heavier compute buffers — accepting a 3.15 GiB gap by
construction:
| Card | Fit | Measured at load | Headroom |
|---|---:|---:|---:|
| ROCm0 (36 layers + mmproj) | 29.19 GiB | 28.40 GiB | 3.46 GiB |
| ROCm1 (29 layers + drafter) | 26.04 GiB | 26.66 GiB | 5.20 GiB |
Both clear the 1.5 GiB floor with room; the fit lands within 0.8 GiB on both
cards, which is the accuracy it has always had (at the 35:30 point it
reproduced ROCm1 to 0.00 and ROCm0 to 0.86). The seam's slack is the 3.15 GiB
gap rounded up, with the trade written in its comment.
**The rope caveat.** The GGUF carries no `context_length` and no rope-scaling
keys (freq_base 1e7, `dimension_sections [11,11,10,0]`); the checkpoint's
trained window is 262144. Positions beyond that — the top 65k of the pool —
extrapolate on the base rope. It runs, and 1.25x is a modest ask of a rope,
but it is untrained territory, and the seam's ctx cap encodes 327680 with
that note.
**Vision: this build has no mmproj autoload.** The first 327680/36:29 deploy
came up healthy and *text-only*: image requests answered 500 "image input is
not supported — hint: … provide the mmproj" and the load log had no mmproj
line, so `llama-server` fb27a525 does not pick up `mmproj*.gguf` from the
model directory. The serve script now passes `--mmproj` explicitly (the
frank-small pattern), refuses to start without the file when vision is on, and
the deploy handler's preflight checks for it. Verified end-to-end after the
fix: a generated 64x32 test image was described from its pixels — with
thinking on the model reasoned about "the three horizontal bars" (its reading
of the crude glyph) and with thinking off answered the letter question in one
token.
The e2e crawl spec flaked once on the first 327680 deploy (1 failed / 31
passed) and passed 32/32 on the redeploy; the service itself was healthy
throughout (health gate green, `NRestarts=0`).
## Verified serving behaviour (2026-09-16) ## Verified serving behaviour (2026-09-16)
- Load: `model loaded` ~25 s after start with a warm page cache, then - Load: `model loaded` ~25 s after start with a warm page cache, then
@@ -458,13 +503,13 @@ produced wrong numbers on this fleet:
- **It separates devices differently from `llama-server`.** `/` splits devices - **It separates devices differently from `llama-server`.** `/` splits devices
*within one configuration*, `,` splits *sweep values* — so this service's *within one configuration*, `,` splits *sweep values* — so this service's
`--tensor-split 35,30` is `-ts 35/30` to llama-bench, and the comma form `--tensor-split 36,29` is `-ts 36/29` to llama-bench, and the comma form
silently benches each card on its own instead. Likewise `--device silently benches each card on its own instead. Likewise `--device
ROCm0,ROCm1` → `-dev ROCm0/ROCm1`. ROCm0,ROCm1` → `-dev ROCm0/ROCm1`.
- **There is no `-c`.** The context is a consequence of the test shape: - **There is no `-c`.** The context is a consequence of the test shape:
`n_ctx = n_prompt + n_gen + n_depth`. No bench can therefore prove that a `n_ctx = n_prompt + n_gen + n_depth`. No bench can therefore prove that a
configuration's activation buffers fit beside the *deployed* KV — that needs configuration's activation buffers fit beside the *deployed* KV — that needs
the live unit at 262144 across two slots. the live unit at 327680 across two slots.
- **A test that cannot allocate calls `exit(1)`**, taking the whole process with - **A test that cannot allocate calls `exit(1)`**, taking the whole process with
it, so the harness runs one invocation per cell and a failure costs one TSV it, so the harness runs one invocation per cell and a failure costs one TSV
line instead of the rest of the sweep. line instead of the rest of the sweep.