← Open Source
invergent-ai

surogate

Train and serve LLMs at extreme speed and massive throughput.

Model DevelopmentFine-tuningLLM trainingC++
Open on GitHub
Momentum
+0stars in 24 hours0.0%
855
Stars
11
Forks
+2
This week
7
Contributors
Created 2026-01-02 · Updated 2026-10-17 · #13019 today
Top developers
flaviusburcamadalintatmonicaandreea
README

Surogate Engine

Native C++/CUDA LLM training and serving: GGUF, NVFP4, BF16, FP8.

From your first fine-tune to hundreds of concurrent requests.

Website · Documentation · Benchmarks · Quickstart · Models · Examples

136,200 tok/s
Training · 4× RTX 5090
Qwen3-0.6B · FP4 LoRA

2.53× training throughput
vs. Unsloth · 1× H100
Qwen3-0.6B · BF16 on both

802 tok/s
Serving · one user · 1× RTX 5090
Qwen3.5-0.8B · native GGUF

7.0× serving throughput
vs. llama.cpp · 8× RTX 5090
GLM-5.3-Flash · 16 users · decode

Selected results from the repository's training benchmarks and serving benchmarks. Workloads and comparison details below.

Surogate puts training and serving in one toolkit, with dedicated native engines built to push NVIDIA hardware. Pretrain a model, fine-tune with LoRA or QLoRA, optimize with GRPO or DPO, distill a teacher, and serve the result through familiar HTTP APIs.

Speed drives the design: compiled training graphs, fused CUDA kernels, low-precision tensor cores, concurrent serving, and deliberate control over every byte of GPU memory. Scale from a single workstation to multiple GPUs and training clusters, or use system RAM to work with models larger than your cards.

Speed you can measure

Serving: fast for one user. Fast under load.

Native GGUF decoding at 802 tokens/s on one RTX 5090. A 200 GB MoE serving 16 users at 7× llama.cpp's aggregate decode throughput on eight cards.

Model / workload RTX 5090 GPUs Surogate decode Baseline decode Throughput gain
Qwen3.5-0.8B · 1 user 1 802 tok/s vLLM: 346 tok/s 2.32×
Qwen3.5-0.8B · 8 users 1 2,765 tok/s llama.cpp: 683 tok/s 4.05×
Qwen3.5-4B · 100 users 1 5,345 tok/s vLLM: 4,481 tok/s 1.19×
GLM-5.3-Flash · 16 users 8 292.9 tok/s llama.cpp: 41.9 tok/s 7.0×

Responsiveness matters, too. At 100 users, Qwen3.5-4B delivers 40 ms median time to first token, versus 230 ms for vLLM. At 16 users, GLM-5.3-Flash delivers 1.59 seconds, versus 55.13 seconds for llama.cpp.

Training: more experiments per GPU-hour

53,900 training tokens/s on a single H100. 136,200 on four RTX 5090s.

Model Hardware Surogate Unsloth Throughput gain
Qwen3-0.6B 1× H100 80 GB 53,900 tok/s · BF16 21,300 tok/s · BF16 2.53×
Qwen3-0.6B 1× RTX 5090 32 GB 30,100 tok/s · BF16 22,100 tok/s · BF16 1.36×
Qwen3-8B 1× RTX 5090 32 GB 6,900 tok/s · FP4 3,500 tok/s · BF16 1.97×

Need more throughput? Qwen3-0.6B FP4 LoRA scales from 36,400 tok/s on one RTX 5090 to 136,200 tok/s on four: 3.74× aggregate throughput. Qwen3-8B reaches 27,100 tok/s on the same four-card setup.

Every model and GPU we have measured

Each comparison ran both engines on the same kind of GPU with the same requests. A ratio above 1× favours Surogate. The rows where the other engine leads stay in the table.

Serving. Decode and prefill are tokens/s summed over all users, except where a row says "per user".

