RTX 3090에서 Qwen 속도 개선하기
요약
본 글은 RTX 3090 환경에서 Qwen3.8-27B 모델의 추론 속도를 최적화한 경험을 공유합니다. IQ3_S 양자화 가중치, Q8 KV 캐시, MTP4 조합을 통해 코딩 작업 생성 속도가 약 33 토큰/초에서 60 토큰/초로 크게 향상되었습니다. 이 글은 모델의 성능 측정 기준(생성 속도 vs. 전체 작업 시간)과 다양한 최적화 구성 요소에 대한 깊이 있는 분석을 제공합니다.
핵심 포인트
- IQ3_S 양자화 가중치, Q8 KV 캐시, MTP4 조합으로 성능 극대화.
- 코딩 생성 속도는 33 토큰/초에서 60 토큰/초로 크게 개선됨.
- 성능 측정 시 '생성 속도'와 '전체 작업 시간'을 구분하여 이해해야 함.
- 모델 최적화는 가중치 압축(IQ3)과 캐시 형식(Q8 KV)의 조합으로 이루어짐.
이 글은 my blog에 처음 게시되었습니다. 중국어 버전.
지난 며칠 동안 저는 단일 24GB RTX 3090에서 Qwen3.8-27B를 계속 조정했습니다. 코딩 작업 중의 생성 속도는 원래 설정으로 약 33 토큰/초였던 것에서 약 60 토큰/초로 증가했습니다.
주목할 만한 두 가지 다른 발견이 있습니다. 반복적으로 실패하던 작업은 결함 있는 테스트였고, 한 구성은 토큰을 더 빨리 생성했지만 코드를 전달하는 데 3분이 더 걸렸습니다.
현재 제가 가장 선호하는 것은 IQ3_S 양자화 가중치(quantized weights), Q8 KV 캐시, 그리고 MTP4입니다. 일반적인 복구 작업에는 총 컨텍스트 창 크기 128K를 사용할 것입니다. 220K 창은 긴 입력을 처리했지만, 전체 코딩 검증은 아직 불완전합니다. 다음은 이러한 선택으로 이어진 내용입니다.
작성 고지: 본 기사는 기록된 로컬 실험을 통해 AI의 도움을 받아 작성되었으며 실험자가 검토했습니다. 아래 제시된 결과와 한계는 저장된 실행을 기준으로 합니다.
제가 실제로 테스트한 것
이전 게시물은 출력 예산 및 추론 설정에 중점을 두었으며, 결국 23/24의 전달 통과율을 달성했습니다. 이것들은 8가지 작업을 3번 반복한 것이지, 24개의 개별 문제가 아닙니다. 나중에 8회 시도 매개변수 화면은 각 작업을 한 번씩 실행했습니다.
이 테스트 스위트에는 캐싱, 데이터베이스 트랜잭션, 증분 스트림(incremental streams), 경로(paths), 원장 처리(ledger processing), 빌드 종속성(build dependencies), 비동기 동시성(asynchronous concurrency), 페이지네이션을 다루는 6개의 Python 작업과 2개의 TypeScript 작업이 포함되어 있습니다. 이 중 7개는 작성자 복구 작업이며, 하나는 boltons의 고정된 버전(pinned version)에 주입된 결함을 가지고 있습니다. 에이전트는 코드를 검사하고, 파일을 편집하고, 확인을 실행하며, 결과를 전달해야 합니다.
코드가 독립적인 검사를 통과하면 기능적 패스(functional pass)를 기록합니다. 전달된 패스는 정상 완료, 자체 검사 및 최종 인계가 추가로 필요합니다. 이러한 작은 수리 작업들은 구성을 선택하는 데 도움이 되지만, 모든 종류의 프로덕션 저장소 작업을 대표하지는 않습니다.
Tokens/s는 생성 속도를 측정하며, 총 생성 토큰을 총 디코드 시간으로 나눈 값입니다. 여기에는 추론(reasoning) 및 도구 호출 구문이 포함되지만 프롬프트 처리는 제외됩니다. 전체 작업 시간(Whole-task time)에는 파일 접근, 테스트 및 도구 대기 시간이 포함됩니다. 생성 속도와 전달 속도는 다른 측정값입니다.
현재 IQ3를 유지하는 이유
원래 Q4_K_M 파일은 약 15.66 GiB였습니다. 제가 선택한 ISTA-DASLab GSQ-RCO IQ3_S 파일에는 MTP 예측 헤드(prediction head)가 포함되어 있으며 약 11.29 GiB입니다. 가중치가 작을수록 캐시와 런타임 버퍼를 위한 GPU 메모리가 더 많이 남습니다.
두 가지 압축 설정은 혼동하기 쉽습니다: IQ3는 가중치를 압축하고; Q8 KV는 추론 중에 저장되는 어텐션 캐시(attention cache)에 대해 8비트 형식을 사용합니다. 이들은 함께 사용할 수 있습니다. IQ3 파일명이라고 해서 모든 가중치가 정확히 세 비트를 갖는다는 의미도 아닙니다. 이 모델은 서로 다른 텐서에 서로 다른 정밀도를 할당합니다.
저는 Bartowski의 IQ4_XS도 테스트해 보았고, 로컬에서 Q4_0 MTP 헤드를 추가했습니다. 아래 비교는 각 구성별로 8가지 작업을 3번 반복하고, 총 창(window) 크기는 128K, 응답당 출력 제한은 32K, 그리고 xhigh 추론을 사용했습니다.
| Configuration | Generation rate | Delivered |
|---|---|---|
| Original Q4_K_M, MTP off | 33.29 tokens/s | 23/24 |
| ... |
테이블은 아래에서 논의할 Ledger fixture 결함을 포함하여 이전 테스트 점수를 보존합니다. 이러한 역사적 코호트가 모두 재등급된 것은 아니므로, 최종 품질 순위나 완전한 품질 보전을 확립할 수는 없습니다.
네 가지 다른 작업에서 세 번 반복 확인을 진행했을 때, IQ4와 Q4 모두 12개 중 11개의 기능을 수행하고 통과를 달성했습니다. 하지만 새로운 랜덤 시드를 사용한 최종 IQ4 대(vs) IQ3 비교는 제가 IQ3를 유지해야 할 이유를 주었습니다: IQ4가 7.8% 더 빨랐지만, IQ3의 8개 중 7개 대비 8개 중 6개를 달성했고, 전체 작업 시간은 약 2.1% 더 길었습니다. IQ4의 지갑 답변에는 실제 오버플로우 처리 결함이 있었습니다.
이는 전반적인 IQ4 품질이 낮다는 것을 의미하지 않습니다. 또한 제가 즉시 IQ3를 대체해야 할 설득력 있는 이유도 되지 못합니다.
다른 튜닝들도 비슷한 트레이드오프를 보여주었습니다. CPU 스레드를 줄이거나, 다른 CUDA 대기 동작을 사용하거나, ngram 추측을 추가하는 것은 일관된 속도 이점을 제공하지 않았습니다. F16 캐시는 메모리 비용으로 일부 짧은 입력 화면의 성능을 개선했습니다. 더 작은 IQ3_XXS 가중치 또한 짧은 화면에서 이득이 있었지만, 부분적인 코딩 후속 작업 결과는 즉각적인 교체를 뒷받침하지 못했습니다. 짧은 화면은 후보를 선택하는 데 도움이 되지만, 에이전트는 여전히 작업을 해결해야 합니다.
MTP4가 이러한 코딩 작업에서 가장 빨랐습니다
MTP는 주 모델에 검증할 몇 가지 향후 토큰을 제안합니다. 더 많은 초안(draft)을 수락하면 주 모델의 토큰별 생성 작업을 줄일 수 있습니다.
초안 작성 자체에도 비용이 듭니다. 이 로컬 모델은 MTP 헤드를 하나 가지고 있으며, 깊이가 커질수록 반복적으로 호출됩니다. 나중에 거부된 위치는 그 작업을 낭비합니다. MTP4는 라운드당 네 번 보장되는 수락을 의미하는 것이 아니라, 최대 네 개의 제안된 초안 토큰을 의미합니다.
저는 IQ3_S, Q8 KV, 총 128K 창(window), 그리고 64K 출력 제한을 고정하고, 각 코딩 작업을 깊이 2부터 6까지 실행했습니다. 작업당 하나의 공유 시드를 사용하여 40개의 완료된 시도를 만들었습니다.
| Maximum draft tokens | Generation rate |
|---|---|
| 2 | 57.98 tokens/s |
| ... | |
| MTP4는 MTP2보다 약 5.7% 더 빨랐습니다; 깊이를 늘려도 추가적인 이점은 없었습니다. 짧은 입력 화면에서는 MTP2가 선호되었지만, 실제 코딩 작업에서는 MTP4가 선호되었습니다. 저는 후자(MTP4)를 우선시합니다. 왜냐하면 제가 실행하고 싶은 작업에 더 가깝기 때문입니다. |
이 테스트는 8가지 익숙한 작업을 각각 한 번씩 시도한 것이며, 순서와 열 조건이 완벽하게 일치하지 않았습니다. 이는 이 장비에서 선택할 수 있는 옵션일 뿐이며, 모든 모델과 GPU에 대한 보편적인 최적 깊이를 의미하지 않습니다.
Ledger가 테스트를 검토하도록 만든 이유
Ledger는 CSV 레코드와 금액 값을 처리합니다. 반복된 실패로 인해 불충분한 컨텍스트가 그럴듯하게 보이게 했습니다. 진단 결과 두 가지 다른 문제가 발견되었습니다.
첫째, 응답이 실제로 출력 제한에 의해 잘렸습니다. 저는 128K의 전체 창(total window)과 다른 설정은 유지하면서, 단순히 제한을 32K에서 64K로 변경했습니다. 새로운 시도의 가장 긴 응답은 40,612 토큰에 달했으며 기능 및 전달 검사를 통과했습니다. 실제 가장 긴 순차는 약 73K로, 128K 내부에 편안하게 들어왔습니다. 이 작업의 시간도 약 628초에서 1,140초로 증가했습니다.
나중에 MTP 깊이 비교에서 Ledger가 제공한 다섯 가지 답변 모두 출력이나 컨텍스트를 소진하지 않고 실패했습니다. 테스트 파일과 출력 목업(mocks)에는 정상적인 인터페이스가 부족했습니다. 유효한 답변들은 그러한 인터페이스 결함 때문에 거부되었는데, 여기에는 의도된 읽기 오류 동작에 도달조차 하지 못한 일부 케이스가 포함되었습니다.
해당 인터페이스들을 수정한 후, 다섯 가지 변경되지 않은 답변 모두 13/13의 승인 검사를 통과했습니다. 이전에는 12/13이었습니다. 읽기 오류 처리를 의도적으로 생략한 코드는 여전히 실패했으므로, 동작 요구 사항은 완화된 것이 아니었습니다.
저는 새로운 스위트 버전을 만들고 MTP4의 기존 8가지 답변을 재평가했습니다. 기능 및 전달 결과는 새로운 답변을 생성하지 않고 7/8에서 8/8로 변경되었습니다. 이는 잘못된 거부를 수정한 것일 뿐, 모델 자체를 개선한 것은 아닙니다. 다른 과거 코호트(cohort)들은 자동으로 수정된 점수를 받지 못합니다.
이는 제가 실패에 접근하는 방식을 바꾸었습니다: 잘림(truncation)과 코드 결함을 검사하고, 테스트가 실제로 측정한다고 주장하는 동작을 수행하는지 확인합니다.
220K로 긴 입력을 처리하지만 여전히 전체 코딩 유효성 검사가 필요함
입력과 출력은 컨텍스트 창(context window)을 공유합니다. 여기서 K는 1,024 토큰을 의미합니다. 170K 입력 예산에 50K 출력이 필요한 경우 총 220K가 필요합니다. 192K 입력 예산에 64K 출력이 필요한 경우 256K가 필요합니다. 출력 상한선을 높인다고 해서 이 전체 용량 제약이 사라지는 것은 아닙니다.
IQ3_S + Q8 KV + MTP4는 220K 총 창에서 179,532개의 입력 토큰을 처리한 후 짧은 출력을 생성했으며, 이때 GPU 메모리 전체가 약 22.80 GiB까지 최고치를 기록했습니다. 256K에서는 MTP4가 시작 중 할당에 실패했습니다. MTP를 비활성화하고 배치 크기를 줄임으로써 아래의 마이그레이션 실험에서 256K 구성을 완료할 수 있었습니다.
유용성을 테스트하기 위해, 저는 새로운 사양이 오래된 사양을 포함하는 긴 자료 속에 흩어져 있는 12개 서비스에 대한 스키마 마이그레이션 작업을 구축했습니다. 세 가지 접근 방식 모두 MTP를 비활성화했으며 입력 공급 방식에서 차이가 있었습니다.
| 입력 전략 | 실제 입력 토큰 | 독립적 검사 통과 수 |
|---|---|---|
| 256K 창, 전체 자료 사용 | 179,532 | 198/198 |
| ... | ||
| 전체 자료를 유지하는 것이 필요한 정보를 보존했습니다. 자르기(cropping)는 아홉 개 서비스의 사양을 누락시켰습니다. 관련 파일을 미리 선택하는 것도 통과했으며, 전체 자료 사용 시 프롬프트 처리 및 생성에 1,583초가 걸린 것에 비해 약 712초가 소요되었습니다. |
더 큰 창은 정보 손실을 방지하는 데 도움이 되었습니다. 정확한 선택이 더 작은 창으로 작업을 더 빠르게 해결할 수 있게 했습니다. 이것은 하나의 작업, 하나의 시드(seed), 그리고 198개의 검사였으며, 198개의 코딩 문제에 대한 테스트가 아니었습니다. 이는 에이전트가 필요한 모든 파일을 스스로 검색할 수 있는지 여부를 테스트한 것이 아닙니다.
실제 220K 코딩 비교는 8개 작업 중 단 2개만 완료되었습니다. 캐시와 지갑(wallet)은 통과했지만, 세 번째 작업에서 CPU 온도가 샘플링된 93.25°C에 도달하여 설정된 92°C 보호 장치를 작동시켰습니다. 6개 작업에서는 유효한 점수가 없습니다. 170K 입력 전체 경로 다음에 50K 생성 출력도 아직 테스트되지 않았습니다.
지갑(Wallet)은 트레이드오프를 구체화합니다. 220K에서의 생성이 128K 대비 약 6.4% 더 빨랐지만, 출력 토큰 수는 약 35,000개에서 46,000개로 증가했습니다. 작업 시간이 654초에서 835초로 늘어났습니다. 콘텐츠를 약간 더 빠르게 생성하는 것이 여전히 전달 시간을 3분 지연시킬 수 있습니다. 한 가지 관찰만으로는 더 큰 컨텍스트가 장황함을 유발했는지 확정할 수 없지만, 완료 시간과 정확성이 최적화 목표에 포함되어야 합니다.
DFlash2는 아직 생성 속도 이점을 보여주지 못했습니다
DFlash 역시 메인 모델에게 초안 검증을 요청하지만, 별도의 소형 모델은 전체 블록을 병렬로 제안합니다. 로컬 MTP는 초안을 순차적으로 처리합니다. DFlash2는 초안 처리를 더욱 개선했습니다. 이 메커니즘은 테스트할 가치가 있으며, 그 이점은 여전히 하드웨어와 워크로드에 달려 있습니다.
저는 동일한 IQ3_S 타겟, Q8 메인 캐시, 그리고 220K 총 창(window)을 사용하여 MTP4와 DFlash2를 개별적으로 비교했습니다. DFlash2가 활성화되었을 때는 MTP는 비활성화되었습니다. 약 8K, 32K, 179K 토큰의 동일한 콜드 입력이 각 구성에서 한 번씩 실행되어 각각 512개, 512개, 그리고 128개의 토큰을 생성했습니다.
DFlash2의 생성률은 약 3–6% 낮았습니다. 메모리 피크는 약 23.33 GiB로 MTP4 대비 약 540 MiB 높았습니다. 가장 긴 입력의 경우, 요청 시간이 프롬프트 처리 시간도 포함하기 때문에 DFlash2가 약간 더 빨랐습니다(약 303초 대 307초).
저는 일단 MTP4를 유지할 것입니다. 이 짧은 테스트는 긴 출력이나 전체 코딩 작업을 다루지 못했으며, 코딩 품질에 대한 질문에 답하지 못합니다. 이는 이 로컬 구성에서 생성 속도 이점을 보여주지 않습니다.
지금 제가 실행하고 싶은 것
이러한 일반적인 복구 작업들을 위해, 저는 GSQ-RCO IQ3_S + Q8 KV + MTP4를 선택하며, 총 창 크기는 128K이고 응답당 출력 제한은 64K입니다. 입력과 출력은 여전히 같은 창을 공유합니다. Temperature는 1.0으로 유지하고, 사고 과정(thinking) 활성화 및 xhigh 추론 노력을 적용했습니다.
참조 스택은 llama.cpp b11146, CUDA 12.8, 그리고 OpenCode 2.0.20이며, 동시 슬롯은 하나, Flash Attention을 사용하고 모든 모델 레이어는 GPU에 있습니다. 긴 입력의 경우, 코딩 검증을 완료하면서 220K를 고려할 것입니다.
전력 소모와 냉각도 지속적인 사용에 중요합니다. 거의 완성된 초기 코딩 세그먼트 두 개는 평균적으로 약 329W의 GPU 보드 전력을 소비했습니다. 이는 CPU, 다른 구성 요소 및 PSU 손실을 제외한 수치이며, 전체 PC 전력은 벽면에서의 측정이 필요합니다.
이번 라운드는 대략 60 토큰/초의 후보를 산출했으며, 매개변수 변경이 필요한 실패와 테스트 복구가 필요한 실패 간의 구분이 더 명확해졌습니다. IQ3 + MTP4 코딩 품질에 대한 다음 증거는 수정된 스위트 하에서의 반복 실행과 더 광범위한 작업 범위이며, 220K 코호트 완료가 필요합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기