Files
variet_llm/docs/v3_balanced_retuning_log.md
Variet-Worker 0dee779a73 refactor(phase-01): v3 retune fast & balanced roles
fast (Gemma 4 26B-A4B):
- Enable mmproj GPU loading (vision ~1s, 12x faster than CPU)
- KV f16 → q8_0 (save ~2.5 GB VRAM for mmproj)
- Tensor split 0.5,0.5 → 0.43,0.57 (13/17 layers)
- Remove --mlock/--poll/--prio/-t/-tb (no measurable impact)
- measured_tps 74.65 → 71.89 (trade 3.7% speed for vision)

balanced (Qwen 3.5 35B-A3B):
- Tensor split 0.5,0.5 → 0.48,0.52 (enables pipeline parallelism)
- Ubatch 128 → 256 (prefill +78%: 649 → 1,157 t/s)
- mmproj + --no-mmproj-offload (CPU vision, VRAM headroom)
- Remove useless flags same as fast
- measured_tps 61.62 → 64.16 (+4.1%)

Other:
- Document full retuning in docs/v3_{fast,balanced}_retuning_log.md
- Session report at .planning/reports/20260411-session-report.md
- Add bench utilities: bench_short/bench_long/test_ts_ratios
- Speculative decoding (E2B draft) experimented but rejected
  (+14% gen vs -31% cold start + tokenizer mismatch + mmproj conflict)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 14:55:27 +09:00

8.8 KiB
Raw Permalink Blame History

v3 — Balanced Role Retuning Log (Qwen 3.5 35B-A3B)

Date: 2026-04-11 Target role: balanced (Qwen3.5-35B-A3B Q4_K_M) Goal: 기존 measured_tps: 61.62 기준을 재검증하고, 진짜 최적 구성을 실측 기반으로 확정 Result: 최종 TPS 64.16 t/s (짧은 프롬프트) / 62.00 t/s (3,100 토큰 긴 프롬프트) Status: 확정


1. 재튜닝 동기

Phase 01 종료 후 engine_models.jsonbalanced 설정이 여러 이유로 일관되지 않게 수정되어 있었음:

  • --mmproj 추가 (비전 지원용, 다른 작업자가 넣음)
  • --mlock --poll 50 --prio 3 등 Phase 01 최종본과 불일치
  • -ts 0.5,0.5 (이중 GPU 분할) 상태에서 compute buffer OOM 발생
  • 실측 속도가 레퍼런스(61.62) 대비 33~42 t/s 수준으로 떨어짐

재튜닝을 통해 원인 규명 + 안정 + 최적 설정 확정이 목표.


2. 하드웨어 진단 (핵심 발견)

GPU 모델 최대 PCIe 현재
0 RTX 3060 12GB Gen3 x16 Gen3 x4 (슬롯 4레인)
1 RTX 3060 12GB Gen4 x16 Gen4 x16

핵심: GPU 0은 PCIe 3.0 × 4 슬롯에 있음 (3.94 GB/s). GPU 1은 PCIe 4.0 × 16 (31.5 GB/s). GPU 0이 GPU 1의 1/8 대역폭.

이 비대칭이 모든 하이브리드/멀티-GPU 성능 문제의 근본 원인.


3. Qwen3.5-35B-A3B 아키텍처 실측 데이터

llama-server 로드 로그 기준:

architecture  = qwen35moe
file size     = 20.49 GiB (Q4_K_M, 5.08 BPW)
n_params      = 34.66 B
n_layer       = 40
n_head_kv     = 2
n_embd_head_k = 256
n_embd_head_v = 256
n_expert      = 256 (activated: 8)
full_attention_interval = 4

중요: 40 레이어 중 full attention은 10개만 (매 4번째). 나머지 30개는 Gated Delta Net (SSM/Mamba-like) 레이어로 recurrent state 사용. KV 캐시는 10 레이어에만 발생.

KV 캐시 실측

컨텍스트 KV 캐시 (q4_0)
128K 720 MiB
256K 1,440 MiB

