Skip to content

필사 모드: config.json 완전 해부 — 설정 파일 한 장으로 모델 구조 읽기

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.

들어가며

오픈소스 모델을 내려받으면 가중치 파일 옆에 항상 config.json이 있습니다. 스무 줄 남짓한 이 파일에는 모델의 골격이 거의 전부 들어 있습니다. 층이 몇 개인지, 어텐션 헤드가 몇 개인지, 왜 이 모델은 KV 캐시가 작은지가 모두 여기서 결정됩니다.

이 시리즈는 "이 모델이 몇 점을 받았는가"가 아니라 "이 모델이 어떻게 만들어졌고 왜 그렇게 만들었는가"를 다룹니다. 첫 글의 목표는 하나입니다. 이 글을 다 읽으면 처음 보는 config.json을 열어서 구조를 읽어낼 수 있어야 합니다.

수치는 2026-08-12에 논문·공식 리포트·config.json에서 직접 확인했습니다. 모델은 갱신되므로 원본을 다시 확인하세요.

실제 파일부터 보기

Qwen3-8B의 설정 파일입니다. 아래 값은 전부 공개 저장소에서 그대로 가져온 것입니다.

{
  "hidden_size": 4096,
  "num_hidden_layers": 36,
  "num_attention_heads": 32,
  "num_key_value_heads": 8,
  "head_dim": 128,
  "intermediate_size": 12288,
  "rope_theta": 1000000,
  "vocab_size": 151936,
  "tie_word_embeddings": false,
  "max_position_embeddings": 40960,
  "rms_norm_eps": 1e-06,
  "hidden_act": "silu"
}

출처는 https://huggingface.co/Qwen/Qwen3-8B/raw/main/config.json 입니다.

폭과 깊이

hidden_size는 모델의 폭입니다. 토큰 하나가 층 사이를 지나갈 때 실려 가는 벡터의 길이이고, 거의 모든 가중치 행렬의 한 변을 이룹니다. num_hidden_layers는 깊이입니다. 이 두 값이 파라미터 수의 대부분을 좌우합니다.

폭을 키우면 행렬 곱이 커져서 GPU를 잘 채우지만, 파라미터가 폭의 제곱에 비례해 늘어납니다. 깊이를 키우면 파라미터는 선형으로만 늘지만 층을 순차적으로 통과해야 하므로 지연 시간이 늘고, 파이프라인 병렬화 단계도 늘어납니다. 같은 크기를 폭으로 만들지 깊이로 만들지는 학습 안정성과 서빙 형태를 함께 보고 정하는 문제입니다.

어텐션 헤드 두 종류

여기가 처음 보는 사람이 가장 많이 헷갈리는 지점입니다. num_attention_heads는 쿼리 헤드 수, num_key_value_heads는 키·값 헤드 수입니다. 두 값이 같으면 MHA, 키·값 헤드가 1이면 MQA, 그 사이면 GQA입니다.

Qwen3-8B는 32와 8이므로 쿼리 헤드 네 개가 키·값 헤드 하나를 공유합니다. 이 비율이 그대로 KV 캐시 크기를 줄입니다. 토큰 하나가 차지하는 KV 캐시 원소 수는 다음과 같이 계산합니다.

KV 원소/토큰 = 2 x num_hidden_layers x num_key_value_heads x head_dim
             = 2 x 36 x 8 x 128
             = 73,728

같은 모델을 MHA로 만들었다면 (키/값 헤드 32개)
             = 2 x 36 x 32 x 128 = 294,912   ->  4배

fp16 기준으로 원소당 2바이트이므로, 32,768 토큰을 캐시하면 4.50 GiB입니다. MHA였다면 18.00 GiB입니다. 대가는 공짜가 아닙니다. 키·값 헤드를 줄이면 표현력이 줄어들며, GQA 논문은 이를 MQA와 MHA 사이의 절충으로 규정하고 기존 체크포인트를 GQA로 바꿀 때 원래 사전학습 연산량의 5퍼센트만큼 추가 학습이 필요하다고 보고합니다(Ainslie et al., arXiv:2305.13245).

head_dim은 헤드 하나의 차원입니다. 예전 모델은 hidden_size를 헤드 수로 나눈 값이 곧 헤드 차원이었지만, 요즘은 config에 따로 적힙니다. Qwen3-8B는 32 곱하기 128이 4096으로 폭과 맞아떨어지지만, 반드시 맞을 필요는 없습니다.

FFN 크기와 활성화 함수

