kkontosis/LayerStoRm

Run frontier-scale MoE LLMs on a handful of VRAM-constrained consumer GPUs by streaming experts over PCIe.

C++

5

37 commits

updated Sep 8, 2026

See the code

README

LayerStoRm

Run frontier-scale MoE LLMs on a handful of VRAM-constrained consumer GPUs by streaming experts over PCIe.


Currently supported GPUs

FamilyArchitectureNotes
RTX 50xxNVIDIA SM1205090 / 5080 tested; kernels build as 120f

Currently supported models (MLA-family MoE)

ModelSize
GLM-5.3-Flash320 B (18 B active)
GLM-5.2744 B (40 B active)
DeepSeek-V4-Flash284 B (13 B active)

KV quantizations

SchemeBits
1. TurboQuant4.03–5.36
2. FP8 + BF16 RoPE (SnapMLA-style), almost lossless8.06–8.94

Weight quantizations

FormatBits
FP88
NVFP44
GGUF — e.g. UD-Q4_K_XL2–8 (mixed)

TL;DR

LayerStoRm fits large MoE LLMs, with large context, into much smaller VRAM — efficiently. MoE models are almost entirely routed experts, but each token activates only a few — and the router tells you which. LayerStoRm keeps the full expert set in pinned host RAM and streams the activated experts to the GPUs every token, overlapped with compute.

  • GPU VRAM is used as a cache — PCIe streaming bandwidth along with VRAM size, is the budget.
  • Multi-GPU, GPU-only decode
  • 1M context fits on GPU via KV tiering with RAM offload.
  • Prefix cache for agentic coding, with RAM-offloaded checkpoints.

Tested configurations

ConfigGPUsHost RAMInterconnectTotal VRAM
#12× RTX 5090 + 2× RTX 5080512 GB (NUMA-placed) + 64 GB HBMPCIe 5.096 GB

Measured performance

All numbers measured on Config #1.

ModelConfigQuantWeights on diskDraftCtx lengthKV cache quantPrefill (tok/s)Decode (tok/s)TTFT
GLM-5.3-Flash#1UD-Q4_K_XL186.0 GiB(WIP)1MFP8 + BF16 RoPE159 @27k27.0 @0k
24.5 @8k
GLM-5.2#1UD-Q4_K_XL435.2 GiBdspark γ15 (nvfp4, sharded)400kTQ 4-bit + BF16 RoPE28 @8k6.8 @0.4k
5.3 @8k

Requirements

  • 1 or more supported GPUs, PCIe5 verified link recommended
  • Host RAM to pin the model's full expert set: 207.5 GB measured for GLM-5.3-Flash, plus OS and KV overheads (reference box: 512 GB; the weights download alone is 186 GB)
  • CUDA — suggested 13+ — and NCCL 2.20+

Install

Prerequisites (Ubuntu):

sudo apt install build-essential cmake git python3 libnuma-dev liburing-dev libnccl2 libnccl-dev

CUDA (suggested 13+; skip if nvcc --version is already good) — from NVIDIA's repos or installer if apt doesn't have it.

Clone and set up (no sudo from here on; setup.sh is checked in, installs nothing system-wide):

git clone --recursive https://github.com/kkontosis/LayerStoRm.git
cd LayerStoRm
./scripts/setup.sh

Build:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

CMake finds nvcc, the .venv interpreter and pybind11 on its own, and builds the Cython fast bridge as part of the normal build. Override any of them with -DCMAKE_CUDA_COMPILER=…, -DPYTHON_EXECUTABLE=…, -Dpybind11_DIR=… if you need to.

