메뉴
BL
r/LocalLLaMA 37일 전

단일 RTX 3090으로 85 TPS·12만5천 컨텍스트 구현

IMP
9/10
핵심 요약

알리바바의 Qwen3.6-27B 모델이 출시된 지 하루 만에, 단일 소비자용 그래픽 카드(RTX 3090 24GB)에서 데이터센터급 추론 속도(85 TPS)와 12만 5천 토큰의 컨텍스트, 그리고 비전(Vision) 기능을 구현한 오픈소스 스택이 등장했습니다. 이는 기존 API 의존 없이도 GPT급 속도와 개인정보 보호, 무료 추론 비용을 모두 누릴 수 있게 되었음을 의미합니다. 저자는 vLLM의 버그 패치 4개와 최적화를 통해 이론적으로 불가능해 보이던 하드웨어 한계를 극복한 구체적 과정을 공유합니다.

번역된 본문

Qwen3.6-27B를 위한 하룻밤의 스택: 단일 RTX 3090에서 85 TPS, 125K 컨텍스트, 비전(Vision) 구현하기 Wasif Basharat 18분 읽기 · 방금 전

-- 듣기 공유

Qwen3.6이 공개되고 하루 뒤: 소비자용 24GB 그래픽 카드 하나, CUDA 그래프 버그, 4개의 패치, 그리고 이 모델을 완벽하게 구동시킨 스택에 대한 이야기입니다.

[핵심 요약] 1× RTX 3090 (24GB, 230W 전력 제한) 환경에서의 Qwen3.6-27B 성능 ───────────────────────────────────────────── 처리량: 지속 85 TPS / 최대 106 TPS 컨텍스트: 125K 토큰 비전(Vision): 활성화됨 (MoonViT BF16) VRAM: 24GB 중 21.3GB 사용 서버: vLLM · 완전한 OpenAI API 도구 호출(Tools): ✅ 접두사 캐시(Prefix cache): ✅ 추론 디코딩(Spec-decode): MTP n=3 · AL 3.4–3.8 · 수락률 97/95/91%

Lorbus의 공식 모델 카드에 따르면, 같은 모델을 RTX 5090에서 구동할 때 약 60 TPS가 나온다고 명시되어 있습니다. 반면 우리는 VRAM이 25% 적고 순수 연산량이 약 40% 낮은 그래픽 카드에서, 230W의 전력(조용하고 시원함)만으로 지속적으로 85 TPS를 달성했습니다. 아래의 글은 그 방법을 설명합니다.

85 TPS 지속 처리. 106 TPS 최대 처리. 단일 3090에서 100 TPS 장벽을 돌파한 것입니다.

[이 성과가 중요한 이유]

Qwen3.6–27B는 어제 출시되었습니다. 그리고 오늘 아침, 중고로 사도 맥북 에어보다 싼 가격의 GPU에서 데이터센터에 근접한 처리량을 제공하는 오픈소스 스택이 등장했습니다. 본격적인 분석에 앞서 이 점을 곱씹어 볼 만합니다.

• 데이터가 외부로 나가지 않습니다. 규제 대상 워크로드, 개인 메모, 고객 데이터, 사내 코드베이스 등 그동안 GPT급 속도를 쓰기 위해 감수해야 했던 프라이버시 트레이드오프가 사라집니다. 모델이 여러분의 RAID 스토리지에 있는 파일을 직접 읽고, 그래픽 카드 값을 회수하고 나면 추론 비용은 무료입니다.

• 230W 전력 제한에서 85 TPS를 지속하는 3090은 하루에 수백만 개의 토큰을 처리하면서도 전기세는 커피 한 잔 값 수준에 불과합니다. API 지출은 운영 비용이 아니라 하나의 설계 선택지가 됩니다.

• 대기 시간(Latency)은 거의 0에 가깝습니다. 왕복 시간도, 속도 제한도, 전 세계 다른 사용자들과의 큐 대기도 없습니다. 첫 번째 토큰가 로컬 소켓의 속도로 도착합니다. API를 사용할 때 느리게 느껴지던 에이전트 루프가 더 이상 느리지 않으며, 매 턴마다 왕복 시간 비용을 지불하던 도구 호출(Tool-calling) 루프가 극적으로 빨라집니다.

