Qwen3.6-35B-A3B-Escha-W2 — 2-bit quantized (eschamoe)

By Escha Labs Inc.

Escha-W2 is a 2-bit quantized build of Qwen3.6-35B-A3B, a Mixture-of-Experts model with 256 experts, packaged with everything needed to serve it locally through an OpenAI-compatible HTTP API. (The runtime and served model id keep the escha name — see Connecting a client.)

The whole thing is 12.3 GB on disk and runs on a single 24 GB consumer GPU — or on a 16 GB card (e.g. RTX 5060 Ti), where you trade concurrency or context, not both[^ctxcap].

Base model Qwen3.6-35B-A3B (MoE, 256 experts)
Quantization 2-bit experts (eschamoe; mixed 2/3-bit per projection), int8 dense layers
Size on disk 12.3 GB
Minimum GPU 16 GB VRAM (fewer concurrent streams, or less context — your choice[^ctxcap]), 24 GB recommended; NVIDIA Ampere (sm_80) → Blackwell (sm_120)
Platform Linux x86-64, glibc ≥ 2.28 (Ubuntu 20.04+, RHEL/Rocky/Alma 8+) — the wheel is manylinux_2_28
CUDA an NVIDIA driver — no CUDA toolkit needed (ptxas ships inside triton, a PyTorch dependency)
Python 3.12, for the SGLang engine — the ZML engine needs no Python at all
Interface OpenAI-compatible /v1 on port 30000

Contents

Path What it is
*.safetensors, config.json, tokenizer*, vocab.json, merges.txt, *.jinja the quantized weights, tokenizer and config (at the repo root)
opencode.json example client config (see Connecting a client)
LICENSE, THIRD_PARTY_LICENSES/ Apache-2.0 plus the upstream license texts

This repo holds only the model. The runtimes live in a separate repo, EschaLabs/escha-runtime-qwen3moe, one directory per engine: sglang/ (the escha wheel + serve.sh — servers, concurrency, tools, structured output) and zml/ (a single-binary runtime — no Python, no dependencies, and the stronger single-user decode on most cards).

Which engine?

Use sglang/ unless you have a specific reason not to. It is the engine every number on this page was measured with, and the only one that supports concurrency, tool calling, structured output and a reasoning parser.

Choose zml/ when you want a single-user box with no Python at all — one binary, no venv, no CUDA toolkit, 14-second install — and you generate long answers. It is the only way to run this model without a Python environment.

Two things decide whether that trade is worth it on your box:

  • The decode lead is card-dependent. On answers ≥1k tokens, measured 2026-07-27: +15–26% on an RTX 5090 or 3090, +8–11% on a 5080, +2–5% on a 4090 (against a fully tuned SGLang), and a tie on a 5060 Ti. ZML loses short replies on every card, and its first start compiles graphs — 75–145 s on a 4090, minutes on a 16 GB card, versus ~33 s for SGLang.
  • The lead is greedy-only. ZML's fast path fuses 16 decode steps per GPU dispatch with on-device argmax; any temperature > 0 falls back to a per-token loop that is ~2.15× slower (RTX 4090, 512-token answer: 218 tok/s at temperature: 0 vs 102 at 0.6). Send "temperature": 0 for the quoted numbers — including with opencode.json below, which sets 0.6. The SGLang engine samples at full speed.

ZML needs the 24 GB it asks for. On 16 GB cards long prompts fail with an opaque HTTP 500 — measured from ≥2,048 tokens on a 5080 and from ~700 on a 5060 Ti. Use the SGLang engine on 16 GB.


Quickstart

Install the Escha runtime first (wheel + serve.sh + full detail, including two requirements that fail quietly) — then download this model and serve it:

python3.12 -m venv .venv && source .venv/bin/activate
pip install -U pip wheel "huggingface_hub[cli]"

# torch MUST be pinned to 2.9.x. `escha._C` is ABI-linked to libtorch and the wheel does
# NOT declare a torch dependency, so a bare ">=2.9.0" resolves to 2.11 and `import escha`
# then fails with `undefined symbol: _ZN3c10...` — after two multi-GB downloads.
pip install "torch==2.9.*" --index-url https://download.pytorch.org/whl/cu128