GPU Model · weights Load Surogate Other engine Ratio
RTX 5090 Qwen3.5-0.8B · GGUF Q4_K_M 1 user, decode 802 tok/s vLLM (NVFP4): 346 2.32×
RTX 5090 Qwen3.5-0.8B · GGUF Q4_K_M 8 users, decode 2,765 tok/s llama.cpp: 683 4.05×
RTX 5090 Qwen3.5-4B · NVFP4 1 user, decode 313 tok/s vLLM: 249 1.26×
RTX 5090 Qwen3.5-4B · NVFP4 100 users, decode 5,345 tok/s vLLM: 4,481 1.19×
RTX 5090 Qwen3.8-27B · NVFP4 1 user, decode 70.1 tok/s (107.3 with MTP on benchmark prose) vLLM: 71.6 0.98×
RTX 5090 Qwen3.8-27B · NVFP4 100 users, decode 1,321 tok/s vLLM: 1,109 1.19×
RTX 5090 Qwen3.8-27B · NVFP4 100 users, 2,048-token prompts, prefill 12,006 tok/s vLLM: 12,402 0.97×
RTX 5090 Qwen3.6-35B-A3B · NVFP4 100 users, decode 2,607 tok/s vLLM: 2,162 1.21×
RTX 5090 Qwen3.8-Flash-Next · GGUF, experts in host RAM 1 user, decode 35.2 tok/s llama.cpp: 20.8 1.69×
RTX 5090 Qwen3.8-Flash-Next · GGUF, experts in host RAM 16 users, decode 96.7 tok/s llama.cpp: 56.8 1.70×
8× RTX 5090 GLM-5.3-Flash · GGUF 16 users, decode 292.9 tok/s llama.cpp: 41.9 7.0×
H100 Qwen3-8B · FP8 1 user, decode 233.4 tok/s vLLM: 228.8 1.02×
H100 Qwen3-8B · FP8 16 users, decode per user 171.6 tok/s vLLM: 153.6 1.12×
H100 Qwen3-8B · FP8 64 users, decode per user 90.1 tok/s vLLM: 92.4 0.98×
H100 Qwen3-8B · FP8 32 users, 2,048-token prompts, prefill 52.5k tok/s vLLM: 55.1k 0.95×
H100 Qwen3-8B · FP8 same load, time to first token (p50) 661 ms vLLM: 325 ms 0.49×
H100 Qwen3.6-35B-A3B · FP8 1 user, decode 282 tok/s vLLM: 251 1.12×
H100 Qwen3.6-35B-A3B · FP8 64 users, decode 2,291 tok/s vLLM: 1,923 1.19×
H100 Qwen3.6-35B-A3B · FP8 32 users, 2,048-token prompts, prefill 35.7k tok/s vLLM: 39.5k 0.90×
H100 Qwen3.6-35B-A3B · FP8 32 agents, 6k shared system prompt, 8 turns 331 turns/min vLLM: 269 1.23×
H100 Qwen3.6-27B · FP8 64 users, decode 1,434 tok/s vLLM: 1,626 0.88×
DGX Spark Surogate3.7-35B-A3B · NVFP4 1 user, decode 70.4 tok/s vLLM: 60.8 1.16×
DGX Spark Surogate3.7-35B-A3B · NVFP4 8 users, decode 220.8 tok/s vLLM: 204.8 1.08×
DGX Spark Surogate3.7-35B-A3B · NVFP4 32 users, decode 473.6 tok/s vLLM: 406.4 1.17×
DGX Spark Surogate3.7-35B-A3B · NVFP4 8 users, 2,048-token prompts, prefill 6,042 tok/s vLLM: 5,069 1.19×
DGX Spark Surogate3.7-35B-A3B · NVFP4 cold 108k-token prompt, time to first token 22.2 s vLLM: 32.4 s 1.46×
DGX Spark Surogate3.7-35B-A3B · NVFP4 agents at 100k-200k context, warm-turn time to first token (p50), 1 / 8 agents 1.1 s / 1.9 s vLLM: 1.8 s / 7.6 s 1.62× / 4.02×
DGX Spark Surogate3.7-35B-A3B · NVFP4 8 agents at 100k-200k context, turns a minute 15.9 vLLM: 8.6 1.85×
DGX Spark Surogate3.7-35B-A3B · NVFP4 1M-token context with YaRN: cold prompt, then decode 946 s, 15.6 tok/s not measured —
DGX Spark Surogate3.7-35B-A3B · NVFP4 16 users, real text, MTP 444.7 tok/s (362.8 without MTP) not measured —
DGX Spark Qwen3-8B · FP8 1 user, decode 28.8 tok/s vLLM: 22.4 1.29×
DGX Spark Qwen3-8B · FP8 8 users, decode 182.4 tok/s vLLM: 153.6 1.19×
DGX Spark Qwen3-8B · FP8 32 users, decode 470.4 tok/s vLLM: 496.0 0.95×
DGX Spark Qwen3-8B · FP8 8 users, 2,048-token prompts, prefill 5,939 tok/s vLLM: 5,632 1.05×
DGX Spark Qwen3.8-27B · NVFP4 1 user, decode 13.0 tok/s vLLM: 11.4 1.14×
DGX Spark Qwen3.8-27B · NVFP4 32 users, decode per user 7.6 tok/s vLLM: 6.5 1.17×
DGX Spark Qwen3.8-27B · NVFP4 32 users, 512-token prompts, time to first token (p50) 839 ms vLLM: 1,785 ms 2.13×
DGX Spark Qwen3.8-27B · NVFP4 1 user, real text, MTP 29.1 tok/s vLLM (MTP): 18.6 1.56×
DGX Spark Qwen3.8-27B · NVFP4 8 users, real text, MTP 199.4 tok/s vLLM (MTP): 129.4 1.54×
DGX Spark Qwen3.8-27B · NVFP4 16 users, real text, MTP 279.9 tok/s vLLM (MTP): 188.3 1.49×
DGX Spark Gemma 4 12B · NVFP4 32 users, decode 483.2 tok/s vLLM: 409.6 1.18×
DGX Spark Gemma 4 31B · NVFP4 8 users, decode per user 7.7 tok/s vLLM: 6.1 1.26×
DGX Spark Gemma 4 31B · NVFP4 8 users, 2,048-token prompts, prefill 1,106 tok/s vLLM: 1,597 0.69×
DGX Spark Gemma 4 E4B · NVFP4 32 users, decode 972.8 tok/s vLLM: 976.0 1.00×
DGX Spark Gemma 3 12B · NVFP4 32 users, decode 480.0 tok/s vLLM: 406.4 1.18×
DGX Spark Gemma 4 26B-A4B · NVFP4, DFlash 32 users, decode 889.6 tok/s vLLM (DFlash): 889.6 1.00×
DGX Spark Gemma 4 26B-A4B · NVFP4 agents at 100k-200k context, warm-turn time to first token (p50), 1 / 4 agents 2.4 s / 3.5 s vLLM: 7.2 s / 8.4 s 3.03× / 2.41×
DGX Spark Qwen3.8-Flash-Next · NVFP4 1 user, decode 31.4 tok/s (with MTP: 45.9 on real text, 67.2 on benchmark prose) vLLM: does not fit in 121.7 GiB —
DGX Spark Qwen3.8-Flash-Next · NVFP4 16 users, real text, MTP 115.7 tok/s (97.2 without MTP) vLLM: does not fit —
DGX Spark Qwen3.8-Flash-Next · NVFP4 cold 32k-token prompt, prefill 2,008 tok/s llama.cpp (UD-IQ4_XS GGUF): 629 3.2×
DGX Spark EmbeddingGemma-300M · W8 16 clients, one text per request 2,442 texts/s vLLM (BF16): 510-562 4.3×
DGX Spark EmbeddingGemma-300M · W8 4 clients, 32 texts per request 814 texts/s vLLM (BF16): 745 1.09×

