10. 논문 → YAML 포팅 사례 (DeepSeek-V3 / Jamba / DeepSeek-R1 / Titans)
이 튜토리얼은 교수 (P) 와 학생 (S) 의 대화를 통해, 최신 논문 4 편을 EulerStack YAML 로 옮기는 과정 전체를 보여줍니다. 단순한 "이렇게 쓰면 된다" 가 아니라 "왜 이렇게 쓰는지" 를 다음 여덟 단계로 차근차근 풀어갑니다.
각 사례(Case)의 구성은 아래와 같습니다.
| 단계 | 내용 |
|---|---|
| §X.1 배경과 동기 | 이 논문이 왜 나왔나? 해결하려는 병목은 무엇이고 선행 연구와 어떻게 연결되나? |
| §X.2 메커니즘 심화 | 수식 · ASCII 다이어그램 수준에서 동작 원리. 대안과의 차이. |
| §X.3 YAML 유도 | 빈 YAML 에서 출발해 필드를 하나씩 채워가며 왜 그 값인지 설명. |
| §X.4 검증 & 컴파일 | 실제 CLI 명령어와 예상 출력. 파라미터 수 산수. |
| §X.5 파라미터 튜닝 | latent_dim, capacity_factor 등 주요 knob 의 적정 범위. |
| §X.6 함정과 디버깅 | 초보자가 자주 밟는 지뢰 4–6 개. 에러 메시지 → 원인 매핑. |
| §X.7 다른 primitive 와 결합 | MLA + MoE, MLA + MoD 같은 2차 조합의 직교성 / 충돌. |
| §X.8 심화 읽을거리 | 논문 · 후속 연구 · 관련 프리셋 / 튜토리얼 링크. |
목차: - Case 1. DeepSeek-V3 — MLA (Multi-head Latent Attention) - Case 2. Jamba — Mamba × Attention × MoE 하이브리드 - Case 3. DeepSeek-R1 — 2-phase reasoning (execution_modes) - Case 4. Titans — 추론 시점에 학습하는 neural memory - 마무리 — 네 사례의 공통 구조
Case 1. DeepSeek-V3 — MLA (Multi-head Latent Attention)
1.1 배경과 동기
S: 교수님, DeepSeek-V3 논문(2024-12)을 보면 Multi-head Latent Attention 이 핵심이라고 강조합니다. 그냥 attention 변형 하나 같은데, 왜 이렇게까지 떠들썩한가요?
P: 맥락을 먼저 볼까. 2023~24 년에 "긴 컨텍스트 (long context)" 가 LLM 의 핵심 경쟁 축이 됐어. Llama 2 의 4K → Llama 3 의 8K → 32K → 128K 로 치솟았지. 문제는 이 경쟁이 불평등한 비용으로 왔다는 거야.
S: 불평등한 비용이라뇨?
P: attention 의 계산 비용은 FlashAttention 덕에 극적으로 떨어졌는데, 메모리 비용은 그대로 남았거든. 구체적으로 KV 캐시 크기가 병목이야.
KV 캐시 크기 = 2 × n_layers × n_heads × head_dim × seq_len × batch × dtype_bytes
Llama 3 70B 기준 128K 컨텍스트면 레이어당 KV 캐시가 대략 5GB, 80 레이어 곱하면 400GB. bfloat16 기준이야. H100 한 장에 올릴 수 없어.
S: 그래서 업계가 뭘 했나요?
P: 세 갈래로 갔어:
- Grouped-Query Attention (GQA) — Llama 2/3. 여러 head 가 K/V 를 공유. head 개수 대비 1/8 까지 줄임. 단, quality loss.
- Sliding-Window Attention — Mistral / Longformer. 전역 attention 을 포기하고 윈도우 내부만 봄. 단, long-range dependency 가 약해짐.
- Multi-head Latent Attention (MLA) — DeepSeek-V2/V3. K·V 를 하나의 저차원 latent 로 압축해 캐시는 그 latent 만 유지. quality loss 없이 메모리 이득.
3 번이 MLA 야. 2 번은 지역성 을 희생, 1 번은 head 다양성 을 희생, MLA 는 차원 을 희생하는데 쿼리 재구성 시 up-projection 으로 다양성을 회복해. 그래서 품질 저하가 거의 없어.
S: 그럼 MLA 가 현재 왕인가요?
P: 2025년 기준 long-context 메모리 효율에서는 사실상 표준이 됐어. DeepSeek-V2/V3, Qwen 2.5 일부 변형, Kimi 의 MoBA 계열이 모두 MLA 를 채택했어. Llama 계열은 여전히 GQA 지만, 차세대에서 MLA 로 갈 가능성이 높아.
S: DeepSeek-V2 와 V3 차이는?
P: MLA 자체는 V2 에서 도입됐고, V3 는 규모(236B → 671B)와 훈련 기법 (MTP, Multi-Token Prediction)이 커진 버전이야. MLA 구조는 동일. 우리가 YAML 로 옮길 것도 "MLA 한 줄" 이고, 모델 크기는 하이퍼파라미터로 조절해.
1.2 메커니즘 심화
S: MLA 가 정확히 어떻게 동작하는지 수식으로 봤으면 합니다.
P: 표준 MHA 부터 복습. 입력 x ∈ R^{T×d} 가 있을 때:
Q = x W_q (d → d)
K = x W_k (d → d)
V = x W_v (d → d)
attention = softmax(Q K^T / √d_h) V
MHA 는 d 를 n_heads × head_dim 으로 쪼개서 각 head 가 독립적으로
계산해. KV 캐시에 저장하는 건 K 와 V 둘 다 이고, 각각 shape 가
(B, n_heads, T, head_dim).
S: MLA 는?
P: 이렇게 바뀌어:
# Down-projection (한 번만, K/V 공유)
kv_latent = x W_kv (d → l) ← 캐시할 것은 이 하나
# Up-projection (계산 시점에 재구성)
K = kv_latent W_k_up (l → d) ← 쿼리마다 다시 만듦
V = kv_latent W_v_up (l → d)
# Q 는 표준
Q = x W_q (d → d)
S: 그러니까 "K 와 V 는 버리고 그 재료가 되는 latent 만 저장한다" 는 거군요.
P: 정확해. 그래서 KV 캐시 크기가 2 × d → 1 × l 이 돼. l = d/2 면
캐시 메모리 75% 감소. l = d/4 면 87.5% 감소. head-sharing 없이.
S: 그런데 매 step 마다 up-projection 을 다시 해야 하잖아요. 계산량이 늘지 않나요?
P: 두 가지 최적화가 있어.
- Absorb trick: inference 시
Q W_k_up^T를 미리 fused 해두면 up-projection 이 실질적으로 사라져. DeepSeek 구현이 이걸 함. - 병렬화: up-projection 은 행렬곱 하나라서 memory-bound 인 KV 읽기 대비 추가 latency 가 거의 없음 — 메모리에 읽는 비용이 훨씬 크기 때문.
┌─────────────────────────────────────────────────┐
│ Cache layout 비교 │
├─────────────────────────────────────────────────┤
│ MHA: [K: H×D] [V: H×D] → 2HD/token │
│ GQA (4:1): [K: H/4×D] [V: H/4×D] → HD/2 │
│ MLA l=d/2: [kv_latent: L] → L = D/2 │
│ │
│ d_model=768, 32 layers, 128K ctx, bf16: │
│ MHA: 24 GB │
│ GQA: 6 GB │
│ MLA: 6 GB (quality ≈ MHA) │
└─────────────────────────────────────────────────┘
S: 파라미터 수도 보여주세요.
P: attention 블록당:
- MHA:
W_q, W_k, W_v, W_o각d²→4d² - GQA:
W_q (d²), W_k, W_v (d×d/g), W_o (d²)→2d² + 2d²/g - MLA:
W_q (d²), W_kv (d×l), W_k_up, W_v_up (l×d), W_o (d²)→2d² + 3dl
l = d/2 인 MLA 는 2d² + 1.5d² = 3.5d² — MHA 보다 파라미터가 적으면서
캐시는 MHA 의 25%. quality 도 유지. 이래서 "free lunch" 라고 부르는 거야.
1.3 YAML 유도
S: 실제로 EulerStack YAML 로는 어떻게 씁니까?
P: 빈 YAML 에서 시작하자. 먼저 버전과 모델 메타데이터.
schema_version: 1
model:
name: deepseek-v3-clone
d_model: 768 # 768 은 교육용 소규모. 실제 V3 는 d_model=7168
vocab_size: 32000
max_seq_len: 32768 # 32K. V3 는 128K 까지 확장
n_heads: 12 # d_model/n_heads = 64 (head_dim)
n_kv_heads: 12 # MLA 는 GQA 와 직교 — 둘 다 써도 된다
mlp_ratio: 4 # FFN 차원 = 4 × d_model
S: n_kv_heads 를 n_heads 와 같게 둔 건 GQA 를 안 쓴다는 거죠?
P: 맞아. MLA 가 이미 KV 를 latent 로 압축했으니 GQA 를 겹치는 건
redundant 해. DeepSeek 원 논문도 MLA 단독이야. 만약 "MLA + GQA 4:1" 로
더 공격적으로 줄이고 싶다면 n_kv_heads: 3 으로 두면 되는데, quality 가
빠르게 떨어져서 권장하지 않아.
S: 다음은 토크나이저와 embedding 이죠.
P: 응. 실제 DeepSeek 은 자체 100K BPE 를 쓰지만, 학습 목적이면 gpt2 로 대체해서 validate 만 통과시키자.
tokenizer_contract:
type: hf
pretrained: gpt2
add_bos: true
add_eos: true
embedding:
type: learned
positional: rope
rope_theta: 500000.0 # 긴 컨텍스트 용 대형 theta
tie_word_embeddings: true
S: rope_theta: 500000.0 은 왜 이렇게 큰가요? 기본값이 10000 아닙니까?
P: 좋은 질문. RoPE 의 기본 theta=10000 은 GPT-2 시절 설계로 4K 이하
컨텍스트에 맞춰져 있어. 컨텍스트를 32K+ 로 늘리면 고주파 축이 주기 충돌
을 일으켜서 position 식별력이 떨어져. theta 를 키우면 주기가 길어져서
높은 인덱스도 구분 가능해져. Llama 3 는 500K, DeepSeek 은 10M 까지 써.
S: 이제 핵심인 layer_templates.
P: MLA 가 들어가는 라인이야.
layer_templates:
mla_decoder:
mixer:
type: attention
attention:
latent_dim: 384 # ← 이 한 줄이 MLA 의 전부. d_model=768 의 절반
qkv_bias: false
ffn:
type: gated_mlp
activation: swiglu
norm:
type: rmsnorm
position: pre
residual:
type: sequential
scaling: 1.0
state:
kv_cache: true
S: 정말 latent_dim: 384 한 줄이 끝이에요?
P: 끝이야. EulerStack 의 CausalSelfAttention 이 latent_dim 이 있으면
다섯 개 projection (Q, kv_latent, K_up, V_up, out) 을 대신 인스턴스화해.
없으면 표준 fused QKV. 스펙 레이어에서 "MLA 쓸 거다" 만 선언하면 나머지는
런타임이 알아서 해.
S: schedule 은?
P:
layer_schedule:
- template: mla_decoder
repeat: 12 # 교육용. V3 는 61 layers
head:
type: causal_lm
tie_weights: true
compatibility:
compile_target: huggingface
완성. 이게 DeepSeek-V3 MLA 구조 그 자체 야.
1.4 검증 & 컴파일
S: 이걸 어떻게 검증하죠?
P: 저장하고 CLI 한 줄.
eulerstack --lang ko validate --preset deepseek_v3_clone.yml --report
예상 출력 (요약):
[validation] schema ... PASS
[validation] cross-field ... PASS
- mixer.latent_dim=384 < d_model=768 ✓
- d_model=768 % n_heads=12 == 0 ✓
- head_dim = 64 (32–256 권장 범위 내) ✓
[params] estimated: ~85M
- embedding (learned + tied): ~25M
- attention × 12: ~32M (MLA 절감 반영)
- ffn (swiglu) × 12: ~28M
[realism] PASS
- head_dim: 64 (권장 범위)
- rope_theta: 500000 (long-context 정당화 정상)
- n_kv_heads == n_heads: GQA 미사용, MLA 만으로 KV 압축 OK
OK: deepseek_v3_clone.yml is valid.
S: 파라미터 수 85M 이 맞나요? 산수해봐도 되나요?
P:
- Embedding (tied): vocab × d = 32000 × 768 ≈ 24.6M
- Per attention layer (MLA, l=384):
2 × 768² + 3 × 768 × 384=1.18M + 0.88M= 2.06M - Per FFN (SwiGLU, ratio=4): 3 gate/up/down ×
768 × 3072≈ 7.1M (SwiGLU 는 3 matrix) - Per norm: 2 × 768 ≈ 1.5K (negligible)
- 12 layers: 12 × (2.06M + 7.1M) ≈ 110M
- Tied embed: 24.6M 한 번
총 134M. CLI 의 estimate 는 대략적이라 ±20% 정도 차이는 있어.
S: 실제로 HF 모델로 만들어보죠.
P:
eulerstack --lang ko compile --preset deepseek_v3_clone.yml --output-dir ./v3_clone
from transformers import AutoModelForCausalLM
from eulerstack.hf.auto_register import register_eulerstack_auto_classes
register_eulerstack_auto_classes()
model = AutoModelForCausalLM.from_pretrained("./v3_clone", trust_remote_code=True)
# MLA 가 실제로 들어갔는지 확인
from eulerstack.blocks.attention import CausalSelfAttention
mla_layers = [m for m in model.modules()
if isinstance(m, CausalSelfAttention) and m.latent_dim is not None]
print(f"MLA layers: {len(mla_layers)}, latent_dim={mla_layers[0].latent_dim}")
# → MLA layers: 12, latent_dim=384
# Projection 이름도 확인
print([n for n in mla_layers[0].state_dict() if 'proj' in n or 'latent' in n])
# → ['q_proj.weight', 'kv_latent.weight', 'k_up.weight', 'v_up.weight', 'out_proj.weight']
state_dict 에 kv_latent / k_up / v_up 이 나타나면 진짜 MLA 가 인스턴스화된 거야.
1.5 파라미터 튜닝 가이드
S: latent_dim 을 얼마로 설정할지 기준이 있나요?
P: 아래 표가 실전 가이드:
latent_dim |
KV 캐시 절감 | Quality 영향 | 용도 |
|---|---|---|---|
d_model |
0% | 표준 MHA 와 동일 | (의미 없음 — validator 가 거부) |
d_model × 0.75 |
~25% | ~0 | 보수적 — MLA 를 처음 도입할 때 |
d_model × 0.5 |
~75% | ~0 | 권장 출발점. DeepSeek 기본 |
d_model × 0.33 |
~83% | 미세 저하 | 128K+ 메모리 타이트할 때 |
d_model × 0.25 |
~87.5% | 눈에 띄는 저하 | 극한 상황 — A/B 검증 필수 |
d_model × 0.125 |
~94% | 심각한 저하 | 피하기 |
S: head_dim 과는 어떤 관계인가요?
P: latent_dim 을 head_dim 의 정수배로 두는 게 권장돼. KV 캐시의
stride 가 깔끔하게 떨어지고 FlashAttention-like 커널이 잘 맞기 때문.
예: d_model=768, head_dim=64 면 latent_dim ∈ {128, 192, 256, 384, 512}.
S: MLA 를 쓰면서 max_seq_len 을 얼마까지 늘릴 수 있나요?
P: MLA 이득은 컨텍스트가 길수록 커져. 짧은 컨텍스트 (2K 이하) 에선 굳이 쓸 필요 없고, 16K 부터 눈에 띄는 차이가 나고, 128K 에선 사실상 MLA 없이 A100/H100 single-node 서빙이 어려워. DeepSeek 는 128K 를 기본 운영점으로 잡음.
S: rope_theta 와 max_seq_len 관계는?
P: 경험 법칙:
rope_theta ≈ max(10000, 10000 × (max_seq_len / 2048)²)
- 2K: 10K
- 4K: 40K
- 8K: 160K
- 32K: 2.6M (DeepSeek 은 실제로는 500K 만 쓰는데 그래도 충분)
- 128K: 42M (이때는 YaRN / NTK-aware scaling 으로 넘어가는 게 보통)
1.6 함정과 디버깅
S: 제가 MLA YAML 을 쓰면서 밟을 가장 흔한 지뢰가 뭔가요?
P: 여섯 가지야.
함정 1. latent_dim >= d_model
ValidationError (R): mla_latent_dim_range — latent_dim=1024 exceeds d_model=768
Fix: set latent_dim < d_model (commonly d_model/2)
→ 원인: MLA 의 의미는 "압축" 이므로 d_model 이상은 말이 안 됨.
함정 2. latent_dim 이 홀수 혹은 head_dim 의 배수가 아님
warning: mla_latent_dim_range — latent_dim=100 is not a multiple of head_dim=64
→ validate 는 통과하지만 KV cache stride 가 깨져 미묘한 성능 저하. latent_dim
을 64 의 배수로.
함정 3. "MLA 만 쓰면 long context 는 끝" 이라는 착각
→ MLA 는 메모리 를 줄일 뿐, rope_theta 가 작으면 여전히 position
식별력이 떨어져. 함께 조정.
함정 4. MLA 레이어를 kv_cache: false 로 둠
state:
kv_cache: false # ← MLA 를 쓸 이유가 없음
→ MLA 의 존재 이유가 KV 캐시 압축인데 캐시를 끄면 자원만 낭비. 학습 시엔 false 여도 OK 지만 inference 배포는 반드시 true.
함정 5. GQA 와 MLA 의 과도한 중복
n_kv_heads: 2 # 4:1 GQA
attention:
latent_dim: 128 # 추가로 MLA
→ 이론적으로 가능하지만 quality 가 빠르게 저하. MLA 단독으로 충분. n_kv_heads 는 n_heads 와 같게 두는 게 권장.
함정 6. "MLA 를 쓰면 사전학습 weight 를 가져올 수 있다" 는 착각 → EulerStack 은 랜덤 초기화 모델을 만들 뿐. DeepSeek-V3 의 실제 사전학습 weight 는 별도로 다운로드해서 converter 를 써야 해. v1.2 로드맵.
1.7 다른 primitive 와 결합
S: MLA 를 다른 primitive 와 결합할 수 있나요?
P: 네 가지 조합이 실전적:
1.7.1 MLA + MoE (DeepSeek-V3 실제 구성)
layer_templates:
mla_moe:
mixer:
type: attention
attention: { latent_dim: 384 }
ffn:
type: moe
moe: { experts: 32, top_k: 3, router: softmax, capacity_factor: 1.25 }
직교적 — MLA 는 attention 의 메모리, MoE 는 FFN 의 capacity. 둘이 같은 자리를 두고 싸우지 않아. DeepSeek-V3 가 이 조합을 쓰고 있음.
1.7.2 MLA + Jamba-style hybrid
layer_schedule:
- template: mla_decoder
repeat: 6
- template: mamba_block
repeat: 18
보완적 — 전체 레이어 수의 1/4 만 MLA, 나머지는 Mamba. 전역 retrieval 이 필요한 레이어에서만 MLA 가 KV 캐시를 절약. Samba / Jamba 의 1.5 업그레이드 버전으로 볼 수 있어.
1.7.3 MLA + Mixture-of-Depths
layer_schedule:
- template: mla_decoder
repeat: 24
depth_gating:
enabled: true
capacity: 0.5
router: top_k
시너지 — MoD 는 토큰의 50% 만 해당 레이어를 거치게 함. MLA 의 KV 캐시 는 지나가는 토큰만큼만 생성되므로, MoD 의 토큰 절감이 MLA 의 메모리 절감에 직접 곱해짐. 128K 컨텍스트에서 이 조합이 매우 강력.
1.7.4 MLA + execution_modes (R1 + V3)
execution_modes:
- { name: think, max_tokens: 16384, kv_share: true, loss_weight: 0.0 }
- { name: answer, max_tokens: 2048, loss_weight: 1.0 }
이상적 — R1-style reasoning 은 think 구간이 매우 길어서 (16K+) KV
캐시가 병목. MLA 가 이를 직접 해결. 차세대 추론 모델의 표준 구성으로
예상됨.
1.8 심화 읽을거리
- 원 논문: DeepSeek-V3 Technical Report, arXiv:2412.19437 (2024)
- 이전 버전: DeepSeek-V2, arXiv:2405.04434 — MLA 가 처음 도입됨
- 후속 연구: MLA 를 FlashAttention-3 에 통합한 커널 구현 (오픈소스 여러 개)
- EulerStack 프리셋:
configs/presets/arch_advanced_mla.yml,llm_{0p1b,0p8b,2b,4b,16b}_mla.yml - 관련 튜토리얼: 09 신규 primitive §4
- 다음 실험:
arch_advanced_mla의 schedule 을mla_decoder:repeat=8 → mamba_block:repeat=4 → mla_decoder:repeat=8로 쪼개서 3:1 hybrid 로 만들기. MLA 와 Mamba 가 서로 보완하는지 측정.
Case 2. Jamba — Mamba × Attention × MoE 하이브리드
2.1 배경과 동기
S: Jamba 는 Mamba 와 attention 을 섞는다는데, 단순히 번갈아 쌓는 거 아닌가요?
P: 그보다 깊은 이야기야. 2023~24 년은 SSM(state-space models) 르네상스 였어. S4 → H3 → Mamba 로 이어지는 흐름이 "attention 은 필요 없다" 는 주장을 강하게 밀었지.
S: Mamba 의 어떤 점이 그랬나요?
P: Mamba 는 선형 시간 O(N) 에 시퀀스를 처리하면서도 표현력이 attention 에 근접했어. 구체적으로:
- 시간 복잡도: attention
O(N²)vs MambaO(N) - 메모리: attention KV 캐시
O(N)(시퀀스 길이에 선형) vs Mamba 고정 stateO(1) - 처리량: 긴 시퀀스에서 Mamba 가 10~20 배 빠름
S: 그런데 왜 "attention 이 필요없다" 가 정답이 아니었나요?
P: Mamba 의 약점이 있어. In-context learning (ICL) 이야. "문맥에서 주어진 k/v 쌍을 정확히 지목해서 복원하는" 능력이 attention 에 크게 못 미쳐.
S: 왜요? Mamba 도 과거를 기억하는 RNN 이잖아요.
P: 기억하지만 "compressed" 기억이야. attention 의 KV 캐시는 모든 과거 토큰을 손실 없이 들고 있고 softmax 로 임의의 토큰을 지목 가능. Mamba state 는 고정 크기 latent 에 모든 과거를 압축해서 들고 있어. 이 압축이 ICL 을 깎아먹어.
실험적으로 Mamba 만으로 구성된 모델은: - LAMBADA (next-word prediction): attention 과 비슷 - Needle-in-haystack 128K: attention 에 크게 뒤처짐
S: 그래서 Jamba 가 등장한 거군요.
P: 정확해. AI21 Labs 가 2024-03 에 Jamba-1 을 발표하면서 "Mamba 와 attention 을 섞자" 는 아이디어를 검증했어. 구체적 비율이 Mamba 7 : Attention 1.
S: 7:1 이 어디서 나온 거죠?
P: 실험적으로 튜닝한 값이야. Needle task 재현이 가능한 최소 비율이 1/8 (12.5%) attention 이었어. 그 이하로 내리면 ICL 이 무너지고, 더 올리면 Mamba 의 속도 이점이 줄어. sweet spot 이 7:1.
S: Jamba 가 다른 유사 연구와 어떻게 다른가요?
P:
| 연구 | 구성 | 특징 |
|---|---|---|
| Striped Hyena (Together AI, 2023) | Hyena + Attn | Hyena 를 "attention 대체" 로 |
| Samba (Microsoft, 2024) | Mamba + SWA 1:1 | 슬라이딩 윈도우 로컬 + SSM 글로벌 |
| Jamba (AI21, 2024) | Mamba + Attn 7:1 + MoE | FFN 을 MoE 로 대폭 확장 |
| Jamba 1.5 (AI21, 2024-08) | 같은 구조 + 훈련 스케일업 | 256K context |
Jamba 의 특별한 점은 FFN 자리에 MoE 를 얹은 것. attention 은 7:1 로 이미 줄였으니까, FFN 에 capacity 를 몰아서 모델의 지식 저장력을 극대화.
2.2 메커니즘 심화
S: Mamba 와 attention 이 실제로 어떻게 섞이는지 블록 다이어그램으로 보고 싶습니다.
P: 32 layer Jamba 의 schedule 은 이래:
Layer 1: Mamba Layer 5: Mamba Layer 9: Mamba ...
Layer 2: Mamba Layer 6: Mamba Layer 10: Mamba
Layer 3: Mamba Layer 7: Mamba Layer 11: Mamba
Layer 4: Attn Layer 8: Attn Layer 12: Attn
↑ 이 pattern 이 8 번 반복 → 32 layers, 8 개 attention
8 번째마다 attention 이 오는 건데, 그 자리마다 FFN 을 MoE 로 대체해:
Layer 4 (Attn + MoE):
x → norm → attention → + residual
→ norm → MoE(8 experts, top-2) → + residual
Layer 1-3 (Mamba):
x → norm → mamba2 → + residual
→ norm → gated_mlp(SwiGLU) → + residual
S: 왜 Mamba 레이어의 FFN 은 MoE 가 아니고 일반 gated_mlp 인가요?
P: 두 가지 이유.
- Mamba 자체가 "mixer+FFN 결합"에 가까움. Mamba 블록은 state update 도 있고 input-dependent gating 도 있어서 attention 처럼 "순수 mixer" 가 아니야. 여기다 MoE 를 얹으면 redundancy.
- MoE 는 attention 과 "서로 다른 축" 의 capacity. attention 은 토큰 간 정보 교환, MoE 는 토큰별 처리 변형. 같이 두면 상호 보완.
S: in-context learning 은 왜 attention 1/8 만으로 충분한가요?
P: needle task 를 풀려면 "특정 과거 토큰을 정확히 지목하는" 능력이 모델 전체에 한 번씩만 있으면 돼. 8 개 attention 레이어가 있으니까 8 번의 "글로벌 lookup 기회" 가 주어지는 셈. 그 사이에 끼인 Mamba 는 토큰 수준의 패턴 인식과 지역성을 맡아.
2.3 YAML 유도
S: 빈 YAML 에서 출발해 Jamba 구조를 만들어 봅시다.
P: 먼저 모델 메타.
schema_version: 1
model:
name: jamba-clone
d_model: 768 # 교육용. Jamba-1 은 d_model=4096
vocab_size: 32000
max_seq_len: 32768
n_heads: 12
n_kv_heads: 4 # GQA 3:1 — attention 레이어 KV 추가 절감
mlp_ratio: 4
tokenizer_contract:
type: hf
pretrained: gpt2
add_bos: true
add_eos: true
S: n_kv_heads: 4 는 GQA 3:1 이죠. Jamba 가 GQA 를 쓰나요?
P: 사용해. attention 레이어가 1/8 밖에 안 되긴 해도 그 몇 안 되는 레이어가 KV 캐시의 전부야. GQA 로 추가 압축하는 게 합리적. 실제 Jamba 는 GQA 4:1 을 씀.
S: 다음 embedding.
P:
embedding:
type: learned
positional: rope
rope_theta: 500000.0
tie_word_embeddings: true
S: 잠깐, Mamba 는 positional encoding 이 필요 없다고 들었는데요?
P: Mamba 는 recurrent 라 position 정보를 state 에 암묵적으로 담아. 하지만
attention 레이어는 필요해. Jamba 는 attention 레이어에만 RoPE 를 적용해.
YAML 에서 positional: rope 를 선언하고 Mamba 는 자동으로 무시.
S: 이제 템플릿.
P: 두 개 필요해. Mamba 용 하나, Attention+MoE 용 하나.
layer_templates:
mamba_block:
mixer:
type: mamba
mamba:
variant: mamba2 # Mamba2 (SSD 계산)
d_state: 128 # SSM 내부 state 차원
d_conv: 4 # local conv kernel size
expand: 2 # internal expansion ratio
ffn:
type: gated_mlp
activation: swiglu
norm: { type: rmsnorm, position: pre }
state: { ssm_state: true, kv_cache: false }
attn_moe:
mixer:
type: attention
attention:
qkv_bias: false
ffn:
type: moe
moe:
experts: 8
top_k: 2
router: softmax
capacity_factor: 1.25
z_loss: 0.001
norm: { type: rmsnorm, position: pre }
state: { kv_cache: true }
S: d_state: 128 이 큰 건가요 작은 건가요?
P: Mamba2 기본이 64~128 이야. d_state 가 클수록 "기억 용량" 이 크지만
속도는 느려져. Jamba 는 128 로 잡았어.
S: capacity_factor: 1.25 는요?
P: MoE 의 load balancing 파라미터. 1.0 이면 각 expert 가 정확히
tokens / experts 개 토큰을 받을 수 있는 공간만 가져. 1.25 는 25% 버퍼를
주는 거야. 훈련 중에 라우터가 불균등하게 배치해도 overflow 가 덜 생겨.
추론 시엔 1.0 으로 내려도 안전.
S: schedule 이 핵심이네요.
P: 이게 Jamba 의 정체성이야.
layer_schedule:
# 8 반복 × 4 layer (Mamba×3 + Attn+MoE×1) = 32 layers
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
S: 이렇게 길게 반복하는 게 좀 지저분한데요.
P: let: 을 쓰면 훨씬 깔끔해져.
let:
mamba_per_cycle: 3
total_cycles: 8
# schedule 을 동적으로 작성할 수는 없지만 (v1 은 Level 1 산술만 지원),
# n_layers 총합 ${let.mamba_per_cycle * 8 + 8} 를 확인하는 용도로 활용 가능.
실제로 YAML 수준에선 반복을 for-loop 처럼 쓸 수 없어. 대신 schedule 의
긴 목록을 수용 가능한 형태로 받아들이는 것이 설계 언어 (ADL) 수준
설명성의 trade-off. 같은 문제가 HDL 계열에도 있었어 — Verilog 초기엔
반복 구조가 없다가 generate ... endgenerate 블록이 도입됐고, VHDL 은
generate 스테이트먼트로 해결했지. EulerStack 도 schedule: 에 반복
iterator 를 도입하는 것이 v1.x 로드맵에 있어.
S: head 와 훈련 힌트는?
P:
head:
type: causal_lm
tie_weights: true
training_hints:
init: normal_0.02
dropout: 0.0
checkpointing: true # 32 layers 는 메모리 절약을 위해 checkpointing ON
seed: 1234
compatibility:
compile_target: huggingface
2.4 검증 & 컴파일
S: validate 하면 뭐가 나오죠?
P:
eulerstack validate --preset jamba_clone.yml --report
[validation] schema ... PASS
[validation] cross-field ... PASS
- mamba_block.state.ssm_state=true ↔ mixer=mamba ✓
- attn_moe.state.kv_cache=true ↔ mixer=attention ✓
- MoE: top_k=2 ≤ experts=8 ✓
[params] estimated: ~1.04B
- embedding: ~25M
- mamba layers (24): ~240M (state + gating)
- attn+moe layers (8): ~280M (attn + 8×moe expert)
- ffn (gated_mlp, mamba side): ~480M (SwiGLU 가 큼)
- norms, output: ~15M
[realism] PASS
- positional: rope + mamba mixer: warning 없음 (attention 이 섞여 있음)
- MoE expert ratio: 8 × 1/4 layers = 정상
OK: jamba_clone.yml is valid.
S: 왜 활성 파라미터는 적은가요?
P: MoE 덕분. 총 1.04B 지만, 매 forward 에서 활성화되는 건:
- embedding (25M)
- mamba × 24 (240M)
- attn+moe × 8 중 attn 부분 (attn ~50M) + MoE 는 top-2 만 활성 (2/8) → 70M 중 17.5M
합산 활성 ~330M. "작은 모델 비용에 큰 모델 용량" 이라는 MoE 의 전형적 이득. DeepSeek-V3 가 이걸 극한까지 밀어 671B 총 / 37B 활성을 만든 거.
2.5 파라미터 튜닝 가이드
S: Mamba:Attention 비율을 왜 7:1 로 두나요?
P: 아래가 실전 가이드:
| Mamba:Attn | ICL 성능 (needle) | 속도 | 용도 |
|---|---|---|---|
| 0:1 (순수 attn) | 최고 | 느림 (O(N²)) | 기본선. Llama 계열 |
| 1:1 (Samba 비율) | 거의 최고 | 중간 | 균형. 긴 context 우선 |
| 3:1 | 상위 | 빠름 | 일반 권장 |
| 7:1 (Jamba 비율) | 충분 | 빠름 | Jamba 기본 |
| 15:1 | 저하 눈에 띔 | 매우 빠름 | 위험 — needle 실패 |
| 1:0 (순수 Mamba) | 매우 낮음 | 최고 | 특수 용도만 |
S: MoE 의 experts 와 top_k 는?
P:
experts × top_k |
활성 비율 | 대표 모델 | 특징 |
|---|---|---|---|
| 8 × 2 | 25% | Mixtral, Jamba | 표준. 안정적 |
| 16 × 2 | 12.5% | Phi-3.5-MoE | 더 sparse, 더 capacity |
| 64 × 6 | 9.4% | DeepSeek-V2 | fine-grained |
| 256 × 8 | 3.1% | DeepSeek-V3 | 극단적 fine-grained |
"fine-grained" = expert 개수 많게, top_k 도 함께 키우는 전략. expert 당 차원이 작아져서 각 expert 가 더 좁은 전문성을 가짐. DeepSeek 이 이걸 밀었고 성능 이득이 입증됨.
S: capacity_factor 는?
P:
1.0: 이론 최소. load balancing 이 거의 완벽할 때만 안전.1.25: 표준 권장. 훈련 중 25% 버퍼. 대부분 상황 OK.1.5: 매우 불균형한 초기 훈련. 안정화 후 1.25 로 내려도 됨.2.0+: 거의 쓰지 않음. 버퍼 과잉으로 메모리 낭비.
2.6 함정과 디버깅
함정 2.1. Mamba 만 쓰고 ICL 이 안 되는 현상 → 증상: needle benchmark 점수 급락. 원인: attention 비율 0. 해법: 최소 1/8 은 attention 유지.
함정 2.2. ssm_state: false 로 설정
state:
ssm_state: false # ← Mamba 인데 state 가 없음
→ Mamba 는 state 가 정체성. cross-field validator 가 CompatibilityError
를 던져. ssm_state: true 필수.
함정 2.3. Mamba 레이어에 attention: { latent_dim: ... } 을 얹음
mixer:
type: mamba
attention: # ← mamba 인데 attention sub-object
latent_dim: 128
→ validator 가 "sub-object 'attention' not allowed when type='mamba'" 로 거부.
함정 2.4. MoE 의 top_k > experts
moe: { experts: 4, top_k: 8 } # ← 불가능
→ ValidationError (R14): top_k=8 > experts=4.
함정 2.5. positional: none 을 Attention 이 섞인 모델에 설정
→ 가능은 하지만 attention 레이어가 position 을 구분 못 해서 훈련이 불안정.
Jamba 는 positional: rope 가 정답. Mamba 는 자동으로 무시.
함정 2.6. capacity_factor: 1.0 으로 훈련 시작
→ 초기 라우팅이 매우 불균형 → 많은 토큰이 drop → loss 가 튐. 1.25 로 시작,
안정되면 내림.
함정 2.7. MoE 를 매 레이어에 둠
# attn_moe 를 32 번 반복
- template: attn_moe
repeat: 32
→ 총 파라미터 8 배 폭증, 활성은 2/8 만. Jamba 철학은 "MoE 는 attention 레이어에만". Mixtral 처럼 모든 layer 에 MoE 를 둘 거면 따로 설계해야 함.
2.7 다른 primitive 와 결합
2.7.1 Jamba + MLA — 차세대 추론 최적화
layer_templates:
attn_mla_moe:
mixer:
type: attention
attention:
latent_dim: 384 # MLA
ffn:
type: moe
moe: { experts: 8, top_k: 2, router: softmax, capacity_factor: 1.25 }
강력 — Jamba 의 1/8 attention 레이어가 KV 캐시 전부인데, 그 레이어에 MLA 로 추가 압축. 이론적으로 DeepSeek-V3 × Jamba.
2.7.2 Jamba + execution_modes
execution_modes:
- { name: think, max_tokens: 8192, kv_share: true, loss_weight: 0.0 }
- { name: answer, max_tokens: 2048, loss_weight: 1.0 }
보완적 — 추론 단계에서 긴 think 구간을 Mamba 가 O(N) 으로 처리, 최종 answer 는 attention 레이어가 retrieval. 메모리 / 속도 최적.
2.7.3 Jamba + Titans memory
layer_templates:
attn_with_mem:
mixer: { type: attention, attention: {} }
ffn: { type: moe, moe: {...} }
memory:
type: neural_memory
update_at_inference: true
params: { hidden: 1024 }
inner_lr: 0.001
실험적 — attention 레이어에만 Titans memory 추가. 대화형 세션에서 추론 시점 학습이 가능. 연구 주제로 좋음.
2.7.4 Jamba + Mixture-of-Depths
layer_schedule:
- template: mamba_block
repeat: 3
- template: attn_moe
repeat: 1
depth_gating:
enabled: true
capacity: 0.5
router: top_k
시너지 — attention 레이어만 MoD 로 skip. 토큰의 50% 만 retrieval 을 거침. "단순한 토큰은 Mamba 로, 어려운 토큰만 attention 으로" 라는 해석.
2.8 심화 읽을거리
- 원 논문: Lieber et al., "Jamba: A Hybrid Transformer-Mamba Language Model," arXiv:2403.19887 (2024)
- 후속: Jamba 1.5 technical report (2024-08)
- 이론 배경: Gu & Dao, "Mamba: Linear-Time Sequence Modeling with Selective State Spaces," arXiv:2312.00752 (2023)
- 대체 하이브리드: Samba (Microsoft, 2024), Zamba (Zyphra, 2024)
- EulerStack 프리셋:
configs/presets/arch_advanced_jamba.yml,configs/presets/arch_advanced_samba.yml,llm_{0p1b,0p8b,2b,4b,16b}_jamba.yml - 관련 튜토리얼: 09 신규 primitive, mixers/02_mamba.md
- 다음 실험: Jamba 기본 7:1 을 3:1 로 바꿔 arch_advanced_samba 와 비교. 32K context 에서 needle-in-haystack 점수가 얼마나 차이 나는지.
Case 3. DeepSeek-R1 — 2-phase reasoning (execution_modes)
3.1 배경과 동기
S: R1 은 "추론 먼저, 답변 나중" 하는 모델이라는데, 아키텍처가 바뀐 건가요?
P: 정답은 거의 안 바뀌었다 야. R1 의 아키텍처는 DeepSeek-V3 와 사실상 동일 (MLA + fine-grained MoE). 바뀐 건 훈련과 생성 전략이지 구조가 아니야.
S: 그런데 왜 이렇게 화제인가요?
P: 2024 년 말, OpenAI 가 o1 을 발표했어. 긴 "chain-of-thought" 추론을 RL 로 학습했다는 블랙박스 모델. 업계는 "어떻게 하는지?" 로 술렁였지. 2025-01 에 DeepSeek 이 R1 을 오픈 소스 로 공개하면서 "o1 이 하는 건 이런 것" 을 증명했어. 그 방법이:
- Base 모델 (DeepSeek-V3) 에
<think>태그 기반 장문 추론 을 할 수 있게 훈련 - 추론 단계에서 RL (GRPO 변형) 로 "정답에 도달하는 추론" 을 학습
- 생성 시
think단계는 사용자에게 숨기고answer만 출력
S: 그럼 아키텍처는 정말 그냥 V3 인가요?
P: 정확해. 핵심 변경은 학습 레시피 + 생성 메타데이터 야. R1 이 야기한 진짜 혁신은 "RL 만으로 추론 능력을 만들 수 있다" 는 증명. 아키텍처 논문이라기보다 훈련 논문이지.
S: 그러면 EulerStack 은 R1 을 어떻게 표현하나요?
P: v1 은 이런 상황을 위해 execution_modes + transition 이라는
선언형 메타데이터를 제공해. 아키텍처는 그대로 두고 "이 모델은 2-phase
reasoning 을 한다" 는 계약을 config 에 새겨두는 거야. 훈련 스크립트와
generate() 가 이 메타데이터를 읽어서 동작해.
S: 왜 이걸 아키텍처 필드가 아니라 execution_modes 로 분리했나요?
P: 세 가지 이유:
- 모델 구조가 실제로 변하지 않으므로, 구조 필드에 넣으면 거짓말이 돼.
- 여러 종류의 phase 전략이 있어 — R1 (think/answer), Quiet-STaR (per-token rationale), o3 (multi-round). 메타데이터로 두면 전략 간 교체가 YAML diff 수준.
- 훈련 / 서빙 파이프라인이 일관된 계약을 읽기 위해 — 훈련은 loss_weight 을, 서빙은 visible_to_user 를, eval 은 kv_share 를 본다. 단일 metadata 블록으로.
3.2 메커니즘 심화
S: R1 의 실제 훈련 과정을 더 자세히 보여주세요.
P: 4 단계로 나뉘어.
Stage 1 — Cold start
입력: "Prove that √2 is irrational."
출력: "<think>
Assume √2 = a/b in lowest terms...
Then a² = 2b², so a is even.
Let a = 2c, then 4c² = 2b², b² = 2c²
So b is also even, contradiction.
</think>
<answer>
√2 is irrational because assuming rationality
leads to a contradiction.
</answer>"
규칙 기반 reward 로 supervised fine-tune.
Stage 2 — Reasoning-focused RL
- <think> 구간의 길이와 "해결 정확도" 를 reward 로 RL (GRPO)
- <answer> 는 고정된 template 에 맞춰 출력
Stage 3 — Rejection sampling + SFT - RL 로 생성한 궤적 중 "정답에 도달한" 것만 골라 재훈련 데이터로
Stage 4 — Full RLHF + preference
- <answer> 의 helpfulness / harmlessness
S: <think> 구간이 얼마나 긴가요?
P: R1 의 think 는 평균 2000~4000 토큰 이고 어려운 문제에선 16K+ 까지 늘어나. 전체 컨텍스트가 32K 일 때 think 가 28K 를 차지하는 경우도 있어.
S: 그래서 max_seq_len 이 크게 필요하군요.
P: 응. 그리고 KV share 가 중요해져. think 를 생성하면서 쌓인 KV 를 answer 단계에서 재사용하지 않으면 메모리 낭비가 커. R1 은 share.
S: Quiet-STaR 은 R1 과 어떻게 다른가요?
P: Zelikman et al. (NeurIPS 2024). 다른 접근이야:
| R1 | Quiet-STaR | |
|---|---|---|
| Phase 구조 | 긴 think 한 번, 그 다음 answer | 매 토큰마다 작은 rationale |
| Rationale 길이 | 2K~16K | 16 (짧음) |
| Transition | <think_end> 특수 토큰 |
고정 길이 스텝 |
| Training signal | 최종 정답 reward | 다음 토큰 예측 loss 감소 |
두 접근은 EulerStack 의 같은 execution_modes 스키마로 표현 가능해.
3.3 YAML 유도
S: R1 YAML 을 빈 파일부터 만들어 봅시다.
P: base 구조는 V3 와 동일 (MLA + MoE). 여기서는 MLA 만 쓸게.
schema_version: 1
model:
name: r1-clone
d_model: 1024 # 교육용 scale
vocab_size: 32000
max_seq_len: 16384 # think(8K) + answer(2K) + 여유
n_heads: 16
n_kv_heads: 4 # GQA
mlp_ratio: 4
tokenizer_contract:
type: hf
pretrained: gpt2
add_bos: true
add_eos: true
embedding:
type: learned
positional: rope
rope_theta: 500000.0 # long context
tie_word_embeddings: true
S: max_seq_len 을 어떻게 잡나요?
P: sum(execution_modes.max_tokens) + buffer 로 잡아. think 8192 +
answer 2048 + 버퍼 6144 = 16384. execution_modes_budget 이라는 realism
rule 이 이걸 자동 체크해.
S: 다음 템플릿.
P: MLA attention 하나.
layer_templates:
reasoner:
mixer:
type: attention
attention:
latent_dim: 512 # d_model/2 — long think 에서 KV 캐시 절감
qkv_bias: false
ffn:
type: gated_mlp
activation: swiglu
norm: { type: rmsnorm, position: pre }
state: { kv_cache: true }
MoE 를 추가할 수도 있지만 (실제 R1 은 MoE), 튜토리얼이니까 단순화.
layer_schedule:
- template: reasoner
repeat: 24
head:
type: causal_lm
tie_weights: true
compatibility:
compile_target: huggingface
S: 여기까지는 그냥 V3 네요. R1 은 어디서 나타나나요?
P: 맨 밑에 execution_modes 가 추가되는 것 이 R1 의 전부야.
execution_modes:
- name: think
max_tokens: 8192
kv_share: true # answer 가 think 의 KV 를 재사용
loss_weight: 0.0 # primary LM loss 에서 제외
visible_to_user: false # 서빙 시 사용자에게 숨김
per_token_rationale: false # R1 은 R1, Quiet-STaR 이 true
- name: answer
max_tokens: 2048
kv_share: false
loss_weight: 1.0 # 정답은 LM loss 에 포함
visible_to_user: true
per_token_rationale: false
transition:
type: special_token
token: "<think_end>"
S: kv_share: true 의 의미를 다시 짚어주세요.
P: think 단계를 생성할 때 쌓은 KV 캐시를, answer 단계가 시작될 때
그대로 이어서 사용 한다는 뜻. 만약 false 면 answer 가 빈 KV 로
시작해서 think 를 "다시 읽어야" 해 — 낭비. R1 은 당연히 true.
S: per_token_rationale 은?
P: Quiet-STaR 전용 플래그야. R1 은 false. Quiet-STaR 같으면:
execution_modes:
- name: rationale
max_tokens: 16
per_token_rationale: true # 매 토큰마다 작은 rationale
loss_weight: 0.1
visible_to_user: false
- name: answer
max_tokens: 256
loss_weight: 1.0
visible_to_user: true
S: transition.type 은 뭐가 있죠?
P: 두 가지:
special_token: 특정 토큰 (예<think_end>) 이 생성되면 phase 전환. R1 이 사용.budget_exhausted:max_tokens에 도달하면 강제 전환. 무한 루프 방지용.
special_token 을 기본으로 쓰고, budget_exhausted 는 fallback 으로
이해하면 돼. 많은 레시피가 "둘 중 먼저 발생" 으로 결합 해.
3.4 검증 & 컴파일
S: validate 는?
P:
eulerstack validate --preset r1_clone.yml --report
[validation] schema ... PASS
[validation] cross-field ... PASS
- MLA latent_dim=512 < d_model=1024 ✓
- d_model=1024 % n_heads=16 == 0 (head_dim=64) ✓
[validation] execution_modes ... PASS
- 2 modes: [think, answer]
- transition: special_token ("<think_end>") ✓
- execution_modes_budget: 8192 + 2048 = 10240 ≤ max_seq_len=16384 ✓
[params] estimated: ~480M
[realism] PASS
- kv_share=true + think_before_answer: 표준 R1 패턴
OK: r1_clone.yml is valid.
S: compile 하면 config.v1_extensions 에 뭐가 들어가나요?
P:
from transformers import AutoConfig
cfg = AutoConfig.from_pretrained("./r1_clone", trust_remote_code=True)
print(cfg.v1_extensions)
# {
# 'execution_modes': [
# {'name': 'think', 'max_tokens': 8192, 'kv_share': True,
# 'loss_weight': 0.0, 'visible_to_user': False,
# 'per_token_rationale': False},
# {'name': 'answer', 'max_tokens': 2048, 'kv_share': False,
# 'loss_weight': 1.0, 'visible_to_user': True,
# 'per_token_rationale': False},
# ],
# 'transition': {'type': 'special_token', 'token': '<think_end>'},
# 'schedule_kinds': [...]
# }
이 필드가 훈련 스크립트 와 서빙 generate 가 각자 읽는 공통 계약.
3.5 파라미터 튜닝 가이드
S: think.max_tokens 는 얼마로?
P: 문제 난이도에 달려있어. 가이드:
| 용도 | think max_tokens | answer max_tokens |
|---|---|---|
| 간단한 QA (역사, 상식) | 512 | 512 |
| 수학 증명 중급 | 2048 | 1024 |
| 수학/코딩 olympiad | 8192 | 2048 |
| Agent 다단계 작업 | 16384 | 4096 |
| 연구 수준 난제 | 32768 | 8192 |
R1 은 8K think 를 기본으로 권장.
S: loss_weight: 0.0 이 think 를 학습 안 하는 건가요?
P: primary LM loss 에서 제외한다는 뜻. RL stage 에서 별도 reward 로 학습. LM loss 로 think 를 학습하면 "긴 문장을 외우는" 효과가 생겨서 일반화가 안 돼.
Quiet-STaR 은 다르게 써: loss_weight: 0.1 — 적은 가중치로 LM loss 에
반영. "다음 토큰 예측이 잘 되는 rationale" 을 직접 학습하려는 전략.
S: kv_share 는 언제 false 인가요?
P: 두 경우:
- multi-turn reasoning — 각 turn 이 독립적인 think 를 한다면 think KV 를 세션 간 공유하지 않음. 이때 think 는 false 가 될 수 있음.
- think 를 재시작하는 프로토콜 — 실패한 think 를 버리고 다시 생성.
R1 기본은 think.kv_share: true, answer.kv_share: false. (think 의 KV 를
answer 가 이어쓰지만, answer 생성이 끝나면 think KV 는 버림.)
3.6 함정과 디버깅
함정 3.1. execution_modes.sum(max_tokens) > model.max_seq_len
model: { max_seq_len: 4096 }
execution_modes:
- { name: think, max_tokens: 8192 } # ← 예산 초과
- { name: answer, max_tokens: 2048 }
→ realism execution_modes_budget 경고 발생. 훈련 중 position overflow.
함정 3.2. transition.token 이 tokenizer vocab 에 없음
transition:
type: special_token
token: "<think_end>" # vocab 에 추가하지 않으면 unk
→ validate 는 통과하지만 런타임에 생성 중 "<"=토큰, "think_end"=다음 토큰, 등 여러 토큰으로 쪼개져 transition 감지 실패. tokenizer 에 special token 추가 필수:
tokenizer.add_special_tokens({"additional_special_tokens": ["<think_end>"]})
함정 3.3. "execution_modes 를 선언하면 자동으로 그렇게 동작한다" 는 오해
→ EulerStack 은 메타데이터만 보존. 실제 phase-aware generate 와 RL 훈련은
사용자가 이 메타데이터를 읽어 구현해야 함. 샘플 generate 루프는
examples/r1_generate.py (v1.2 로드맵) 참조.
함정 3.4. per_token_rationale: true 를 R1 모드에 설정
→ R1 은 "한 번의 긴 think". per_token_rationale 은 Quiet-STaR 전용.
혼동 주의.
함정 3.5. kv_share: true 인데 think 와 answer 의 position 을 따로 카운트
→ answer 가 KV 를 이어쓰니까 position index 도 이어져야 함. answer 의 첫
토큰 position = think 토큰 수 + 1. 구현 시 잊기 쉬움.
함정 3.6. "loss_weight=0 → 학습 안 됨" 이라 생각하고 RL 도 안 함 → loss_weight 은 LM supervised loss 의 가중치. RL reward 는 별도. 둘 다 0 으로 두면 진짜 학습 안 됨. R1 은 LM loss = 0, RL reward = 정답 기반 reward.
3.7 다른 primitive 와 결합
3.7.1 R1 + MLA (권장 조합)
위의 YAML 예제가 이미 이 조합. think 가 길수록 KV 캐시 가 병목이니 MLA 가 자연스러운 파트너.
3.7.2 R1 + Titans memory
layer_templates:
reasoner_with_memory:
mixer: { type: attention, attention: { latent_dim: 512 } }
ffn: { type: gated_mlp }
memory:
type: neural_memory
update_at_inference: true
params: { hidden: 2048 }
inner_lr: 0.001
persistence: session # think 단계에서 축적된 통찰을 answer 가 활용
실험적 — think 단계에서 memory 가 "왜 이 경로로 가는지" 를 축적하고, answer 가 그 memory 를 활용. 아직 학계 정설은 없지만 연구 주제로 흥미.
3.7.3 R1 + MoE
실제 R1 은 DeepSeek-V3 기반이라 MoE 가 들어있어. 튜토리얼 단순화를 위해 위 YAML 은 뺐는데, 실전 규모로 키우려면:
ffn:
type: moe
moe: { experts: 64, top_k: 6, router: softmax, capacity_factor: 1.25 }
3.7.4 R1 + Neural-ODE integrator
layer_schedule:
- integrator:
type: ode_rk4
steps: 4
body: reasoner
output: token
연구 — think 의 추론 과정을 "ODE 흐름" 으로 해석. Chain-of-thought 를 연속 동역학 시스템으로 보는 시각. 아직 실험 단계.
3.8 심화 읽을거리
- 원 논문: "DeepSeek-R1: Incentivizing Reasoning Capability in LLMs via Reinforcement Learning," arXiv:2501.12948 (2025)
- 선행: OpenAI "Learning to Reason with LLMs" blog (o1 announcement, 2024-09)
- 관련: Zelikman et al., "Quiet-STaR: Language Models Can Teach Themselves to Think Before Speaking," arXiv:2403.09629 (NeurIPS 2024)
- 후속: o3 technical report, Kimi k1.5 report
- EulerStack 프리셋:
configs/presets/arch_expert_reasoning_r1.yml - 관련 튜토리얼: 09 신규 primitive §12
- 다음 실험:
arch_expert_reasoning_r1에 MLA 추가. think 의 max_tokens 를 8192 → 16384 로 늘리고 rope_theta 를 1M 까지 키워 실제 long-think 가 가능한지 테스트.
Case 4. Titans — 추론 시점에 학습하는 neural memory
4.1 배경과 동기
S: "test time 에 학습한다" 는 게 말이 되나요?
P: 정말로 돼. Titans (Behrouz, Zhong, Mirrokni — Google, 2024-2025) 는 이 아이디어를 학계 수준에서 입증한 논문이야. 핵심은:
모델 전체가 아니라, 각 레이어에 붙은 작은 "memory 모듈" 만 inner gradient step 으로 추론 시점에 업데이트한다.
S: 왜 이게 필요한가요? KV 캐시가 있잖아요.
P: KV 캐시의 한계를 보자:
| 메커니즘 | 매개변수? | 시퀀스 길이에 종속? | 업데이트 방식 |
|---|---|---|---|
| KV cache | ✗ non-parametric | ✓ 선형 증가 | 토큰 추가만 (역진 불가) |
| Mamba state | ✗ (있지만 고정 크기) | ✗ | recurrent update |
| Titans memory | ✓ parametric | ✗ | gradient step |
Titans 의 특별한 점은 매개변수를 가진 작은 네트워크 이고 그 매개변수가 추론 중에 gradient-based 로 업데이트된다는 거야. KV 는 "뭘 봤는지" 를 저장, Titans memory 는 "보면서 뭘 학습했는지" 를 저장.
S: 선행 연구가 있나요?
P:
| 연구 | 연도 | 아이디어 | Titans 와의 관계 |
|---|---|---|---|
| Memorizing Transformers (Wu et al.) | ICLR 2022 | 외부 KV memory + k-NN lookup | 비-parametric, Titans 의 조상 |
| RETRO (Borgeaud et al.) | ICML 2022 | retrieval-augmented | 외부 DB, Titans 는 내부 파라미터 |
| Infini-attention (Google, 2024) | 2024-04 | compressive memory with MLP | Titans 에 가장 가까움 |
| TTT layer (Sun et al., 2024) | 2024-07 | mixer 전체를 inner-optim | 레이어 전체 vs Titans 는 보조 모듈 |
| Titans (Behrouz et al.) | 2024-12 | small MLP per layer, inner SGD at inference | ★ |
Titans 는 TTT 의 "inner optimizer" 아이디어를 "보조 memory 모듈" 에 한정해 적용한 실용화 버전으로 볼 수 있어.
S: Titans 가 실제로 뭘 할 수 있나요?
P: 논문의 벤치마크에서:
- Needle-in-haystack (2M context): Transformer + RAG 를 초과
- 계속 학습되는 대화: 세션 내 일관성 향상
- Long-form 지식 축적: 책 한 권을 읽으면서 "요약" 이 memory 에 점진적 축적
일반 LLM 은 컨텍스트가 넘치면 잊지만, Titans 는 "memory 에 요약해서" 기억함. 이게 "test-time learning" 의 실체야.
4.2 메커니즘 심화
S: 수식으로 보여주세요.
P: Titans memory 모듈 M 은 작은 MLP:
M_θ(x) = W_2 · GeLU(W_1 · LayerNorm(x) + b_1) + b_2
θ = {W_1, b_1, W_2, b_2, m_state}
m_state ∈ R^h ← "persistent memory vector"
Forward 는 일반 residual:
y = x + g(x) ⊙ M_θ(x) where g(x) = sigmoid(W_g x)
g(x) 는 gate — memory 의 기여도를 토큰별로 조절.
S: "추론 시점 업데이트" 는 어떻게 하나요?
P: 매 forward 뒤에 optional hook 이 호출돼:
# 1. "Surprise" loss 계산
surprise = || M_θ(x) - x ||² ← memory 가 현재 hidden 을 얼마나
잘 재구성하는가
# 2. memory 파라미터만 (모델 본체 아님!) gradient step
θ ← θ - η · ∇_θ surprise
S: 왜 surprise 가 reconstruction MSE 인가요?
P: 정보이론적 해석이야. memory 가 x 를 잘 재구성하지 못하면 "x 는 예상 밖" → 기억할 만한 사건. 크게 업데이트해서 memory 가 x 를 더 잘 재구성하도록 학습. 반대로 예상되는 hidden 에는 update 가 작아 — 이미 "알고 있으므로".
┌───────────────────────────────────────────────────────┐
│ Surprise learning loop │
├───────────────────────────────────────────────────────┤
│ │
│ token_t ──→ layer ──→ hidden_t │
│ │ │
│ ┌───────┴───────┐ │
│ │ │ │
│ forward surprise │
│ │ │ │
│ ▼ ▼ │
│ y = x + M(x) || M(x) - x ||² │
│ │ │
│ ▼ │
│ ∇_θ surprise │
│ │ │
│ ▼ │
│ θ ← θ - η · ∇_θ │
│ │
└───────────────────────────────────────────────────────┘
S: 모델 본체의 gradient 는 흐르지 않나요?
P: memory 파라미터에만 흐르게 격리해. 구현 상:
# pseudo-code
with torch.enable_grad():
for p in memory.parameters():
p.requires_grad_(True)
for p in base_model.parameters():
p.requires_grad_(False)
surprise = mse(memory(x_det), x_det) # x_det = x.detach()
surprise.backward()
with torch.no_grad():
for p in memory.parameters():
p.sub_(p.grad, alpha=inner_lr)
p.grad = None
x 를 detach 해서 outer graph 에 grad 가 새지 않도록 하고, memory 파라미터에만 step. outer training 은 건드리지 않아.
S: persistence 가 뭔가요?
P: memory 가 얼마나 오래 유지되는지의 정책:
per_query: 한 forward pass 가 끝나면 memory 를 초기 상태로 리셋. 단발성.session: 한 대화 세션 동안 유지. 대화 끝나면 리셋. 기본값.persistent: 영구.save_pretrained시 model.safetensors 에 포함. 다음 세션에도 이어짐.
persistent 는 A/B 테스트나 여러 사용자가 공유하는 서빙에서 위험해 — 모든
사용자 데이터가 한 memory 에 쌓이기 때문. 서빙은 session 이 안전.
4.3 YAML 유도
S: 빈 YAML 에서.
P:
schema_version: 1
model:
name: titans-demo
d_model: 768
vocab_size: 32000
max_seq_len: 8192
n_heads: 12
n_kv_heads: 4
mlp_ratio: 4
tokenizer_contract:
type: hf
pretrained: gpt2
add_bos: true
add_eos: true
embedding:
type: learned
positional: rope
rope_theta: 500000.0
tie_word_embeddings: true
S: 이제 template 에 memory 가 들어가는 거죠.
P: 응. 핵심 부분.
layer_templates:
attn_with_memory:
mixer:
type: attention
attention:
qkv_bias: false
ffn:
type: gated_mlp
activation: swiglu
norm: { type: rmsnorm, position: pre }
state: { kv_cache: true }
memory:
type: neural_memory
update_at_inference: true # inference 중 grad step 활성화
params:
hidden: 1024 # memory 내부 MLP 크기
inner_lr: 0.001 # SGD step size
persistence: session # per_query | session | persistent
S: hidden: 1024 는 어떻게 정해지나요?
P: memory 의 표현력 을 결정하는 핵심 파라미터야. 권장 범위:
hidden |
파라미터 추가 (d=768 기준) | 용도 |
|---|---|---|
| 256 | ~0.4M/layer | 최소. memory 가 거의 비활성 |
| 512 | ~0.8M/layer | 가벼움. fact 암기 정도 |
| 1024 | ~1.6M/layer | 표준 권장. Titans 논문 |
| 2048 | ~3.2M/layer | 큰 표현력. 장문 요약 |
| 4096 | ~6.4M/layer | 과도. 오버피팅 위험 |
d_model 의 1~2 배가 sweet spot.
S: inner_lr: 0.001 은?
P: 훈련 시 outer LR (AdamW 3e-4) 보다 커도 괜찮아. inner step 은
memory 만 건드리고, step 하나로 끝나기 때문에:
0.0001— 매우 보수적. memory 가 거의 업데이트 안 됨0.001— 표준0.01— 공격적. 빠른 학습, 불안정 가능0.1+— 위험. memory 가 "최근 surprise" 에 과도 반응
Titans 논문은 0.001 기준.
S: 모든 레이어에 memory 를 달아야 하나요?
P: 아니. 선택적이야. 예를 들어 24 layer 중 끝 8 layer 만:
layer_templates:
plain_attn: # memory 없음
mixer: { type: attention, attention: {} }
ffn: { type: gated_mlp }
attn_with_memory: # memory 있음
mixer: { type: attention, attention: {} }
ffn: { type: gated_mlp }
memory: { ... }
layer_schedule:
- template: plain_attn
repeat: 16 # 앞 16 개는 plain
- template: attn_with_memory
repeat: 8 # 뒤 8 개가 memory 장착
"앞쪽은 패턴 인식, 뒤쪽은 기억 축적" 이라는 직관.
S: 전체 YAML.
P:
layer_schedule:
- template: attn_with_memory
repeat: 18
head:
type: causal_lm
tie_weights: true
compatibility:
compile_target: huggingface
4.4 검증 & 컴파일
S: validate 출력은?
P:
[validation] schema ... PASS
[validation] memory ... PASS
- type: neural_memory ∈ {neural_memory, associative, retrieval} ✓
- persistence: session ∈ {per_query, session, persistent} ✓
- params.hidden: 1024 > 0 ✓
[params] estimated: ~310M
- base attention + ffn: ~280M
- Titans memory × 18 layers: ~29M
[realism] PASS
OK: titans_demo.yml is valid.
S: 실제로 로드해서 memory 가 살아있는지 확인하려면?
P:
from transformers import AutoModelForCausalLM
from eulerstack.hf.auto_register import register_eulerstack_auto_classes
from eulerstack.components.titans_memory import TitansMemoryModule
register_eulerstack_auto_classes()
model = AutoModelForCausalLM.from_pretrained("./titans_demo",
trust_remote_code=True)
mems = [m for m in model.modules() if isinstance(m, TitansMemoryModule)]
print(f"Titans memory modules: {len(mems)}")
# → Titans memory modules: 18
print(f"params per memory: {sum(p.numel() for p in mems[0].parameters()):,}")
# → params per memory: ~1.6M
S: inference-time update 는 어떻게 호출하나요?
P: 모델에 표준 hook 이 달려있어.
model.eval()
ids = tokenizer("Paris is the capital of France.",
return_tensors="pt").input_ids
# 1. forward
out = model(ids, output_hidden_states=True)
# 2. 표준 hook — 이 한 줄이 "test-time learning" 그 자체
surprise = model.step_memory_at_inference(out.hidden_states[-1])
print(surprise)
# {
# 'eulerstack.layers.0.titans_memory': 0.4231,
# 'eulerstack.layers.1.titans_memory': 0.3894,
# ...
# 'eulerstack.layers.17.titans_memory': 0.2013,
# }
반환값은 각 레이어 memory 의 surprise loss. 시간이 지나면서 이 값이 감소 하는 경향 을 보여야 해 — memory 가 점점 더 잘 "기억" 하고 있다는 뜻.
4.5 파라미터 튜닝 가이드
S: memory 를 모델의 어느 깊이에 둘까요?
P: 두 가지 접근:
전략 A — "모든 레이어" (Titans 논문 기본)
# 24 layer 모두 memory
layer_schedule:
- template: attn_with_memory
repeat: 24
총 파라미터 증가 대략 10~15%. 모든 레이어가 기여.
전략 B — "후반부만" (효율 중심)
layer_schedule:
- template: plain_attn
repeat: 18
- template: attn_with_memory
repeat: 6 # 뒤 25% 만
파라미터 증가 3%. 경험적으로 memory 의 효과 75% 이상 유지. 권장.
전략 C — "중간 레이어만" (hypothesis)
layer_schedule:
- template: plain_attn
repeat: 8
- template: attn_with_memory
repeat: 8 # 중간 1/3
- template: plain_attn
repeat: 8
연구 중. 표현 학습의 "중간층" 에만 memory 를 두는 가설.
S: update_at_inference=false 를 쓰는 경우는?
P: 훈련 전용 모드 야. outer optimizer 가 memory 도 함께 학습하지만, inference 에서는 memory 가 "frozen" 상태. hook 은 no-op.
언제 쓰나?
- Serving 에서 memory drift 를 원하지 않을 때 — A/B 테스트 중.
- 훈련 중에만 학습해서 "평균 기억" 을 만들고 배포는 고정 — 모든 사용자 에게 동일한 memory.
- 디버깅 — inference update 가 의심될 때 비교용.
production 에서는 session persistence + update_at_inference: true 가
기본.
4.6 함정과 디버깅
함정 4.1. persistence: persistent 를 multi-user 서빙에 사용
→ 보안/프라이버시 사고 직행. 모든 사용자 데이터가 같은 memory 에 축적.
A 사용자의 memory 를 B 사용자가 읽는 꼴. 서빙은 반드시 session,
각 세션마다 모델 인스턴스 격리.
함정 4.2. update_at_inference=true + 매우 큰 inner_lr
memory:
update_at_inference: true
inner_lr: 0.5 # ← 너무 큼
→ 첫 몇 토큰 뒤 memory 가 수렴을 잃어 drift. 서빙 중 답변 품질이 "떨어지는" 현상. 0.001 이하 권장.
함정 4.3. memory 를 모든 mixer 타입에 무분별하게 적용
layer_templates:
mamba_with_memory:
mixer: { type: mamba, ... }
memory: { type: neural_memory, ... }
→ 가능하지만 Mamba 는 이미 state 로 "기억" 을 하고 있어. memory 와 역할 중복으로 훈련 불안정. attention 레이어에만 두는 게 안전.
함정 4.4. params.hidden < d_model/2
memory:
params: { hidden: 128 } # d_model=768 기준 너무 작음
→ memory 의 표현력이 부족해 "아무 것도 기억 안 함". hidden ≥ d_model/2
를 최소 기준으로.
함정 4.5. surprise 가 처음부터 0
surprise = model.step_memory_at_inference(hidden)
print(surprise)
# {'...': 0.0001, '...': 0.0001, ...}
→ 초기화가 잘못됐을 가능성. TitansMemoryModule 은 out_proj.weight 를
0 으로 초기화하도록 돼 있어 (module 이 처음엔 identity 에 가까움). 그러면
surprise 가 작아. 몇 스텝 훈련 후 재확인.
함정 4.6. inference update 후 surprise 가 오히려 증가
→ 증상: 시간이 갈수록 surprise 가 커짐. 원인 두 가지:
1. inner_lr 이 커서 overshoot — 줄여라.
2. input distribution 이 훈련과 크게 다름 — 예: 완전히 다른 언어. memory 가
적응 중이라 일시적일 수 있음. 10~20 토큰 뒤 안정되는지 관찰.
4.7 다른 primitive 와 결합
4.7.1 Titans + MLA
layer_templates:
mla_with_memory:
mixer:
type: attention
attention: { latent_dim: 384 } # MLA
ffn: { type: gated_mlp }
memory:
type: neural_memory
update_at_inference: true
params: { hidden: 1024 }
inner_lr: 0.001
강력 — MLA 가 KV 캐시를 줄이고 memory 가 "장기 기억" 을 맡음. long context (128K+) 에서 특히 시너지.
4.7.2 Titans + R1 (execution_modes)
layer_templates:
reasoner_with_memory:
mixer: { type: attention, attention: { latent_dim: 512 } }
ffn: { type: gated_mlp }
memory:
type: neural_memory
update_at_inference: true
params: { hidden: 2048 } # 큰 memory
inner_lr: 0.001
persistence: session
execution_modes:
- { name: think, max_tokens: 8192, kv_share: true, loss_weight: 0.0 }
- { name: answer, max_tokens: 2048, loss_weight: 1.0 }
연구 가치 큼 — think 구간의 논리를 memory 에 축적, answer 생성이 참조. 멀티턴에서 "이전 turn 의 추론" 을 이어가는 효과. 2025-26 에 이 조합 이 많이 연구될 것으로 예상.
4.7.3 Titans + Jamba
layer_templates:
attn_moe_with_memory:
mixer: { type: attention, attention: {} }
ffn:
type: moe
moe: { experts: 8, top_k: 2, router: softmax, capacity_factor: 1.25 }
memory:
type: neural_memory
update_at_inference: true
params: { hidden: 1024 }
attention 레이어 (1/8) 에만 memory. Mamba 의 O(N) + attention 의 retrieval + Titans 의 long-term.
4.7.4 Titans + TTT (double inner-optim)
실험적 — TTT 레이어 자체가 inner gradient 를 씀. 같은 모델에 Titans memory 를 추가로 두면 inner-optim 이 두 곳. 이론적으로 안정성 확보가 어렵고 실전 보고는 아직 없음. 연구 주제.
4.8 심화 읽을거리
- 원 논문: Behrouz, Zhong, Mirrokni, "Titans: Learning to Memorize at Test Time," Google, 2024-12/2025
- 선행: Wu et al., "Memorizing Transformers," ICLR 2022
- 선행: Borgeaud et al., "Improving Language Models by Retrieving from Trillions of Tokens" (RETRO), ICML 2022
- 유사: Munkhdalai et al., "Infini-attention," arXiv:2404.07143 (2024)
- 핵심 영감: Ha & Schmidhuber, "Fast Weights" (2017)
- EulerStack 프리셋:
configs/presets/arch_expert_titans_memory.yml - 관련 튜토리얼: 09 신규 primitive §10
- 테스트:
tests/test_titans_memory_runtime.py(12 개 테스트 — 모듈 단위부터 HF 왕복까지) - 다음 실험:
arch_expert_titans_memory의inner_lr을[0.0001, 0.001, 0.01]로 변화시키며 세션 끝에서의 surprise loss 추이를 비교. 어느 값에서 "학습" 이 실제로 일어나는지 관찰.
마무리 — 네 사례의 공통 구조
| 사례 | 바뀐 primitive | EulerStack 필드 | 런타임 (v1.1) | 핵심 아이디어 |
|---|---|---|---|---|
| DeepSeek-V3 | attention KV 압축 | attention.latent_dim |
✅ Core | 차원 희생 → 메모리 이득, quality 유지 |
| Jamba | mamba/attn 하이브리드 + MoE | layer_schedule + ffn.type: moe |
✅ Core | 7:1 비율로 속도와 ICL 둘 다 |
| DeepSeek-R1 | 추론 단계 분리 | execution_modes: + transition: |
✅ Core (metadata) | 구조 불변, 훈련 · 생성 레시피만 |
| Titans | test-time parametric memory | template.memory: + step_memory_at_inference |
✅ Core (v1.1) | inference 중 memory 만 grad step |
네 사례의 공통 학습
- "한 YAML 파일이 한 논문" — 어떤 사례든 아키텍처 변경이
modeling_xxx.py200 줄이 아니라 YAML 5~20 줄로 표현됐어. - 직교성 (orthogonality) 설계 — MLA 는 FFN 을 건드리지 않고, MoE 는 attention 을 건드리지 않고, execution_modes 는 구조를 건드리지 않고, Titans memory 는 forward path 를 건드리지 않아. 그래서 조합이 쉬움.
- "메타데이터 먼저, 런타임은 점진적으로" — Schema-first. R1 의 execution_modes 는 아직 generate 가 실험 단계지만 메타데이터는 이미 왕복. Titans 는 v1.0 에 schema, v1.1 에 runtime.
- 레고 블록은 진짜 레고 — 결합이 산수 — MLA × Jamba × R1 × Titans =
4 가지 논문을 한 YAML 에 얹을 수 있어. §1.7 / §2.7 / §3.7 / §4.7 의
조합 예제를 모으면
arch_expert_kitchen_sink.yml같은 capstone 이 나옴.
다음 단계
- 자기 논문 옮기기 실습 — 본인이 관심 있는 5 번째 논문을 같은 구조로 정리.
배경 → 메커니즘 → YAML → validate → 튜닝 → 함정 → 결합 → 읽을거리.
쓴 YAML 이
eulerstack validate --report를 통과하면 대부분 올바르게 옮긴 것. - 5-tier 프리셋 비교 —
arch_advanced_mla/arch_advanced_jamba/arch_expert_reasoning_r1/arch_expert_titans_memory네 프리셋을 열어 diff 해보세요. "단 한 primitive 만 바뀌는 구조" 가 눈에 들어옵니다. - 캡스톤 프리셋 —
arch_expert_kitchen_sink은 위 4 사례의 primitive 를 모두 한 모델에 결합. 실제 HF 훈련에서 loss 가 감소하는지tests/test_kitchen_sink_preset.py가 자동 회귀 확인. - 튜토리얼 9 로 돌아가 각 primitive 의 YAML 필드 레퍼런스를 다시 한 번.
- 52 개 프리셋 를 브라우즈:
eulerstack --lang ko presets list.