Get a model (GGUF weights + the model's HF tokenizer/metadata files, downloaded next to the weights — the engine resolves the tokenizer, chat template and generation config from the weights directory first; repo test-data/ is only a loudly-logged fallback):

.toolchain/bin/uv pip install huggingface_hub
.venv/bin/hf download unsloth/GLM-5.3-Flash-GGUF --include "UD-Q4_K_XL/*" --local-dir models/GLM-5.3-Flash-GGUF
.venv/bin/hf download zai-org/GLM-5.3-Flash --exclude "*.safetensors" --local-dir models/GLM-5.3-Flash-GGUF/UD-Q4_K_XL

Serve

CUDA_DEVICE_ORDER=PCI_BUS_ID \
.venv/bin/python python/cli/serve.py --autoconfig \
    --model models/GLM-5.3-Flash-GGUF/UD-Q4_K_XL/GLM-5.3-Flash-UD-Q4_K_XL-00001-of-00006.gguf \
    --max-sequence-length 1048576 --max-concurrent 2 \
    --model-name glm-5.3-flash --host 127.0.0.1 --port 8000
curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model": "glm-5.3-flash", "max_tokens": 128,
       "messages": [{"role": "user", "content": "What is the capital of France?"}]}'

Notes, kept short:

  • Autoconfig derives the whole recipe from the weights and your hardware, explains every derived field, and refuses (naming the binding constraint) rather than boot into OOM.
  • The call above is the boot-verified configuration: on a 2×5090 + 2×5080 box it derives snapmla, tp=2, EP4, KV tiering, superchunk stride 2048 — and serves 1M context at concurrency 2. Measured on it: 24.5 tok/s decode (8k prompt), 159 tok/s prefill.
  • Ask only for the context you need. 1048576 engages KV tiering, which costs ~10–16%; a smaller ask derives a faster untiered config (the hand-tuned 200k champion reaches 27.4 tok/s decode). Untested context lengths are derived the same way but have not been measured.
  • CUDA_DEVICE_ORDER=PCI_BUS_ID keeps CUDA numbering matched to the PCI order the placement assumes (mixed 5090/5080 boxes can otherwise swap GPU roles).
  • Add LAYERSTORM_DETERMINISTIC_EP_COMBINE=1 for run-to-run reproducible greedy output.
  • /v1/completions, streaming SSE, logprobs, tool calls, reasoning content, and guided JSON output all work.

Going deeper

Status and limitations

Highly experimental — early research-grade, under rapid development. Interfaces, configs, and on-disk formats change without notice; correctness outside the gated model/hardware combinations is not guaranteed. Not for production.

  • Single node; modest concurrency (concurrency-2 boot-verified on GLM-5.3-Flash; further requests queue with 503 + Retry-After)
  • Every performance change is gated on bit-identical golden-token tests
  • Active work: predictive expert prefetching (EPM), batched decode (B>1), CPU hybrid decode, AMD and multi-node support

License and attributions

MIT — see LICENSE.md. Third-party notices in THIRD_PARTY_NOTICES.md: SM120 MLA attention kernels derive from FlashMLA (MIT) and CUTLASS (BSD-3-Clause); CPU/GGUF quantized-GEMM and MXFP4/GGUF decode paths derive from the llama.cpp / ik_llama.cpp lineage (MIT); parts of the serving layer follow vLLM and SGLang (Apache-2.0).

Contributing

Issues and PRs welcome — measurements from other SM120 boxes especially. Performance claims need a number and its regime; correctness changes need the golden-token gates under tests/ green. Start with docs/DESIGN.md and DEVELOPMENT.md.

References

The design is drawn from published work. These are influences — the implementations here are independent unless THIRD_PARTY_NOTICES.md records that code was adapted.

Reflected in the engine

Each of these shaped a subsystem that ships:

Background

Read while designing the above; not implemented here.

Attention, KV cache and long context

MoE offloading, expert caching and prefetching

Speculative decoding, early exit and layer skipping

DSpark and Training-Free Loosely Speculative Decoding are listed without links because the copies consulted here carry no canonical URL.

Thanks

LayerStoRm stands on the shoulders of the open inference ecosystem — for reference implementations, design ideas, and (where noted in THIRD_PARTY_NOTICES.md) adapted code:

And thank you to the authors of the work referenced above. Nearly every subsystem here started as someone else's published idea; the measurements in this project's ledgers exist because that work was shared openly. Errors in adapting it are mine.

Contributors

kkontosis

37 commits

kkontosis/LayerStoRm