Also measured, without another engine alongside: single-user decode of Qwen3-0.6B at 685 tok/s and Qwen3.5-0.8B at 563 tok/s on an H100; Qwen3-0.6B at 220 tok/s, Qwen3.5-4B NVFP4 at 73 tok/s, Gemma 3 1B Q8_0 at 138 tok/s and Qwen3.6-27B NVFP4 at 12.0 tok/s on a DGX Spark, the last at the Spark's memory-bandwidth limit.

Training. LoRA, tokens/s.

GPU Model Surogate Unsloth Ratio
H100 80 GB Qwen3-0.6B 53,900 · BF16 21,300 · BF16 2.53×
H100 80 GB Qwen3-8B 11,600 · FP8 8,900 · BF16 1.30×
H100 80 GB Qwen3-14B 7,200 · FP8 5,600 · BF16 1.29×
RTX 5090 Qwen3-0.6B 30,100 · BF16 22,100 · BF16 1.36×
RTX 5090 Qwen3-8B 6,900 · FP4 3,500 · BF16 1.97×
4× RTX 5090 Qwen3-0.6B 136,200 · FP4 — —
4× RTX 5090 Qwen3-8B 27,100 · FP4 — —
DGX Spark Qwen3-0.6B ~7,100 · FP8 — —
DGX Spark Qwen3-8B 1,433 · FP8 — —
DGX Spark Qwen3.6-35B-A3B 674 · FP8 — —