(초기 추정 5GB는 오류였음 — 40레이어 전부 attention이라고 오해)


4. -ts (Tensor Split) 비율 스윕 결과

자동화 스크립트(scripts/test_ts_ratios.py)로 여러 비율 테스트:

ratio status PP c0 model c1 model c0 compute c1 compute
0.5,0.5 ready Fallback 10,540 9,931 203 123
0.48,0.52 ready ON 10,036 10,434 600 384
0.47,0.53 ready ON 10,036 10,434 600 384
0.45,0.55 error
0.43,0.57 error
0.40,0.60 error

해석:

  • 40 레이어 기준 llama.cpp가 ratio를 정수 레이어로 반올림: 0.48 & 0.47 둘 다 19/21 분할이라 동일한 메모리 배치
  • 0.5,0.5 (20/20)에서는 CUDA0 compute buffer가 PP 모드 요구치(600 MiB)를 수용 못해 자동 Fallback
  • 0.45,0.55 이상은 CUDA1이 22+ 레이어 적재로 OOM
  • 결론: PP on 유일 비율은 0.48,0.52 (또는 동등한 0.47,0.53)

5. -ub (Ubatch) 스윕 결과 — 핵심 발견

짧은 프롬프트만 테스트해서 처음에 -ub 효과를 놓쳤음. 긴 프롬프트(3,100 토큰)로 재측정:

설정 PP Prompt t/s Gen t/s 3,100 토큰 prefill GPU0 여유
ub 128 ON 649 62.01 4.85s 216 MiB
ub 256 OFF 1,157 62.00 2.68s 411 MiB
ub 384 b 768 OFF 1,275 61.61 2.43s 133 MiB

핵심 인사이트:

  1. -np 1 단일 사용자 환경에서 PP는 실질 이득 없음 — Pipeline Parallelism은 다중 요청 배칭에 의미가 있음. 단일 시퀀스면 overlap 할 대상이 없음.

  2. PP off가 오히려 유리 — compute buffer 작아져서 -ub 더 올릴 수 있음 → prefill 속도 대폭 향상

  3. -ub 수익률 체감:

    • 128 → 256: +78% (649 → 1,157 t/s)
    • 256 → 384: +10.2% (1,157 → 1,275 t/s)
    • 안정성 대비 256이 스윗 스팟
  4. Gen 속도는 -ub와 무관 — 모두 62 t/s. Gen은 KV 캐시 크기 + PCIe x4 병목이 결정.


6. mmproj 처리 결정

Qwen3.5-35B-A3B는 natively 멀티모달이라 mmproj 필요. 하지만 GPU에 올리면:

VRAM 수지 (256K, -ts 0.48,0.52):
  모델 가중치:  10,036 (GPU0) + 10,434 (GPU1)
  KV 캐시:     720 + 720 = 1,440 MiB
  Compute:    ~600 + ~384 MiB
  mmproj:     858 MiB   ← 추가 부담 → OOM

해법: --no-mmproj-offload 추가 → mmproj를 CPU RAM에 유지.

항목 GPU 오프로드 CPU 오프로드
VRAM 절약 858 MiB
텍스트 추론 동일 동일 (손실 0)
이미지 인코딩 GPU 빠름 CPU 6.4초 (640×640 기준)

Hermes Agent 사용 패턴 = 95% 텍스트, 가끔 스크린샷 → CPU 오프로드가 확실히 유리.

이미지 토큰 계산식

patch_size = 16
n_merge    = 2
→ tokens = (width/32) × (height/32)
해상도 토큰
640×640 400
768×768 576
1024×1024 1,024 (권장 최소)
2048×2048 4,096 (최대)

7. 제거된 옵션 (실측 영향 없음 확인)

옵션 제거 이유 Δ TPS
--mlock 전용 추론기. 시스템 RAM 여유. mmap 페이지 잠금 불필요 0.04
--poll 50 GPU polling. -np 1 환경에선 효과 없음 0.00
--prio 3 프로세스 우선순위. 전용기라 경쟁 없음 0.00