Run frontier-scale MoE LLMs on a handful of VRAM-constrained consumer GPUs by streaming experts over PCIe.

C++

5

37 commits

updated Sep 8, 2026

See the code

README

LayerStoRm

Run frontier-scale MoE LLMs on a handful of VRAM-constrained consumer GPUs by streaming experts over PCIe.


Currently supported GPUs

FamilyArchitectureNotes
RTX 50xxNVIDIA SM1205090 / 5080 tested; kernels build as 120f

Currently supported models (MLA-family MoE)

ModelSize
GLM-5.3-Flash320 B (18 B active)
GLM-5.2744 B (40 B active)
DeepSeek-V4-Flash284 B (13 B active)

KV quantizations

SchemeBits
1. TurboQuant4.03–5.36
2. FP8 + BF16 RoPE (SnapMLA-style), almost lossless8.06–8.94

Weight quantizations

FormatBits
FP88
NVFP44
GGUF — e.g. UD-Q4_K_XL2–8 (mixed)

TL;DR

LayerStoRm fits large MoE LLMs, with large context, into much smaller VRAM — efficiently. MoE models are almost entirely routed experts, but each token activates only a few — and the router tells you which. LayerStoRm keeps the full expert set in pinned host RAM and streams the activated experts to the GPUs every token, overlapped with compute.

  • GPU VRAM is used as a cache — PCIe streaming bandwidth along with VRAM size, is the budget.
  • Multi-GPU, GPU-only decode
  • 1M context fits on GPU via KV tiering with RAM offload.
  • Prefix cache for agentic coding, with RAM-offloaded checkpoints.

Tested configurations

ConfigGPUsHost RAMInterconnectTotal VRAM
#12× RTX 5090 + 2× RTX 5080512 GB (NUMA-placed) + 64 GB HBMPCIe 5.096 GB

Measured performance

All numbers measured on Config #1.

ModelConfigQuantWeights on diskDraftCtx lengthKV cache quantPrefill (tok/s)Decode (tok/s)TTFT
GLM-5.3-Flash#1UD-Q4_K_XL186.0 GiB(WIP)1MFP8 + BF16 RoPE159 @27k27.0 @0k
24.5 @8k
GLM-5.2#1UD-Q4_K_XL435.2 GiBdspark γ15 (nvfp4, sharded)400kTQ 4-bit + BF16 RoPE28 @8k6.8 @0.4k
5.3 @8k

Requirements

  • 1 or more supported GPUs, PCIe5 verified link recommended
  • Host RAM to pin the model's full expert set: 207.5 GB measured for GLM-5.3-Flash, plus OS and KV overheads (reference box: 512 GB; the weights download alone is 186 GB)
  • CUDA — suggested 13+ — and NCCL 2.20+

Install

Prerequisites (Ubuntu):

sudo apt install build-essential cmake git python3 libnuma-dev liburing-dev libnccl2 libnccl-dev

CUDA (suggested 13+; skip if nvcc --version is already good) — from NVIDIA's repos or installer if apt doesn't have it.

Clone and set up (no sudo from here on; setup.sh is checked in, installs nothing system-wide):

git clone --recursive https://github.com/kkontosis/LayerStoRm.git
cd LayerStoRm
./scripts/setup.sh

Build:

cmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j$(nproc)

CMake finds nvcc, the .venv interpreter and pybind11 on its own, and builds the Cython fast bridge as part of the normal build. Override any of them with -DCMAKE_CUDA_COMPILER=…, -DPYTHON_EXECUTABLE=…, -Dpybind11_DIR=… if you need to.