• 가중치(Weights)를 소유합니다. Qwen은 관대한 라이선스로 이 모델을 배포했습니다. 이 모델은 갑작스럽게 지원 중단되거나, 몰래 재조정되거나, 가격이 인상되지 않습니다. 화요일에 여러분의 사용 사례에 잘 맞았던 모델이라면, 금요일이나 내년에도 똑같이 작동합니다.

• 파인튜닝이 주말 프로젝트가 됩니다. 서빙 스택이 검증되면, 특정 도메인에 특화된 LoRA를 교체하는 데 수주가 아니라 몇 시간만 걸립니다. 비전 기반 모델 + 도메인 데이터 = 여러분만의 프라이빗 멀티모달 모델입니다.

중고 소비자용 GPU에서 비전(Vision) + 125K 컨텍스트 + 도구 호출 + 85 TPS를 달성한 것은 이번 주를 기준으로 완전히 새로운 수준의 역량입니다.

이 글의 나머지 부분은 우리가 어떻게 이 성과를 이뤄냈는지, 그리고 여러분이 오늘 밤 어떻게 여러분의 GPU에 이것을 구현할 수 있는지를 다룹니다.

[모델, 그리고 왜 이 문제가 어려운가]

Qwen3.6–27B는 알리바바의 Qwen 팀이 2026년 4월 22일에 공개한 조밀한(Dense) 비전-언어 모델(Vision-Language Model)입니다. 이는 Qwen3-Next 제품군의 일부로, 하이브리드 어텐션 아키텍처(Hybrid Attention Architecture)를 특징으로 합니다. 즉, DeltaNet(Gated Linear Attention, 순환 상태)과 표준 소프트맥스 어텐션 레이어가 교차로 배치되어 있습니다. 여기에 추론 디코딩(Speculative Decoding)을 위한 네이티브 Multi-Token Prediction(MTP) 헤드가 추가되었습니다.

이론적으로만 보면 소비자용 GPU를 위한 완벽한 꿈의 모델입니다:

  • 27B 파라미터 = INT4 기준 약 17GB로, 24GB VRAM에 아주 여유롭습니다.
  • 비전 타워는 BF16을 유지하는 소형 MoonViT로 약 0.9GB를 차지합니다.
  • MTP 헤드 = 추론 엔진이 이를 잘 다루기만 하면 공짜로 추론 디코딩을 사용할 수 있습니다.

하지만 실제로는, 이러한 '이론적인' 전제들이 소비자용 하드웨어에서는 보이지 않는 벽에 부딪힙니다. 가장 큰 문제 3가지는 다음과 같습니다:

  1. DeltaNet의 순환 상태는 기존의 모든 표준 추론 디코딩 파이프라인을 망가뜨립니다. 초안 토큰을 거부하려면 상태를 되돌려야(roll back) 하는데, 선형 어텐션(Linear Attention) 순환은 되돌릴 수 없습니다. vLLM, SGLang, llama.cpp 메인라인 모두 초기 상태에서는 이를 올바르게 처리하지 못했습니다.

  2. 대부분의 INT4 양자화(Quantization)는 MTP 헤드를 제외하거나, 이 역시 INT4로 양자화해버립니다. 어느 쪽이든 vLLM의 Qwen3_5MTP 로더는 기대하던 가중치(mtp.fc.weight)를 찾지 못합니다. 결과적으로 MTP가 아무런 매개변수 없이 조용히 로드되고(→ 0%의 초안 수락률), 속도 향상은커녕 오버헤드 비용만 치르게 됩니다.

  3. TurboQuant KV 캐시(125K 컨텍스트를 가능하게 하는 핵심 요소)는 하이브리드 모델에서 로드되기를 거부합니다. vLLM은 NotImplementedError 오류를 발생시킵니다.

