> EulerStack > 튜토리얼 > 9. v1 Phase B 신규 프리미티브 워크스루 (MLA / Titans / MoD / Dual-Stream / Neural-ODE / TTT)

9. v1 Phase B 신규 프리미티브 워크스루 (MLA / Titans / MoD / Dual-Stream / Neural-ODE / TTT)

이 튜토리얼은 EulerStack v1 에서 새로 추가된 14 개 primitive 를 하나씩 YAML 로 작성하고 검증하는 단계별 가이드입니다. 각 primitive 는:

  1. 무엇을 가능하게 하는지 (근거 논문 / 상황)
  2. YAML 로 어떻게 쓰는지 (최소 예제 + 주석)
  3. 언제 쓸지 (실전 사용 가이드라인)
  4. 런타임 상태 (Core / Component / Plugin-track)

순서로 다룹니다. schema_version: 1 을 기본으로 두고, 기존 attention / mamba / retnet / hyena / moe baseline 에 얹을 수 있는 구조로 설계되어 있습니다.

런타임 전체 상태는 runtime_primitive_status.md 매트릭스를 참조하세요 (내부 자산).


0. 사전 준비

pip install -e .
eulerstack --lang ko schema          # 스키마 요약 출력 (5 개 언어 지원)

모든 예제는 eulerstack validate --preset <파일> 으로 즉시 검증 가능합니다. --report 옵션을 붙이면 파라미터 추정 + realism 체크 + reserved-namespace 경고가 함께 나옵니다.


1. per-layer override (B1.1) — 스케줄 수준 값 교체

상황: 템플릿은 그대로 두고 특정 레이어 그룹의 일부 값 (residual scaling, attention window 등) 만 바꾸고 싶을 때.

schema_version: 1
# ... (model/tokenizer/embedding 생략)
layer_templates:
  attn_dense:
    mixer: { type: attention, attention: { window: null } }
    ffn:   { type: gated_mlp }
    residual: { type: sequential, scaling: 1.0 }

layer_schedule:
  - template: attn_dense
    repeat: 6
    override:                          # 첫 6 개만 교체
      residual: { scaling: 0.5 }
      attention: { window: 128 }
  - template: attn_dense
    repeat: 6                          # 나머지 6 개는 템플릿 기본값 그대로

허용 필드 (whitelist, 값 타입 한정): - residual.scaling - attention.window, attention.attn_drop - norm.type, norm.position - ffn.activation

mixer.type 변경은 불허 — 타입이 다른 레이어는 새 템플릿으로 분리합니다.

런타임: ✅ Core. 정규화 단계에서 per-layer 템플릿 복제본에 override 가 적용됩니다.


2. let: + ${…} 표현식 (B1.2)

상황: d_model = n_heads × d_head 같은 의존 관계를 YAML 수준에서 표현하고 싶을 때.

schema_version: 1

let:
  n_heads: 16
  d_head: 64
  layers: 24