RTX 5090 serving rows: 2026-08-30 to 2026-09-07, cards at a 400 W limit, vLLM 0.27.1 and llama.cpp CUDA builds. H100 and DGX Spark rows: 2026-10-05 to 2026-10-09, vLLM 0.31. On the DGX Spark, vLLM's FP8 KV cache fails to start, so vLLM ran a BF16 cache; Surogate ran a BF16 cache for the 35B's short-prompt rows and an FP8 cache for its long-context and MTP rows, for Flash-Next and for Qwen3.8-27B. Qwen3.8-Flash-Next's NVFP4 release needs 123.5 GiB in vLLM on a 121.7 GiB Spark; a public vLLM preview with MTP is reported at 31-41 tok/s for one user there (not measured here). Surogate's Flash-Next rows run the 105 GB artifact converted from that release, and its prefill row is against llama.cpp on Unsloth's UD-IQ4_XS GGUF. Benchmark prose is the repeated 512-token text the throughput rows use, where up to 95% of MTP drafts are accepted; "real text" means distinct Wikipedia passages, where 52-54% are. Full methods: serving benchmarks, training benchmarks, and the pull requests behind each result (#296-#309).

Two engines. One workflow.

Training engine

From raw text to specialized models, with Python configuration and native C++/CUDA execution.

Capability What you get
Pretraining & full fine-tuning Train from scratch, continue pretraining, or update the full model with SFT.
LoRA & QLoRA Adapter training with BF16 bases or FP8, NVFP4, and BnB/NF4 quantization; supported pre-quantized checkpoints and stacked LoRA adapters.
Native precision recipes BF16, hybrid FP8, and Blackwell NVFP4, with configurable model, gradient, and adapter precision.
GRPO reinforcement learning Reward environments, evaluation, and policy updates with native serving; shared-weight single-GPU BF16 LoRA across supported training families except Nemotron.
DPO preference training Learn from chosen/rejected pairs, with an inline frozen reference, optional length normalization, and differing-span masking.
Knowledge distillation Capture teacher top-K distributions, then train a student with KL divergence and optional cross-entropy.
Multi-GPU & multi-node Native threaded data parallelism, ZeRO sharding, communication overlap, and Ray for multi-node training.
Models beyond one GPU's capacity Dispatch pipeline parallelism streams frozen weights for LoRA across PCIe GPUs, including systems without NVLink or GPU-to-GPU P2P.
MoE training Expert parallelism, load balancing, routing metrics, and expert imbalance detection.
Memory control CPU offload for weights, gradients, optimizer state, activations, and quants; recomputation and tiled MLP execution for long contexts.
Multimodal fine-tuning Qwen3-VL and Qwen3.5 vision training examples, plus text-backbone training for supported multimodal checkpoints.
Optimizers & monitoring AdamW 8-bit, NorMuon, Weights & Biases, loss charts, checkpoints, and resume.
Adaptive training Phase detection, early stopping, learning-rate management, token budgeting, and dynamic epoch adjustment.
Extensible architectures Python DSL with ahead-of-time automatic differentiation, explicit graphs, and native kernel dispatch.

Explore training modes, precision recipes, memory management, GRPO, DPO, and distillation.

Serving engine

A native C++/CUDA HTTP server built for quick responses, concurrent workloads, and efficient model placement.