# 1. runtime: fetch the sglang/ engine dir (wheel + serve.sh), install the wheel.
#    Use the glob — a pinned wheel filename goes stale on every rebuild.
hf download EschaLabs/escha-runtime-qwen3moe --include "sglang/*" --local-dir .
pip install ./sglang/escha-*.whl     # pulls transformers>=5.8 + the full dep closure

# 2. this model:
hf download EschaLabs/Qwen3.6-35B-A3B-Escha-W2 --local-dir ./escha-w2

MODEL=./escha-w2 bash sglang/serve.sh

Sanity-check the stack before serving — the first line must print three Trues:

python -c "import torch, escha, sglang; print(torch.cuda.is_available(), hasattr(torch.ops.escha, 'escham_moe_linear'), bool(sglang.__version__))"
python -c "import escha; print(escha.__version__)"     # paste this into bug reports

Then:

curl -s http://127.0.0.1:30000/v1/models | python3 -m json.tool

If generation looks like fluent nonsense, check your transformers version first. Below 5.8 the server does not fail — it logs one warning and then serves with the wrong architecture parameters. This is the single most likely cause of bad output.


Connecting a client

The server speaks the standard OpenAI API, so anything that can point at a custom base URL works — LM Studio, opencode, Open WebUI, the openai Python package, plain curl.

Base URL : http://127.0.0.1:30000/v1
Model    : escha-qwen36-35b-a3b-w2      (override with SERVED_NAME=...)
API key  : not required for localhost

