Qwen3.8-27B → CMF — one file, one Rust binary, no Python
cargo install cortiq-cli # 0.5.76+
hf download infosave/Qwen3.8-27B-cmf qwen38-27b-q4t.cmf --local-dir .
cortiq 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:
curl http://localhost:8080/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "qwen38-27b-q4t", "messages": [{"role": "user", "content": "Hi!"}]}'
/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:
sudo apt install libvulkan1 libglvnd0 libegl1 libgl1 libglx0
XDG_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:
CMF_GPU_ADAPTER=1 cortiq run qwen38-27b-q4t.cmf --prompt "..."
CMF_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:
CMF_GPU_ADAPTER=1 cortiq worker qwen38-27b-q4t.cmf --listen 127.0.0.1:9911 --token S &
CMF_GPU_ADAPTER=0 cortiq run qwen38-27b-q4t.cmf --prompt "..." \
--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.
Across the network
Machine B (holds the tail layers):
cortiq worker qwen38-27b-q4t.cmf --listen 0.0.0.0:9911 --token SECRET
Machine A (the coordinator; same .cmf, verified by directory hash):
cortiq run qwen38-27b-q4t.cmf \
--prompt "..." \
--peer 192.168.1.42:9911 --net-token SECRET --net-dtype f16
--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:
examples/aquarium-q4tp.html— the ladder-scale file, 9468 tokens in 391 s on an RTX 5090examples/aquarium-q4t.html— 288 s on an RTX 5090examples/aquarium-q8_2f.html— the 8-bit file's take
O(1) long-context mode
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.
# Vulkan / discrete GPUs (since 0.5.78), ~25 tok/s on an RTX 5090:
CMF_O1_GPU=1 cortiq run qwen38-27b-q4t.cmf --o1 all --prompt "..." --max-tokens 2000
# Apple Silicon (since 0.5.79), ~4.7 tok/s on an M4 24 GB at any depth:
CMF_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 ≤ 196andm ≤ 32; anything larger falls back to the CPU step for those layers (it says so in the log — run withRUST_LOG=infoto see refusals). - Prompts shorter than
window + sink + 8skip 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
sha256sum -c qwen38-27b-q4tp.cmf.sha256 # or -q4t / -q8_2f
cortiq info qwen38-27b-q4tp.cmf
Документация на русском
Одна модель — один файл .cmf, один Rust-бинарник cortiq, без Python:
cargo install cortiq-cli # 0.5.77+
hf download infosave/Qwen3.8-27B-cmf qwen38-27b-q4t.cmf --local-dir .
cortiq 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 ГБ не
помещается.
中文文档
一个模型 — 一个 .cmf 文件,一个 Rust 可执行文件 cortiq,无需 Python:
cargo install cortiq-cli # 0.5.77+
hf download infosave/Qwen3.8-27B-cmf qwen38-27b-q4t.cmf --local-dir .
cortiq run qwen38-27b-q4t.cmf --prompt "用三句话解释快速排序。"
| 文件 | 位宽 | 大小 | 解码速度(RTX 5090) | wikitext-2 困惑度 |
|---|---|---|---|---|
qwen38-27b-q4tp.cmf |
4 位,阶梯缩放 | 14.3 GB | 48.7 tok/s · 贪心+推测解码 76 tok/s(逐位精确的 f32 验证:66) | 8.79 |
qwen38-27b-q4t.cmf |
4 位 | 15.4 GB | 49.4 tok/s | 8.86 |
qwen38-27b-q8_2f.cmf |
8 位 | 27.4 GB | 33.0 tok/s | — |
所有数字来自同一台机器、同一基准(cortiq bench --core,0.5.80,取中位数);
推测解码一行在基准自身文本上测得,真实提示词上的收益取决于草稿头与主干的
一致程度:2.3k 上下文的代码提示 56.5 对 45.7 tok/s,散文则保持普通速度
(引擎的监视器会在不划算处停止推测)。困惑度在相同的 12 个 512 token 窗口
上测得。该模型受内存带宽限制,因此 4 位文件不仅更小,解码也比 8 位快约 1.5 倍。
q4tp 保留 q4t 的 4 位权重,把每个 32 权重 tile 的缩放系数存为按行
阶梯上的一级:字节少 7.5%,质量不变(困惑度甚至略低),是 16 GB 显卡的
选择。两个 4 位文件都直接由 bf16 检查点量化而来(从 HF 逐分片流式转换),
而非互相转换。贪心解码默认开启推测解码(--greedy 或服务器请求
temperature: 0,0.5.80 起,Vulkan):模型自带的 MTP 头一次起草五个
token,一次批量提交在 int8 激活的矩阵向量核上完成验证,监视器持续把每轮
产出的 token 数与普通 token 比较 —— 连续四轮不划算即停止推测(散文常常
不划算),稍后再试,因此有收益的提示保住收益,没有的按普通速度走。
CMF_VERIFY_I8=0 切回 f32 验证(基准 66 tok/s),贪心输出与普通路径
逐位一致;默认的 int8 可能把接近平局的 token 解成另一个同样贪心的续写。
CMF_GRAPH_SPEC=0 关闭推测。采样(temperature > 0)
走普通路径。
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 号卡,自动启动的 worker 用 1 号卡,层间切分走本地回环。
追求吞吐量(多并发请求)用 cortiq serve 模型.cmf --gpus 2:每张卡
一个完整副本。
跨机网络: 第二台机器运行 cortiq worker 模型.cmf --listen 0.0.0.0:9911 --token 密钥,第一台机器加 --peer 地址:9911 --net-token 密钥 --net-dtype f16。cortiq peers 可发现局域网内的 worker。
采样参数(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 选择切换到
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 GB 内存的机器上收益最大。输出与完整注意力
并非逐位相同(带精确窗口的近似)。Vulkan 用 CMF_O1_GPU=1;
Metal 用 CMF_O1_METAL=1(0.5.79 起)。
macOS(Apple Silicon,Metal)。 自 0.5.79 起,27B 可直接在 Mac
GPU 上运行(此前文件超出单个 Metal 缓冲区上限,会静默回退到 CPU)。
M4 mini 24 GB 实测:解码 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,
与上下文深度无关,注意力状态恒定大小。Mac 请选 q4t;q8_2f
(27.4 GB)无法装入 24 GB 内存。
Model tree for infosave/Qwen3.8-27B-cmf
Base model
Qwen/Qwen3.8-27B