Capability What you get
Familiar APIs OpenAI-compatible Chat Completions, Completions, and Responses; Anthropic-compatible Messages. See the API guide for supported fields.
Streaming, reasoning & tools Streaming output, separate reasoning content, thinking controls, and model-specific function-call parsers.
Concurrent serving Continuous batching, chunked prompt processing, CUDA graphs, and up to 128 active sequences per model, with a configurable pending queue.
Prompt reuse Prefix caching and optional checkpoints for edited conversation turns.
Speculative decoding MTP, including supported multi-GPU models, and DFlash with a compatible drafter on a single GPU.
Native GGUF Supported K-quants, Q8_0, legacy and IQ formats; split-file loading and direct access to supported source weights.
Hugging Face checkpoints Repo IDs or local safetensors, with automatic preparation and caching; supported BF16, FP8, and NVFP4 exports.
KV memory on demand Elastic cache allocation, automatic capacity sizing, BF16/FP8 cache options, and shared spare cache memory across models.
Runtime LoRA Load and unload compatible PEFT adapters without restarting; select an adapter per request.
Several models on one GPU Named models, priorities, and optional sleep/wake to move idle models into system RAM.
Large models on available hardware Multi-GPU layer pipelines, CPU weight offload for every serving generation model, plus GPU expert caching and CPU/GPU expert compute sharing for every supported MoE family.
Vision & embeddings Images and video for supported vision models; EmbeddingGemma on GPU or AVX-512 CPU through a separate embeddings server.
Operations API-key authentication, health checks, Prometheus metrics, request logs, tokenization, and cache statistics.

Formats, LoRA, vision, speculation, and placement options depend on the model family. Multi-model hosting, sleep mode, and DFlash currently require one GPU. Serving guide → · CLI reference → · Deployment examples →

Supported models

Training and serving have different architecture coverage. Model dimensions come from the checkpoint; the examples below are representative sizes, with precision and memory requirements depending on the configuration.

Training

Family Representative models / sizes Examples or implementation
Qwen3 0.6B, 1.7B, 4B, 8B, 14B, 32B BF16, FP8, FP4 & QLoRA
Qwen3 MoE 30B-A3B, 235B-A22B MoE recipes
Qwen3-VL 2B, 4B, 8B, 32B Vision & text training
Qwen3.5 / Qwen3.6 dense 3.5: 0.8B, 2B, 4B, 9B, 27B; 3.6: 27B Text, vision & pipeline examples
Qwen3.5 / Qwen3.6 MoE 35B-A3B; 3.5 also 122B-A10B, 397B-A17B MoE recipes
Llama 3.1 / 3.2 3.1: 8B, 70B, 405B; 3.2: 1B, 3B Llama example
MiniCPM5 1B, 2B BF16 LoRA
Spark-X2.5 1.7B, 4B BF16 LoRA
Gemma 4 E2B, 12B, 26B-A4B; text backbones LoRA recipes
Nemotron 3 / Cascade 2 Nano 30B-A3B, Super 120B-A12B, Cascade 2 30B-A3B Nemotron recipes
GPT-OSS 20B, 120B; MXFP4 checkpoints use QLoRA GPT-OSS recipes
Laguna Laguna-S-2.1 FP8 LoRA
LFM2 / LFM2.5 LFM2: 350M, 700M, 1.2B, 2.6B; LFM2.5-350M example BF16 & FP8 LoRA

Additional architecture definitions include Gemma 3, LFM2-MoE, and LFM2-VL. Check their implementation and validation coverage before using a new checkpoint. DeepSeek-V4, Flash-Next, and GLM-5.3-Flash training definitions still have deferred components and are not listed as ready-to-train models.

Serving

