Split View: config.json 완전 해부 — 설정 파일 한 장으로 모델 구조 읽기
config.json 완전 해부 — 설정 파일 한 장으로 모델 구조 읽기
- 들어가며
- 실제 파일부터 보기
- 폭과 깊이
- 어텐션 헤드 두 종류
- FFN 크기와 활성화 함수
- 어휘 크기와 임베딩 묶기
- 손으로 파라미터 세기
- rope_theta와 문맥 길이
- 마치며
- 참고 자료
- 직접 해보기
- 시리즈
들어가며
오픈소스 모델을 내려받으면 가중치 파일 옆에 항상 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_act가 silu인 것은 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_theta와 max_position_embeddings가 문맥 길이의 실체를 알려 줍니다. 파라미터 수를 손으로 세어 공개 값과 맞춰 보는 습관을 들이면, 어떤 모델을 만나도 구조를 읽을 수 있습니다.
참고 자료
- Qwen3-8B config.json: https://huggingface.co/Qwen/Qwen3-8B/raw/main/config.json
- Mixtral-8x7B-v0.1 config.json: https://huggingface.co/mistralai/Mixtral-8x7B-v0.1/raw/main/config.json
- Qwen3 Technical Report (arXiv:2505.09388): https://arxiv.org/abs/2505.09388
- The Llama 3 Herd of Models (arXiv:2407.21783): https://arxiv.org/abs/2407.21783
- GQA (Ainslie et al., arXiv:2305.13245): https://arxiv.org/abs/2305.13245
직접 해보기
- 신경망 아키텍처 탐색기 — 층과 폭을 바꿔 가며 구조가 어떻게 달라지는지 확인해 보세요.
- VRAM 계산기 — 파라미터 수와 문맥 길이로 필요한 메모리를 추정해 보세요.
- 뉴럴넷 실습실 — 작은 신경망을 직접 굴려 보며 감을 잡아 보세요.
시리즈
- 이전 글: 이 글이 시리즈의 첫 번째입니다.
- 다음 글: MoE 라우팅 — 전문가는 어떻게 뽑히는가
Anatomy of config.json — Reading a Model From One Settings File
- Introduction
- Start With a Real File
- Width and Depth
- Two Kinds of Attention Head
- FFN Size and Activation
- Vocabulary Size and Tied Embeddings
- Counting Parameters by Hand
- rope_theta and Context Length
- Closing
- References
- Try It Yourself
- Series
Introduction
Download any open-source model and you will find a config.json sitting next to the weights. Those twenty-odd lines contain nearly the entire skeleton of the model. How many layers, how many attention heads, and why this particular model has a small KV cache are all decided here.
This series is not about what a model scores. It is about how a model is built and why those choices were made. The goal of this first post is simple: when you finish it, you should be able to open a config.json you have never seen before and read its structure.
All figures were verified directly against papers, official reports, and config.json files on 2026-08-12. Models get updated, so check the originals again.
Start With a Real File
Here is the settings file for Qwen3-8B. Every value below is taken verbatim from the public repository.
{
"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"
}
The source is https://huggingface.co/Qwen/Qwen3-8B/raw/main/config.json.
Width and Depth
hidden_size is the width of the model. It is the length of the vector a token carries as it moves between layers, and it forms one side of nearly every weight matrix. num_hidden_layers is the depth. Together these two values account for most of the parameter count.
Increasing width makes the matrix multiplications larger, which fills the GPU well, but parameters grow with the square of the width. Increasing depth grows parameters only linearly, yet every layer must be traversed in sequence, so latency rises and the number of pipeline-parallel stages rises with it. Whether to build a given size out of width or depth is a decision made together with training stability and the intended serving shape.
Two Kinds of Attention Head
This is where newcomers stumble most often. num_attention_heads is the number of query heads and num_key_value_heads is the number of key/value heads. When the two are equal you have MHA, when key/value heads number one you have MQA, and anything in between is GQA.
Qwen3-8B has 32 and 8, so four query heads share one key/value head. That ratio translates directly into KV cache size. The number of KV cache elements one token occupies is computed like this.
KV elements/token = 2 x num_hidden_layers x num_key_value_heads x head_dim
= 2 x 36 x 8 x 128
= 73,728
Had the same model been built as MHA (32 key/value heads)
= 2 x 36 x 32 x 128 = 294,912 -> 4x
At fp16 each element is 2 bytes, so caching 32,768 tokens costs 4.50 GiB. As MHA it would be 18.00 GiB. The saving is not free. Cutting key/value heads reduces representational capacity, and the GQA paper frames the technique as an interpolation between MQA and MHA, reporting that converting an existing checkpoint to GQA takes additional training equal to 5 percent of the original pre-training compute (Ainslie et al., arXiv:2305.13245).
head_dim is the dimension of a single head. Older models defined head dimension implicitly as hidden_size divided by head count, but these days it is written into the config explicitly. For Qwen3-8B, 32 times 128 equals 4096 and matches the width, though it does not have to.
FFN Size and Activation
intermediate_size is the inner dimension of the FFN. Qwen3-8B expands from 4096 to 12288 and comes back down. A hidden_act of silu signals a SwiGLU-family block, and that structure uses three matrices: gate, up, and down. So FFN parameters must be counted as three times, not two. Miss this and your parameter arithmetic will never close.
Vocabulary Size and Tied Embeddings
vocab_size is the number of rows in the embedding matrix. One caution here. The Qwen3 config says 151936, but the Qwen3 technical report gives the tokenizer vocabulary as 151,669 (arXiv:2505.09388). Downloading the tokenizer file and checking it directly also yields 151,669. The gap is padding that rounds the embedding matrix up to a hardware-friendly size. In other words, vocab_size is the embedding matrix size, not the tokenizer vocabulary count.
tie_word_embeddings decides whether the input embedding and the output layer share weights. Table 1 of the Qwen3 report shows 0.6B, 1.7B, and 4B tying them while 8B, 14B, and 32B do not. The smaller the model, the larger the share of the total that embeddings occupy, so tying pays off more. For Qwen3-8B a single embedding matrix is 151936 times 4096, roughly 620 million parameters.
Counting Parameters by Hand
Now let us count the full parameter total using only the values above.
Embedding : 151,936 x 4,096 = 622,329,856
Output layer : untied, so the same size = 622,329,856
One layer:
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 (gate/up/down) : 3 x 4,096 x 12,288 = 150,994,944
2 x RMSNorm : 4,096 x 2 = 8,192
subtotal = 192,946,432
36 layers : 192,946,432 x 36 = 6,946,071,552
final norm : 4,096 = 4,096
total = 6,946,071,552 + 622,329,856 x 2 + 4,096
= 8,190,735,360
The parameter count Hugging Face reports for Qwen3-8B through safetensors metadata is 8,190,735,360. Not a single parameter off. Counting Mixtral-8x7B the same way gives 46,702,792,704, which also matches the published value exactly. If this arithmetic closes, you have read the config correctly.
rope_theta and Context Length
rope_theta is the base frequency of rotary position embeddings. A larger value makes the positional signal rotate more slowly, which favors long context. Llama 3 uses 500,000 (arXiv:2407.21783, Table 3). Qwen3 and Mixtral use 1,000,000.
max_position_embeddings is the trained positional range, and there is a trap here. The Qwen3-8B config says 40960 while Table 1 of the technical report lists context length as 128K. Reading the report, long-context pre-training was done at 32,768, and a fourfold extension is obtained at inference time with YaRN and DCA. So 128K is not a trained length but the figure once extension techniques are switched on. When a config number and a marketing number disagree, this is usually why.
Closing
config.json is a summary of the model. Width and depth set the parameters, the ratio of query heads to key/value heads sets the KV cache, tie_word_embeddings sets the weight class of small models, and rope_theta together with max_position_embeddings tells you what the context length really is. Get into the habit of counting parameters by hand and reconciling them against the published total, and you will be able to read the structure of any model you meet.
References
- Qwen3-8B config.json: https://huggingface.co/Qwen/Qwen3-8B/raw/main/config.json
- Mixtral-8x7B-v0.1 config.json: https://huggingface.co/mistralai/Mixtral-8x7B-v0.1/raw/main/config.json
- Qwen3 Technical Report (arXiv:2505.09388): https://arxiv.org/abs/2505.09388
- The Llama 3 Herd of Models (arXiv:2407.21783): https://arxiv.org/abs/2407.21783
- GQA (Ainslie et al., arXiv:2305.13245): https://arxiv.org/abs/2305.13245
Try It Yourself
- Neural network architecture explorer — vary layers and width and watch the structure change.
- VRAM calculator — estimate the memory you need from parameter count and context length.
- Neural net lab — run a small network yourself to build intuition.
Series
- Previous: this is the first post in the series.
- Next: MoE Routing — How an Expert Gets Picked