광고
~ / posts / developer

LLM 컨텍스트 길이 늘리기, YaRN·rope_scaling 설정별 비용과 품질 비교

오픈 모델로 64K·128K 입력을 받으려면 처음부터 긴 길이로 학습된 모델이 가장 싸고, 정적 YaRN은 짧은 입력 품질을 깎아요. 128K 요청 1건의 KV 메모리, 프리필 연산량, 미세조정 GPU 비용, 방식별 품질 수치와 vLLM 설정·체크리스트를 정리했어요.

32K로 학습된 모델에 긴 계약서 묶음이나 코드 저장소를 넣으려 할 때, "rope_scaling 한 줄만 넣으면 되나?", "128K로 늘리면 GPU가 얼마나 더 드나?"부터 막히죠. 결론부터 말하면 필요한 길이까지 원래 학습된 모델이 있으면 그 모델을 쓰는 게 가장 싸고 안전하고, 없을 때만 모델 카드가 검증한 YaRN factor를 장문 전용 서버에만 켜는 게 무난해요. 설정 없이 max_model_len만 키우는 건 선택지가 아니에요.

RoPE의 회전 원리는 알고 있다고 보고, 이 글은 고르는 데 필요한 숫자만 다뤄요. config.json 읽는 법, 길이별 메모리·연산량, 미세조정 비용, 방식별 품질, vLLM 설정과 점검표 순서예요.

광고

내 모델이 몇 토큰까지 되나, config.json 읽는 법

먼저 원래 학습 길이와 이미 들어간 스케일링을 봐요. config.json의 세 칸이에요.

Hugging Face transformers 최신 소스(modeling_rope_utils.py)는 이 칸 이름을 rope_parameters로 바꿨고 예전 이름도 받아 줘요. rope_type은 linear(PI), dynamic(동적 NTK), yarn, longrope, llama3 등이에요. 두 이름을 다 읽는 점검 스크립트예요.

import json
import sys

def ctx_check(path, need_len):
    c = json.load(open(path))
    rs = c.get("rope_scaling") or c.get("rope_parameters") or {}
    rtype = rs.get("rope_type") or rs.get("type") or "default"
    max_pos = c["max_position_embeddings"]
    native = rs.get("original_max_position_embeddings", max_pos)
    head_dim = c.get("head_dim") or c["hidden_size"] // c["num_attention_heads"]
    kv = 2 * c["num_hidden_layers"] * c["num_key_value_heads"] * head_dim * 2  # bf16
    print(f"[{path}] rope_type={rtype} theta={c.get('rope_theta')}")
    print(f"  설정 최대 {max_pos:,} / 스케일링 전 길이 {native:,}")
    print(f"  토큰당 KV {kv // 1024}KiB, {need_len:,}토큰 1건 {kv * need_len / 2**30:.1f}GiB")
    if need_len <= max_pos:
        print("  → 설정 그대로 가능")
    else:
        print(f"  → 확장 필요, factor 후보 {need_len / native:.2f}")

for p in sys.argv[2:]:
    ctx_check(p, int(sys.argv[1]))

Llama 3.1 8B config.json, Qwen2.5-7B-Instruct config.json, Qwen3-8B config.json을 받아 python3 ctx_check.py 65536 llama31.json qwen25.json qwen3.json으로 돌린 결과예요.

[llama31.json] rope_type=llama3 theta=500000.0
  설정 최대 131,072 / 스케일링 전 길이 8,192
  토큰당 KV 128KiB, 65,536토큰 1건 8.0GiB
  → 설정 그대로 가능
[qwen25.json] rope_type=default theta=1000000.0
  설정 최대 32,768 / 스케일링 전 길이 32,768
  토큰당 KV 56KiB, 65,536토큰 1건 3.5GiB
  → 확장 필요, factor 후보 2.00
[qwen3.json] rope_type=default theta=1000000
  설정 최대 40,960 / 스케일링 전 길이 40,960
  토큰당 KV 144KiB, 65,536토큰 1건 9.0GiB
  → 확장 필요, factor 후보 1.60

Llama 3.1은 이미 llama3 스케일링(factor 8, 8K → 128K)이 들어간 상태라 YaRN을 또 얹으면 안 돼요. Qwen3-8B는 config상 40,960이지만, Qwen3-8B 모델 카드는 이 값이 출력 32,768 + 프롬프트 8,192를 잡아 둔 것이고 원래 길이는 32,768이라고 설명해요. 그래서 64K용 factor는 1.60이 아니라 2.0이에요. config와 모델 카드를 같이 읽어야 하는 이유예요.