model:
  name: "let-demo"
  d_model: ${let.n_heads * let.d_head}       # 1024
  vocab_size: 32000
  max_seq_len: ${let.layers * 512}           # 12288
  n_heads: ${let.n_heads}
  n_kv_heads: ${let.n_heads // 2}            # 8

layer_schedule:
  - template: decoder
    repeat: ${let.layers}

허용 연산: + - * / // + 괄호 + let.<name> 참조. 조건문·함수 호출 · 문자열 연산은 전부 거부됩니다 (Level 1).

런타임: ✅ Core. validate 전 pre-pass 에서 전부 해소.


3. Reserved namespace (B0/B6)

상황: 플러그인이 읽을 메타데이터나 아직 정식 primitive 가 아닌 실험을 YAML 에 남겨두고 싶을 때.

schema_version: 1
# ... (일반 필드)

experimental.online_adaptation:       # WARNING 만 발생, ERROR 아님
  reward_source: reward_model
vendor.acme.telemetry:
  endpoint: "https://telemetry.acme"
future.symbolic_interface:
  mode: sidecar

eulerstack validate --report 실행 시 [reserved_namespace] 라벨로 경고 표시됩니다. 플러그인이 등록된 환경에서는 동일 키가 기능적으로 해석됩니다.


4. MLA — attention.latent_dim (B2.1)

근거: DeepSeek-V3 Technical Report (2024). KV 를 공유 latent 로 압축해 캐시 메모리 감소.

layer_templates:
  mla_decoder:
    mixer:
      type: attention
      attention:
        latent_dim: 384     # d_model=768 의 절반 → KV 캐시 약 50% 절감
    ffn: { type: gated_mlp }

실전 가이드: - 보통 latent_dim ≈ d_model / 2 부터 시작 - 긴 컨텍스트 (≥ 16K) 에서 효과 극대화 - latent_dim ≥ d_model 이면 검증 실패

런타임: ✅ Core. CausalSelfAttention(latent_dim=…) 이 실제 compressed KV projection 을 수행. forward/backward/kv-cache 모두 지원.

데모 preset: configs/presets/arch_advanced_mla.yml


5. Branched mixer — mixer.type: branched (B2.2)

근거: Jamba (Lieber et al., AI21, 2024) 의 layer-level hybrid 를 per-token routing 으로 일반화.

layer_templates:
  branched_layer:
    mixer:
      type: branched
      branched:
        branches:
          ssm:  { type: mamba,     mamba: { variant: mamba2 } }
          attn: { type: attention, attention: {} }
        selector:
          type: learned_gate      # 또는 top_k
          top_k: 1
          input: hidden
    ffn: { type: gated_mlp }

제약: - 브랜치 2 개 이상 필수 - 브랜치 안에 또 다른 branched 금지 (v1 에서는 1-레벨만)

런타임: 🟡 Fallback. 현재 컴파일은 첫 브랜치로 대체 실행, 원 spec 은 config.stack.pattern[].\_v1_extras.branched 에 보존. 실 routing 은 플러그인 트랙.


6. TTT layer — mixer.type: ttt_layer (B2.3)

근거: Sun et al. 2024, "Learning to (Learn at Test Time): RNNs with Expressive Hidden States".

layer_templates:
  ttt_block:
    mixer:
      type: ttt_layer
      ttt:
        inner_model: { type: mlp, hidden: 256 }
        inner_optimizer: sgd
        inner_lr: 0.01
        inner_steps_per_token: 1
    ffn: { type: gated_mlp }
    state:
      ssm_state: true          # TTT 는 지속 내부 가중치가 있으므로 기본 true

런타임: 🔌✅ 플러그인 레퍼런스 구현 가능 (v1.1). eulerstack.plugins.ttt 를 import 하면 실제 per-token meta-learning 루프를 수행하는 TTTBlock 이 plugin registry 에 등록되고, core modeling 이 Mamba fallback 을 자동으로 업그레이드합니다. import 하지 않으면 기존 Mamba fallback 이 유지됩니다 (공통프롬프트 §7 격리).

import eulerstack.plugins.ttt            # 한 줄 import 으로 활성화
from eulerstack.compiler.compile import compile_to_hf_model
model = compile_to_hf_model(ir, seed=0)  # 이제 TTTBlock 이 인스턴스화됨

구현 특징 (functional fast-weights): - 토큰마다 inner-loss(MSE reconstruction) 를 autograd.grad 로 미분해 SGD 로 fast-weight 텐서 갱신 - 지속 inner 파라미터 self.inner_net 는 forward 종료 시점에 with torch.no_grad(): copy_ 로 한 번에 업데이트 — in-place 버전 충돌 없이 outer training 과 공존

테스트: tests/test_ttt_plugin_runtime.py (10) + tests/test_runtime_hf_training_e2e.py::TestHFExportTTTTraining.


7. Mixture-of-Depths — schedule[].depth_gating (B3.1)

근거: Raposo et al. ICML 2024.

layer_schedule:
  - template: attn_block
    repeat: 32
    depth_gating:
      enabled: true
      capacity: 0.5           # 토큰의 50% 만 해당 레이어 통과
      router: top_k           # 또는 learned_gate

실전 가이드: - capacity: 0.5 가 논문 기본값. 0.25 까지 낮추면 추가 속도, 품질 하락 가능 - router: top_k 결정적 · 재현 가능. learned_gate 는 soft routing

런타임: 🟢 Component. 사용법:

from eulerstack.components.depth_gate import DepthGate

gate = DepthGate(d_model=768, capacity=0.5, router="top_k")
y = gate(x, body_fn=my_attention_layer)

데모 preset: configs/presets/arch_advanced_mod.yml


8. Parallel (monoidal) 스케줄 — schedule[] parallel: (B3.2)

근거: PaLM (2023) within-layer parallel, Flamingo (2022) dual-tower, Jamba (2024) 의 monoidal 일반화.

layer_schedule:
  - parallel:
      - stream: fast
        body:
          - { template: mamba_block, repeat: 6 }
      - stream: slow
        body:
          - { template: attn_block, repeat: 6 }
    merge:
      type: concat            # concat | add | gated | cross_attn
      projection: true        # concat 의 경우 N*d_model → d_model 투영

제약: - 스트림 ≥ 2 - 스트림 body 안에 다시 parallel / integrator 넣기 금지 (flat 만) - 스트림 이름 고유

런타임: 🟢 Component. 사용법:

from eulerstack.components.parallel_stream import ParallelStream

p = ParallelStream(
    [fast_stream_module, slow_stream_module],
    d_model=768,
    merge_type="concat",
    merge_projection=True,
    stream_names=["fast", "slow"],
)
y = p(x)

데모 preset: configs/presets/arch_expert_dual_stream.yml


9. Integrator — schedule[] integrator: (B3.3)

근거: Universal Transformer (Dehghani 2019), PonderNet (Banino 2021), Diffusion-LM (Li 2022), Coconut (Hao 2024) — 네 연구 라인의 통합. v1.1 부터는 Neural-ODE 해석 (Chen et al. 2018) 도 core 에서 지원합니다.

9a. discrete — 독립 가중치 K 단계 (기본)

layer_schedule:
  - integrator:
      type: discrete          # Diffusion-LM 스타일 — K 개 독립 가중치
      steps: 4
      body: refine_block
      output: token           # 또는 hidden (Coconut latent reasoning)

기본 compile 은 bodyK 개 독립 복사본 으로 펼칩니다. 같은 모듈을 shared-weight 로 K 번 적용하고 싶다면 DiscreteIntegrator 컴포넌트로 직접 조립할 수 있습니다.

from eulerstack.components.integrator import DiscreteIntegrator
integrator = DiscreteIntegrator(refine_block, steps=4)   # shared weights

9b. ode_euler / ode_rk4 — Neural-ODE shared-weight (v1.1 core ✨)

layer_schedule:
  - integrator:
      type: ode_rk4           # 또는 ode_euler
      steps: 4
      body: refine_block
      output: token

의미: body(x) 를 "미분 항" f(x) 로 해석하고, dt = 1/steps 로 K 단계 수치적분을 수행합니다. 가중치는 공유steps 를 늘려도 파라미터 수는 늘지 않습니다.

from eulerstack.components.integrator import ODEIntegrator
odeint = ODEIntegrator(refine_block, steps=4, method="rk4")

런타임 경로: EulerStackLayer._forward_ode 에서 per-step RoPE / attention mask 를 올바르게 흘리면서 RK4 를 수행합니다. KV 캐시는 ODE 경로에서 비활성화됩니다 (해석이 모호함).

9c. ode_adaptive — 예약 (plugin-only)

adaptive step-size 제어 (torchdiffeq 등) 는 여전히 reserved 입니다. 정식 플러그인이 나오기 전에는 validator 가 거부합니다.


10. Memory module — template.memory: (B4.1)

근거: Titans (Behrouz et al., Google, 2024-2025).

layer_templates:
  attn_with_memory:
    mixer: { type: attention, attention: {} }
    ffn:   { type: gated_mlp }
    memory:
      type: neural_memory
      update_at_inference: true
      params:
        hidden: 2048
      inner_lr: 0.001
      persistence: session    # per_query | session | persistent

런타임: ✅ Core (v1.1). TitansMemoryModule 이 template 에 memory: 가 선언된 모든 레이어에 자동 결합됩니다. 훈련 중에는 outer 옵티마이저가 메모리 파라미터를 함께 학습하고, 추론 시에는 표준 훅 step_memory_at_inference 로 inner SGD 스텝을 수행합니다 — HF save_pretrained → from_pretrained 왕복 후에도 그대로 동작합니다.

from transformers import AutoModelForCausalLM
from eulerstack.hf.auto_register import register_eulerstack_auto_classes

register_eulerstack_auto_classes()
model = AutoModelForCausalLM.from_pretrained("./titans_model", trust_remote_code=True)

ids = tokenizer("앞 turn 에서 등장한 사실", return_tensors="pt").input_ids
out = model(ids, output_hidden_states=True)
surprise = model.step_memory_at_inference(out.hidden_states[-1])
# surprise: {"eulerstack.layers.0.titans_memory": 0.42, ...}

데모 preset: configs/presets/arch_expert_titans_memory.yml


11. Shape-change layer — template.shape_change: (B4.2)

근거: Hourglass Transformer (Nawrot et al. 2021).

layer_templates:
  wide_block:     { mixer: { type: attention, attention: {} }, ffn: { type: gated_mlp } }
  bottleneck:
    mixer: { type: attention, attention: {} }
    ffn:   { type: gated_mlp }
    shape_change:
      d_out: 128             # 여기서 hidden 을 d_out 으로 축소
      projection: linear     # linear | conv1d | mlp

런타임: 🔌 Plugin-track. Core modeling 이 layer 간 d_model 고정 가정이라 shape-changing residual wire-up 은 플러그인이 제공.


12. Reasoning mode — execution_modes: + transition: (B5)

근거: DeepSeek-R1 (2025), OpenAI o1/o3 (2024), Quiet-STaR (NeurIPS 2024).

아키텍처는 변하지 않습니다 — 훈련 레시피와 generate() 가 읽는 메타데이터일 뿐입니다.

execution_modes:
  - name: think
    max_tokens: 8192
    kv_share: true
    loss_weight: 0.0        # primary LM 손실에서 제외
    visible_to_user: false
  - name: answer
    max_tokens: 2048
    loss_weight: 1.0
    visible_to_user: true

transition:
  type: special_token
  token: "<think_end>"

Quiet-STaR 변형 (토큰마다 rationale 생성):

execution_modes:
  - name: rationale
    max_tokens: 16
    per_token_rationale: true       # Zelikman 2024
    loss_weight: 0.1
    visible_to_user: false
  - name: answer
    max_tokens: 256
    loss_weight: 1.0
    visible_to_user: true

런타임: ✅ Core (메타데이터 round-trip). Generate 경로가 phase 분리를 honour.

데모 preset: configs/presets/arch_expert_reasoning_r1.yml


13. Reserved integrator 타입 (B3.3, v1.x+)

ode_rk4 / ode_euler 는 v1.1 에서 core 로 승격됐습니다 (§9b 참조). v1.0 에서 reserved 였던 타입 중 현재 남아 있는 것은 ode_adaptive 뿐입니다.

layer_schedule:
  - integrator:
      type: ode_adaptive     # RESERVED — 플러그인 (torchdiffeq 등) 이 필요
      steps: 8
      body: refine_block

상태: 스키마 예약. adaptive step-size 제어에는 torchdiffeq 같은 전용 라이브러리가 필요하므로 플러그인 트랙으로 남깁니다. 일반 고차 수치적분은 이미 ode_rk4 로 충분합니다.


14. Weight form 예약 (future)

tensor network weight (MPS/MERA/TT) 는 weight_form: 필드로 예약되어 있으나 v1.0 스키마 enum 에는 아직 없습니다. 필요 시 vendor.tensor.weight_form: mera 처럼 reserved namespace 로 미리 써두면 plugin 등장 시 자연스럽게 연결됩니다.


검증 & 컴파일 체인

모든 primitive 를 조합한 스펙은 아래 한 줄로 검증됩니다:

eulerstack --lang ko validate --preset my_spec.yml --report

리포트에는 다음이 포함됩니다: - 스키마 통과 여부 - 추정 파라미터 수 - 층 수 (integrator 는 K 로 펼친 수) - realism 경고 (RoPE head_dim, MoE expert 수 등) - reserved-namespace 경고 (해당 시)

컴파일 후 HF 커스텀 모델로 저장:

eulerstack --lang ko compile --preset my_spec.yml --output-dir ./my_model
from transformers import AutoModelForCausalLM
model = AutoModelForCausalLM.from_pretrained("./my_model", trust_remote_code=True)
# config.v1_extensions 에 execution_modes / schedule_kinds / _v1_extras 전부 보존

"이걸 다 같이 쓰면 정말 돌아가?" — Capstone preset

위 primitive 를 한 스펙에 전부 담은 캡스톤 preset 이 있습니다: configs/presets/arch_expert_kitchen_sink.yml.

TDD 검증 (tests/test_kitchen_sink_preset.py) 10 개:

  1. YAML 이 validate_v2 를 통과
  2. normalize_to_ir 이 20 개 expanded layer 를 생성
  3. override 가 Titans memory / ODE 메타를 보존 (회귀 가드)
  4. compile_to_hf_model 이 실제 EulerStackForCausalLM 인스턴스 생성
  5. 1-스텝 forward 가 예상 logits shape 반환
  6. save_pretrained → AutoModelForCausalLM.from_pretrained 왕복 후 forward 결과 동일 (atol=1e-5)
  7. config.v1_extensionsexecution_modes / ode_rk4 메타 보존
  8. HF 훈련 25 step 동안 loss 감소 (plugin 미설치)
  9. 같은 훈련이 eulerstack.plugins.ttt 임포트 후에도 loss 감소 (plugin 활성)

즉, "이걸 전부 한 번에 조합해도 compile → save_pretrained → train 이 정말 돌아간다" 가 자동 회귀 테스트로 매일 검증됩니다.

다음 단계