intermediate_size는 FFN 내부 차원입니다. Qwen3-8B는 4096에서 12288로 세 배 늘렸다가 다시 줄입니다. hidden_actsilu인 것은 SwiGLU 계열을 쓴다는 뜻이고, 이 구조는 게이트·업·다운 세 개의 행렬을 씁니다. 그래서 FFN 파라미터는 두 배가 아니라 세 배로 세야 합니다. 이 지점을 놓치면 파라미터 계산이 맞지 않습니다.

어휘 크기와 임베딩 묶기

vocab_size는 임베딩 행렬의 행 수입니다. 주의할 점이 있습니다. Qwen3의 config는 151936이지만, Qwen3 기술 리포트는 토크나이저 어휘 크기를 151,669로 적습니다(arXiv:2505.09388). 실제로 토크나이저 파일을 받아 확인해도 151,669였습니다. 차이는 임베딩 행렬을 하드웨어에 맞는 크기로 올림한 여유분입니다. 즉 vocab_size는 토크나이저 어휘 수가 아니라 임베딩 행렬 크기입니다.

tie_word_embeddings는 입력 임베딩과 출력 레이어의 가중치를 공유할지 정합니다. Qwen3 리포트 표 1을 보면 0.6B, 1.7B, 4B는 묶고 8B, 14B, 32B는 묶지 않습니다. 작은 모델일수록 임베딩이 전체에서 차지하는 비중이 커서 묶으면 이득이 크기 때문입니다. Qwen3-8B 기준으로 임베딩 행렬 하나는 151936 곱하기 4096, 약 6.2억 파라미터입니다.

손으로 파라미터 세기

이제 위 값만으로 전체 파라미터 수를 세어 봅니다.

임베딩      : 151,936 x 4,096                      =   622,329,856
출력 레이어  : 묶지 않았으므로 같은 크기            =   622,329,856

층 하나:
  q_proj    : 4,096 x (32 x 128)                   =    16,777,216
  k_proj    : 4,096 x ( 8 x 128)                   =     4,194,304
  v_proj    : 4,096 x ( 8 x 128)                   =     4,194,304
  o_proj    : (32 x 128) x 4,096                   =    16,777,216
  q_norm, k_norm : 128 x 2                         =           256
  FFN (게이트/업/다운) : 3 x 4,096 x 12,288        =   150,994,944
  RMSNorm 2개 : 4,096 x 2                          =         8,192
  합계                                             =   192,946,432

층 36개    : 192,946,432 x 36                      = 6,946,071,552
최종 norm  : 4,096                                 =         4,096

전체       = 6,946,071,552 + 622,329,856 x 2 + 4,096
           = 8,190,735,360

허깅페이스가 안전텐서 메타데이터로 보고하는 Qwen3-8B의 파라미터 수는 8,190,735,360입니다. 한 개도 틀리지 않고 맞습니다. 같은 방식으로 Mixtral-8x7B도 세어 보면 46,702,792,704가 나오고, 공개된 값과 정확히 일치합니다. 이 계산이 맞으면 config를 제대로 읽은 것입니다.

rope_theta와 문맥 길이

rope_theta는 회전 위치 임베딩의 기준 주파수입니다. 값이 클수록 위치 신호가 천천히 회전해 긴 문맥에 유리합니다. Llama 3는 500,000을 씁니다(arXiv:2407.21783, 표 3). Qwen3와 Mixtral은 1,000,000입니다.

max_position_embeddings는 학습된 위치 범위입니다. 여기에 함정이 있습니다. Qwen3-8B의 config는 40960인데 기술 리포트 표 1은 문맥 길이를 128K로 적습니다. 리포트를 보면 장문맥 사전학습은 32,768에서 했고, 추론 시 YaRN과 DCA로 네 배를 확보한다고 되어 있습니다. 즉 128K는 학습된 길이가 아니라 확장 기법을 켰을 때의 값입니다. config의 숫자와 홍보 문구가 다를 때는 대개 이런 이유입니다.

마치며

config.json은 모델의 요약본입니다. 폭과 깊이가 파라미터를 정하고, 쿼리 헤드와 키·값 헤드의 비율이 KV 캐시를 정하고, tie_word_embeddings가 작은 모델의 체급을 정하고, rope_thetamax_position_embeddings가 문맥 길이의 실체를 알려 줍니다. 파라미터 수를 손으로 세어 공개 값과 맞춰 보는 습관을 들이면, 어떤 모델을 만나도 구조를 읽을 수 있습니다.

참고 자료

직접 해보기

시리즈

현재 단락 (1/63)

오픈소스 모델을 내려받으면 가중치 파일 옆에 항상 `config.json`이 있습니다. 스무 줄 남짓한 이 파일에는 모델의 골격이 거의 전부 들어 있습니다. 층이 몇 개인지, 어텐...

작성 글자: 0원문 글자: 3,997작성 단락: 0/63