Get a model (GGUF weights + the model's HF tokenizer/metadata files, downloaded next to the weights — the engine resolves the tokenizer, chat template and generation config from the weights directory first; repo test-data/ is only a loudly-logged fallback):

.toolchain/bin/uv pip install huggingface_hub
.venv/bin/hf download unsloth/GLM-5.3-Flash-GGUF --include "UD-Q4_K_XL/*" --local-dir models/GLM-5.3-Flash-GGUF
.venv/bin/hf download zai-org/GLM-5.3-Flash --exclude "*.safetensors" --local-dir models/GLM-5.3-Flash-GGUF/UD-Q4_K_XL

Serve

CUDA_DEVICE_ORDER=PCI_BUS_ID \
.venv/bin/python python/cli/serve.py --autoconfig \
    --model models/GLM-5.3-Flash-GGUF/UD-Q4_K_XL/GLM-5.3-Flash-UD-Q4_K_XL-00001-of-00006.gguf \
    --max-sequence-length 1048576 --max-concurrent 2 \
    --model-name glm-5.3-flash --host 127.0.0.1 --port 8000
curl -s http://127.0.0.1:8000/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{"model": "glm-5.3-flash", "max_tokens": 128,
       "messages": [{"role": "user", "content": "What is the capital of France?"}]}'

Notes, kept short:

  • Autoconfig derives the whole recipe from the weights and your hardware, explains every derived field, and refuses (naming the binding constraint) rather than boot into OOM.
  • The call above is the boot-verified configuration: on a 2×5090 + 2×5080 box it derives snapmla, tp=2, EP4, KV tiering, superchunk stride 2048 — and serves 1M context at concurrency 2. Measured on it: 24.5 tok/s decode (8k prompt), 159 tok/s prefill.
  • Ask only for the context you need. 1048576 engages KV tiering, which costs ~10–16%; a smaller ask derives a faster untiered config (the hand-tuned 200k champion reaches 27.4 tok/s decode). Untested context lengths are derived the same way but have not been measured.
  • CUDA_DEVICE_ORDER=PCI_BUS_ID keeps CUDA numbering matched to the PCI order the placement assumes (mixed 5090/5080 boxes can otherwise swap GPU roles).
  • Add LAYERSTORM_DETERMINISTIC_EP_COMBINE=1 for run-to-run reproducible greedy output.
  • /v1/completions, streaming SSE, logprobs, tool calls, reasoning content, and guided JSON output all work.

Going deeper

Status and limitations

Highly experimental — early research-grade, under rapid development. Interfaces, configs, and on-disk formats change without notice; correctness outside the gated model/hardware combinations is not guaranteed. Not for production.

  • Single node; modest concurrency (concurrency-2 boot-verified on GLM-5.3-Flash; further requests queue with 503 + Retry-After)
  • Every performance change is gated on bit-identical golden-token tests
  • Active work: predictive expert prefetching (EPM), batched decode (B>1), CPU hybrid decode, AMD and multi-node support

License and attributions

MIT — see LICENSE.md. Third-party notices in THIRD_PARTY_NOTICES.md: SM120 MLA attention kernels derive from FlashMLA (MIT) and CUTLASS (BSD-3-Clause); CPU/GGUF quantized-GEMM and MXFP4/GGUF decode paths derive from the llama.cpp / ik_llama.cpp lineage (MIT); parts of the serving layer follow vLLM and SGLang (Apache-2.0).

Contributing

Issues and PRs welcome — measurements from other SM120 boxes especially. Performance claims need a number and its regime; correctness changes need the golden-token gates under tests/ green. Start with docs/DESIGN.md and DEVELOPMENT.md.

References

The design is drawn from published work. These are influences — the implementations here are independent unless THIRD_PARTY_NOTICES.md records that code was adapted.

Reflected in the engine

Each of these shaped a subsystem that ships:

Background

Read while designing the above; not implemented here.

Attention, KV cache and long context

MoE offloading, expert caching and prefetching

Speculative decoding, early exit and layer skipping

DSpark and Training-Free Loosely Speculative Decoding are listed without links because the copies consulted here carry no canonical URL.

Thanks

LayerStoRm stands on the shoulders of the open inference ecosystem — for reference implementations, design ideas, and (where noted in THIRD_PARTY_NOTICES.md) adapted code:

And thank you to the authors of the work referenced above. Nearly every subsystem here started as someone else's published idea; the measurements in this project's ledgers exist because that work was shared openly. Errors in adapting it are mine.

Contributors

kkontosis

37 commits

Languages

C++

63.8%

Python

27.4%

Cuda

7.5%