길이를 늘리는 방식 다섯 가지, 무엇을 바꾸나

방식하는 일추가 학습짧은 입력 영향
그냥 늘리기max_model_len만 키움없음쓰면 안 됨 (학습 길이 밖에서 무너짐)
정적 스케일링고정 factor (vLLM·SGLang·llama.cpp)없음 또는 미세조정모든 요청에 걸려 떨어질 수 있음
동적 스케일링길이에 맞춰 factor 갱신없음학습 길이 안에서는 그대로
직접 미세조정PI·YaRN으로 긴 문서 학습수백~천 스텝데이터에 따라 변함
장문 학습 모델처음부터 길게 학습된 모델없음(제작사가 함)설계된 상태

"그냥 늘리기"는 숫자로 분명해요. Position Interpolation 논문(Chen 외, 2023) 표 1에서 2K로 학습된 LLaMA 7B에 4K 이상을 그대로 넣으면 PG19 perplexity가 1,000을 넘었어요. 2K에서는 7.20이었어요. vLLM도 막아 둬요. vLLM model.py 소스는 max_model_len이 config에서 계산한 최대치보다 크면 오류를 내고, VLLM_ALLOW_LONG_MAX_MODEL_LEN=1로 우회하면 RoPE 모델은 그 위치에서 nan이 나온다고 경고해요.

필요한 컨텍스트 길이가 학습 길이 이하인지, 장문 학습 모델이 있는지, 모델 카드에 검증된 YaRN factor가 있는지, 미세조정이 가능한지를 차례로 물어 그대로 쓰기·모델 바꾸기·장문 전용 서버·직접 미세조정·RAG로 가지를 나누는 판단 순서도
위에서부터 물어서 처음 '예'가 나오는 칸이 가장 싸고 안전한 선택이에요

128K 요청 한 건이 드는 KV 메모리와 GPU 비용

늘릴 수 있느냐와 별개로 긴 요청은 비싸요. KV 캐시가 길이에 정비례해서, 128K 요청 1건이 Qwen2.5-7B 7.0GiB, Llama 3.1 8B 16.0GiB, Qwen3-8B 18.0GiB예요. H100 80GB 한 장 기준으로 메모리 상한을 계산했어요(80GiB × 0.92 − bf16 가중치 − 활성값 4GiB를 가정, KV 몫 약 54~55GiB).

H100 1장에 메모리상 동시에 담기는 요청 수 (요청 길이별)
Qwen2.5-7BLlama 3.1 8BQwen3-8B
02550751001251508K · Qwen2.5-7B 126건8K · Llama 3.1 8B 54건8K · Qwen3-8B 48건8K32K · Qwen2.5-7B 31건32K · Llama 3.1 8B 13건32K · Qwen3-8B 12건32K64K · Qwen2.5-7B 15건64K · Llama 3.1 8B 6건64K · Qwen3-8B 6건64K128K · Qwen2.5-7B 7건128K · Llama 3.1 8B 3건128K · Qwen3-8B 3건128K

요청마다 표시된 길이를 다 채운다고 본 상한이에요. KV 헤드가 4개인 Qwen2.5-7B가 같은 메모리로 두 배 넘게 담아요.

단위: 건 · 자료: 각 모델 config.json 값으로 직접 계산 (80GiB × 0.92 − bf16 가중치 − 활성값 4GiB 가정)
표로 보기
구분Qwen2.5-7BLlama 3.1 8BQwen3-8B
8K1265448
32K311312
64K1566
128K733

돈으로 바꾸면 이래요. Lambda 가격표의 H100 SXM 1장 인스턴스는 시간당 4.29달러(2026-10-26 확인, 세금 별도)라, 한 달(730시간) 3,131.7달러예요. Llama 3.1 8B 기준으로 128K 슬롯 하나는 월 약 1,044달러(3건), 32K 슬롯은 약 241달러(13건), 8K 슬롯은 약 58달러(54건)예요. 최대 길이를 128K로 열어 두면 피크 때 긴 요청 몇 개가 KV를 다 차지해 짧은 요청이 밀려요. 동시 요청 계산은 vLLM KV 캐시 용량 계산에 자세히 있어요. GiB와 GB가 섞이면 수십 % 틀리니 데이터 용량 변환기로 단위를 먼저 맞추세요.

긴 입력의 지연, 프리필 연산량은 길이 제곱으로 는다

