Qwen3.5-9B · FP8 (dynamic)
8-bit quantization of Qwen/Qwen3.5-9B, produced for efficient vLLM serving. Quantized by axteam.
Revision 2026-11-02 (config fix): the earlier
config.jsonexcluded the vision tower from quantization with the patternre:model\.visual\..*, which does not match the names vLLM uses for these modules (visual.*). vLLM 0.32 therefore built the vision layers as FP8 and loaded the BF16 vision weights into them, so image input gave wrong answers; text input was not affected. Onlyconfig.jsonchanged (the pattern now also matches vLLM's names); the weights are the same. Checked with vLLM 0.32.0 on 2026-11-02: the vision weights now load as BF16, and a synthetic test image (red circle, blue square, the caption "QWEN TEST 2026") is described correctly. If you downloaded this repo before 2026-11-01 23:17:21 UTC (revisionf360b7a), downloadconfig.jsonagain.
| Base model | Qwen/Qwen3.5-9B |
| Method | FP8 (dynamic) |
| Format | compressed-tensors float-quantized (scheme FP8_DYNAMIC) |
| Weights / activations | W8A8 — FP8 E4M3 weights (per-output-channel scale), dynamic per-token FP8 activations |
| Architecture | Hybrid (linear-attention + full-attention) · Dense · multimodal (vision) · MTP head |
| Size on disk | ~12.4 GB |
| Calibration | None (data-free static weight scales) |
| License | Apache-2.0 |
Quantization details
- Scheme — W8A8 — FP8 E4M3 weights (per-output-channel scale), dynamic per-token FP8 activations, stored as compressed-tensors
float-quantized(schemeFP8_DYNAMIC). - Kept in BF16 — the vision tower & projector (
model.visual.*), the multi-token-prediction head (mtp.*), all RMSNorms except the gatedlinear_attn.norm, token embeddings, the LM head, the SSM non-linear partslinear_attn.conv1d/dt_bias. Kept in FP32, as in the original:linear_attn.A_logand the gatedlinear_attn.norm. Left unquantized to preserve quality (about 28% of all parameters in this build). - Tokenizer /
chat_template/ preprocessor configs are identical to the original (the original ships nogeneration_config.json, so none is included here).config.jsonis the original plus aquantization_configblock.
This is post-training quantization (PTQ) — no retraining. FP8 dynamic is calibration-free.
Benchmarks (measured)
Every column was measured with the same harness and settings — lm-evaluation-harness on vLLM, greedy, completion-style prompts without a chat template (0- or 5-shot, as listed in each row). MMLU here is lm-eval's generative variant (mmlu_generative: the model writes the answer letter and only an exact match on the first line counts), so it is not directly comparable with MMLU scores measured another way (e.g. log-likelihood scoring). Percentages are recovery vs. the BF16 original.
| Benchmark | BF16 (original) | FP8-dynamic (this repo) | AWQ-8bit | NVFP4A16 | NVFP4 | AWQ-4bit |
|---|---|---|---|---|---|---|
| MMLU (5-shot, generative) | 33.03 | 46.82 (141.8%) | 32.37 (98.0%) | 32.15 (97.3%) | 35.06 (106.1%) | 33.29 (100.8%) |
| GSM8K (5-shot, strict) | 87.11 | 86.81 (99.7%) | 86.96 (99.8%) | 84.38 (96.9%) | 84.23 (96.7%) | 86.81 (99.7%) |
| ARC-Challenge (0-shot) | 55.55 | 55.72 (100.3%) | 55.89 (100.6%) | 54.44 (98.0%) | 54.01 (97.2%) | 56.48 (101.7%) |
| Winogrande (5-shot) | 73.72 | 74.19 (100.6%) | 74.51 (101.1%) | 73.01 (99.0%) | 73.16 (99.3%) | 73.40 (99.6%) |
| KMMLU (5-shot, direct) | 58.39 | 58.05 (99.4%) | 58.51 (100.2%) | 58.26 (99.8%) | 57.41 (98.3%) | 56.96 (97.6%) |
| HAE-RAE (0-shot) | 69.48 | 69.11 (99.5%) | 69.39 (99.9%) | 70.21 (101.1%) | 68.47 (98.5%) | 67.09 (96.6%) |
| Average | 62.88 | 65.12 (103.6%) | 62.94 (100.1%) | 62.07 (98.7%) | 62.06 (98.7%) | 62.34 (99.1%) |
| Average without MMLU | 68.85 | 68.78 (99.9%) | 69.05 (100.3%) | 68.06 (98.9%) | 67.46 (98.0%) | 68.15 (99.0%) |
Note on MMLU: this task is scored on generated text (
mmlu_generative), so the score depends on whether the model answers in exactly the format the scorer expects (for MMLU only a bare answer letter on the first line counts). For this model it swings widely between builds of the same model (MMLU 32.2–46.8), and only one quantized build, FP8-dynamic, scores well above the BF16 original (141.8%). This most likely reflects how each build formats its answers rather than quantization quality, but per-question outputs were not saved, so it was not checked answer by answer. The second average leaves it out.
Evaluation (measured)
Fidelity to the BF16 original on an internal mixed English/Korean set (100 prompts, BF16 greedy answers scored under each build — same harness for every row).
| Metric | This model | BF16 original |
|---|---|---|
| Perplexity (lower = closer) | 1.4669 | 1.4506 (+1.1%) |
| Top-1 next-token agreement | 95.8% | 99.2% |
These measure fidelity to the base model, not absolute task scores.
Requirements
| Runtime | vLLM — the architecture is in vLLM ≥ 0.17.0; tested here with vLLM 0.32.0. |
| vLLM install | vLLM 0.32 itself needs Python 3.11–3.14, torch 2.13 (CUDA 13.0 build, so an NVIDIA driver with CUDA 13 support), transformers ≥5.16.1,<5.20 and compressed-tensors 0.17.0 (both pinned by vLLM; 0.17.0 reads this checkpoint, which was saved with 0.19.0 — do not upgrade it separately). |
| GPU | NVIDIA Turing (sm75, e.g. T4) or newer. FP8 math runs on Ada / Hopper / Blackwell (sm89+); on Turing and Ampere vLLM switches to weight-only FP8 automatically. V100 (sm70) is not supported. (Kernel choice per GPU from vLLM 0.32's selection code; only B200 was run here.) |
| Memory | Weights: 12.4 GB. Add KV cache (grows with context length × concurrent requests) and a few GB for activations / CUDA graphs; use --tensor-parallel-size N when the weights do not fit one GPU. |
| Transformers (without vLLM) | transformers>=5.2.0 + compressed-tensors>=0.15.0 (checked on CPU with Qwen3.5-0.8B FP8 / AWQ-4bit / NVFP4A16 / NVFP4). |
| trust_remote_code | not needed |
Usage (vLLM)
Start an OpenAI-compatible server:
vllm serve axteam/Qwen3.5-9B-FP8-dynamic --max-model-len 32768
Query it:
curl http://localhost:8000/v1/chat/completions -H "Content-Type: application/json" -d '{
"model": "axteam/Qwen3.5-9B-FP8-dynamic",
"messages": [{"role": "user", "content": "대한민국의 수도는 어디인가요?"}],
"max_tokens": 512
}'
Offline inference in Python:
from vllm import LLM, SamplingParams
llm = LLM(model="axteam/Qwen3.5-9B-FP8-dynamic", max_model_len=32768)
params = SamplingParams(max_tokens=1024)
out = llm.chat([{"role": "user", "content": "Explain model quantization in two sentences."}], params)
print(out[0].outputs[0].text)
# image input (URL or data: URI)
messages = [{"role": "user", "content": [
{"type": "image_url", "image_url": {"url": "https://example.com/your-image.png"}},
{"type": "text", "text": "Describe this image."},
]}]
out = llm.chat(messages, params)
print(out[0].outputs[0].text)
Thinking mode is on by default in the chat template; to turn it off pass
chat_template_kwargs={"enable_thinking": False}(Pythonllm.chat(..., chat_template_kwargs=...), or"chat_template_kwargs": {"enable_thinking": false}in the request body). Text-only serving: add--limit-mm-per-prompt '{"image": 0, "video": 0}'to skip loading the vision encoder's memory budget.
Reducing KV-cache memory (optional, serve-time)
The KV cache is kept in BF16 by default. KV-cache precision is a runtime choice, independent of the weight quantization above. This is a hybrid model: only its 8 full-attention layers keep a KV cache, while its 24 linear-attention (Gated DeltaNet) layers keep a fixed-size state per request, which --kv-cache-dtype does not change. FP8 halves the full-attention KV cache, so the saving grows with context length and is small for many short requests:
vllm serve axteam/Qwen3.5-9B-FP8-dynamic --kv-cache-dtype fp8
License
Quantized derivative of Qwen/Qwen3.5-9B (Apache-2.0). All original weights, tokenizer and chat template belong to the Qwen team.
한국어 요약
Qwen/Qwen3.5-9B의 FP8 (W8A8) 양자화 빌드 · 제작 axteam
개요
| 항목 | 내용 |
|---|---|
| 원본 모델 | Qwen/Qwen3.5-9B |
| 양자화 방식 | FP8 동적 양자화 (W8A8) |
| 저장 형식 | compressed-tensors float-quantized (scheme FP8_DYNAMIC) |
| 모델 구조 | 하이브리드 어텐션(선형 어텐션 + 풀 어텐션) · Dense · 멀티모달(비전) · MTP 헤드 |
| 용량 | 약 12.4 GB |
| 보정 데이터 | 없음 (가중치 스케일은 가중치만으로 계산, 활성화 스케일은 실행 시 계산) |
양자화 상세
- 가중치: FP8(E4M3), 출력 채널별 스케일
- 활성화: 실행 시 토큰별 동적 FP8
- 양자화 절차: PTQ(학습 후 양자화, 재학습 없음), 가중치 스케일은 미리 계산하고 활성화 스케일은 실행 시 토큰마다 계산
- BF16 유지: 비전 타워·투영층(
model.visual.*), MTP 헤드(mtp.*), 모든 RMSNorm(게이트linear_attn.norm제외), 토큰 임베딩, LM 헤드, SSM의 선형층 외 파라미터(linear_attn.conv1d·dt_bias) —linear_attn.A_log·게이트linear_attn.norm은 원본과 같이 FP32 유지 — 전체 파라미터의 약 28% - 원본 파일: 토크나이저·chat template·전처리 설정은 원본과 동일(원본에
generation_config.json이 없어 이 리포에도 없음),config.json은 원본에quantization_config블록만 추가
품질 (실측)
- 원본 대비 충실도: PPL 1.4669 (원본 1.4506, +1.1%, 낮을수록 원본에 가까움), 다음 토큰 top-1 일치율 95.8% (원본 자체 기준값 99.2%) — 내부 영어·한국어 혼합 프롬프트 100개, 원본(BF16)의 greedy 답변을 기준 텍스트로 측정
- 벤치마크 평균: 65.12 (원본 62.88, 103.6%) — MMLU(생성형)·GSM8K·ARC-Challenge·Winogrande·KMMLU·HAE-RAE 6종 평균, lm-evaluation-harness + vLLM, chat template 없는 완성형 프롬프트(과제별 0·5-shot, 표 참고)·greedy, 모든 빌드를 같은 설정으로 측정
- MMLU(생성형) 제외 평균: 68.78 (원본 68.85, 99.9%) — MMLU(생성형)는 생성한 답이 채점기가 기대하는 형식 그대로여야 점수가 나는 과제; 이 모델에서는 같은 모델의 빌드끼리 MMLU(생성형) 32.2~46.8로 크게 흔들리고 FP8-dynamic 빌드 하나만 원본보다 크게 높음(141.8%), 답 형식 차이로 보이나 문항별 출력을 저장하지 않아 문항 단위로는 확인하지 않음
- 한국어 벤치마크: KMMLU 58.05 (원본 58.39, 99.4%) · HAE-RAE 69.11 (원본 69.48, 99.5%)
- MMLU 방식: lm-eval 생성형 변형(
mmlu_generative) — 모델이 답 글자를 생성하고 첫 줄이 정확히 일치해야 정답으로 채점하므로, 다른 방식(예: log-likelihood 채점)으로 잰 MMLU 점수와 직접 비교 불가
요구사항
- 실행 엔진: vLLM 0.17.0 이상(이 구조를 지원하는 첫 버전), 이 빌드는 vLLM 0.32.0에서 실행 확인
- vLLM 0.32 설치 조건: Python 3.11~3.14, torch 2.13(CUDA 13.0 빌드, CUDA 13 지원 드라이버 필요), transformers 5.16.1 이상 5.20 미만, compressed-tensors 0.17.0 — transformers·compressed-tensors는 vLLM이 버전을 고정하므로 compressed-tensors를 따로 업그레이드하지 말 것 (이 체크포인트는 0.19.0으로 저장됐지만 0.17.0에서도 로드됨)
- GPU: NVIDIA Turing(sm75, 예: T4) 이상, V100(sm70) 미지원 — FP8 연산은 Ada·Hopper·Blackwell(sm89 이상)에서 수행, Turing·Ampere는 vLLM이 가중치 전용 FP8로 자동 전환 (GPU별 지원 여부는 vLLM 0.32 커널 선택 코드 기준, 실제 실행은 B200에서만 확인)
- 메모리: 가중치 12.4 GB + KV 캐시(컨텍스트 길이 × 동시 요청 수에 비례) + 활성화·CUDA graph용 수 GB — GPU 한 장에 다 들어가지 않으면
--tensor-parallel-size N으로 분산 - Transformers로 직접 사용: transformers 5.2.0 이상 + compressed-tensors 0.15.0 이상 (Qwen3.5-0.8B의 FP8·AWQ-4bit·NVFP4A16·NVFP4 빌드로 CPU에서 확인)
- trust_remote_code: 불필요
사용법
- 서버 실행:
vllm serve axteam/Qwen3.5-9B-FP8-dynamic --max-model-len 32768— OpenAI 호환 API - Python:
LLM(model="axteam/Qwen3.5-9B-FP8-dynamic", max_model_len=32768).chat(...)— 전체 예시는 위 영어 본문 'Usage (vLLM)' 절 참고 - thinking 모드: 기본 켜짐 — 끄려면
chat_template_kwargs={"enable_thinking": False}전달(Python은llm.chat()인자, HTTP는 요청 본문의"chat_template_kwargs": {"enable_thinking": false}) - 이미지 입력: 메시지에
image_url항목 사용 - 텍스트만 사용할 때:
--limit-mm-per-prompt '{"image": 0, "video": 0}'— 비전 타워용 메모리 예약을 생략해 메모리 절약 - KV 캐시 절감(선택):
vllm serve에--kv-cache-dtype fp8추가 — 하이브리드 구조라 KV 캐시는 풀 어텐션 8개 층에만 있고, 선형 어텐션(Gated DeltaNet) 24개 층의 요청별 고정 크기 상태는 이 옵션으로 바뀌지 않음 → 풀 어텐션 KV 캐시만 절반으로 줄어 긴 컨텍스트에서 효과가 크고 짧은 요청이 많을 때는 작음 (가중치 양자화와 별개인 실행 옵션)
참고
- 수정 이력 (2026-11-02, 설정 수정): 이전
config.json은 비전 타워를 양자화에서 빼는 규칙(re:model\.visual\..*)이 vLLM이 쓰는 모듈 이름(visual.*)과 맞지 않아, vLLM 0.32가 비전 층을 FP8로 만들고 BF16 비전 가중치를 그대로 넣었음 → 이미지 입력 답이 틀림(텍스트 입력은 영향 없음) —config.json의 규칙만 vLLM 이름까지 맞게 고침(가중치 동일) — vLLM 0.32.0 확인(2026-11-02): 비전 가중치가 BF16으로 로드됨, 모델이 시험 그림(빨간 원·파란 사각형·글자 "QWEN TEST 2026")을 바르게 설명 — 2026-11-01 23:17:21 UTC(리비전f360b7a) 이전에 받았다면config.json만 다시 받을 것
라이선스
- 라이선스: Apache-2.0 — 원본 모델의 라이선스를 그대로 따름
- 권리: 원본 가중치·토크나이저·chat template은 Qwen 팀(Alibaba) 소유, 이 리포는 양자화 파생물