The project's README from github.com/mw00/project-maya. As one markdown file: README.md.
Run GLM-5.3-Flash - a 321-billion-parameter AI model - on your own GPU(s)
One NVIDIA GPU or several (up to 16), AMD (experimental) · Linux, Windows (experimental) · chat in the browser, pictures, OpenAI- and
Anthropic-compatible API
☕ Support Project Maya - buy me a coffee
Maya runs GLM-5.3-Flash (zai-org, MIT license): a mixture-of- experts model with 321 B parameters, of which about 18 B work on each token, and a context of up to 1 M tokens. Models this size normally need a server with hundreds of GB of GPU memory. Maya's engine keeps the most-used experts on your GPU(s), the next ones in RAM and the rest on your NVMe SSD, and moves them as the conversation needs them. Nothing leaves your machine.
Maya grew out of Strata (MIT): its engine started from Strata's and was rewritten for GLM-5.3-Flash (the expert tiers across VRAM, RAM and SSD, the two-GPU split, MTP decoding), and its server and dashboard started from Strata's and were reworked for Maya (a new dashboard, images on demand, the thinking budget).
AMD (experimental): Linux and Windows on RX 7900 XT / XTX, R9700 / RX 9070 and Strix Halo / Gorgon Halo (Radeon 8060S / 8065S), one GPU or two (Strix Halo: one), text only - see docs/AMD_MAYA.md.
Maya installs Maya-S, Project Maya's own compact quant of GLM-5.3-Flash (96.5 GB, on Hugging Face), made for PCs with a smaller memory pool across RAM and VRAM. It is made from Z.ai's FP8 release - the precision the model is served at - with statistics from the FP8 model itself and error-feedback rounding of the experts, and it keeps the model's MTP block, which drafts tokens ahead (speculative decoding on two GPUs or more).
It keeps 97.9% of the full FP8 model's accuracy on zero-shot tasks (ARC-Easy, ARC-Challenge, HellaSwag, WinoGrande, PIQA; 400 questions each, the same for both models). On held-out text it picks the same next token as the FP8 model 83% of the time, and it writes long answers (6,000-14,000 tokens) without looping. Details: bench/results/MAYA-S.md.
Maya-S24 (94.7 GB) is Maya-S with the same 2-bit routed experts (most of the model) and only its attention and
shared experts - the small part every token runs through - in 4-bit (Q4_K) instead of 6-bit: about 1.5 GB less that
has to stay on the GPU, so a 24 GB card holds more experts. On one Tesla V100 limited to 24 GB it decodes
14% faster than Maya-S, and 11% faster on the full 32 GB (19.1 vs 17.2 tokens/s); prefill is the
same. It keeps 97.7% of the FP8 model's zero-shot accuracy (Maya-S: 97.9%) and picks the same next token as the
FP8 model 83% of the time, like Maya-S. On cards of 24 GB or less the setup recommends it; else
./setup.sh --setup --model Maya-S24 (Windows: START-MAYA.bat --setup --model Maya-S24).
Details: bench/results/MAYA-S24.md.
Maya-M (116 GB) is the larger quant, made for PCs with a bigger memory pool across RAM and VRAM: more bits where
they count - IQ2_S gate/up experts, IQ3_XXS down projections and IQ3_S in the most sensitive layers - with the same
FP8 statistics and error-feedback rounding, calibrated toward tool calls and front-end code. It is closer to the FP8
model than Maya-S token by token: 23% lower KL divergence, and it picks the same next token as the FP8 model 86%
of the time; on the zero-shot tasks both keep 97.9% of the FP8 model's accuracy. Set it
up with ./setup.sh --setup --model Maya-M (Windows: START-MAYA.bat --setup --model Maya-M).
Details: bench/results/MAYA-M.md.
Maya-M-Derisked (116 GB) is Maya-M with a directional weight modification by
Blackfrost_AI that reduces blanket refusals. It is not a new quant: the same IQ2_S
files, tensors, MTP draft block and size as Maya-M, with some of its weights changed. It is experimental - how close it
stays to Maya-M has not been measured yet - and it has
a repo of its own; it reads pictures
with Maya's vision files, like the other models. Set it up with ./setup.sh --setup --model Maya-M-Derisked
(Windows: START-MAYA.bat --setup --model Maya-M-Derisked).
Maya-L (156.3 GB) is the largest, made for PCs with the biggest memory pool: Maya-M's recipe one step up -
IQ3_S gate/up experts, IQ4_XS down projections and Q5_K in the most sensitive layers - with Maya-M's FP8 statistics and
error-feedback rounding. It is the closest to the FP8 model: 99.2% of its zero-shot accuracy (the same score on
HellaSwag and PIQA), a KL divergence 35% below Maya-M's (0.188 vs 0.291, the same engine), and the same next token as
the FP8 model 90% of the time. It is the most demanding of them: it is fastest when VRAM and RAM together hold most
of its 156 GB (what does not fit is read from the SSD while it answers): a user's RTX 4090 with 192 GB of RAM holds
all of it there and decodes 16.4 tokens/s (#63). Set it up with
./setup.sh --setup --model Maya-L (Windows: START-MAYA.bat --setup --model Maya-L).
Details: bench/results/MAYA-L.md.
Files downloaded before 2026-10-09 name the architecture glm5next, an early spelling.
python tools/gguf_fix_arch.py <the model's first .gguf> --in-place gives them the standard name, glm5-next,
rewriting only the header. Maya reads either name.
Measured with Maya-S. A token is about ¾ of a word. ./maya.sh --bench measures your machine the same way.
| Machine | Decode (writing the answer) | Prefill (reading your prompt) |
|---|---|---|
| 2x Tesla V100 32 GB (PCIe 3), Xeon E5-2690 v4, 30 GB RAM, one NVMe | up to 40 tokens/s | up to 670 tokens/s |
| 1x Tesla V100 32 GB (PCIe 3), Core i5-12600T, 64 GB RAM, one NVMe | up to 19 tokens/s | up to 620 tokens/s |
Measured by users with ./maya.sh --bench (the model and the context as each row says). Send yours: --bench,
then --report, in a
GitHub issue.
| Machine | Decode (writing the answer) | Prefill (reading your prompt) | By |
|---|---|---|---|
| 2x NVIDIA CMP 170HX 64 GB (Ampere GA100; PCIe Gen2 x4 each), 2x Xeon E5-2690 v4, 91 GB RAM - Maya-M, every expert in VRAM | 61.3 tokens/s (mean of 3 answers) | 514 tokens/s (8K-token prompt) | @ZackO2o (v1.0.6, #22) |
| NVIDIA RTX 4090 24 GB (PCIe 4.0 x16), Ryzen 9 9950X3D, 192 GB DDR5-6000 (2 channels), Windows 11 - Maya-L, 128K context, every expert in VRAM or RAM | 16.4 tokens/s (mean of 3 answers) | 1371 tokens/s (8K-token prompt) | @npc97 (v1.0.24, #63) |
| GPU | NVIDIA, compute capability 7.0 or newer (V100 and newer); one GPU, or up to 16 that share the model (two split the layers in the middle; with more, each takes a share sized to its free VRAM). The engine fills whatever VRAM you have with the most-used experts: more VRAM is faster. Measured: 1 and 2x V100 32 GB; by users: 2x CMP 170HX (above), 1x RTX 3090 and nine GPUs (8x RTX 5060 Ti 16 GB + the 3090). AMD (experimental): RX 7900 XT / XTX, Radeon AI PRO R9700 / RX 9070 (one GPU or two) and Strix Halo / Gorgon Halo, Radeon 8060S / 8065S (one GPU), text only (docs/AMD_MAYA.md). |
| RAM | It runs with 32 GB (the 2x V100 machine in the speed table above has 30 GB). More RAM keeps more experts close and is faster; what does not fit is read from the SSD while it answers. |
| Disk | ~100 GB free on a fast NVMe SSD (Maya-S is 96.5 GB, its pictures encoder 1.1 GB, and the engine reads from the model while it answers; Maya-M and Maya-M-Derisked need ~120 GB, Maya-L ~160 GB). Not a hard disk. |
| System | Linux (x86-64; a CPU with AVX2 is best - without it the engine still runs, its CPU expert lane on ggml's slower kernels), NVIDIA driver, CUDA toolkit 12.x (CUDA 13 can be used for Turing and newer, but it no longer compiles for Volta/V100), g++, Python 3.10+. Windows 10/11: experimental, with Visual Studio 2022 Build Tools instead of g++ (Windows). Not WSL2. AMD: ROCm 7 instead of the NVIDIA driver and CUDA (on Windows AMD's ROCm SDK wheels, which the setup offers to install). |
The installer checks all of this and prints the exact command for anything missing. It installs nothing system-wide by itself.
You need: an NVIDIA GPU (V100 / RTX 20 or newer) on Linux (Windows: experimental), ~100 GB free on
an NVMe SSD, a current NVIDIA driver
and the CUDA toolkit (12.x for a V100; the engine is compiled for your GPU). Everything else - Python, the engine, the
model - is set up for you, the way Strata does it. On an AMD RX 7900 XT / XTX, R9700 / RX 9070 or Strix Halo / Gorgon Halo
(experimental, Linux with ROCm 7, or Windows): ./maya.sh --backend hip --gpu 0 --check first (Windows:
START-MAYA.bat --backend hip --gpu 0 --check; two cards: --gpus 0,1; Strix Halo stays one GPU), then
docs/AMD_MAYA.md.
git clone https://github.com/mw00/project-maya.git && cd project-maya
(or download it and unzip it)../setup.sh (the same as ./maya.sh).http://127.0.0.1:8080.Next time, just run ./setup.sh again (or the model's ./run-maya-<model>.sh): it starts right away, nothing is
downloaded twice, on the same screen - its dashboard shows the Monitor's numbers (the speed, where the experts live, the
GPUs, the requests), Tab its log. Ctrl+C stops it.
Updating: the dashboard's About says when a new version is out, and its Update button does it: Maya
downloads the new code (git), compiles only the engine files that changed and loads the same model again - the model
is not downloaded again, and your settings stay. By hand: git pull, then ./setup.sh.
(The check asks GitHub for the latest release, at most every six hours; MAYA_UPDATE_CHECK=0 turns it off.)
It takes 20-40 minutes plus the download:
.venv and gets llama.cpp's source at a pinned commit (it lists both and asks);curl commands, and downloads only
when you answer y; every file is checked against its published sha256. You can run the commands yourself
instead, or use files you already have: ./maya.sh --gguf-dir DIR - other quants than these four are
experimental: they run, but Maya is not measured with them;--no-vision skips it;maya-<model>.json and run-maya-<model>.sh - with the settings tuned for this PC earlier, or
it offers the tuning (about 10-15 minutes; ./maya.sh --calibrate any time) - and starts the dashboard.The start takes a few minutes: the engine pins most of the free RAM (all but about 6 GB) for its expert tier and warms its caches. Other programs get little RAM while Maya runs.
| Option | |
|---|---|
--setup |
set up again (other GPUs, context, model folder) |
--check |
only check the PC |
--gguf-dir DIR |
use GLM-5.3-Flash GGUF files you already have: their folder, or the .gguf file (the first one of a split model) when the folder holds several models. The folder must be writable: the pack goes inside it |
--models-dir DIR |
where downloaded models go, each in a folder named after it - DIR/Maya-L/ holds that model's GGUF files (default ../Maya-data/models); put it on the NVMe |
--download-model |
download the model without asking (the commands and size are still printed) |
--no-vision |
text only: no image encoder |
--gpu N / --gpus 0,1,2,3 |
one GPU, or several (up to 16) that split the model's layers |
--context N |
context length in tokens: 8192, 32768 (default), 65536, 131072 |
--port N, --host 0.0.0.0 --api-key KEY |
another port; reachable from your network (always set a key; several: KEY1,KEY2) |
--env KEY=VALUE |
an engine setting kept in the config (see Tuning) |
--host-compiler g++-12 |
when your g++ is newer than your CUDA accepts ("unsupported GNU version") |
--rebuild, --repack |
compile the engine / build the pack again |
--calibrate |
tune the engine's CPU lane for this PC (see Tuning), then start; with --no-start only tune |
--yes |
the recommended answers (the model download still needs --download-model) |
--plain |
the setup in plain text with typed answers, and Maya in the terminal, not on their own screen (a pipe gets this too, and --yes a plain setup); the setup screen's whole output is in maya-setup.log |
http://127.0.0.1:8080 - Chat (your chats kept in this browser, instructions per chat,
edit and regenerate, code with a preview for HTML pages), a live Monitor of the model, the expert caches and
your GPU/CPU/RAM (with Copy report for an issue), and About (the version and its Update button when
a new one is out, this PC, how to connect your tools). Settings (the gear in the chat) changes the context size: the model reloads with it in a minute or
two, and the dashboard shows what the size costs in GPU memory on this PC.http://127.0.0.1:8080/v1
(any model name; any API key unless you set one). Anthropic's API: http://127.0.0.1:8080/v1/messages
(Claude Code: ANTHROPIC_BASE_URL=http://127.0.0.1:8080). Tool calls (function calling) work through both, streamed
as the model writes them; a call the model only quotes in a code block stays text.none, low, high, max; OpenAI's medium is High and
xhigh Max; Anthropic's budget_tokens under 2K is Low, under 8K High, else Max). A reasoning block is capped at
32K tokens, then the answer follows ("thinking_budget" in the config; 0 = no cap).image_url parts (OpenAI) / image blocks (Anthropic). The image
encoder runs only while a new picture is read - a second or two to start, in GPU memory the model lends it - so
the model keeps its whole GPU cache the rest of the time. On the first start Maya measures how much memory the
encoder needs on your GPU and picks the largest picture size that fits it well (vision-memory.json)../maya.sh --setup --host 0.0.0.0 --api-key <secret>. Always set a key.STRATA_HTTP_BACKLOG).The engine sizes itself: it splits the layers across the GPUs it is given (up to 16; with more than two, each GPU takes layers in proportion to its free VRAM), fills each GPU's free VRAM with experts, sizes its RAM tier from the free RAM, and measures the CPU against the PCIe link at start to decide how many RAM experts the CPU computes itself.
Tuning for your PC (./maya.sh --calibrate, also offered at the end of the setup): that start-up guess times one
expert each way; the tuning measures the real output speed instead, in one engine run (about 10-15 minutes, most of
it loading the model), with a few splits of the RAM-tier experts between the CPU and the PCIe link and with fewer CPU
threads - more threads than the memory can feed only wait, and on a hybrid CPU the efficiency cores can hold the rest
up. Every measurement answers prompts it has not answered before, as a chat's text is new to the expert tiers (the
same few answers over and over left VRAM holding exactly their experts, and the speed it reported was one no chat
reached), and the engine works on a copy of your expert usage file, so the tuning's answers do not change what the
next start loads first. A setting is kept when it is more than 3% faster than the engine's own choice. The result
goes into the config's "env" (STRATA_GLM_PCIE_SHARE, STRATA_GLM_CPU_LANE) and into
~/.config/project-maya/calibration.json for this PC, model and context, so setting up again keeps it. Stop a
running server first: the tuning needs the GPU(s).
These settings change what the engine chooses (put them in the config with --env, or into its "env" block):
| Setting | Default | |
|---|---|---|
STRATA_GLM_RAM_HEADROOM_GB |
6 | RAM left free for the system when the RAM tier is sized; it also takes one more GPU's prompt buffers, pinned after the measurement - a split of three or more GPUs sets the others' aside on top, and each later GPU measures again and leaves at least half of it free |
STRATA_GLM_RAM_GB |
from free RAM | a fixed RAM-tier size in GB |
STRATA_GLM_RAM_RESIDENT |
off | 1 (or --glm-ram-resident): the RAM tier holds every expert not in VRAM and nothing is evicted to disk. The start fails if it cannot. For PCs whose RAM holds everything off-card (a 4090 D with 128 GB: decode 1.9x as fast with PROMOTE_MIN=6). STRATA_GLM_RAM_SLACK is extra slots per MoE layer (default 16) |
STRATA_GLM_SPLIT |
auto: Strata's split search on 2-4 GPUs, by free VRAM with more |
the first layer of each later GPU (24, or 7,12,17,22,27,32,37,41 for nine); 0 = one GPU. The config's "layer_split" sets the same. auto prices every placement before loading: each card's room for experts after its layers' weights and state, the share of each layer's routes the experts it then holds take (your usage counts; Strata's coverage curve without them), each layer's reads over the card's memory bandwidth and each miss over the host's RAM speed - and takes the fastest one every card can start (on a two-GPU split that drafts with the model's MTP block the two cards work on consecutive tokens, so the token costs the slower card: RTX 3090 + 5060 Ti drafting with a NextN block, 24 -> 26, the cards 25.3 / 32.2 -> 28.1 / 29.8 ms a token, decode +3-5%). STRATA_GLM_SPLIT_LOG=1 prints every placement's prediction |
STRATA_GLM_PARALLEL_LOAD |
on | a split's GPUs load at once, a thread each: they plan their RAM tiers one after another in GPU order (each gets the tier a load one by one gives it), then pin and warm them at the same time (4 x Tesla T4, Maya-L from a cold page cache: start to the first token 142 -> 96 s). 0 = one GPU after another |
STRATA_GLM_CPU_LANE |
one thread per physical core (one GPU, or one pool shared by a split of 3+ GPUs: at most one NUMA node's; two GPUs: half each; cores without SMT: two thirds of them) | CPU threads for RAM-tier experts; 0 = off (the tuning sets it) |
STRATA_GLM_CPU_LANE<n> |
the setting above | the same for CUDA<n> alone (STRATA_GLM_CPU_LANE0=6, STRATA_GLM_CPU_LANE1=2): two cards on links of different speed want different counts - the slower the link, the more CPU threads help. RTX 4070 Ti SUPER on PCIe 3.0 x4 + RTX 5070 Ti on 4.0 x16, split 17: 6 / 2 threads beat the default 4 / 4 |
STRATA_GLM_CPU_PIN |
Linux: on with two GPUs on a host with two NUMA nodes or more. Windows: never | a split whose GPUs have a pool each (two GPUs, or STRATA_GLM_CPU_SHARED=0): every GPU's CPU lane on CPUs of its own, a thread a physical core of them (the SMT siblings stay free) - a whole NUMA node while there are enough (its GPU's node when the GPUs hang off different ones), else an even share of a node's physical cores - so one card's idle workers never spin on the cores the other's are using (2 x Xeon Gold 6152, RTX 3090 + 5060 Ti: decode 15.4 -> 19.8 tok/s); on one NUMA node it stays off - there the parts' pools sharing every core were faster (two V100s on one 14-core Xeon: 25.8 tok/s unpinned, 24.7 pinned). 1 = pinned on any Linux host, 0 = unpinned. Linux only: on Windows the engine pins nothing whatever this says, and one GPU is never pinned anywhere, so 0 changes nothing there |
STRATA_GLM_CPU_SHARED |
on with 3+ GPUs | a split of three or more GPUs runs its cards one after another, so one CPU pool serves them all in turn, sized as one GPU's; 0 = a pool per GPU with the cores divided between them (A/B), 1 = one pool for two GPUs too. A card given its own count (STRATA_GLM_CPU_LANE<n>) keeps a pool of its own |
STRATA_GLM_CPU_CAL |
unset | a file (e.g. ~/.config/project-maya/cpu-cal.txt): the CPU lane's timing at start (an expert on the CPU, one over PCIe; ~1.7 s a GPU) is kept there, a line a GPU, and later starts read it. A new engine build, another pack, card, slot or thread count times again; a line that decode finds more than 15% off five times in a row is dropped, and the next start times again |
STRATA_GLM_KDA_GRAPH |
off | experimental: 1 replays single-GPU KDA decode layers as CUDA graphs; DSA, MTP/split, profiling, dumps, prefetch and lookahead stay direct. Two thinking-Max 32K/2048 pairs on v1.0.21: 30.73 -> 31.45 tok/s (+2.35%). Current-main full native/quality validation is pending; see scope and checks |
STRATA_GLM_CPU_SPLIT |
about 48 pieces in all | decode: each CPU-lane thread's share of a token's RAM-tier experts is cut into this many pieces (1-64), claimed in turn, so one thread held up by the disk readers doesn't hold up the token. Few threads take several pieces each (6 threads: 8 - one V100, Maya-S: 17.1 tok/s against 14.3 with one); 40 or more take one each, which streams the memory best |
STRATA_GLM_PCIE_SHARE |
measured at start | the share of a token's RAM-tier experts copied over PCIe and run on the GPU instead of on the CPU: 0 = the CPU takes every one, 1 = none (the tuning sets it; STRATA_GLM_CPU_PLAN = the split per expert count, digits for 0..8) |
STRATA_GLM_PREFETCH_N |
0 | 1 or 2: each layer copies up to this many of the next layer's predicted experts (its router on this layer's input) that are not in VRAM into that layer's spares while it computes. STRATA_GLM_PREFETCH_AT: when the copy starts - route (the default: at once, beside this layer's own PCIe fetch and CPU lane), fetch (after this layer's fetch) or cpu (after its CPU lane); STRATA_GLM_PREFETCH_BLOCKS: the copy's blocks (default half the SMs); STRATA_GLM_PREFETCH_RANK: copy only the prediction's first n ranks (its first guesses are right almost always, its 5th-8th mostly not). Maya-M on an RTX 3090 + 3060 with RAM_RESIDENT=1, decode at 21K: off 19.64, N=1 17.0, N=1 AT=fetch BLOCKS=4 19.75, + RANK=2 20.22 tokens/s (VRAM hits 64 -> 69 %); Maya-L there (bigger experts, a busier link): no gain |
STRATA_GLM_NUMA |
on with 2+ NUMA nodes | 0 = allocate the RAM tier without spreading it page by page over the sockets' memory |
STRATA_GLM_PREFILL_CHUNK |
unset | --prefill N from the environment (the older setting; it wins over the config's --prefill) |
STRATA_PREFILL_LEND_PCT, STRATA_GLM_PREFILL_MB |
90 or 85, unset | --prefill auto: the share of each card's expert-pool slots a prompt may borrow for its buffers - as Strata, 90 when at least 90% of the experts' bytes are held pinned (in VRAM or the RAM tier), else 85 - or a fixed budget in MB |
STRATA_GLM_PREFILL_TAIL_SKIP |
on | single-device prompts without a loaded NextN/MTP block: skip the last layer's attention output projection and FFN after updating all its caches; 0 restores the full computation. Splits and GLM_CB_DIR seam dumps keep the full path |
STRATA_GLM_PREFILL_WINDOW |
the chunk's tokens | prompts: the expert output rows kept on the GPU at once - each expert set's rows are added into the layer's output as the window fills, instead of every routed row waiting for one combine (~40 KB a token instead of ~185, so a chunk holds ~2x the tokens); 0 = every row (the old layout) |
STRATA_GLM_USAGE |
<pack>/expert_usage.txt |
where your expert usage is kept between starts (the warm-up loads your experts first); 0 = off |
STRATA_GLM_SLOTS |
4 | conversations kept aside on the SSD, so switching back to one doesn't re-read its prompt; 0 = off |
STRATA_GLM_SLOT_MIN, STRATA_GLM_SLOT_GB, STRATA_GLM_SLOT_DIR |
1024, 16, <pack>/slots |
the shortest conversation kept aside (tokens, down to 1), their total size on disk (GB), and the folder |
STRATA_GLM_SLOT_KEEP, STRATA_GLM_SLOT_DAYS |
off, 7 | 1: the kept conversations outlive the engine - the folder is not emptied at start (a slot is kept when its .meta names this model, engine version and pack, else removed), the conversation in the model is kept when the engine ends, and a slot unused for STRATA_GLM_SLOT_DAYS days is removed. With a supervisor that stops the model when it idles (llama-swap), the next request after a restart reads only its new tokens (a 4K-token conversation back in 0.2 s instead of re-read) |
STRATA_GLM_PROMOTE |
8 | when the CPU computes every RAM-tier expert (it beats the PCIe link), experts moved between VRAM and RAM in the background per token, so VRAM follows what you use; 0 = off |
STRATA_GLM_PROMOTE_MIN |
0 | a fetched expert is kept in VRAM only when its aged route count is at least this. 0 or 1 is the old rule (keep it whenever a spare is free). A flat route table promotes one-off experts and then evicts them; 6 stopped that churn on one 4090 D with 128 GB of RAM; with little RAM it costs (2x V100, 30 GB: 29.6 -> 28.3 tokens/s) |
STRATA_GLM_PROMOTE_FILL |
24 | while VRAM has free expert slots (after a prompt gives back what it borrowed), up to this many of the hottest RAM-tier experts are copied into them per token (several per layer) instead of STRATA_GLM_PROMOTE; 0 = the same pace as the moves |
STRATA_GLM_VRAM_EVICT |
unset | lru: a layer's spare is refilled by evicting its least recently used expert instead of its least-used by the aged counts. It matters as much as experts are promoted (fetched over PCIe rather than computed by the CPU lane): Maya-L on an RTX 3090 + 3060 with a RAM tier and an NVMe tier, decode at 21K +2.6% (VRAM hits 54.5 -> 55.9 %); Maya-M there with STRATA_GLM_CPU_PLAN=012234567 (one PCIe fetch a route at most) unchanged |
STRATA_GLM_MV_RDNA |
AMD: on for the Ryzen AI Max APUs (gfx115x) | the decode's dense GEMVs (the Q6_K and BF16 projections) in one RDNA3 kernel that keeps two blocks' loads in flight, bit for bit the original kernels' (Radeon 8065S, Maya-S: decode +3.1%); 1 = on any gfx11 (an RX 7900: not measured yet), 0 = off. NVIDIA: no effect |
STRATA_GLM_MTP_GGUF |
the model's own | two GPUs or more: a GGUF holding the MTP draft block to draft with - for a model published without one, or a more precise block than its own (tools/maya_quant/mtp_gguf.py writes a model's block alone); STRATA_GLM_NO_MTP=1 = no drafting |
STRATA_GLM_MTP_KEEP |
2 | two GPUs or more: the draft block computes the experts it is missing from VRAM only among its route's n best-scored ones (CPU lane / PCIe as for any route) and skips the rest - a draft only has to be a good guess, but a rejected one costs the first GPU a redo. 2 drafts better than skipping all and was never slower (2x V100: 82-83% accepted against 76-81%; RTX 3090 + 3060: 19.5 -> 20.6 tok/s); 0 = skip every missing expert, STRATA_GLM_MTP_MISS=1 = fetch them all |
STRATA_GLM_SPEC_HEAD |
half the GPUs | more than two GPUs: how many of the split's first GPUs form the head group of the speculative decode - the head group runs the draft's position while the rest finish the current token, as the two halves of a two-GPU split do (4x Tesla T4, Maya-S: decode 14.1 -> 21.0 tok/s against no drafting); STRATA_GLM_NO_SPEC=1 = token by token |
STRATA_GLM_SERVICE_IDLE_MS |
200 | the engine's tier threads (one per GPU) spin while a decode routes experts and sleep after this long without one, so an idle engine uses ~1% of a core instead of one core per GPU; 0 = spin always |
STRATA_GLM_PREFILL_CPU |
on | prompts: the least routed RAM-tier experts are computed on the CPU while the GPU loads the rest over PCIe, the split balanced each layer so both finish together; 0 = off. STRATA_GLM_PREFILL_CPU_ROW_MS fixes the CPU cost of a row it plans with (default: learned) |
STRATA_GLM_PRESTAGE |
160 on one GPU, 0 on more | prompts: experts copied to the GPU while a layer's attention runs (the PCIe link is idle then), into a buffer of this many experts borrowed from the pool's tail - the next layer's most routed RAM-tier ones; 0 = off. STRATA_GLM_PRESTAGE_ADAPT=1 (experimental, not yet measured) learns each layer's count from how long its attention takes |
STRATA_GLM_PREFILL_TRACE |
off | 1: per layer of every prompt chunk, the attention time and when the prestage copies, the copy lane and the CPU lane ended (debug) |
STRATA_GLM_KQ |
on | prompts' CPU experts: the multi-token AVX-512 Q3_K/Q2_K kernel (about 2x ggml's from 8 tokens an expert); 0 = ggml's dots only |
STRATA_GLM_PREFILL_SUB |
NVIDIA: up to 4096; AMD: 256 | prompts: the sub-batch the attention layers, the dense FFN and the shared expert run in (16-8192). Unset on NVIDIA, the attention layers' and the dense FFN's is 256 doubled while it fits in memory the chunk's MoE buffers already take (fewer, larger GEMMs, each weight dequantized once a sub-batch) and the shared expert's stays 256; 256 = the old sub-batches |
STRATA_GLM_KV_INT8 |
off | 1 (or --kv int8 in the config's "args"): the attention's latent cache in INT8 - 512 codes and one FP16 scale per 32 values, 544 bytes a token and layer instead of 1024. One V100, 128K context: state 1.78 -> 1.13 GB, 84 more expert slots; no measurable quality change (KL against FP16 within FP16's own run-to-run spread) |
STRATA_GLM_DSA_SCORE |
on | prompts: the sparse attention's indexer scores as a register-tiled FP32 GEMM (a 3090, 4096 tokens at position 10K: 78.8 -> 5.6 ms); 0 = the warp-per-pool kernel |
STRATA_GLM_PREFILL_ATTN |
tensor cores | prompts' sparse attention kernel: on Ampere and newer an mma.sync kernel with 32 heads a block (a 3090, 26.6K-token prompt: 832 -> 966 tok/s); wmma = the 91 KB shared-memory kernel Volta runs, tcreg = the register kernel Turing runs, f32 = the FP32 kernel. AMD: wmma2, the default on gfx12 (R9700 / RX 9070: prompts +8-10%), or f16q, the default on gfx11 and Strix Halo. STRATA_GLM_PREFILL_ATTN_CHECK=1 compares the chosen kernel with the FP32 one (debug) |
STRATA_GLM_DROP_CACHE |
on with 2+ NUMA nodes | before the RAM tier is pinned, the model files' clean page cache is dropped (the engine reads experts with O_DIRECT): a cached GGUF filling one node made the interleaved tier land 78% on the other, and the CPU lane read one socket's memory; 0 = keep it |
STRATA_GLM_PROFILE_WEIGHT |
1 | the weight of the pack's routing profile (expert_counts.txt) against your usage file in the start-up order of the expert tiers; 0 = your usage only |
STRATA_GLM_LOOP_THINK, STRATA_GLM_LOOP_ANSWER |
256, 1024 | the loop guard: when the last this-many generated tokens are one pattern of at most 32 tokens repeated exactly (a quantized model can fall into 0 0 0 ... until max_tokens), thinking is closed at once, and in the answer the model's current tool-call argument (or else the turn) is closed so an agent goes on; a second loop in the same answer ends it. 0 = off |
STRATA_GLM_TIMING, STRATA_GLM_POOL_STATS |
off | 1 = timing and cache statistics in the engine log |
STRATA_GLM_ROUTE_LOG |
off | <prefix>: every decode route as a line in <prefix>.<GPU> - the layer, its experts, which were fetched, missed or computed on the CPU, then after a | the 16 near misses (the next ranks by the same score) - for cache studies: tools/glm_tier_replay.py replays a log through a model of the VRAM tier's rules and alternatives |
STRATA_GLM_SCORE_PREFILL |
off | with STRATA_GLM_SCORE=<c> (score --tokens after the first c): 1 reads those c tokens through the prompt path instead of one by one, so a long context is scored in minutes (debug: comparing KV-cache formats at long context) |
STRATA_GLM_THINK_RESERVE |
1024 | the server: a thinking block is closed early enough to leave the answer at least this many tokens, or a quarter of the request's max_tokens if that is more (the config's "thinking_budget" is lowered per request to fit) - a request whose max_tokens runs out while the model is still thinking otherwise ends with no answer at all |
STRATA_ENGINE_STALL_S |
90 | the server: an engine silent this long that also used no CPU, disk or GPU in that time is stuck - it is ended, the request gets an error and the next request starts it again (a silent engine that is working is never ended); 0 = off |
STRATA_WATCHDOG_S |
180 | the engine: a request that finishes no prompt layer and no token for this long has hung, even with a thread spinning (#40). The engine writes where it stopped to its log (on Windows also maya-stall-<pid>.dmp, every thread's stack: attach both to an issue) and ends; the request gets an error and the next request starts it again. 0 = off |
STRATA_HTTP_BACKLOG, STRATA_MAX_BODY_MIB |
256, 256 | the server: connections that may wait to be accepted, and the largest request body in MiB (a larger one gets a 413 before it is read) |
STRATA_ENGINE_QUIT_S |
50 | the server: how long the engine gets to end (and keep its conversation, with STRATA_GLM_SLOT_KEEP) after a stop - SIGTERM is handled like Ctrl+C, a second one is ignored; a supervisor's own grace (llama-swap's unloadTimeout) should exceed it |
STRATA_ENGINE_WRAP_S |
40 | the server: on a stop, a request in progress is wrapped up instead of dropped - its thinking is closed at once and it answers for up to this long (then it is cut), so the client gets an answer and the turn ends; requests still queued are refused. Keep it plus the engine's end inside the supervisor's grace (llama-swap's unloadTimeout); 0 = cut at once |
A routing profile for a GGUF of your own. At start the engine fills VRAM with each layer's most used experts:
your usage file (above) blended with the pack's profile, expert_counts.txt / expert_prior.txt. To make one, start
the model with STRATA_GLM_USAGE=/tmp/profile.txt (a fresh file), send it requests typical of your use (code, docs,
chat, languages), stop it, then run python tools/glm_expert_prior.py <pack folder> /tmp/profile.txt.
Prompt chunks (Strata's --prefill). The engine reads a prompt in chunks, and every expert a chunk routes to is
copied into VRAM once per chunk, so larger chunks read long prompts faster; a chunk's buffers are borrowed from the
expert pool while the prompt runs. The setup writes --prefill auto into the config's "args" (a setup again keeps
what you changed there):
| Argument | What it does |
|---|---|
--prefill auto |
the largest chunk, in steps of 256 tokens, whose buffers each card's expert pool can lend - at most 90% of its slots (85% when under 90% of the experts' bytes are in VRAM or the pinned RAM tier), always keeping a route's experts and the spares - up to 32768 tokens on one GPU and 8192 on a split - each the faster there (one V100, 26K-token prompts: 559 tok/s at 32768, 367 at 8192; two V100s: 709 at 8192, 551 at 32768). On a split every card reads the same chunks, so the smallest card's sets it, and the log names a card that holds it below the first card's |
--prefill N |
chunks of N tokens (32768, say), halved until each card's pool can lend them - only a route's experts and the spares must stay; 0 = token by token. On a split with 96 GB of RAM or more the setup points to 32768: 32768-token chunks read prompts 21-35% faster there in Strata's community benchmarks |
One card streams nearly every expert over PCIe for each chunk, so fewer, larger chunks pay off on long prompts. On a split, a prompt that fits one chunk runs the cards one after the other, while two or more keep both busy.
Reporting a problem or your speed: run ./maya.sh --report (Windows: START-MAYA.bat --report) right after
a slow answer or the error, and attach the maya-report.txt it writes in the Maya folder. It holds your GPUs, CPU,
RAM and disks, your Maya setup and the engine's speed lines - where the time goes, token by token - so the engine
can be tuned for your machine. Nothing is sent anywhere; your home folder shows as ~ and no API key is included.
For a speed report, also run ./maya.sh --bench with Maya stopped (Windows: START-MAYA.bat --bench): a
standard test of a few minutes - decode on three questions, prefill at 2k and 8k tokens - that writes
maya-bench.txt, which the report then includes. Both work on AMD too (--backend hip), and --config FILE picks
one installed setup when you have several.
./maya.sh --setup --host-compiler g++-12 (install g++-12
first)../maya.sh again (or the printed curl command): it continues where it stopped.--port 8081 starts another one.maya-<model>.log in the Maya folder.Experimental: the same installer sets Maya up natively on Windows 10/11 (64-bit), and the engine and the image encoder compile there with Visual Studio 2022 and CUDA 12.8 (CUDA 13 works for RTX 20 and newer). Maya is developed and measured on Linux; on Windows 11 a user runs Maya-L on an RTX 4090, built with CUDA 13.4 (the speed table above, #63). Tell us how it runs on yours.
Install once:
nvidia-smi is the
driver's capability, not proof that the toolkit (nvcc) is installed.winget install -e --id Python.Python.3.12 --scope user.Open a new PowerShell or Command Prompt after installing the prerequisites. Clone the repository (or open the extracted folder), then check the PC:
git clone https://github.com/mw00/project-maya.git
cd project-maya
.\START-MAYA.bat --check
--check reports the GPUs, toolkit, compiler, RAM and page file without downloading the model or building the
engine. Maya finds Visual Studio's compiler environment itself; a Developer Command Prompt is not needed.
Start the setup, putting the model on an NVMe SSD with enough free space for the chosen model. Change the drive and folder to suit your PC:
.\START-MAYA.bat --setup --models-dir "D:\Maya-models"
Choose the model and context when asked. The launcher creates its own .venv; setup installs its Python
packages, CMake and Ninja there, builds the engine, and asks before downloading the model. Later, run
.\START-MAYA.bat (or double-click it) to start the installed model, then open http://127.0.0.1:8080.
All ./maya.sh options also work here; PowerShell needs the leading .\. Add --plain for plain-text setup.
--check recommends roughly the selected GPUs' total VRAM plus
9 GB of page-file capacity (about 57 GB for a 48 GB card). If it warns, set a custom size at least as large as it
recommends, with enough free disk space: System > About > Advanced system settings > Performance > Settings >
Advanced > Virtual memory. Restart Windows after changing it. "System managed" can remain too small on a
large-RAM PC (#20).--nvcc "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v12.8\bin\nvcc.exe" to the setup command..\START-MAYA.bat --calibrate --no-start to tune the CPU/PCIe
split and thread count for your PC. Then start Maya normally. See Tuning for the optional RAM-resident
tier and other settings, and Something went wrong? for --bench / --report.START-MAYA.bat in Windows itself.--calibrate once: it tunes Maya for your PC, and a setup for another context keeps its settings.START-MAYA.bat --backend hip --gpu 0 --setup builds the HIP engine with AMD's HIP SDK, or offers AMD's ROCm SDK wheels in .venv when there is none
(docs/AMD_MAYA.md).
tools\hip\build_maya_windows.bat builds it by hand (an RX 7900 XTX,
#54).Project Maya is free and open source. If it is useful to you, you can support its development: buymeacoffee.com/peasantsmith. Thank you!
Speed reports, bug reports and pull requests are welcome: CONTRIBUTING.md says what helps most.
third_party/ggml/LICENSE).serve/web/fonts/OFL.txt).