프리필 연산량은 대략 2 × 파라미터 수 × n(행렬 곱)과 2 × 층 수 × n² × 어텐션 폭(인과 마스크를 건 QKᵀ·AV)의 합이에요. Llama 3.1 8B(32층, 어텐션 폭 4,096)로 직접 계산했어요.

입력 길이프리필 연산량8K 대비토큰당 연산 8K 대비어텐션 비중
8,1921.49 × 10¹⁴1배1배11.8%
32,7688.08 × 10¹⁴5.4배1.35배34.8%
65,5362.18 × 10¹⁵14.6배1.83배약 52%
131,0726.61 × 10¹⁵44.3배2.77배68.1%

첫 토큰 시간(TTFT)은 이 연산량에 거의 비례해서, 8K에 1초 걸리는 환경이면 128K는 단순 비례로 약 44초예요. FlashAttention도 n² 연산 자체는 없애지 못하고, 디코드도 쌓인 KV를 매번 읽어 길수록 느려져요. 필요한 부분만 넣는 검색(RAG)과 비교할 때 이 표가 기준이에요. 한국어 문서의 실제 토큰 수는 한국어 LLM 토큰 비용 비교처럼 쓰는 모델의 토크나이저로 세야 해요.

정적 YaRN과 동적 스케일링, 짧은 입력 품질 차이

Qwen2.5-7B-Instruct 모델 카드는 factor 4.0 YaRN으로 131,072까지 다룬다고 하면서, vLLM은 정적 YaRN만 지원해 factor가 입력 길이와 상관없이 고정되고 짧은 텍스트 성능에 영향이 있을 수 있다며 필요할 때만 넣으라고 해요. Qwen3 카드는 평소 길이가 65,536이면 factor 2.0처럼 필요한 만큼만 키우라고 해요.

그 영향은 YaRN 논문(Peng 외, 2023) 부록 표 5에서 볼 수 있어요. 2K로 학습된 LLaMA 7B에 미세조정 없이 s=16을 고정으로 건 경우와, 길이에 맞춰 바꾸는 동적 방식을 Proof-pile 문서로 비교한 값이에요(perplexity, 낮을수록 좋음).

미세조정 없는 YaRN, 고정 factor 16과 동적 factor의 평가 길이별 perplexity
정적 YaRN s동적 YaRN
0123452K4K8K16K32K2K · 정적 YaRN s 0perplexity4K · 정적 YaRN s 4.2perplexity8K · 정적 YaRN s 4.2perplexity16K · 정적 YaRN s 3.7perplexity32K · 정적 YaRN s 3.5perplexity3.52K · 동적 YaRN 4perplexity4K · 동적 YaRN 3.7perplexity8K · 동적 YaRN 3.6perplexity16K · 동적 YaRN 3.3perplexity32K · 동적 YaRN 3.5perplexity3.5

원래 모델의 2K perplexity는 4.05예요. 고정 factor는 짧은 입력에서 손해가 가장 크고, 32K에서는 두 방식이 같아져요.

단위: perplexity · 자료: YaRN 논문(arXiv 2309.00071) 표 5, LLaMA 7B · Proof-pile 10문서 · 슬라이딩 윈도 S=256
표로 보기
구분정적 YaRN s동적 YaRN
2K04
4K4.23.7
8K4.23.6
16K3.73.3
32K3.53.5

같은 표에서 학습 없이 PI를 s=16으로 걸면 2K부터 perplexity가 100을 넘었어요. 학습 없이 고정 factor를 쓴다면 YaRN이어야 해요. 동적 방식은 길이마다 회전 기준이 바뀌어 KV 캐시와 쓰기 까다로워서(논문은 RoPE 적용 전 KV를 캐시하라고 해요), 주요 서빙 프레임워크는 정적 YaRN을 구현해요. 그래서 서빙에서는 짧은 요청용 기본 서버와 장문 전용 YaRN 서버를 나눠 길이로 라우팅하는 구성이 현실적이에요.

광고
광고

직접 미세조정 비용과 방식별 품질

검증된 확장이 없거나 도메인 장문 성능이 중요하면 직접 미세조정을 검토해요. YaRN 논문 표 4의 방식별 A100 시간에 Lambda 가격표의 8장 인스턴스 A100 SXM 80GB 단가(GPU당 시간당 2.79달러, 2026-10-26 확인)를 곱했어요.

