標籤: Qwen3.6

  • 單卡 543 tok/s:Qwen3.6-35B NInfer 實戰

    單卡 543 tok/s:Qwen3.6-35B NInfer 實戰

    📌 本文重點

    • NInfer + A3B 讓 35B 長上下文在單卡可行
    • C++/CUDA 專門優化長序列 decode 提升 tok/s
    • 適合單卡、長上下文、低併發高價值請求場景

    在做長上下文推理服務時,最大的痛點通常是:單卡吞吐上不去、65K token 類型的長序列一跑就卡死整張 GPU。NInfer + Qwen3.6-35B-A3B 這套組合的價值,就在於:在單張 RTX 5090 上,65,536 token decode 仍能穩定 542 tok/s,讓「高吞吐長上下文 API」在單卡環境變成可行選項,而不是只能堆多卡集群。

    💡 關鍵: 在單張 RTX 5090 上達到約 542 tok/s 的 65K 長序列 decode,意味著 35B 長上下文模型不再一定需要多卡集群即可實用化


    重點說明:NInfer 能快的關鍵

    1. A3B 量化與權重重排:把算力真正用在 GEMM 上

    Qwen3.6-35B-A3B 使用的是針對 NInfer 特化的 A3B 量化格式

    • 3-bit activation + 8-bit/混合權重布局(實作細節在 NInfer repo),搭配自訂權重重排
    • 權重在轉換階段就依據 GPU memory coalescing 規則重新排列,確保 warp 讀取連續、避免 strided access
    • 實際效果:在 35B 這種級別模型上,VRAM 需求從完整 FP16 大幅下降到單卡可容納,同時減少 global memory 帶寬壓力

    對你的專案意味著:

    • 如果你卡在「35B 單卡裝不下或 decode 隨著 context 變長越來越慢」,A3B + 重排可以把 VRAM 壓到可部署範圍,同時保持高吞吐
    • 相比一般 INT4/FP8 方案,因為權重 layout 為 NInfer kernel 量身打造,訪存效率更可預期,不用自己調一堆 tile 參數

    💡 關鍵: A3B 量化加上專門的權重重排,核心價值是在不犧牲太多精度下,把 35B 模型壓進單卡 VRAM,並穩定撐起長上下文推理

    2. C++/CUDA 層的 kernel fusion 與 KV cache 策略

    NInfer 沒有走通用框架路線,而是針對 Qwen3.6-35B decode path 完全手工展開與 fusion

    • Kernel fusion:將 RMSNorm、linear、bias、activation 等步驟在 CUDA kernel 層面合併,減少 kernel launch overhead 與中間結果回寫 global memory
    • 分段 KV cache(segmented KV):KV cache 依 context 長度切段管理,而不是單一巨大 buffer
    • 長序列時只把當前段載入 SM,減少無效訪存
    • 用 ring buffer / sliding window 思路,在 65K token 上仍維持穩定延遲
    • 長序列 decode 優化
    • decode kernel直接針對「單 request、長序列」做 tuning,而非多併發
    • blockDim.x / gridDim.x 固定在實測最優配置,犧牲部分通用性換極限吞吐

    對開發者的直接好處:

    • 如果你的場景是 少量高價值請求 + 極長上下文(RAG, 多輪會話, code review),NInfer 可以在單卡提供接近「專用推理盒」的效能
    • 不用自己啃 CUDA kernel,只要用它給好的 Qwen3.6-35B-A3B 權重與啟動方式,就能拿到接近 Reddit 文中 542 tok/s 的表現(硬體足夠時)

    3. 與 vLLM / TensorRT-LLM 的差異與適用場景

    vLLM / TensorRT-LLM

    • 優點:多模型、多硬體、多併發排程,KV cache 管理通用、與 Python 生態整合好
    • 缺點:單模型、單卡、長序列極致 tuning 受限於通用抽象(scheduler、通用 kernel)

    NInfer

    • 優點:
    • 針對 Qwen3.6-27B/35B 深度優化,長序列 decode 有明顯優勢
    • C++ 單 binary,方便嵌入 C++ backend 或自訂 server
    • 缺點:
    • 模型種類有限,目前專注 Qwen3.6 特定 checkpoint
    • 生態與工具較少,要自己接 gRPC/HTTP

    什麼時候真的值得換堆疊?

    • 你的主服務 pattern 是:單卡 + 長上下文 + 單/低併發 + 想把 tok/s 壓到極限
    • 願意為一個主模型專門維護一套 C++ 推理 binary,而不是通用 LLM 平台

    如果你是多模型、多 tenant API、需要動態換模型,那就維持 vLLM/TensorRT-LLM;如果只有一個主力 35B 長上下文模型要跑滿一張高階 GPU,NInfer 值得考慮。


    實作範例:單卡部署 NInfer + Qwen3.6-35B-A3B

    1. 環境準備與模型下載

    硬體參考:

    • RTX 5090:目標是 Reddit 實測 542 tok/s 等級
    • 4090 / A100 也可,但 tok/s 與可用 context 會較低,細節後面說

    CUDA / driver:

    • 建議使用 CUDA 12.x 並搭配對應的最新 NVIDIA driver
    • 確保 nvcc --versionnvidia-smi 顯示版本相容
    # 取得 NInfer 原始碼
    git clone https://github.com/Neroued/ninfer.git
    cd ninfer
    
    # 建置(示例,實際依 repo 說明調整)
    mkdir build && cd build
    cmake .. -DCMAKE_BUILD_TYPE=Release
    make -j$(nproc)
    
    # 模型權重(在 Hugging Face 上)
    # 例如:Qwen3.6-35B-A3B 已轉好的 ninfer artifact
    huggingface-cli download Neroued/qwen3_6_35b_a3b --local-dir ./models/qwen35_a3b
    

    如果只拿到原始 Qwen3.6-35B 權重,通常要執行 repo 提供的 權重轉換工具(例如 convert_qwen36_to_a3b 類型的 binary),把 FP16/FP32 權重轉成 A3B 格式並依 NInfer 的 layout 重排:

    ./tools/convert_qwen36_to_a3b \
      --src /path/to/qwen3.6-35b-fp16 \
      --dst ./models/qwen35_a3b \
      --quant a3b \
      --reorder-layout
    

    關鍵是 --quant a3b--reorder-layout 這類選項,一定要開啟才能達到官方的吞吐水準。

    💡 關鍵: 權重轉換時開啟正確的量化與重排選項,是從原始 Qwen 權重複現 NInfer 官方性能的必要步驟

    2. 最小推理程式碼(C++)

    以下是簡化版推理程式碼示例,展示如何啟動 A3B 量化模型並執行單次長序列 decode:

    #include "ninfer/ninfer.h"  // 假設 NInfer 封裝 header
    
    int main() {
        // 1. 初始化引擎與裝置設定
        ninfer::EngineConfig cfg;
        cfg.model_path = "./models/qwen35_a3b";
        cfg.device_id = 0;
        cfg.enable_a3b = true;            // **啟用 A3B 量化**
        cfg.max_context_len = 65536;      // **長上下文設定**
    
        auto engine = ninfer::Engine::Create(cfg);
    
        // 2. 準備輸入(這裡假設已有 tokenizer)
        std::string prompt = "You are a helpful assistant...";
        std::vector<int32_t> input_ids = tokenize(prompt);  // 自行實作
    
        ninfer::DecodeParams params;
        params.max_new_tokens = 65536;    // decode 長度
        params.temperature = 0.7f;
        params.top_p = 0.9f;
    
        // 3. 單 request 推理
        auto result = engine->Decode(input_ids, params);
    
        std::cout << detokenize(result.output_ids) << std::endl;
        std::cerr << "tok/s: " << result.tokens_per_sec << std::endl; // **實測吞吐**
    
        return 0;
    }
    

    實務上你會:

    • 用自己的 tokenizer / pre-processor 替換示例中的 tokenize / detokenize
    • Engine 包成 service 層,避免每次 request 重新載入權重

    3. 接上 gRPC / HTTP 與監控

    NInfer 本身是 C++ library,你可以:

    • cpp-httplib / Crow / Pistache 做 HTTP server
    • gRPC C++ 做 RPC 層,暴露 /Generate 之類的 API

    簡化 HTTP 伺服器示例:

    #include "httplib.h"
    #include "ninfer/ninfer.h"
    
    int main() {
        ninfer::EngineConfig cfg = ...; // 同上
        auto engine = ninfer::Engine::Create(cfg);
    
        httplib::Server svr;
    
        svr.Post("/generate", [&](const httplib::Request &req, httplib::Response &res) {
            auto json = nlohmann::json::parse(req.body);
            std::string prompt = json["prompt"];
            int max_tokens = json.value("max_tokens", 2048);
    
            std::vector<int32_t> input_ids = tokenize(prompt);
            ninfer::DecodeParams params;
            params.max_new_tokens = max_tokens;
    
            auto result = engine->Decode(input_ids, params);
    
            nlohmann::json out;
            out["text"] = detokenize(result.output_ids);
            out["tok_s"] = result.tokens_per_sec;
            out["latency_ms"] = result.latency_ms;
    
            res.set_content(out.dump(), "application/json");
        });
    
        svr.listen("0.0.0.0", 8080);
    }
    

    監控方面:

    • 在 wrapper 層計算 qps、平均/95th latency、tokens/sec,用 Prometheus client C++ export
    • 定期拉 nvidia-smi --query-gpu=utilization.gpu,memory.used 或使用 NVML API,收集 GPU utilization / memory 指標

    建議與注意事項:踩坑指北

    1. VRAM 規劃:65K token 與 batch size 的取捨

    • Qwen3.6-35B-A3B 在 5090 上跑 單 request 65K token 是合理目標,但同時放大 batch size 就會立刻撞 VRAM
    • 建議配置:
    • 長上下文優先時,batch size 控制在 1–2,避免 KV cache 乘上 batch 維度
    • 想提高併發:將 max_context_len 降到 16K–32K,或改用 Qwen3.6-27B 變種

    實務做法:在測試環境跑一個 VRAM profiling:

    # 監控長序列 decode 中的 VRAM
    watch -n 1 "nvidia-smi --query-gpu=memory.used --format=csv,noheader"
    

    觀察在不同 max_new_tokens / batch 組合下的峰值 VRAM,用來決定 service 預設值。

    2. GPU 驅動 / CUDA 版本相容性

    • 使用 過舊的 driver 或 CUDA 會直接造成 kernel 無法載入、或效能大幅下降(無法使用新指令集)
    • 建議:跟隨 NInfer repo 中的 tested CUDA version,不要自行回退到 11.x
    • 若要在 A100 上跑,確認你有對應的 data center driver;consumer driver 在 data center 卡上常有意料外問題

    3. 不同 GPU 的性能預期

    大致可以這樣預估(以長序列單 request 為主):

    • RTX 5090
    • 目標:~500 tok/s @ 65K decode(與 Reddit 實測同量級)
    • 瓶頸:主要是 memory 帶寋與 SM 排程,已由 NInfer kernel 盡量打滿
    • RTX 4090
    • 預估:250–350 tok/s @ 65K decode,視具體 OC/散熱而定
    • 瓶頸:VRAM 較小,可能需要調低 context 或關閉部分優化
    • A100 80G
    • 預估:350–450 tok/s,但優化方向不同(更多重視多併發 vs 單 request)
    • 若你已在 TensorRT-LLM 上有穩定 pipeline,要評估是否真的需要切到 NInfer 的專用堆疊

    4. 何時不要用 NInfer

    • 需要支援多種模型(Llama, Mistral, 自訓模型)且頻繁切換:用 vLLM / TGI / TensorRT-LLM 更實際
    • 主要場景是 高併發短上下文聊天 API:通用框架的排程優化會比 NInfer 的單 request 長序列優化更有價值

    5. 維運架構建議:高吞吐長上下文推理 API

    一個可維運的典型架構可以是:

    • Layer 1:API Gateway
    • 負責認證、流量控制、路徑切分(例如 /chat vs /long-context
    • Layer 2:NInfer Service(C++ binary)
    • 每張 GPU 一個 service process,固定跑 Qwen3.6-35B-A3B
    • 使用 gRPC / HTTP 暴露 GenerateLongContext API,限制最大 context / tokens
    • Layer 3:監控與自動化
    • Prometheus 收集:qps, latency_ms, tokens_per_sec, gpu_util, gpu_mem_used
    • Alert 針對:latency 機率分佈偏移、tokens/sec 突然下降(可能是 driver/CUDA 問題)

    對團隊來說:

    • 把 NInfer 看成一個專用長上下文推理引擎,只做一件事(跑滿那張 GPU)
    • 其他模型與場景繼續走既有的 Python/vLLM/TensorRT-LLM 堆疊,減少大規模遷移風險

    總結來說,Qwen3.6-35B-A3B + NInfer 提供了一條實務友善的路:在單卡上達成 35B 級別模型的長上下文高吞吐推理,而不必一開始就堆多卡集群。只要你能接受專用 C++ binary、模型種類受限,這套方案可以非常直接地改善「長上下文慢到不可用」的痛點。

    🚀 你現在可以做的事

    • 到 GitHub 搜尋並 git clone Neroued/ninfer,依說明完成編譯與基本測試
    • 到 Hugging Face 搜尋 Qwen3.6-35B-A3B 或相關 artifact,實際下載並執行權重轉換
    • 在你的現有服務中加入一個長上下文專用路由,接上 NInfer C++ service 做 tok/s 與延遲對比測試