Views
No views yet
qwen3denseescha) quantized models of the qwen3_5 dense
architecture (Qwen3.8-27B and siblings). One repo per model architecture, one directory per
engine — this architecture currently has one engine, sglang/.SGLang — sglang/ | |
|---|---|
| Best for | everything: single user, teams, agents |
| Concurrency | continuous batching, paged KV, optional radix prefix cache |
| Tool calls / JSON schema / thinking parser | yes |
| Interface | OpenAI-compatible (/v1/chat/completions, /v1/completions, /v1/models) |
| Install | Python 3.12 venv + CUDA-12 PyTorch, then one wheel |
sglang install is needed, and none should be
present — the wheel ships its own.| Model repo | Bits |
|---|---|
| EschaLabs/Qwen3.8-27B-Escha-W2 | 2-bit, mixed-rate (escha) |
This runtime targets theqwen3_5dense architecture. Its wheel also happens to register theeschamoemixture-of-experts method, so aqwen3_5_moemodel will load too — but the tuning, the defaults insglang/serve.shand the documentation here are all written for the dense architecture. For a mixture-of-experts model useescha-runtime-qwen3moe, whose defaults are measured on it. A model of a genuinely different architecture will not load — use the matchingescha-runtime-<arch>repo.
sglang/INSTALL.md.1python3.12 -m venv .venv && source .venv/bin/activate
2pip install -U pip wheel
3pip install "torch==2.9.*" --index-url https://download.pytorch.org/whl/cu128 # cu12 torch FIRST
4pip install ./sglang/escha-*.whl # pulls the bundled sglang fork + its full dep closure
5
6hf download EschaLabs/Qwen3.8-27B-Escha-W2 --local-dir ./Qwen3.8-27B-Escha-W2
7MODEL=./Qwen3.8-27B-Escha-W2 bash sglang/serve.sh1python -c "import torch, escha, sglang; print(torch.cuda.is_available(), hasattr(torch.ops.escha, 'escham_decode_gemv'), escha.__version__)"
2curl -s http://127.0.0.1:30000/v1/models | python3 -m json.toolpip install "torch==2.9.*"is a hard pin, not a suggestion. A baretorch>=2.9resolves to a newer minor andimport eschathen fails withundefined symbol: _ZN3c10...— the compiled extension is ABI-linked to libtorch, and that ABI is not stable across PyTorch minors.
reasoning_content and the
answer in content — read both, or you will see half the response.chat_template_kwargs (a top-level enable_thinking field
is silently ignored):{ "chat_template_kwargs": {"enable_thinking": true, "reasoning_effort": "xhigh"} }reasoning_effort is "xhigh" (the default), "medium" or "low"; anything else makes the
template raise, which surfaces as an HTTP 400 rather than a silent fallback. It works by injecting
one sentence of system instruction — xhigh asks the model to validate assumptions and weigh
alternatives, low asks it to keep thinking brief, and medium injects nothing at all, so
medium is the neutral, unsteered model rather than a midpoint. It therefore asks for shorter
reasoning; it does not bound it. If you are running a benchmark
or an agent, set a thinking budget instead, which forces </think> after N reasoning tokens so
an answer is always produced: see
sglang/INSTALL.md → Bounded thinking and
sglang/thinking_budget.py. Without one, the usual failure is
finish_reason: "length" with content: null, which a harness scores as wrong rather than as
slow.sglang/INSTALL.md → Running on your GPU.cp312-only) + CUDA-12 PyTorch 2.9.x. The wheel handles every
other dependency.ptxas and from a CUDA toolkit, so "driver only"
does not cover it. On slim container images a stripped libisl breaks cc1 while
gcc --version still succeeds, and the failure surfaces ~40 s in as a gcc
CalledProcessError inside cuda_graph_runner.py — which reads like a runtime bug and is not.
Preflight in sglang/INSTALL.md.MAMBA_RATIO=0.3 sizes the recurrent-state pool, which clamps max_running_requests to
8–9 on a 24 GB card, so the 12/16 entries in the default CUDA_GRAPH_BS are dropped and
never captured. To serve more streams raise MAXREQ/MAXMAMBA with MEM — the throughput
recipe is in the
model card; for
long context (128k measured on a 24 GB card) see
By VRAM.
16 GB is now measured too, on an RTX 5060 Ti — ~30 tok/s single-stream, and far more context
than we had guessed: 110,592 tokens, with an fp8 KV cache doing most of that work. See
The 16 GB tier.--tp-size N) now works. The escha
parameter class pins its own weight loader, which meant sglang's TP slicing never ran and
every rank kept the whole checkpoint (rank 0 died with weight must have shape (dim, width)). It now slices per rank, including the fused-on-disk GDN in_proj_qkv,
which is split into its three sub-projections first.Single-GPU users are unaffected. Every new code path is gated onworld_size > 1; at--tp-size 1the loader is byte-for-byte what 1.1.1 did. Verified as an identical shard layout and byte-identical greedy output.TP > 1 is new and lightly tested — treat it as experimental. It was contributed and validated by @ginerJuanUdesa on 2× RTX 3090 (symmetric 6.02 GB/rank, coherent greedy output). We have one GPU and could not reproduce it, and no numerical equivalence check against--tp-size 1has been run yet. If you use it for evaluation, sanity-check a benchmark against the single-GPU numbers first. Note that a multi-rank all-reduce reorders float accumulation, so TP > 1 output is not expected to match TP = 1 bit-for-bit even when correct.On Ampere/Ada/Hopper you can addDETERMINISTIC=1to remove that reduction-order variance if you want a stricter comparison.
process_weights_after_loading now takes the rank's device
instead of a hardcoded cuda:0. The hardcode put every 2-bit buffer on cuda:0 while
the input tensor sat on the server's actual device, so any run not on device 0 —
--tp-size > 1, or a single-GPU launch with --base-gpu-id N and no
CUDA_VISIBLE_DEVICES — hit an illegal memory access on the first forward, behind a
traceback that pointed at the kernel rather than at the cause. Bit-identical wherever
cuda:0 was already correct, which is every configuration serve.sh ships. Reported
with a diagnosis and a fix by @ginerJuanUdesa.escha) serving path; the 1.0.x
wheels registered eschamoe only, so a dense checkpoint failed at registry lookup.ESCHA_ROUTE
resolves to lovelace on sm_80/sm_86, but forcing ESCHA_ROUTE=blackwell measured 1.72×
faster single-stream on an RTX 3090 (23.6 → 40.7 tok/s, TPOT 42.4 → 24.6 ms) with identical
output. The two routes are bit-identical launch geometries, so this is safe to set; the gain is
batch-1-only (parity at 2–16). Serving one user on Ampere? Set it.DETERMINISTIC=1 fails on consumer Blackwell (sm_120). The deterministic attention kernel
requests 104 KB of shared memory per block, above the sm_120 limit, and the server exits during
startup. It works on Ampere, Ada and Hopper.DETERMINISTIC=1 when you need
reproducibility, and never A/B two configurations by diffing one generation.torch.ops.escha.escham_decode_gemv_max_m()). The shipped default list stops at 16 because
that is where aggregate throughput peaks on a 4090; capture at 24/32 works and is worth it if
you serve that many streams. Past 32 a batch falls through to a large-M path meant for prefill,
so the runtime refuses to capture it rather than bake in the wrong kernel.ATTN_BACKEND=triton is required on consumer Blackwell (RTX 50-series). The default
flashinfer backend asserts on this hybrid architecture at sm_120. The assertion names three
acceptable backends — triton, trtllm_mha, fa4 — of which only triton has been run on
this model. Note that sm_120 shows steeper long-prompt decode decay than sm_89 (88.5% vs 96.3%
of short-prompt rate at a 5,000-token prompt); the attention path is the obvious suspect and
nobody has run the A/B that would confirm it.developer role. It accepts system, user,
assistant and tool; anything else raises Unexpected message role. and surfaces as an HTTP
400 from the template, not as a server fault. Several OpenAI-compatible agent harnesses send
role: "developer" for their system prompt and so fail every request — map it to system
client-side, or patch the template. The same template also raises on genuinely malformed
conversations (a missing user query, a system message in the wrong position) and on a
reasoning_effort outside xhigh/medium/low. All of this is the base model's own template,
carried over unmodified.NVRM: Xid ... 79, GPU has fallen off the bus four times out of four on an RTX 5060 Ti 16 GB, 12–18 minutes into a sustained
single-stream agent workload, and each time the card needed a full host power cycle — FLR,
secondary-bus reset and remove/rescan all reported success while the device stayed in D3cold. It
reproduced across two driver branches, two runtime versions, both KV dtypes and three context
lengths, in prefill and in decode alike. The card is passed through to a VM with vfio.gpu-burn, or a
different model on a stock runtime. This is the one test that settles it: if that also falls
off the bus, the runtime is not involved.nvidia-smi was sampled at 5 s, which cannot see the sub-millisecond
spikes that trip a PSU's over-current protection, so "166 W under a 180 W cap with no throttle
flags" does not rule power out. Log power.draw.instant and temperature.memory at 100 ms,
and check PSU headroom on the rail feeding the card.vfio-pci disable_idle_d3=1, and pcie_aspm=off pcie_port_pm=off on the host command line.LICENSE.
All bundled third-party code is permissive (Apache-2.0 / MIT / BSD-3-Clause) — no copyleft.
Full texts and the component inventory:
THIRD_PARTY_LICENSES/. Model weights are not in this repo and carry
their own license in the model repository.