7B 모델 컨텍스트 확장 미세조정의 GPU 비용 (A100 시간 × 2.79달러)
YaRN 2K→32KYaRN 2K→32K · 357달러357달러YaRN 4K→64KYaRN 4K→64K · 714달러714달러YaRN 4K→128KYaRN 4K→128K · 1,071달러1,071달러PI 2K→16KPI 2K→16K · 1,786달러1,786달러NTK-aware 4K→100KNTK-aware 4K→100K · 17,856달러17,856달러

마지막 줄은 Code Llama의 장문 학습이에요. 데이터 준비·실패한 실험·평가 비용은 빠져 있어요.

단위: 달러 · 자료: YaRN 논문 표 4의 A100 시간(128·256·384·640·6400) × Lambda A100 SXM 단가 2.79달러로 직접 계산
표로 보기
구분학습 비용
YaRN 2K→32K357
YaRN 4K→64K714
YaRN 4K→128K1,071
PI 2K→16K1,786
NTK-aware 4K→100K17,856

YaRN은 Llama 2 7B를 PG19 64K 조각, 전역 배치 64로 400스텝 학습해 64K(s=16)를 만들었고, 거기서 200스텝을 더 해 128K(s=32)로 늘렸어요. 사전학습 데이터의 약 0.1% 미만이에요. PI 논문은 1,000스텝 이내로 LLaMA 7B~65B를 32,768까지 늘렸어요. 반대로 Llama 3 논문은 8K에서 128K까지 6단계로 늘리며 장문 사전학습에만 약 800B 토큰을 썼어요. 이 비용을 제작사가 이미 냈다는 게 장문 학습 모델을 먼저 권하는 이유예요.

같은 예산(LLaMA 7B, 2K × 16, 400스텝 미세조정)으로 YaRN 논문이 잰 값이에요.

방식2K perplexity32K perplexityARC-cHellaSwagMMLUTruthfulQA
원래 모델 (2K)4.05–51.077.835.734.3
PI5.703.5744.870.225.934.1
NTK-aware4.398.4947.473.927.732.6
NTK-by-parts4.142.8148.576.632.733.4
YaRN4.192.7748.177.230.035.1

긴 입력은 YaRN과 NTK-by-parts가 가장 좋고, 짧은 입력 벤치마크는 모두 원래 모델보다 떨어졌어요(MMLU는 NTK-by-parts가 더 높음). 논문은 미세조정 데이터(PG19)가 사전학습 데이터와 달라서 생긴 차이도 있다고 보고, Llama 2 7B의 YaRN s=16 모델은 MMLU 43.8 → 42.5로 차이가 작았어요. 어떤 방식이든 미세조정 후에는 기존 평가 세트를 꼭 다시 돌려야 한다는 뜻이에요.

상황별 추천

상황추천이유
필요한 길이가 학습 길이 안아무것도 켜지 않기짧은 입력에서 손해만 있어요
64K~128K가 자주 필요, 교체 가능그 길이로 학습된 모델장문 학습·검증이 끝나 있어요
모델 유지, 카드에 YaRN 안내최소 factor, 장문 전용 서버짧은 요청을 건드리지 않게요
긴 요청은 가끔길이 기준 라우팅 또는 RAG128K 슬롯 하나가 8K 슬롯 18개 값
도메인 장문 성능 중요YaRN으로 수백 스텝 미세조정같은 예산에서 품질이 가장 좋았어요
카드 검증 길이를 넘기고 싶음미세조정 없이는 넘기지 않기품질을 장담할 수 없어요

"128K 지원"도 재 봐야 해요. RULER 논문(Hsieh 외, 2024)은 32K 이상을 내세우는 모델 대부분이 단순 바늘 찾기는 거의 다 맞혀도 어려운 과제에서는 길이가 늘수록 크게 떨어졌고, 32K에서 만족스러운 성능을 유지한 건 절반뿐이었다고 보고해요.

vLLM에서 YaRN 켜기와 도입 체크리스트

Qwen 카드에는 vllm serve ... --rope-scaling '{...}' --max-model-len 131072 형태가 나와 있지만, 최신 vLLM 소스의 인자 목록에는 --rope-scaling이 없고 --hf-overrides로 config 값을 덮어써요. 또 위 model.py는 yarn·llama3 타입이면 max_position_embeddings가 이미 늘어난 값이라고 보고 factor를 다시 곱하지 않아서, 원래 값이 32,768인 모델은 이 칸도 같이 올려야 max_model_len이 통과해요. Qwen3-8B를 64K로 여는 예시예요.