제거 후 속도: 64.16 t/s (유지)


8. 최종 확정 옵션

{
  "balanced": {
    "display_name": "Qwen 3.5 35B (Balanced)",
    "model_path": "models/Qwen3.5-35B-A3B-Q4_K_M.gguf",
    "measured_tps": 64.16,
    "args": [
      "--mmproj",            "models/mmproj-F16.gguf",
      "--no-mmproj-offload",
      "-ngl",                "999",
      "-c",                  "262144",
      "-np",                 "1",
      "-fa",                 "on",
      "--cache-type-k",      "q4_0",
      "--cache-type-v",      "q4_0",
      "-ub",                 "256",
      "-b",                  "512",
      "-t",                  "6",
      "-tb",                 "6",
      "-ts",                 "0.48,0.52"
    ]
  }
}

9. 최종 실측 성능

텍스트 추론

시나리오 Prompt t/s Gen t/s VRAM 여유
짧은 프롬프트 (170 tok) 64.16 GPU0 411 / GPU1 539 MiB
긴 프롬프트 (3,100 tok) 1,157 62.00 동일

비전 추론 (mmproj CPU)

단계 속도 / 시간
이미지 인코딩 (CPU, 640×640) 5.3초 (encode) + 1.0초 (decode) = 6.4초
이미지 이후 생성 62 t/s

VRAM 최종

GPU 0  11,900 MiB (여유 216 MiB)  Gen3 x4   [PCIe 병목]
GPU 1  11,710 MiB (여유 401 MiB)  Gen4 x16
합계   23,610 MiB 중 사용  │ 966 MiB 여유

CPU RAM

llama-server Working Set: ~23 GB
├── mmap 모델 (lazy)            20.5 GB
├── mmproj (CPU 할당)             0.86 GB
├── CUDA_Host compute buffer      0.39 GB
├── CPU compute buffer            0.25 GB
└── 기타                          ~0.08 GB

10. 알려진 구조적 제약

  1. GPU 0 PCIe 3.0 x4 슬롯 병목 — Gen 속도 62 t/s 상한의 주원인. 물리적 한계라 소프트웨어로 해결 불가.
  2. Pipeline Parallelism 자동 Fallback — compute buffer가 -ub 256 시 CUDA0 한계 초과. 다만 -np 1 환경에선 실질 손실 없음.
  3. mmproj CPU 상주 — 이미지 인코딩 시 GPU 대비 ~3-5배 느림. 사용 빈도가 낮아 허용.

향후 개선 여지

  • GPU 0을 PCIe 4.0 x16 슬롯으로 물리 이전 시 Gen 속도 추가 이득 기대 (~70+ t/s 가능성)
  • 비전 사용이 잦아지면 --no-mmproj-offload 재고 필요

11. 레퍼런스 대비

Phase 01 측정치:  61.62 t/s
v3 확정치:      64.16 t/s  (+4.1%)

Phase 01은 단일 GPU 환경에서 튜닝되었음 (found 1 CUDA devices 로그 확인). 현재는 듀얼 GPU (비대칭 PCIe) + mmproj 제약 + PP 동작을 모두 반영한 새로운 baseline.


12. 검증 절차 (재현용)

# 기동
run_variet_engine.bat

# 짧은 프롬프트 속도
curl -s http://localhost:8000/v1/chat/completions \
  -H "Content-Type: application/json" \
  -d '{"model":"balanced","messages":[{"role":"user","content":"Write 200 words about computing history."}],"max_tokens":300}' \
  | python -c "import json,sys; d=json.load(sys.stdin); print(d['timings']['predicted_per_second'])"

# 긴 프롬프트 속도
python scripts/bench_long.py "verify"

# VRAM 확인
nvidia-smi --query-gpu=index,memory.used,memory.free,pcie.link.gen.current,pcie.link.width.current --format=csv

Document sealed: 2026-04-11