최근에 qwen에서 qwen3.8 27b를 출시하였다.

그 외에 Qwen3.8 Next Flash도 출시했는데 이 또한 SOTA 모델급이란 얘기에 드디어 로컬 모델도 많이 발전했다는 걸 느꼈다.
이제는 정말 로컬 모델로 사용할 수 있을 것으로 보인다.
물론 사용은 할 수 있지만 속도나 품질이 문제일 수 있지만 말이다.
어쨌든 Qwen3.8-27B가 나온 김에 최적의 속도가 나오는 효율 구간을 찾아 측정해보았다.
품질은 뭐, 위의 표 대로 믿고 가는 거다.
물론 측정 이후에 사용하면서 느끼는 건 생각보다 많이 똑똑해졌구나를 느껴서 굳이 품질에 대한 측정은 하지 않았다.
측정 환경
- HW: AMD Radeon AI PRO R9700 (gfx1201 / RDNA4, 32,624MiB), i7-10700 + 32GB RAM, Windows 10 Pro
- 엔진: llama.cpp b10435 Vulkan (비교용 ROCm은 lemonade b1311 / gfx120X)
- 모델: Qwen3.8-27B - Unsloth UD-Q4_K_XL / Q5_K_XL / Q6_K_XL
아래 모든 수치는 GGML_VK_DISABLE_HOST_VISIBLE_VIDMEM=1을 켠 상태다.
이 보드(MSI MAG B460M MORTAR)는 Resizable BAR가 없어서, 이 변수를 빼면 Vulkan이 3분의 1 속도로 돈다.
테스트를 해보면서 몇가지 발견한 점이 있어 함께 공유해보겠다.
KV 양자화는 속도를 아끼는 수단이 아니다
이게 제일 크게 뒤집힌 결론이다.
보통 KV 캐시를 q8_0으로 양자화하면 메모리도 줄고 대역폭도 줄어서 빨라진다고 생각한다.
나도 그렇게 알고 쓰고 있었다.
얕은 깊이만 재면 실제로 그렇게 나온다.
하지만 실제론 달랐다.
| KV | MTP | d0 | 10,439 | 43,209 | 60,392 | 121,300 |
|---|---|---|---|---|---|---|
| q8_0 | off | 28.76 | 27.71 | 25.92 | 25.11 | 22.56 |
| q8_0 | n3 | 58.98 | 54.57 | 45.96 | 43.43 | 35.62 |
| f16 | off | 29.14 | 27.83 | 25.32 | 24.17 | 20.90 |
| f16 | n3 | 52.19 | 55.56 | 49.16 | 48.35 | 42.47 |
역전되는 구간이 10k 이하다.
d0에서만 q8_0이 이기고 그 위로는 전부 f16이다.
121k에서 f16 n3(42.47)이 q8_0 n3(35.62)보다 19.2% 빠르다.
그런데 여기 재미있는 대비가 하나 있다.
MTP를 끄고 보면 121k에서 q8_0이 f16보다 7.9% 빠르다(22.56 vs 20.90).
KV가 작으니 대역폭을 덜 먹어서 당연하다.
그런데 MTP를 켜는 순간 같은 깊이에서 16.1%로 뒤집힌다.
메커니즘은 prefill 수치가 알려준다.
MTP off 기준 q8_0의 prefill 손실이 d0에서 -4.2%인데 121k에서 -28.2%로 증가한다.
MTP는 수락 토큰당 추가 forward를 돌리고 그때마다 KV 전체를 다시 읽는다.
양자화 KV의 디퀀트 비용이 MTP에서 n+1배로 증폭되는 것이다.
AR은 토큰당 한 번만 내니 작은 KV의 이득이 살아남고, MTP는 그 이득을 디퀀트 비용으로 다 잃는다.
MTP 이득 배율(n3 / off)로 보면 더 선명하다.
| KV | d0 | 10k | 43k | 60k | 120k |
|---|---|---|---|---|---|
| q8_0 | 2.05배 | 1.97배 | 1.77배 | 1.73배 | 1.58배 |
| f16 | 1.79배 | 2.00배 | 1.94배 | 2.00배 | 2.03배 |
q8_0에서는 MTP 이득이 깊이와 함께 무너지고, f16에서는 2배가 끝까지 유지된다.
결국 KV 양자화는 속도를 파는 게 아니라 속도를 희생해서 컨텍스트를 확보하게 되는 것이고, 컨텍스트가 깊을수록 속도는 나빠진다.
참고로 bf16도 같이 재봤는데, 얕은 깊이에서 f16과 동등하거나 살짝 나았다.
다만 깊이까지 재보면 121k에서 tg -14.3%, prefill -31.0%로 벌어진다.
VRAM은 바이트 단위로 같은데 그렇다.
f16 쓸 자리에 bf16을 넣을 이유는 없다.
컨텍스트가 깊어질수록 높은 양자화의 속도가 양호해진다
Q4 / Q5 / Q6를 파라미터 전부 동일하게 놓고 비교했다.
KV = q8_0 기준
| MTP | 깊이 | Q4 | Q5 | Q6 | Q5/Q4 | Q6/Q4 |
|---|---|---|---|---|---|---|
| off | d0 | 28.76 | 26.62 | 21.74 | -7.4% | -24.4% |
| n3 | d0 | 58.98 | 56.40 | 45.67 | -4.4% | -22.6% |
| n4 | 43k | 49.21 | 52.02 | 47.30 | +5.7% | -3.9% |
| n4 | 120k | 34.67 | 35.89 | 34.41 | +3.5% | -0.7% |
얕은 곳에서는 가중치 크기(16.35 / 18.83 / 24.14GiB)가 그대로 순위로 나온다.
Q4 압승이고 Q6는 24% 정도 낮다.
깊은 곳에서는 Q5가 Q4를 앞선다.
2.5GiB 더 무거운데 더 빠르다.
깊이에서는 토큰당 메모리 트래픽을 KV 읽기가 지배하는데, ctx 131072에 f16이면 KV만 8GiB고 이건 세 quant가 완전히 동일하다.
가중치 15% 차이가 전체 트래픽에서 묻힌다.
Q6가 깊은 컨텍스트에서 격차를 메우는 이유는 무거운 quant일수록 MTP의 영향을 더 잘 받기 때문이다.
| quant | 120k n3 | 120k n4 |
|---|---|---|
| Q4 | 1.58배 | 1.54배 |
| Q5 | 1.67배 | 1.69배 |
| Q6 | 1.76배 | 1.92배 |
AR 기준선이 낮을수록 투기 디코딩이 영향을 줄 여지가 크다.
Q6는 MTP 없이 17.95t/s로 처참한데 n4를 켜면 34.41까지 올라와 Q4(34.67)와 0.7% 차이로 붙는다.
다만 Q4 대 Q5는 동률로 봐야 한다.
n3 기준 42.47 vs 42.82로 노이즈 범위고, n4에서 Q5가 8.3% 앞서 보이지만 그건 단발 측정이다.
같은 조합 Q4 n4를 3회 재보니 49.34 / 43.72 / 42.05로 크게 흔들렸다.
적재되는 것과 쓸 수 있는 것은 다르다
Q6_K_XL + f16 KV로 ctx 131072를 올리면 VRAM 31.44GB로 로드에 성공하지만 제대로 쓸 수가 없다.
| Q6 f16 vs Q6 q8_0 | prefill | tg |
|---|---|---|
| d0 | 99.9 → 35.2 (−65%) | 45.67 → 14.50 (−68%) |
| 43k | 520.4 → 56.6 (−89%) | 40.85 → 11.26 (−72%) |
로드는 되는데 왜 이렇게 되는지 좀 풀어서 적어둔다.
VRAM에 들어가야 하는 건 가중치만이 아니다
llama.cpp가 GPU에 올리는 것은 세가지이다.
| 덩어리 | 성격 | Q6 + f16 @ctx131072 |
|---|---|---|
| 가중치 | 고정. 한 번 올리면 끝 | 24.14 GiB |
| KV 캐시 | 고정. ctx만큼 미리 잡음 | f16 = 8.00 GiB |
| 연산 버퍼 | 매 스텝 읽고 쓰는 작업공간 | 나머지 |
연산 버퍼는 어텐션 스코어 행렬이나 중간 계산값 같은 걸 담는 자리다.
-b 2048 -ub 512가 이 크기를 정한다.
앞의 둘과 달리 토큰을 만들 때마다 계속 접근하는 놈이라, 여기가 느려지면 그대로 생성 속도가 된다.
셋을 더하면 34.65GiB가 필요한데 이 카드에서 실제로 쓸 수 있는 건 31.86GiB다.
2.8GiB가 넘친다.
넘치는데 왜 에러 없이 뜨나
Windows가 VRAM에 자리가 없으면 시스템 RAM 일부를 GPU 메모리인 것처럼 빌려준다.
그래서 llama-server가 에러 없이 뜨고, 겉보기엔 정상이다.
적재는 되는데 쓸 수 없다가 이 상태다.
문제는 그 빌려온 메모리가 그래픽카드 안이 아니라 메인보드 건너편에 있다는 거다.
GPU가 거기 접근하려면 PCIe 슬롯을 통과해야 한다.
| 어디서 읽나 | 속도 |
|---|---|
| VRAM (카드 안) | 650 GB/s |
| 시스템 RAM (PCIe 3.0 x16 건너) | 약 16 GB/s |
40배 차이다.
그래서 무슨 일이 벌어지나
연산 버퍼는 토큰 하나 만들 때마다 필요하다. 그게 카드 밖으로 밀려나 있으면, 토큰마다 PCIe를 왕복해야 한다.
한 번 옮겨놓고 끝나는 게 아니라 매 토큰 반복된다.
시간으로 보면 이렇다.
| 토큰 하나에 걸리는 시간 | |
|---|---|
| 정상 (48.69 t/s) | 20.5 ms |
| 넘친 상태 (10.07 t/s) | 99.3 ms |
차이 79ms가 전부 데이터 기다리는 시간이다.
계산 자체는 20ms면 끝나는데 데이터가 도착하기를 80ms 기다린다.
GPU가 일하는 시간보다 기다리는 시간이 네 배다.
이게 병목이 계산이 아니라 데이터 이동이라는 증거가 하나 더 있다.
같은 조건에서 -ub 512를 -ub 128로 낮추면 17.11 → 30.11t/s가 된다. (1.76배)
계산량은 똑같고 한 번에 옮기는 덩어리만 작게 쪼갠 건데 이만큼 회복된다.
그냥 GPU가 느린 거라면 배치 크기 바꾼다고 이렇게 안 변한다.
결론
그래서 결론이 뭐라고 묻는다면 아래와 같이 정리할 수 있다.
깊이별로 정리하면 이렇다.
전부 Vulkan b10435 + GGML_VK_DISABLE_HOST_VISIBLE_VIDMEM=1 전제다.
| 컨텍스트 | KV | MTP | 실측 | 비고 |
|---|---|---|---|---|
| ~1만 | q8_0 | n3 | 약 54~59 t/s | 기동 직후 편향 제외한 정상 상태 |
| 1만 ~ 13만 | f16 | n3 | 42.47 t/s @121k | 3회 재현, 산포 0.09% |
| 13만 ~ 26만 | q8_0 | n3 | 32.14 t/s @185k | f16이 못 담는다 |
컨텍스트 상한은 전부 실제로 채워서 쟀다.
Q4 + q8_0이면 네이티브 262,144를 전부 VRAM에 담는다(27.59GB).
185k 깊이에서도 32t/s로 쓸 수 있어서 장식이 아니다.
다만 prefill이 282.8t/s라 18.5만 토큰을 채우는 데 11분이 걸린다.
프롬프트 캐시 없이는 대화형으로 못 쓴다. f16의 실질 상한은 131,072다.
| 편성명 | 모델 | KV | MTP | d0 | 121k | VRAM |
|---|---|---|---|---|---|---|
q4-n3 |
UD-Q4_K_XL | f16 | n3 | 52.19 | 42.47 | 26.3G |
q4-n4 |
〃 | f16 | n4 | 51.43 | 42.05 | 26.5G |
q5-n4 |
UD-Q5_K_XL | f16 | n4 | 51.98 | 41.82 | 29.2G |
q6-n4 |
UD-Q6_K_XL | q8_0 | n4 | 48.20 | 34.41 | 30.2G |
명령어는 이 형태 하나에서 모델 파일과 n-max만 바뀐다.
set GGML_VK_DISABLE_HOST_VISIBLE_VIDMEM=1
b10435-vulkan\llama-server.exe ^
-m llm_models\Qwen3.8-27B-UD-Q4_K_XL.gguf ^
-ngl 99 -c 131072 -ctk f16 -ctv f16 -fa on -b 2048 -ub 512 ^
--jinja --reasoning-format deepseek -np 1 ^
--spec-type draft-mtp --spec-draft-n-max 3 ^
--load-mode none --cache-ram 12288 ^
--temp 1.0 --top-p 0.95 --top-k 20 --min-p 0.0 ^
--reasoning-budget 12288 ^
--reasoning-budget-message "I have enough information. Answer now." ^
--host 0.0.0.0 --port 8080
RDNA4는 여전히 그냥 켜면 빠른 단계가 아니며 각종 실험과 노력이 들어가야 하는 아키텍쳐이다.
다행히 여러 사람들의 노력에 의해 vllm을 사용한다거나 FP8을 사용한다거나 하면 성능이 성능이 올라갈 수 있게 되었다.
싱글 R9700에서는 백엔드는 Vulkan로, KV는 f16 고정, MTP는 n3, 나머지는 손대지 않는 게 나을 것 같다.
같은 R9700이나 RDNA4 카드로 27B를 굴리는 분들에게, 특히 ReBAR 없는 구형 보드에 꽂아둔 분들에게 이 글이 도움이 되었으면 한다.
참고로 나는 Q5_K_XL과 120k의 조합으로 사용중이다.
'홈서버 > LLM' 카테고리의 다른 글
| [LLM] R9700에서 Qwen3.6-27B 벤치마크 (0) | 2026.06.04 |
|---|---|
| [LLM] 로컬 LLM(Qwen3.5 35B&9B) vs OpenRouter, 비용 면에서 뭐가 더 나을까? (2) | 2026.04.04 |
| [LLM] RTX4060Ti 16GB에서 Qwen3.5 35B-A3B Q3 vs 9B Q4, 뭐가 더 나을까? (0) | 2026.03.29 |
| [LLM] Qwen3.5 2B, 4B, 9B, 27B, 35B-A3B 구동 후기 (0) | 2026.03.16 |