원문 보기
원문 보기 (영어)
An Overnight Stack for Qwen3.6–27B: 85 TPS, 125K Context, Vision — on One RTX 3090 Wasif Basharat 18 min read · Just now -- Listen Share A day after Qwen3.6 dropped: a consumer 24 GB card, a CUDA-graph bug, four patches, and the stack that made it sing. The headline Qwen3.6-27B on 1× RTX 3090 (24 GB, 230W cap) ───────────────────────────────────────────── Throughput 85 TPS sustained / 106 TPS peak Context 125 K tokens Vision Enabled (MoonViT BF16) VRAM 21.3 / 24 GB Server vLLM · full OpenAI API Tools ✅ Prefix cache ✅ Spec-decode MTP n=3 · AL 3.4–3.8 · accept 97/95/91% Lorbus’s own model card quotes ~60 TPS on an RTX 5090 for the same model. We did 85 TPS sustained — on a card with 25% less VRAM and ~40% less raw compute — at 230W (quiet and cool). The write-up below is how. 85 TPS sustained. 106 TPS peak. Past the 100 TPS barrier on a single 3090. Why this matters Qwen3.6–27B shipped yesterday. As of this morning, an open-source stack exists that serves it at datacenter-adjacent throughput on a GPU you can buy used for less than a MacBook Air. That’s worth pausing on before the deep dive. Your prompts stop leaving your machine. Regulated workloads, personal notes, customer data, internal codebases — the privacy tradeoff you’ve been making for GPT-class latency evaporates. The model reads your files on your RAID. Inference is free after the card pays for itself. At 85 TPS sustained on a 230W cap, a 3090 serves millions of tokens a day on a power bill that rounds to coffee money. API spend becomes a design choice, not an operating cost. Latency is the wire. No round-trip, no rate limit, no queuing behind the rest of the planet. First token arrives at the speed of a local socket. Agent loops that felt sluggish against an API stop feeling sluggish — and tool-calling loops, where you’re paying the round-trip every turn, get dramatically snappier. You own the weights. Qwen shipped these under a permissive license. They don’t get deprecated, silently re-tuned, or price-hiked. If the model works for your use case on Tuesday, it works on Friday and next year. Fine-tuning becomes a weekend project. Once your serving stack is validated, swapping in a LoRA for a domain-specialized version is hours, not a capex conversation. Vision-capable base + your domain data = your own private multimodal model. Vision + 125K context + tool calling + 85 TPS on a used consumer GPU is, as of this week, a new category of capability. The rest of this write-up is how we got it onto ours — and how you can put it on yours by tonight. The model, and why the problem is hard Qwen3.6–27B landed on 2026–04–22 as a dense vision-language model from Alibaba’s Qwen team. It’s part of the Qwen3-Next family — meaning it has a hybrid attention architecture : interleaved DeltaNet (Gated Linear Attention, recurrent state) and standard softmax attention layers. Plus a native Multi-Token Prediction (MTP) head for speculative decoding. On paper, it’s a dream model for a consumer GPU: 27B parameters = ~17 GB in INT4, comfortably on 24 GB Vision tower is a compact MoonViT that stays BF16 (~0.9 GB) MTP head = free speculative decoding if the inference engine plays nice In practice, every one of those “on paper” assumptions hits an invisible wall on consumer hardware. The three big ones: DeltaNet’s recurrent state breaks every standard speculative-decoding pipeline. Rejecting a draft token means rolling the state back — and linear-attention recurrences can’t be rolled back. vLLM, SGLang, llama.cpp mainline — none of them handled it correctly out of the box. Most INT4 quants drop the MTP head or quantize it to INT4 too. Either way, vLLM’s Qwen3_5MTP loader can't find the weight it's expecting ( mtp.fc.weight ). Result: MTP silently loads with zero parameters → 0% draft acceptance → you're paying the overhead with none of the speedup. TurboQuant KV cache (the thing that makes 125K context possible) refuses to load on hybrid models. vLLM raises NotImplementedError at arg_utils.py:1652 the moment it sees a Mamba-like layer. And even when you work around that , the backend has a subtler bug that crashes CUDA graph capture specifically when speculative decoding is enabled. Each of these stopped us cold on first contact. This is the story of getting past all three. The journey False start: “The model is broken” First symptom, 2026–04–22. We downloaded three Qwen3.6–27B GGUF quants via aria2c -i url-list to max throughput. Everything loaded. Everything produced multi-script gibberish — Chinese + Latin + Korean + Greek + Malayalam token salad, or infinite loops of " is is is is is..." . We spent ~6 hours hypothesizing: new attention variant? Broken sampling? Flash-attention version mismatch? Chat template drift? Upstream llama.cpp bug on qwen35 arch? The actual answer was embarrassingly mundane. aria2c silently corrupted the files. All three GGUFs came down at exactly the advertised size but with wrong bytes mid-file. Size checks passed; SHA256 checks didn't — which nobody had run yet. Re-downloaded via hf download with HF_HUB_ENABLE_HF_TRANSFER=1 and verified against HF's x-linked-etag header. Model worked immediately. Lesson (filed permanently under LEARNINGS.md): after any download ≥2 GB, sha256sum against HF's linked-etag. Never trust size alone. The first hypothesis on garbage output should always be file integrity, not the model. Baseline: “Vanilla INT4, no spec-dec, ~38 TPS” First real working config was cyankiwi AWQ-INT4 (19 GB) on vLLM :latest : A1: 38 TPS / 8K ctx / 21.4 GB VRAM Coherent output (“Capital of France → Paris”), full OpenAI API, nothing exotic. This was the first working path after the GGUF fiasco and gave us a baseline. Then we tried to turn on MTP: A3: FAIL — OOM MTP head needs 2.37 GB Base model weights 21.24 GB 24 GB card: nope. vLLM had allocated a fresh BF16 MTP head — 2.37 GB of parameters for a fused linear prediction layer — because cyankiwi’s quant didn’t include one. The Qwen3_5MTP loader defaults to instantiating BF16 when the quant omits the head tensors. Dead on a 24 GB card. Breakthrough #1: Lorbus’s clever quant Enter Lorbus/Qwen3.6-27B-int4-AutoRound — 19 GB total, AutoRound INT4 calibration, group_size 128, symmetric packing. Standard stuff. Except Lorbus's README had a paragraph that turned out to be the whole game: A plain auto-round run on a Qwen3.5/3.6 model packs mtp.fc as INT4. In that form, vLLM skips loading the layer entirely (param name mismatch between fc.qweight and the expected fc.weight ), which makes MTP speculative decoding produce 0% acceptance. This release dequantizes mtp.fc back to BF16 after AutoRound finishes. Translation: Lorbus manually dequantized the one weight that matters for MTP, costing ~100 MB . Everything else stays INT4. vLLM’s loader now finds exactly what it expects, and the MTP head runs at its intended BF16 precision alongside the INT4 base. We loaded it with --speculative-config '{"method":"mtp","num_speculative_tokens":1}' : L2: 54.6 TPS (narr) / 59.0 TPS (code) / 8K ctx / 20.3 GB VRAM Mean AL 1.9 · per-pos accept 78–96% First working speculative decoding on a Qwen3-Next hybrid on our stack. Ever. +31% narrative, +43% code over no-spec. And the MTP head footprint? 280 MiB. Not 2.37 GB. Because Lorbus packed the transformer-layer portions INT4 along with the base , leaving only the final fc projection in BF16. The single-card fit is a design decision, not luck. Why does this work where the DeltaNet rollback problem doesn’t bite? Because num_speculative_tokens=1 is a single-step propose/verify. There's no multi-step state rewind — accept or reject happens atomically per token, and DeltaNet state advances exactly once per committed token. The invariant holds. The MTP sweep: n=3 is the sweet spot With MTP working, we asked: how many speculative tokens should we draft per step? n=1: 54.6 / 59.0 TPS AL 1.9 per-pos 96% n=2: 61.0 / 69.7 TPS AL 2.4 per-pos 82/56% n=3: 63.8 / 79.7 TPS AL 3.4