Family Coverage
Qwen3 / Qwen3 MoE Dense and mixture-of-experts text models.
Qwen3.5 / Qwen3.6 / Qwen3.8 Dense hybrid models, including supported BF16, FP8, and NVFP4 exports.
Qwen3.5 / Qwen3.6 MoE Including 35B-A3B; optional speculative decoding with compatible draft weights.
Qwen3.8 Flash-Next GGUF and NVIDIA's NVFP4 release, MTP, CPU offload, GPU expert caching, and multiple GPUs.
GLM-5.3-Flash GGUF, CPU/GPU expert compute, multiple GPUs, and MTP.
Llama Llama-family text models, including TinyLlama.
Gemma 3 / Gemma 4 Text generation; Gemma 4 dense, E-series, and MoE variants.
LFM2 / LFM2.5 Dense text models from safetensors or GGUF.
MiniCPM5 Safetensors and GGUF, with thinking controls.
Spark-X2.5 1.7B and 4B safetensors, thinking controls, and spark25 tool parsing; runtime LoRA is not yet supported.
EmbeddingGemma 300M Embeddings on NVIDIA GPU or AVX-512 CPU.

For per-family format support, conversion behavior, and hardware details, see the serving model guide.

Quickstart

Install

Use Linux x86_64 and Python 3.12 with a supported NVIDIA GPU and CUDA 13 (driver 580 or newer), or a DGX Spark (GB10, Linux aarch64). See hardware for the separate training and serving GPU targets.

curl -LsSf https://github.com/invergent-ai/surogate/releases/latest/download/install.sh | bash
source .venv/bin/activate

The installer verifies the install and downloads the example configurations. The wheel is also installable on its own, with no index flags — every dependency resolves from PyPI:

pip install https://github.com/invergent-ai/surogate/releases/latest/download/surogate-+cu130-cp312-abi3-manylinux_2_39_x86_64.whl

On a DGX Spark the installer picks the manylinux_2_39_aarch64 wheel, built for GB10 only.

There is no CUDA 12 package. The serving engine's W8 and NVFP4 kernels declare more shared memory per block than a CUDA 12 toolkit will assemble for the RTX line, so CUDA 13.0 is the floor for building it, and a package that serves is the product. The engine carries its own FFmpeg, numa and ICU; it expects the system's glib and X11 client libraries, which a minimal server image may lack (Ubuntu: libglib2.0-0t64 libx11-6 libxext6 libxrender1). The installer checks.

Serve a model

surogate serve Qwen/Qwen3.5-0.8B \
  --served-model-name surogate \
  --port 8080 --max-model-len 4096 \
  --max-num-seqs 16 --kv-capacity auto

The first launch prepares and caches the checkpoint. Later launches reuse that preparation. You can also pass a local safetensors directory or a supported .gguf file.

Send a streaming request from another terminal:

curl -N http://127.0.0.1:8080/v1/chat/completions \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "surogate",
    "messages": [{"role": "user", "content": "Explain why low latency matters."}],
    "max_tokens": 256,
    "stream": true
  }'

Point existing OpenAI-compatible clients at http://127.0.0.1:8080/v1. To try a Blackwell NVFP4 checkpoint, use a supported export such as nvidia/Qwen3.6-27B-NVFP4. More serving examples →

Train an adapter

Save this as train.yaml:

model: Qwen/Qwen3-0.6B
output_dir: ./output

recipe: bf16                  # fp8-hybrid for FP8; nvfp4 for Blackwell FP4
lora: true
lora_rank: 16
lora_alpha: 32
lora_target_modules: [q_proj, k_proj, v_proj, o_proj, gate_proj, up_proj, down_proj]

sequence_len: 2048
sample_packing: true
per_device_train_batch_size: 2
gradient_accumulation_steps: 4
learning_rate: 2e-4
max_steps: 100
save_steps: 50

datasets:
  - path: mlabonne/FineTome-100k
    type: auto
surogate sft train.yaml

Choose a precision recipe for your GPU, or start with the checked-in training examples. For memory-constrained runs, see QLoRA and CPU offloading.

Serve what you trained

The completed training run exports its final adapter directly to output/. Merge it into its base model, then start the server:

surogate merge \
  --base-model Qwen/Qwen3-0.6B \
  --checkpoint-dir output \
  --output merged

surogate serve merged --served-model-name my-finetune --port 8080

Use "model": "my-finetune" in requests. To create a quantized GGUF for serving:

surogate quantize --model merged --output merged-Q4_K_M.gguf --type q4_k_m
surogate serve merged-Q4_K_M.gguf --served-model-name my-finetune

Run one server at a time on the same port. Compatible adapters can also be loaded at runtime with --enable-lora.

Run GRPO on one GPU