vllm serve Qwen/Qwen3-8B \
  --hf-overrides '{"rope_scaling": {"rope_type": "yarn", "factor": 2.0,
                   "original_max_position_embeddings": 32768},
                   "max_position_embeddings": 65536}' \
  --max-model-len 65536

버전마다 바뀌어 왔으니 vllm serve --help와 시작 로그의 max_model_len을 꼭 확인하세요. YaRN의 어텐션 보정값(0.1·ln(s) + 1, s=2면 1.069)은 factor로 자동 계산돼요.

도입 전 계산(필요 길이 p95, 원래 학습 길이, 요청당 KV GiB, 프리필 연산 배수), 설정 확인(rope_type 중복, factor 최소화, max_position_embeddings, 시작 로그), 품질 검증(짧은 입력 회귀, 길이별 정답률, 위치별 바늘 찾기, TTFT p99)을 세 칸으로 나눈 체크리스트
가운데 칸에서 하나라도 어긋나면 품질 검증 전에 설정부터 다시 봐요
  1. 필요한 길이를 p95·p99로 재고 그 길이까지만 열어요.
  2. 기존 스케일링을 확인해요. 이미 llama3·yarn이 있으면 덧씌우지 않아요.
  3. 요청당 KV와 GPU 대수, 월 비용을 미리 계산해요.
  4. 짧은 입력 회귀 테스트를 돌려요. 켠 서버에서 기존 평가 세트 점수를 비교해요.
  5. 긴 입력은 길이별·위치별로 재요. 문서 앞·중간·끝에 답을 두고 정답률과 TTFT p99를 기록해요.
광고
광고

자주 묻는 질문

max_model_len만 131072로 올리면 안 되나요?

안 돼요. 학습 길이 밖에서는 본 적 없는 회전 각도가 나와 출력이 무너져요. vLLM은 config 최대치보다 크면 오류를 내고, 우회하면 nan이 나올 수 있다고 경고해요. rope_scaling을 함께 바꾸고 카드가 검증한 범위 안에서 쓰세요.

Llama 3.1에도 YaRN을 켜면 128K보다 더 늘어나나요?

Llama 3.1은 이미 llama3 스케일링(factor 8)으로 128K까지 학습돼서, 덧씌우는 건 검증되지 않은 설정이에요. 더 길게 필요하면 더 긴 길이로 학습된 모델을 찾거나 입력을 줄이는 편이 안전해요.

factor는 크게 잡아 두는 게 여유 있지 않나요?

정적 YaRN은 factor가 모든 요청에 걸려서 크게 잡을수록 짧은 입력이 손해예요. 학습 없이 s=16을 고정하면 2K perplexity가 4.05에서 4.61로 올랐어요. Qwen 카드도 필요한 길이에 맞추라고 권해요.

YaRN과 PI 중 미세조정에는 무엇을 쓰나요?

같은 400스텝에서 YaRN이 32K perplexity 2.77로 PI(3.57)보다 좋았고 2K 손실도 작았어요. Llama 2 7B 4K → 8K에서는 YaRN 400스텝이 PI 1,000스텝과 비슷했어요. rope_type을 yarn으로 두고 학습하면 돼요.

긴 컨텍스트가 되는데 RAG가 아직 필요한가요?

대부분 필요해요. Llama 3.1 8B에서 128K 입력의 프리필 연산은 8K의 약 44배이고, 동시 처리 수는 54건에서 3건으로 줄어요. 문서 전체를 봐야 하는 과제가 아니면 관련 부분만 넣는 쪽이 빠르고 싸요.

정리

더 깊이 읽기

이 글은 실무에서 판단할 때 필요한 것 위주로 정리했어요. 같은 주제의 내부 동작 원리는 devboi 기술 블로그의 RoPE 위치 인코딩 원리 — 컨텍스트 창 늘리는 PI·YaRN에서 도식과 코드로 단계별로 풀었어요.

참고한 자료

#LLM 컨텍스트 길이 늘리기#rope_scaling 설정#YaRN factor#vLLM max-model-len#128K 컨텍스트 비용#긴 문서 LLM 서빙#Position Interpolation 미세조정#장문 KV 캐시 메모리
← 이전 글LLM 양자화 형식 고르기, FP8·AWQ·GGUF 메모리·속도·GPU 비용 비교다음 글 →LoRA 파인튜닝 언제 쓰나, QLoRA·전체 학습 메모리와 비용 계산
광고

더 둘러보기

💻 개발자 다른 도구

🔥 많이 찾는 도구

🔮 재미로 한 번 더

📝 읽어 볼 만한 글

글 전체 보기 →