Qwen3.8-27B → CMF — one file, one Rust binary, no Python
bash
1cargo install cortiq-cli # 0.5.76+2hf download infosave/Qwen3.8-27B-cmf qwen38-27b-q4t.cmf --local-dir .3cortiq run qwen38-27b-q4t.cmf --prompt "Explain quicksort in three sentences."
Qwen3.8-27B is a 27B hybrid:
48 GatedDeltaNet linear-attention layers and 16 full-attention layers,
262k context, thinking mode. This repo is that checkpoint converted to
the CMF container — a single
memory-mapped file read by cortiq, a Rust binary with no ML framework
under it. GPU via Vulkan/Metal/DX12 with a CPU fallback; NVIDIA, AMD,
Intel and Apple silicon run the same file.
file
bits
size
decode, RTX 5090
wikitext-2 ppl
qwen38-27b-q4tp.cmf
4-bit tiled, ladder scales
14.3 GB
48.7 tok/s plain · 76 tok/s greedy with speculative decode (66 with the bit-exact f32 verify)
8.79
qwen38-27b-q4t.cmf
4-bit tiled
15.4 GB
49.4 tok/s plain
8.86
qwen38-27b-q8_2f.cmf
8-bit
27.4 GB
33.0 tok/s
—
Steady-state decode over Vulkan, single stream, cortiq bench --core
on one harness (0.5.80, medians of runs), speculative rows on the
bench's own text; on a real prompt the gain depends on how well the
draft head agrees with the trunk — a 2.3k-token code prompt decodes at
56.5 tok/s against 45.7 plain, an essay sits at the plain rate because
the engine's monitor stops speculation where it does not pay.
Perplexity on the same twelve 512-token windows of wikitext-2. The
family is memory-bandwidth-bound, so the 4-bit files are not just
smaller — they decode ~1.5× faster than 8-bit.
q4tp keeps q4t's nibbles and stores each 32-weight tile's scale as
a rung on a per-row ladder: 7.5% fewer bytes at the same quality (its
perplexity is a hair lower), the file for a 16 GB card. Both 4-bit
files were quantized straight from the bf16 checkpoint, streamed shard
by shard from the hub — never one from the other. The two are the same
weights on two layouts; on this card the q4t decode kernel still
streams a little faster, so q4t is the plain-speed pick and q4tp the
size pick.
Speculative decode is on by default for greedy (--greedy, or a
server request with temperature: 0) on Vulkan graphs since 0.5.80:
the model's own MTP head drafts five tokens, one batched submit
verifies them on an int8-activation matvec, and a monitor keeps
averaging tokens-per-round against the plain token — it stops
speculation after four losing rounds (free prose often does not pay)
and retries later, so a prompt that gains keeps the gain and one that
does not sits at the plain rate. CMF_VERIFY_I8=0 switches the verify
to f32 (66 tok/s on the bench) and makes the greedy continuation
byte-identical to the plain path; the int8 default can resolve a
near-tie differently — a different but equally greedy continuation.
CMF_GRAPH_SPEC=0 disables speculation. Sampling (temperature > 0)
stays on the plain path — the speculative sampling arm exists
(CMF_GRAPH_SPEC_SAMPLE=1, exact by construction) but at the instruct
row 60% of drafts are accepted and the round breaks even.
Server and API
cortiq serve qwen38-27b-q4t.cmf --port 8080
The server speaks the OpenAI API, so anything that talks to OpenAI
talks to it:
/v1/chat/completions, /v1/completions and /v1/models are live;
--ollama additionally listens on an Ollama-compatible port for tools
that expect that shape. --host 127.0.0.1 keeps it local-only. A web
dashboard sits on the same port.
Which GPUs does Vulkan see?
cortiq gpu
Lists every adapter with its index, name, driver and memory budget, and
measures what a round trip to the device costs (an empty submit vs
submit+dispatch+readback — on a healthy setup that's microseconds).
If the list is empty on Linux, install the loader libraries and retry:
bash
1sudoaptinstall libvulkan1 libglvnd0 libegl1 libgl1 libglx0
2XDG_RUNTIME_DIR=/tmp cortiq gpu # headless boxes need the env
vulkaninfo --summary (from vulkan-tools) is the system-level cross
check. To pin cortiq to a specific card, set CMF_GPU_ADAPTER to the
index from cortiq gpu — or to a name substring:
bash
1CMF_GPU_ADAPTER=1 cortiq run qwen38-27b-q4t.cmf --prompt "..."2CMF_GPU_ADAPTER=5090 cortiq run qwen38-27b-q4t.cmf --prompt "..."
Two GPUs
One command:
cortiq run qwen38-27b-q4t.cmf --prompt "..." --gpus 2
It pins the coordinator to adapter 0, spawns a local cortiq worker
pinned to adapter 1, and splits the layer stack between them over
loopback (the same machinery as the network split, wire cost ~zero
locally). The log names both pins at startup — check it the first time:
two identical cards otherwise both answer "I am the best adapter" and
land on the same silicon, which runs but crawls.
--gpus v1 is exactly two cards. For more, chain explicitly — each
worker takes a layer span:
bash
1CMF_GPU_ADAPTER=1 cortiq worker qwen38-27b-q4t.cmf --listen 127.0.0.1:9911 --token S &2CMF_GPU_ADAPTER=0 cortiq run qwen38-27b-q4t.cmf --prompt "..."\3 --peer 127.0.0.1:9911 --net-token S --peer-split 32
For THROUGHPUT (many parallel requests rather than one fast stream),
prefer the server's replica mode instead:
cortiq serve qwen38-27b-q4t.cmf --gpus 2
When the model fits one card, each GPU runs a full replica and requests
decode in parallel; when it does not fit, the server switches to a
layer split. It prints which mode it chose and why.
--peer-split N picks the first layer the worker runs (default: half
the stack). --net-dtype f16 halves the wire bytes; f32 is
bit-exact. cortiq peers lists workers announcing themselves on the
local network — the beacon carries identity and geometry, never the
token.
macOS — Apple Silicon (Metal)
Since 0.5.79 the 27B runs on the Mac GPU out of the box — earlier
versions silently fell back to the CPU because the 14.4 GiB file
exceeds Metal's single-buffer cap (the engine now maps it as
overlapping windows).
cortiq run qwen38-27b-q4t.cmf --prompt "..." # no env vars needed
Measured on an M4 Mac mini, 24 GB unified memory:
tok/s
decode
5.8
prefill @ 2k context
20.8
CPU-only (pre-0.5.79)
3.7
For long context on a Mac, add the Metal O(1) mode: decode holds
~4.7 tok/s independent of depth and the attention state stays
fixed-size instead of growing with the KV cache:
CMF_O1_METAL=1 cortiq run qwen38-27b-q4t.cmf --o1 all --prompt "..."
q4t is the Mac build; q8_2f (27.4 GB) does not fit 24 GB machines.
Sampling
Qwen's recommended parameters for this release:
mode
temperature
top_p
top_k
presence_penalty
repetition_penalty
thinking
1.0
0.95
20
0.0
1.0
instruct (--no-think)
0.7
0.80
20
1.5
1.0
All six knobs are exposed since 0.5.77: --temperature, --top-p,
--top-k, --min-p, --presence-penalty, --rep-penalty. The
aquarium example below was generated with the instruct row verbatim.
One more setting that matters for LONG generations: CMF_MAX_SEQ. The
engine sizes its KV cache to 32768 by default (the model itself goes to
262144); when a generation crosses that ceiling the cache evicts half
and quality degrades — the log warns when it happens. Raise it if you
ask for very long outputs and have the memory:
CMF_MAX_SEQ=65536 cortiq run qwen38-27b-q4t.cmf --prompt "..." --max-tokens 50000
Example
Three one-shot generations from the same 7 KB Russian spec — a Three.js
aquarium with fish, bubbles and click-to-feed — same seed, official
instruct sampling, so the set doubles as a quant comparison. Download
and open in a browser:
Nyström O(1) attention replaces KV-cache attention on the flagged
layers: memory stays constant instead of growing with the context
(the 16 full-attention layers keep a fixed landmark skeleton; the 48
linear layers were O(1) already), and decode speed stays flat at any
depth.
bash
1# Vulkan / discrete GPUs (since 0.5.78), ~25 tok/s on an RTX 5090:2CMF_O1_GPU=1 cortiq run qwen38-27b-q4t.cmf --o1 all --prompt "..." --max-tokens 200034# Apple Silicon (since 0.5.79), ~4.7 tok/s on an M4 24 GB at any depth:5CMF_O1_METAL=1 cortiq run qwen38-27b-q4t.cmf --o1 all --prompt "..."
Parameters
flag
default
meaning
--o1 all|deepN|i,j,k|off
file hint
which full-attention layers switch to O(1): all, the deepest N (deep8), an explicit list, or force off. Overrides CMF_O1 and the converter hint
--o1-m
32
landmark budget — the far-field's rank. More = better long-range recall, 32 is the validated maximum the GPU kernels accept
--o1-window
128
exact sliding window: the most recent tokens attended exactly
--o1-sink
4
permanent exact keys at the sequence start (attention sinks)
Practical settings:
Defaults are the validated optimum — start with plain --o1 all.
The GPU kernels accept sink + window ≤ 196 and m ≤ 32; anything
larger falls back to the CPU step for those layers (it says so in
the log — run with RUST_LOG=info to see refusals).
Prompts shorter than window + sink + 8 skip the skeleton entirely
(exact attention — nothing to approximate yet).
The prefill runs on the CPU by design: it records the query trace
that seals the landmark skeleton after the prompt. First token of a
long prompt is slower; every token after is where this mode pays.
Where it wins: contexts past ~8k, memory-tight machines (24 GB Macs),
and any workload where decode must not degrade with depth. At short
contexts plain attention is equal or faster — O(1) already matches it
at 2k on an M4 (4.7 vs 4.2 tok/s).
Output is not bit-identical to full attention (it is an approximation
with an exact window); quality holds while the conversation fits the
window + landmarks regime the defaults were validated on.
Verify
bash
1sha256sum -c qwen38-27b-q4tp.cmf.sha256 # or -q4t / -q8_2f2cortiq info qwen38-27b-q4tp.cmf
Документация на русском
Одна модель — один файл .cmf, один Rust-бинарник cortiq, без Python:
bash
1cargo install cortiq-cli # 0.5.77+2hf download infosave/Qwen3.8-27B-cmf qwen38-27b-q4t.cmf --local-dir .3cortiq run qwen38-27b-q4t.cmf --prompt "Объясни квиксорт в трёх предложениях."
файл
биты
размер
декод, RTX 5090
ppl wikitext-2
qwen38-27b-q4tp.cmf
4, лестница масштабов
14.3 ГБ
48.7 tok/s · 76 tok/s greedy со спекуляцией (66 с побитово точной f32-проверкой)
8.79
qwen38-27b-q4t.cmf
4
15.4 ГБ
49.4 tok/s
8.86
qwen38-27b-q8_2f.cmf
8
27.4 ГБ
33.0 tok/s
—
Все числа — один стенд и один бенч (cortiq bench --core, 0.5.80,
медианы); спекулятивные — на тексте самого бенча, на реальном промпте
выигрыш зависит от согласия черновой головы с моделью: код на 2.3k
контекста — 56.5 против 45.7 tok/s, эссе идёт на скорости plain (монитор
сам останавливает спекуляцию там, где она не окупается). ppl на одних и
тех же 12 окнах по 512 токенов. Семейство упирается в пропускную
способность памяти, поэтому 4-битные файлы не только меньше — они и
декодируют в ~1.5× быстрее 8-битного.
q4tp хранит те же ниблы, что q4t, а масштаб каждой плитки из 32 весов —
как ступень на построчной лестнице: на 7.5% меньше байт при том же качестве
(ppl даже чуть ниже) — файл для карты на 16 ГБ. Оба 4-битных файла
квантованы прямо из bf16-чекпойнта (потоково с HF), не один из другого.
Спекулятивный декод включён по умолчанию для greedy (--greedy или
temperature: 0 в запросе к серверу) на Vulkan с 0.5.80: собственная
MTP-голова модели предлагает пять токенов, один батч-сабмит проверяет
их матвеком на int8-активациях, а монитор всё время сравнивает токены за
раунд с обычным токеном — после четырёх проигрышных раундов спекуляция
останавливается (проза часто не окупается) и позже пробуется снова, так
что промпт, который выигрывает, выигрыш сохраняет, а который нет — идёт
на скорости plain. CMF_VERIFY_I8=0 переводит проверку на f32 (66 tok/s
на бенче) и делает greedy-продолжение побитово идентичным обычному; int8
по умолчанию может иначе разрешить близкий тай-брейк — другое, но столь
же greedy продолжение. CMF_GRAPH_SPEC=0 отключает спекуляцию. Сэмплинг
(temperature > 0) идёт обычным путём (спекулятивный сэмплинг есть за
CMF_GRAPH_SPEC_SAMPLE=1, но на instruct-ряду принимается 60% черновиков
и раунд выходит в ноль).
Сервер с OpenAI-совместимым API:cortiq serve qwen38-27b-q4t.cmf --port 8080 — работают /v1/chat/completions, /v1/completions,
/v1/models; флаг --ollama добавляет Ollama-совместимый порт.
Какие карты видит Vulkan:cortiq gpu — список адаптеров с
индексами и цена круга до устройства. Пиновка: CMF_GPU_ADAPTER=индекс
или подстрока имени (CMF_GPU_ADAPTER=5090).
Две карты:cortiq run модель.cmf --prompt "..." --gpus 2 —
координатор на адаптере 0, автоматический воркер на адаптере 1, сплит
слоёв через loopback. Для пропускной способности (много параллельных
запросов) — cortiq serve модель.cmf --gpus 2: по полной реплике на
карту.
По сети: на второй машине cortiq worker модель.cmf --listen 0.0.0.0:9911 --token СЕКРЕТ, на первой — те же run-флаги плюс
--peer адрес:9911 --net-token СЕКРЕТ --net-dtype f16. cortiq peers
находит воркеров в локальной сети.
Сэмплинг (официальные ряды Qwen): думающий режим — temperature 1.0,
top-p 0.95, top-k 20; инструктный (--no-think) — temperature 0.7,
top-p 0.80, top-k 20, presence-penalty 1.5. Все шесть ручек доступны
с 0.5.77. Для очень длинных генераций поднимите CMF_MAX_SEQ
(по умолчанию 32768, модель умеет 262144).
Примеры: три аквариума в
examples/
(q4tp, q4t, q8_2f) сгенерированы одним промтом с одним seed — готовое
сравнение квантов.
O(1) длинный контекст — параметры.--o1 all|deepN|i,j,k|off —
какие attention-слои перевести на O(1) (обычно all); --o1-m 32 —
бюджет ландмарок (валидированный максимум GPU-ядер); --o1-window 128
— точное скользящее окно; --o1-sink 4 — постоянные точные ключи в
начале. Лимиты ядер: sink+window ≤ 196, m ≤ 32 (сверх — слой уходит на
CPU-шаг, с записью в лог при RUST_LOG=info). Префилл в этом режиме
идёт на CPU намеренно — он записывает трассу, запечатывающую скелет.
Память под внимание константна, скорость декода не падает с глубиной;
выгодно от ~8k контекста и на машинах с 24 ГБ. Вывод не бит-в-бит с
полным вниманием (это аппроксимация с точным окном). Vulkan:
CMF_O1_GPU=1; Metal: CMF_O1_METAL=1 (с 0.5.79).
macOS (Apple Silicon, Metal). С 0.5.79 модель работает на GPU мака
из коробки (раньше файл не влезал в лимит одного Metal-буфера и всё
тихо уходило на CPU). Замер на M4 mini 24 ГБ: декод 5.8 tok/s,
префилл на 2k контексте 20.8 tok/s (на CPU было 3.7). Для длинного
контекста — Metal-режим O(1): CMF_O1_METAL=1 cortiq run … --o1 all —
декод держит ~4.7 tok/s независимо от глубины, память под внимание
фиксированная. Для мака берите q4t; q8_2f (27.4 ГБ) в 24 ГБ не
помещается.