Load the base model once for both serving and training. Native co-locate mode supports BF16 safetensors models with LoRA for text rollouts across the supported training families, excluding Nemotron. Dense Qwen3 and Qwen3.5 use optimized serving; other families reuse the training model for generation and recompute the prefix per token, which is slower. MoE models require lora_dtype: bf16, and the entire base must fit on one GPU. It generates a batch of rollouts, pauses generation for the training update, then generates the next batch with the updated adapter. Per-step adapter updates stay in GPU memory.

Create the three configuration files from the Single-GPU GRPO guide, using backend: surogate for inference and a fresh output directory:

CUDA_VISIBLE_DEVICES=0 surogate grpo-colocate \
  --train train.yaml --infer infer.yaml --orch orch.yaml

Training buffers remain reserved during generation, so choose a model and context length that fit your GPU. Quantized bases, multiple GPUs, and checkpoint resume are not yet supported in this native mode. See the GRPO guide for the separate-GPU runner.

Docker and source builds

The container is ghcr.io/invergent-ai/surogate:latest (also tagged latest-cu130 and by release version).

# From the directory containing train.yaml; output stays in ./output on the host.
docker run --gpus all --rm \
  -v "$PWD:/workspace" -w /workspace \
  ghcr.io/invergent-ai/surogate:latest-cu130 sft train.yaml

For development, clone the repository and install with a CUDA toolkit, NCCL development libraries, and FFmpeg/libcurl development packages for serving. See CMake for the full build configuration:

git clone https://github.com/invergent-ai/surogate.git
cd surogate
uv venv --python 3.12
source .venv/bin/activate
uv pip install -e .

make serve-build rebuilds the serving engine in a source checkout. Installation details →

Why it is fast

  • Compiled training graphs. A Python DSL defines the model; ahead-of-time autodiff produces its backward graph so the native runtime can plan execution and memory across both passes.
  • Kernels that do more per launch. Fused operations, specialized matrix multiplication, low-precision tensor cores, and CUDA graphs reduce dispatch overhead and memory traffic.
  • Serving that keeps work moving. Continuous batching, chunked prefill, prefix reuse, and speculative decoding improve throughput and latency for different request patterns.
  • Memory treated as part of the engine. Planned buffer reuse, asynchronous offload, elastic KV caches, and expert placement make more of the available GPU and system memory useful.

Read how training works, the DSL guide, or the serving benchmark analysis.

Hardware

Component Current requirements / targets
Platform Linux x86_64, and Linux aarch64 for DGX Spark (GB10); the published wheels target Python 3.12 and CUDA 13 (driver 580+).
Training SM89+ in the current build: Ada (RTX 40 series, L4/L40), Hopper (H100/H200), and supported Blackwell targets, including GB10 (SM121, DGX Spark).
FP8 / NVFP4 training FP8 requires SM89+; native NVFP4 requires a supported Blackwell GPU and matching build.
Generative serving Default x86_64 builds target Ada (SM89: RTX 40 series, L4/L40), Hopper (SM90a: H100/H200) and RTX Blackwell (SM120a: RTX 50 series, RTX PRO); aarch64 builds target GB10 (SM121a: DGX Spark). NVFP4 checkpoints need SM120 or SM121.
CPU embeddings AVX-512 CPU; generative serving still requires a GPU when using CPU offload.
Multi-GPU / offload NCCL for distributed training; sufficient system RAM for offloaded weights and state. Dispatch-PP supports PCIe systems without NVLink.

The training and serving engines have separate CUDA build targets. Check the build configuration when targeting a GPU beyond the default serving build.

Explore and contribute

Start here Go deeper
Training examples Configuration reference
Serving examples API reference
Pretraining Multi-GPU · Multi-node · Dispatch-PP
GRPO · DPO RL environments · Distillation
Training benchmarks Serving benchmarks · Benchmark tools

Contributions are welcome: model support, kernels, precision recipes, benchmarks, documentation, and bug fixes. Include the problem, how to reproduce or validate the change, and any GPU or architecture assumptions in your pull request. Open an issue or send a PR.

Apache 2.0 · License · Built by Invergent

Nearby in the ranking
Similar items