--- type: configuration title: FreeToken frank-default-small Runbook description: FreeToken v0.1.2 serving batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8 as frank-default-small on Dankserver (RTX 3090). tags: - freetoken - dankserver - frank-default-small - qwen3.6 - moe - fp8 timestamp: 2026-08-30 --- # FreeToken frank-default-small Runbook The `frank-default-small` service on Dankserver is served by **FreeToken v0.1.2** — an edge-native MoE serving engine that keeps expert weights in host RAM with an LRU GPU cache. Model history on this runtime: official `Qwen/Qwen3.6-35B-A3B-FP8` (since 2026-09-02) → `batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8` (2026-08-30, same format and pool budget). The engine itself replaced the llama.cpp Tiel-Coder-35B-A3B (UD-Q6_K_XL) deployment. ## Model | Field | Value | |-------|-------| | HuggingFace | `batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8` | | Lineage | Qwen/Qwen3.6-35B-A3B → huihui-ai abliterated → this FP8 (quantizer batsclamp) | | Architecture | `qwen3_5_moe` (Qwen3_5MoeForConditionalGeneration) | | Quant | native modelopt block-fp8 e4m3, dynamic activations, 128×128 `weight_block_size`, bf16 `weight_scale_inv` — byte-format identical to the official FP8 repo | | BF16 kept | lm_head, embed_tokens, all norms, router gates, mamba state params, visual encoder, MTP module | | Experts | un-fused per-expert layout (`mlp.experts.{0..255}.*`) matching official Qwen FP8 — same FreeToken loader path | | Size on disk | ~35 GB (26 safetensors shards) | | Path | `/home/dank/models/huihui-qwen36-35b-a3b-abliterated-fp8` | | Layers | 40 (10 full-attention + 30 GDN/linear-attention) | | Experts | 256 per layer, 8 used per token | | KV heads | 2 × 256 dim | | Context | 262,144 (model max) | | Chat template | froggeric/Qwen-Fixed-Chat-Templates (fixed Qwen3.6 template, shipped in `tokenizer_config.json`; FreeToken reads it from the checkpoint — no override) | **Important:** this is the Huihui *abliterated* finetune (refusals removed) — not the base Qwen weights served before 2026-08-30, and not the earlier Tiel-Coder finetune. Expect a direct-answers assistant. ## Runtime | Field | Value | |-------|-------| | Engine | FreeToken v0.1.2 (`ft` CLI) | | Venv | `/home/dank/freetoken/.venv` (uv-managed CPython 3.12) | | Dependencies | torch 2.11.0+cu130, flashinfer 0.6.17, apache-tvm-ffi | | CUDA toolchain | pip-installed nvidia-cuda-nvcc/crt/nvvm/runtime 13.2.86 | | API | OpenAI-compatible (`/v1/chat/completions`, `/v1/models`) | ## Pool Configuration The GPU budget (~17.6 GiB after weights + fixed caches) is split MoE-first between expert residency and KV pages: | Pool | Size | VRAM | Notes | |------|------|------|-------| | MoE cache | 2,048 slots (20%) | 6.0 GiB | LRU expert cache, out of 10,240 total | | KV cache | 453,005 tokens | 8.6 GiB | ~20 KiB/token (10 attn layers only) | | Mamba state | 24 slots | 1.4 GiB | Per-sequence GDN state (caps concurrency) | ### Live Resize KV and MoE can be re-partitioned without restart: ```bash ft ctl --base-url http://127.0.0.1:7770 cache --kv N --moe M --wait 300 ``` - **Growing KV** (shrinking MoE): works live. - **Shrinking KV** (growing MoE): requires restart (old + new pools cannot coexist in VRAM during the swap → OOM). - The fit check refuses overcommit: if the plan doesn't fit, the old cache is retained and serving continues. ### Benchmark Results (2026-09-02, base FP8 checkpoint) See [[freetoken-benchmark-sweep]] for the full bs1/bs3/bs4/bs6 sweep across KV pool sizes 8k–700k. At the production config (20% residency, bs4): | Metric | Value | |--------|-------| | bs1 decode | ~30 tok/s | | bs4 aggregate | ~87 tok/s | | bs4 per-request | ~22 tok/s | | Prefill (4k) | ~1,130 tok/s | ## Quantization Compatibility FreeToken v0.1.2 supports these safetensor quants for `qwen3_5_moe`: | Format | Detection | Works | |--------|-----------|-------| | BF16 (no quant config) | default | ✅ (experts too large for 60 GB RAM) | | modelopt block-fp8 (128×128) | `quant_method: "fp8"` + `weight_block_size` | ✅ (current) | | NVFP4 (modelopt) | `quant_algo: "NVFP4"` | ✅ (best for VRAM) | | NVFP4 (compressed-tensors) | 4-bit float, group_size=16, strategy=tensor_group | ✅ | | Per-tensor FP8 (modelopt) | scalar `weight_scale` | ✅ | | Per-channel FP8 (compressed-tensors) | `weight_scale: [O, 1]` | ❌ loader bug | | Quark W8A8 INT8 | per-channel scales | ❌ loader bug | | GGUF | only `gemma4` arch | ❌ for qwen3_5_moe | ## Files | File | Purpose | |------|---------| | `scripts/serve-frank-small.sh` | Serve script (launches `ft serve`) | | `scripts/frank-default-small.env` | Tunables (model path, pool sizes) | | `scripts/frank-default-small.service` | Systemd unit | ## Limitations - **Model identity**: serves the Huihui abliterated FP8 finetune, not the Tiel-Coder coder finetune from the llama.cpp era. - **JIT compilation**: first startup compiles flashinfer/tvm-ffi kernels (~5–15 min cold). Cached afterward in `~/.cache/flashinfer` and `~/.cache/tvm-ffi`. - **CUDA toolchain**: driver-only install (no system CUDA toolkit). The venv provides pip-installed nvcc 13.2.86 for JIT compilation. All nvidia-cu13 packages must be at the same version. - **Env var collisions**: never name tunables `TEMP`, `HOST`, or `GPU_MAX_HEAP_SIZE` (HIP runtime reads these). ## Operational quirks - **`model` field is required** in `/v1/chat/completions` bodies — FreeToken rejects requests without it with a 422 (`Field required`), unlike llama.cpp's server which defaults to the loaded model. Send `"model": "frank-default-small"`. - Load on this swap took well under the old llama.cpp numbers: weights → experts (parallel build) → CUDA graph capture → Uvicorn in ~2 minutes; the 2026-08-30 swap verified ~40 tok/s decode on a 282-token completion. ## Citations - FreeToken paper: arXiv 2608.16157 - FreeToken PyPI: `freetoken[accel]` v0.1.2 - HuggingFace model: `batsclamp/Huihui-Qwen3.6-35B-A3B-abliterated-FP8` - Upstream weights: `huihui-ai/Huihui-Qwen3.6-35B-A3B-abliterated`, `Qwen/Qwen3.6-35B-A3B-FP8` - Fixed chat template: `froggeric/Qwen-Fixed-Chat-Templates`