opencode.json in this folder is a ready-made config for opencode — copy it to ~/.config/opencode/opencode.json. It sets temperature: 0.6 (Qwen's recommended sampling for answer quality); on the ZML engine that halves decode speed — set 0 there if you want the headline throughput instead.

If you expose the server beyond your own machine, set HOST=0.0.0.0 and API_KEY=..., and put it behind a VPN or tunnel rather than opening the port directly to the internet.


Thinking mode

The model can reason before answering. Toggle it per request via chat_template_kwargs — a top-level enable_thinking field is ignored:

{
  "model": "escha-qwen36-35b-a3b-w2",
  "messages": [{"role": "user", "content": "..."}],
  "chat_template_kwargs": {"enable_thinking": true}
}

With thinking on, the reasoning arrives in reasoning_content and the answer in content — read both. To turn thinking off for the whole server instead, start it with THINK=0.

usage.reasoning_tokens reports how much of the answer went to reasoning — use it to size a thinking budget.


Tuning

serve.sh documents every knob at the top of the file. The ones that matter most on a 24 GB card:

Variable Default Notes
MEM 0.78 Fraction of VRAM reserved for the weight + KV pool. Too low fails, with "Not enough memory … increase --mem-fraction-static". Lower it only together with CTXLEN.
CTXLEN 32768 Context length. Raise once the defaults work.
GRAPHS 1 CUDA graphs — mandatory for performance on this launch-bound hybrid MoE (eager is ~4.4× slower). Set 0 only to debug a capture failure.
RADIX 1 Prefix caching. RADIX=0 is worth ~20% single-stream decode here — the default is 1 for multi-turn agent reuse, so set it explicitly. See below.
THINK 1 0 serves with thinking disabled by default.
SERVED_NAME escha-qwen36-35b-a3b-w2 The model id clients must use.

For per-architecture (incl. the RTX 50-series ATTN_BACKEND=triton knob) and per-VRAM (16 / 24 / 40 GB+) launch recipes, see the runtime's "Running on your GPU" cookbook.


Verified configurations

Each command below was run on 2026-07-27 on the first card named in its heading, and produced the numbers in Performance across GPUs; a second name is a same-arch, same-VRAM sibling the recipe should carry to, not a separately measured card. Copy the line for your card. MODEL= and VENV= are omitted for brevity — set MODEL to your download directory.

RTX 4090 / L40S — 24 GB, sm_89

RADIX=0 MAXMAMBA=32 MAXREQ=32 CUDA_GRAPH_BS="1 2 4 8 16 32" \
  MEM=0.78 CTXLEN=32768 bash sglang/serve.sh          # 225 tok/s bs1 · 1,321 tok/s @ bs32

RTX 3090 / A6000 — 24 GB, sm_86 (Ampere)

RADIX=0 MAXMAMBA=16 MAXREQ=16 CUDA_GRAPH_BS="1 2 4 8 16" \
  MEM=0.78 CTXLEN=32768 bash sglang/serve.sh          # 154 tok/s bs1 · 390 tok/s @ bs16
# serving ≥8 concurrent streams? add INT8=off  (+12–20% aggregate, costs 2.2 GB of KV pool)

RTX 5090 — 32 GB, sm_120

# single user (best latency)
INT8=on ATTN_BACKEND=triton MEM=0.82 CTXLEN=32768 bash sglang/serve.sh    # 283 tok/s bs1
# batched (best throughput)
ATTN_BACKEND=triton MEM=0.82 CTXLEN=32768 MAXREQ=32 MAXMAMBA=48 RADIX=0 \
  CUDA_GRAPH_BS="1 2 4 8 16 32" bash sglang/serve.sh                      # ~2,670 tok/s @ bs32

RTX 5080 / 5060 Ti — 16 GB, sm_120

# many streams, short context — 16 concurrent 8k conversations
ATTN_BACKEND=triton MEM=0.92 CTXLEN=8192 CHUNK=2048 MAXREQ=16 MAXMAMBA=16 \
  RADIX=0 GRAPHS=1 CUDA_GRAPH_BS="1 2 4 8 16" bash sglang/serve.sh
# 5080: 212 tok/s bs1 · 914 tok/s @ bs16   |   5060 Ti: 128 tok/s bs1 · 387 tok/s @ bs16

# one stream, full context — the SAME pool spent on 32k instead of 16×8k
ATTN_BACKEND=triton MEM=0.92 CTXLEN=32768 CHUNK=2048 MAXREQ=2 MAXMAMBA=2 \
  RADIX=0 GRAPHS=1 CUDA_GRAPH_BS="1 2" bash sglang/serve.sh

8k is the recipe's per-request cap, not the card's ceiling[^ctxcap] — context and concurrency draw on one shared KV pool, so a 16 GB card gives up one or the other, and which one is your call.

Three settings that are worth getting right

  • CUDA_GRAPH_BS must list your maximum batch size. If MAXREQ=16 but the capture list stops at 8, batch 16 silently runs eager — measured −8.8% aggregate on a 5060 Ti, and it makes batch 16 look like a throughput ceiling when it is not. Costs ~2.5 s of startup and no VRAM.
  • MEM=0.92, not higher, on a 16 GB card. At 0.94 a 16 GB card has ~0.43 GB of headroom and a 1024/1024 batch-16 request can OOM inside the fused MoE op and take the whole server down. 0.92 survives it and costs nothing in throughput.
  • RADIX=0 unless you specifically need prefix caching. On this hybrid model the radix cache is incompatible with the overlap scheduler, so RADIX=1 silently disables it — worth ~20% single-stream decode (measured 187 → 225 tok/s on a 4090) and it also clamps concurrency via the mamba state pool. Keep RADIX=1 only for multi-turn agent workloads that genuinely reuse long prefixes.

This checkpoint is text-only (the qwen3_5_moe config declares a vision tower, but the quantized weights contain none — vision is in the quant ignore list); serve.sh sets SGLANG_VLM_TEXT_ONLY=1 by default so the tower is never instantiated. Do not send image inputs.


Requirements in detail

  • GPU16 GB VRAM minimum (fewer streams or less context, your choice[^ctxcap]; e.g. RTX 5060 Ti), 24 GB recommended; NVIDIA Ampere (sm_80) through Blackwell (sm_120). The runtime ships a fat binary with native kernels for Ampere (sm_80/86), Ada (sm_89), Hopper (sm_90), and Blackwell (sm_100/sm_120), plus PTX for forward-compat on newer GPUs. The kernel launch route is auto-selected per GPU at runtime. Cards older than sm_80 (e.g. Turing) are not supported.
  • An NVIDIA driver — but no CUDA toolkit. ptxas ships inside triton, which PyTorch already installs, and serve.sh probes that copy first; you do not need to install CUDA to serve this model. If discovery ever fails, point TRITON_PTXAS_PATH at a ptxas binary (not its directory — a directory is silently rejected).
  • Linux x86-64 with glibc ≥ 2.28 — the wheel is tagged manylinux_2_28, so Ubuntu 20.04+ and RHEL/Rocky/Alma 8+ are fine. WSL2 is untested.
  • vm.overcommit_memory=1 — on a fresh machine the first Triton compile forks a large process and fails under the default setting. serve.sh prints the one-line fix if it detects this.
  • transformers >= 5.8 — ignore this file's transformers_version for pinning. The runtime wheel installs a compatible transformers for you. Do not pin transformers to "match" any version field you find in the repo's config.json — versions below 5.8 lack this architecture's config class and serve fluent-looking nonsense with only a single warning.

Format notes

  • escha_s_in / escha_s_out ship as all-ones: the trained scales are already folded into escha_rin / escha_rout at export. Do not edit or "re-apply" them — non-ones values would be applied on top of the folded scales.
  • escha_config (int32[9]) and quantization_config.layer_meta are informational (written by the exporter for offline tools). The runtime derives each projection's code rate from the code tensor's shape; layer_meta records it as K (2 for gate_up_proj, 3 for down_proj) with bits mirroring K.
  • The mtp.* tensors (next-token-prediction head) are present in the checkpoint but not served; speculative decoding additionally needs a separate draft export that is not part of this release.

Benchmarks

Two questions matter for a 2-bit build: how much quality did it cost, and how does it serve. Quality is measured against an FP8 baseline[^fp8]; serving is measured on a single RTX 4090.

Which runtime produced these numbers. Every figure on this page — quality and serving — was measured through the SGLang engine of the escha-runtime-qwen3moe repo, using its shipped serve.sh and the launch recipes in sglang/INSTALL.md. The same repo also ships a ZML engine (single-binary, no Python) whose serving profile differs: higher sustained single-stream decode on long answers, but one request at a time — so none of the batched throughput or concurrency figures below apply to it. Pick the engine from the runtime README comparison.

Quality vs FP8

Commonsense-6[^cs6] — thinking-off, same box, paired:

GB boolq piqa arc-e arc-c hellaswag winogrande avg
FP8 baseline 35.0 84.46 82.59 71.93 54.86 83.38 73.40 75.10
this build 12.3 88.38 82.10 73.82 55.38 82.44 74.27 76.06

Capabilities — one representative benchmark per axis, this build vs the FP8 baseline. Retention is this-build ÷ FP8.

Capability Benchmark FP8 this build Δ retention
Broad knowledge MMLU-Pro (n=12,032) 82.3 80.9 −1.4 98.3%
Math reasoning MATH-500 (n=500)[^math] 91.2 93.8 +2.6 102.9%
Graduate science GPQA-Diamond (n=198)[^gpqa] 74.7 77.8 +3.1 104.2%
Coding LiveCodeBench v6 (n=182)[^lcb] 67.0 62.6 −4.4 93.4%
Tool use BFCL-AST, weighted (n=1000)[^bfcl] 88.2 88.9 +0.7 100.8%
Long context RULER, 8k–128k avg[^ruler] 89.4 89.9 +0.5 100.5%
mean[^avg] unweighted, 6 axes 82.1 82.3 +0.2 100.2%

Across the six axes this 2-bit build stays within noise of the ~3× larger FP8 baseline everywhere except long-horizon code generation (LiveCodeBench), the one capacity-bound gap. Coding parity is corroborated by two better-powered paired-McNemar ties with FP8: HumanEval+ 92.07 vs 93.9 and CRUXEval-O 61.75 vs 63.0.[^code]

Evaluation protocol (reproduce these numbers)

Thinking mode and the token budget change reasoning scores materially, so both are stated per benchmark. Both arms (this build and FP8) always ran the identical protocol, so every Δ above is apples-to-apples.

Benchmark Thinking Token budget Notes
MMLU-Pro on, 5-shot CoT chat max_tokens 4,096 13.9% of answers hit the cap (FP8: 13.0% — symmetric). See the caveat below.
MATH-500 on + thinking-budget cap budget 28,672 / max_tokens 32,768 Cap forces </think>0 non-terminations.
GPQA-Diamond on, uncapped thinking 16,384
LiveCodeBench v6 on + thinking-budget cap budget 16,384 / max_tokens 32,768
HumanEval+, MBPP+, CRUXEval-O off 4,096 Thinking-on derails code extraction.
BFCL-AST, Commonsense-6 off 4,096 / loglikelihood
RULER 8k–128k off retrieval

Sampling for the thinking-on runs is Qwen's recommended thinking config: temperature=1.0, top_p=0.95, top_k=20, min_p=0, presence_penalty=1.5, n=1.

Caveat on the MMLU-Pro number (read if you are comparing to published leaderboards). At a 4,096-token cap with thinking on, 13.9% of questions run out of budget mid-reasoning; those are scored from the truncated trace and land at 49.5% correct versus 86.0% for answers that finish. FP8 truncates at the same rate (13.0%), so the −1.4 gap is unaffected — but both absolute numbers are conservative by roughly 2–3 pp against harnesses that allow a larger budget (this is the main reason our FP8 baseline reads 82.3 where Qwen publishes 85.2 for the unquantized model). If you re-run with a bigger budget — or better, with the thinking-budget cap that forces an answer — expect both arms to rise by a similar margin.

Performance across GPUs

Measured end-to-end on five consumer cards with the SGLang engine (sglang/; launch recipes per card in the runtime cookbook). Decode = what one user sees streaming; peak throughput = total server output at the best batch size.

GPU VRAM arch 1-user decode TTFT (2k prompt) peak server throughput ctx in recipe[^ctxcap]
RTX 5090 32 GB sm_120 283 tok/s[^int8on] 0.22 s ~2,670 tok/s @ bs 32 32k
RTX 4090 24 GB sm_89 225 tok/s 0.26 s 1,321 tok/s @ bs 32 32k
RTX 5080 16 GB sm_120 212 tok/s 0.18 s @1k 914 tok/s @ bs 16 8k × 16 streams
RTX 3090 24 GB sm_86 154 tok/s 0.63 s 390 tok/s @ bs 16 32k
RTX 5060 Ti 16 GB sm_120 128 tok/s 0.52 s @1k 387 tok/s @ bs 16 8k × 16 streams

Every row was measured on that physical card with the launch command in Verified configurations above — 2026-07-27, five independent fresh-machine evaluations, one harness.

For scale: fast reading is ~5 words/s (≈7 tok/s) — even the slowest card here decodes ~18× faster than you can read, and a 5090 serves a 32-user pool at interactive speed. Three levers matter on every card: CUDA graphs (GRAPHS=1, the default — this hybrid MoE is launch-bound eager, graphs are worth 4.4×), RADIX=0 for throughput/latency work (worth ~20% single-stream — see Verified configurations), and the INT8 knob (single-user vs batched).

Two things the spread above is not: it is not a VRAM ranking (the 16 GB 5080 beats the 24 GB 3090 by 38%), and it is not a generation ranking. It tracks memory bandwidth and SM count — this is a 2-bit model, so decode is bandwidth-bound at batch 1 and compute-bound at batch. Ampere (3090) is the slowest per stream and also the only card here where the kernel route auto-selects lovelace rather than blackwell.

[^int8on]: 5090 and 3090 single-user numbers use INT8=on (int8-as-stored; measured +21–24% at bs 1 on the 5090, +35–42% on the 3090). Peak-throughput numbers use INT8 off above 24 GB — int8 costs 11–52% at high batch, and the crossover is around concurrency 8 (measured on the 3090). Cards ≤ 24 GB auto-enable int8; if you serve ≥ 8 concurrent streams on a 24 GB card, set INT8=off explicitly.

[^ctxcap]: Every context figure on this page is the per-request cap in a shipped launch recipe, not a hardware limit. Context costs KV, and KV is shared across concurrent requests, so a card spends one pool on either many short streams or few long ones. The 16 GB recipe is tuned for 16 concurrent 8k streams out of a ~59k-token pool; lower MAXREQ/MAXMAMBA and the same card serves the model's full 32k window instead. Both 16 GB recipes, with their measured pool sizes, are in the runtime cookbook.

Serving — NVIDIA ISL/OSL grid, five GPUs

Single-stream decode tok/s by input/output shape, on the standard NVIDIA grid[^grid]. Five independent fresh-machine evaluations, one card each, 2026-07-27. A dash means that evaluator did not run that shape — the five chose overlapping but not identical grids, so the table is a union rather than a full matrix[^gridconv].

ISL / OSL 5090 32 GB 4090 24 GB 5080 16 GB 3090 24 GB 5060 Ti 16 GB
128 / 128 282.1 225.2 211.7 153.5 127.9
128 / 1024 275.9 126.5
128 / 2048 225.2 208.8 151.4
128 / 4096 224.0 201.1
500 / 2000 224.7 205.7
1000 / 1000 224.6 205.6
1000 / 2000 223.9 202.2
1024 / 128 270.6 125.1
1024 / 1024 266.2 148.0 124.0
1024 / 2048 223.9 202.1
2048 / 128 259.6 221.2 198.9 145.7
2048 / 2048 251.8 222.5 196.5 148.6
4096 / 128 117.4
4096 / 1024 116.5
5000 / 500 219.4 185.8
20000 / 2000 202.7

Single-stream decode barely moves with prompt length. From a 128-token prompt to a 2,048-token one it falls 11% on the 5090, 2% on the 4090, 7% on the 5080, 5% on the 3090; the 4090 still holds 90% of its short-prompt rate at a 20,000-token prompt. Decode is bandwidth-bound and the KV read is small next to the weights, so what you pay for a long prompt is TTFT, not tokens per second.

Under concurrency each card's peak, with the shape and recipe that produced it:

GPU peak aggregate at recipe
RTX 5090 3,017.6 tok/s 128/1024, 32 streams batched, INT8 off
RTX 4090 1,321 tok/s 128/128, 32 streams batched, INT8 off
RTX 5080 914.1 tok/s 128/128, 16 streams 16 GB recipe
RTX 3090 389.7 tok/s 128/2048, 16 streams INT8 on
RTX 5060 Ti 387.1 tok/s 128/1024, 16 streams INT8 off

The 4090 grid was also reproduced from scratch on a second 4090 following only these public docs: every bs-1 shape matched within 0.1–1.8%, including the 20,000-token cell to 0.1%.

Latency SLA — MLPerf-style Poisson arrivals, RTX 4090

Poisson arrivals[^sla] — 1000-in / 400-out, 100 requests per point, nearest-rank p99:

arrival rate TTFT p50 TTFT p99 TPOT p99 out tok/s Interactive Conversational
1.0 req/s 168 ms 433 ms 16.3 ms 445 PASS PASS
1.25 req/s 197 ms 1,073 ms 20.6 ms 550 fail PASS
1.5 req/s 304 ms 3,281 ms 20.6 ms 640 fail fail
2.0 req/s 5,947 ms 8,001 ms 20.5 ms 717 fail fail
12.0 req/s 21,454 ms 41,964 ms 19.8 ms 772 fail fail

Saturation is ~1.9 req/s (772 tok/s ÷ 400 output tokens). Past that, waits grow by ordinary queueing, not by any defect. Decode is never the limiter — TPOT keeps 2.4–45× headroom at every rate tested; the binding constraint is always TTFT/prefill[^tpot].

[^fp8]: FP8 is the baseline because it is the closest widely-available reference to full precision (it tracks BF16 on these tasks), and because BF16 for this model does not fit on a 24 GB card at all. FP8 itself needs ~35 GB, so the comparison is against a build that requires substantially more hardware than this one.

[^cs6]: Same box, same in-process harness for both arms, so backend differences cancel. The dense (non-expert) layers here are int8; that is lossless against an fp16-dense build of the same weights (boolq 88.38 vs 88.04), so the size saving costs nothing measurable.

[^math]: MATH-500 is served with a thinking-budget cap — the correct protocol for a reasoning model (0 non-terminations; uncapped, the model over-thinks and truncates, which the cap fixes without changing answer quality). Read the result as parity with FP8; the small margin is capping protocol, not a real quality gain.

[^gpqa]: GPQA-Diamond is run-to-run unstable by ±~5 pp at this sample size, so treat +3.1 as an effective tie with FP8, not a genuine lead.

[^lcb]: LiveCodeBench v6, release_v6 slice (contest dates 2025-01 onward, N=182) — a post-training-cutoff subset chosen to limit contamination. Both builds are scored on the same 182 problems, so read −4.4 as retention vs FP8, not a leaderboard score. Long-horizon code generation is the most capacity-sensitive task measured, and the one clear 2-bit gap.

[^bfcl]: BFCL-AST, matched same-driver run (thinking-off, n=1000, AST-weighted across the four non-live categories). Tool-call form is preserved at 2-bit — a tie with FP8.

[^ruler]: RULER (synthetic long-context retrieval), 4-task average across 8k / 32k / 64k / 128k. Near-lossless through 128k.

[^avg]: Unweighted mean of the six rows — a reading convenience, not a statistic to lean on. The axes have wildly different sample sizes (MMLU-Pro n=12,032 vs LiveCodeBench n=182) and different score scales, so the mean hides the one real gap (coding) behind gains elsewhere. Read the per-axis rows for anything that matters.

[^code]: Paired McNemar (exact two-sided) on identical prompts — per-item comparisons on full native sample sets. Both land on a statistical tie: HumanEval+ turns on just 7 disagreements (2 win / 5 loss of 164 — underpowered), CRUXEval-O is far better powered (64 disagreements) and still ties.

[^grid]: Measured with CUDA graphs on and a 16-request cap (GRAPHS=1 MAXREQ=16), prefix caching off (RADIX=0), and output length pinned so every cell decodes the full OSL. GRAPHS=1 and RADIX=0 are both required to reproduce these numbers; GRAPHS=1 is already the serve.sh default, RADIX=0 is not. Single-stream (bs 1) is flat at ~220 tok/s across shapes because decode is memory-bound, not compute-bound, at batch 1.

[^gridconv]: The five evaluators used their own harnesses, so the single-stream column is the one metric all five report identically (per-stream decode rate, equivalently 1000 / TPOT); it is quoted as measured, never derived. Their aggregate-throughput conventions do not match — two report a decode-window rate and three an end-to-end rate that amortizes prefill and batch ramp — which is why concurrency appears as each card's own peak with its recipe, rather than as extra columns here. Two caveats those peaks inherit: short-output cells at batch understate steady decode, because with only 128–500 output tokens the ramp in and out of the batch is a large share of wall time; and at very long inputs the KV pool cannot hold 16 concurrent requests, so some queue and the figure is pessimistic rather than a tuning miss.

[^sla]: MLPerf Server-style: Poisson arrivals (not synchronized bursts) and p99 rather than median — burst harnesses systematically misreport this workload. Thresholds are the MLPerf interactive categories: Interactive = TTFT p99 ≤ 450 ms and TPOT ≤ 40 ms; Conversational = ≤ 2000 ms and ≤ 200 ms.

[^tpot]: One caveat worth knowing before you turn thinking on: TTFT measures the first token generated, but with thinking enabled the first token a user sees comes after the reasoning block. On real problems that gap is large — first generated token in ~75 ms, first answer token at a median of ~15 s, and a long tail. Capping the thinking budget removes the runaway tail. If latency to a visible answer matters more than reasoning depth, serve with THINK=0.

Licenses and attribution

This repository contains model weights only, released under the Apache License, Version 2.0 (see LICENSE).

  • Model weights — a 2-bit quantized derivative of Qwen3.6-35B-A3B (Apache-2.0, Qwen); base license text at THIRD_PARTY_LICENSES/Qwen-LICENSE.txt.
  • Tokenizer — Qwen (Qwen2Tokenizer), Apache-2.0.
  • Chat template — from froggeric/Qwen-Fixed-Chat-Templates (Apache-2.0, inherited from Qwen), which fixes tool-calling and thinking-mode handling for this model family.

The runtime (the escha wheel: the SGLang serving fork + CUDA kernels, and their third-party licenses — SGLang, exllamav3, AQLM, and the BSD-3/MIT upstreams vendored in SGLang) is distributed separately and carries its own LICENSE + THIRD_PARTY_LICENSES/: EschaLabs/escha-runtime-qwen3moe. All bundled code there is permissive (Apache-2.0 / MIT / BSD-3-Clause) — no copyleft.

Downloads last month
599
Safetensors
Model size
7B params
Tensor type
F32
·
I32
·
F16
·
I16
·
I8
·
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support

Model tree for EschaLabs/Qwen3.6-35B-A3B-Escha-W2

Quantized
(671)
this model

Evaluation results