EulerForge CLI 레퍼런스
GitHub 저장소: https://github.com/eulerwa/eulerforge
English version: cli_en.md
글로벌 옵션
--lang LANG — 출력 언어 설정
모든 서브커맨드에 --lang 지정하면 CLI 출력 언어를 변경합니다.
# 영어로 출력
eulerforge --lang en train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml
# ��본어로 출력
eulerforge --lang ja bench --preset configs/bench/sft_target_only.yml
| 언어 코드 | 언어 |
|---|---|
ko |
한국어 (기본값) |
en |
English |
zh |
中文 |
ja |
日本語 |
es |
Español |
환경변수 EULERFORGE_LANG으로도 설정 가능합니다. --lang이 환경변수보다 우선합니다.
export EULERFORGE_LANG=en
eulerforge train --preset ... # 영어로 출력
명령어
eulerforge train
메인 훈련 파이프라인.
eulerforge train [OPTIONS]
| 옵션 | 설명 |
|---|---|
--preset PATH |
YAML 프리셋 설정 파일 |
--set KEY=VALUE |
설정 값 오버라이드 (반복 가능) |
--output-dir DIR |
체크포인트 출력 디렉토리 |
--run-name NAME |
선택적 실행 이름 접미사 |
--print-config |
해석된 설정 JSON 출력 |
--validate-only |
설정 검증만 수행, 훈련하지 않음 |
--preflight |
모델 로드, 인젝션 적용, 페이즈 검증 — 훈련 없이 |
--metrics-level LEVEL |
메트릭 수준: minimal (기본) 또는 advanced (+ MoE 라우팅 통계) |
--debug |
상세 디버그 로깅 활성화 |
--debug-every N |
N 스텝마다 디버그 로그 출력 (기본값: 50) |
--debug-max-modules N |
디버그 섹션당 최대 모듈 수 (기본값: 50) |
--debug-topk-grad N |
출력할 Top-K 그래디언트 노름 수 (기본값: 20) |
--debug-attn |
어텐션 프로젝션 요약 출력 |
--debug-trainable-names |
학습 가능 파라미터 이름 덤프 |
파이프라인 연속 훈련 (체크포인트 자동 탐지)
model_name에 이전 EulerForge 훈련의 체크포인트 경로를 지정하면, 자동으로 base 모델을 탐지하여 올바르게 로드합니다.
# SFT → DPO 파이프라인 예시
eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
--output-dir outputs/sft
# SFT 체크포인트를 model_name으로 지정 → base 모델 자동 탐지
eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_dpo.yml \
--set model_name=outputs/sft/final \
--output-dir outputs/dpo
동작 원리:
1. model_name 디렉토리에 lora_info.json이 있으면 EulerForge LoRA 체크포인트로 인식
2. 부모 디렉토리의 resolved_config.json에서 원본 base 모델 이름을 추출
3. 이전 체크포인트의 injection 설정(lora_r, lora_alpha, target_keywords, start_layer 등)으로 현재 config를 자동 override — SFT(lora_r=48)→DPO(lora_r=24) 등 LoRA 구조 불일치 방지
4. Base 모델을 로드한 후 LoRA injection 적용 (checkpoint 기준 파라미터)
5. 이전 체크포인트의 LoRA 어댑터 가중치를 복원
주의:
resolved_config.json이 없으면 자동 탐지가 작동하지 않습니다. EulerForgetrain명령으로 생성된 체크포인트만 지원됩니다. DPO 단계에서 LoRA 구조를 다르게 하고 싶다면, 파이프라인이 아닌 별도 훈련으로 진행해야 합니다.
환경 변수
| 환경 변수 | 설명 |
|---|---|
EULERFORGE_MOE_PERF=1 |
MoEFFN 모듈별 forward 시간/토큰 분포 프로파일링 활성화. [MoEPerf] 로그 출력 |
EULERFORGE_MOE_DTYPE_DEBUG=1 |
MoEFFN merge 지점의 dtype 흐름 디버그 로그 활성화. [MoEDType] 로그 출력 (hidden/router/weights/expert_out/buffer dtype) |
EULERFORGE_TRAIN_DEBUG=1 |
훈련 루프 상세 디버그: per-group LR, grad norm 평균, param dtype 분포, phase 전환 시 dequantize 통계 (mean/std/min/max). [TrainDebug]/[DequantDebug] 로그 출력 |
eulerforge convert
임의 JSONL을 EulerForge 표준 raw JSONL로 변환합니다. 기본 철학은 --map 기반 매핑이며, recipe는 편의 기능입니다.
세 가지 모드:
- Map 모드 (기본): --map OUT_KEY=EXPR (반복 가능) — 범용 필드 매핑
- Recipe 모드: --recipe <이름> — 내장 레시피로 일반적인 데이터 구조 변환
- Validate 모드: --validate — 변환 없이 입력 파일 스키마 검증만 수행
# 필드 확인 (입력 파일 구조 탐색)
eulerforge convert --task sft --input data/sft_10k.jsonl --print-sample-flat
# Map 모드 (flat 필드)
eulerforge convert --task sft --input data/custom.jsonl --output data/out.jsonl \
--map prompt=instruction --map response=output
# Map 모드 (중첩 필드 — dot-path 자동 flatten)
eulerforge convert --task prompted_preference --input data/dpo_10k.jsonl --output data/dpo_10k_raw.jsonl \
--map prompt=instruction.value --map chosen=chosen.value --map rejected=rejected.value
# Recipe 모드 (messages 배열)
eulerforge convert --task sft --input data/sft_10k.jsonl --output data/sft_10k_raw.jsonl \
--recipe sft_messages --messages-expr json_record.messages
# Validate 모드 (변환 없이 스키마 검증)
eulerforge convert --task sft --input data/sft_10k_raw.jsonl --validate
| 옵션 | 설명 |
|---|---|
--task |
타겟 태스크: sft, preference, prompted_preference |
--input |
입력 JSONL 파일 경로 |
--output |
출력 표준 raw JSONL 경로 (--validate / --print-sample-flat 불필요) |
--map OUT_KEY=EXPR |
출력 키 → 필드 표현식 매핑 (반복 가능). 예: --map prompt=instruction |
--flatten dot\|none |
flatten 모드: dot(기본) 중첩 dict를 dot-key로 평탄화; none dot-path 직접 탐색 |
--join-sep SEP |
list[str] 값 결합 구분자 (기본값: 줄바꿈) |
--strict |
해석된 값이 None/빈 문자열/빈 리스트이면 에러 |
--recipe |
내장 레시피 이름 |
--messages-expr EXPR |
messages 배열 dot-path (--recipe sft_messages 필수) |
--num-proc |
병렬 워커 수 (기본값: 1) |
--overwrite |
출력 파일 존재 시 덮어쓰기 |
--max-rows |
최대 변환 행 수 (샘플링) |
--validate |
Validate-only 모드: 입력 스키마 검증, 변환 없음 |
--print-sample-flat |
첫 1-2행을 flatten한 키 목록 출력 후 종료 (필드 탐색용) |
내장 레시피
| 레시피 | task | 입력 구조 | 출력 |
|---|---|---|---|
sft_messages |
sft |
임의 dot-path → messages 배열 (--messages-expr 필수) |
{prompt, response} |
sft_instruction_output |
sft |
{instruction, output} |
{prompt, response} |
dpo_nested_value |
prompted_preference |
{instruction.value, chosen.value, rejected.value} |
{prompt, chosen, rejected} |
sft_messages_v1 |
sft |
{json_record.messages: [{role,content}]} |
{prompt, response} |
dpo_nested_v1 |
prompted_preference |
{instruction.value, chosen.value, rejected.value} |
{prompt, chosen, rejected} |
passthrough_prompted_preference_v1 |
prompted_preference |
{prompt, chosen, rejected} |
동일 (extra 키 제거) |
passthrough_sft_prompt_response_v1 |
sft |
{prompt, response} |
동일 (extra 키 제거) |
passthrough_preference_v1 |
preference |
{chosen, rejected} |
동일 (extra 키 제거) |
상세: tutorials/00_data_preprocessing.md
eulerforge preprocess
Raw JSONL을 토큰화된 processed JSONL로 변환합니다.
eulerforge preprocess --task TASK --input RAW.jsonl --output PROCESSED.jsonl --model-name MODEL
| 옵션 | 설명 |
|---|---|
--task |
태스크 타입: sft, preference, prompted_preference |
--input |
입력 raw JSONL 파일 경로 |
--output |
출력 processed JSONL 파일 경로 |
--model-name |
HuggingFace 모델/토크나이저 이름 |
--max-length |
최대 시퀀스 길이 (기본값: 512) |
--num-proc |
병렬 워커 수 (기본값: CPU 코어 50%) |
--text-col |
SFT text 컬럼명 (기본값: text) |
--prompt-col |
prompt 컬럼명 (기본값: prompt) |
--response-col |
response 컬럼명 (기본값: response) |
--chosen-col |
chosen 컬럼명 (기본값: chosen) |
--rejected-col |
rejected 컬럼명 (기본값: rejected) |
상세: tutorials/00_data_preprocessing.md
eulerforge bench
추론 벤치마크. YAML spec으로 target/baseline/judge 모델을 설정하고, 벤치마크 데이터에서 샘플을 추출하여 추론 결과를 비교한다. target은 API 모델(Ollama/OpenAI/Gemini) 또는 학습된 로컬 HF 체크포인트를 지원한다.
eulerforge bench [OPTIONS]
| 옵션 | 설명 |
|---|---|
--preset PATH |
Bench YAML spec 파일 경로 (필수) |
--set KEY=VALUE |
설정 값 오버라이드 (반복 가능) |
--output-dir DIR |
결과 출력 디렉토리 |
--validate-only |
설정 검증만 수행 |
--dry-run |
데이터 샘플만 추출 (모델 호출 없음) |
--target-output-dir PATH |
target 로컬 모델: 학습 출력 루트 디렉토리 |
--checkpoint TYPE |
체크포인트 유형: final(기본) | latest | best |
--target-model-dir PATH |
target 로컬 모델: HF save_pretrained 디렉토리 직접 지정 |
--target-device DEVICE |
target 로컬 모델 device 오버라이드 (예: cuda:0, cuda:1, cpu) |
순차 모델 로딩 (OOM 방지)
모델을 1개씩 로드하여 전체 데이터를 처리한 뒤 언로드합니다. 동시에 2개 이상 모델이 GPU 메모리에 존재하지 않습니다.
Phase 1: target 로드 → 전체 샘플 추론 → 언로드
Phase 2: baseline 로드 → 전체 샘플 추론 → 언로드 (enabled일 때)
Phase 3: judge 로드 → 전체 샘플 평가 → 언로드 (enabled일 때)
Phase 4: 결과 통합 → 기존과 동일한 출력 포맷
LocalHFClient.unload()는 모델/토크나이저 삭제 + torch.cuda.empty_cache() 수행. API 클라이언트(ChatClient/JudgeClient)의 unload()는 no-op.
실행 모드
| 조건 | 모드 | 출력 |
|---|---|---|
| target만 | target-only | target 응답 출력 |
| target + baseline | comparison | 둘 다 출력 |
| judge + target만 | pointwise | 점수(1-10) + 해설 |
| judge + target + baseline | pairwise | 승자(A/B/tie) + 점수 + 해설 |
Bench YAML Spec
target 지정 방법 (정확히 하나만 사용):
bench:
task: sft # sft | preference
data_path: data/sft_1k_bench_raw.jsonl
sample:
k: 10
seed: 42
shuffle: true
generation:
max_new_tokens: 256
temperature: 0.7
top_p: 0.95
models:
target:
# 방법 A: API 모델 (Ollama/OpenAI/Gemini)
provider: ollama # ollama | openai | gemini
model: "qwen3:0.6b"
base_url: "http://localhost:11434/v1"
# 방법 B: 학습 출력 디렉토리 (자동 체크포인트 해석)
# output_dir: "outputs/run_20260301_120000"
# checkpoint: "final" # final | latest | best (기본: final)
# device: "auto" # 기본: auto
# dtype: "auto" # 기본: auto
# 방법 C: HF 모델 디렉토리 직접 지정
# provider: local_hf # 생략 가능 (자동 설정)
# model_dir: "outputs/run_20260301_120000/final"
baseline:
enabled: false
# API 방식 (Ollama/OpenAI/Gemini):
provider: ollama
model: "qwen3:4b"
# 또는 HF 모델 직접 로드 (provider 불필요):
# model_dir: "Qwen/Qwen2.5-0.5B" # HF Hub 이름 또는 로컬 경로 모두 가능
# device: "cuda:0"
# dtype: "float16"
# 참고: 파이프라인 스크립트에서 --set bench.models.baseline.enabled=false로
# 덮어쓰면 preset의 baseline 설정이 무시됩니다.
judge:
enabled: false
provider: ollama
model: "gemma3:27b"
mode: pointwise # pointwise | pairwise
mitigate_position_bias: true # pairwise A/B 스왑 2회
output:
out_dir: outputs/bench
save_jsonl: true
print_examples: true
print_max_chars: 1500
사용 예제
# API 모델 사용
eulerforge bench --preset configs/bench/sft_target_only.yml
# 학습 출력 디렉토리에서 final 체크포인트 로드
eulerforge bench --preset configs/bench/sft_local.yml \
--target-output-dir outputs/run_20260301_120000
# latest 체크포인트 사용
eulerforge bench --preset configs/bench/sft_local.yml \
--target-output-dir outputs/run_20260301_120000 --checkpoint latest
# 모델 디렉토리 직접 지정
eulerforge bench --preset configs/bench/sft_local.yml \
--target-model-dir outputs/run_20260301_120000/final
# GPU 지정 (judge가 GPU 0을 사용할 때, target을 GPU 1에 로드)
eulerforge bench --preset configs/bench/sft_local.yml \
--target-output-dir outputs/run_20260301_120000 --target-device cuda:1
# 설정 오버라이드
eulerforge bench --preset configs/bench/sft_target_only.yml --set bench.sample.k=20
# 검증만
eulerforge bench --preset configs/bench/sft_target_only.yml --validate-only
# 샘플 확인 (모델 호출 없음)
eulerforge bench --preset configs/bench/sft_target_only.yml --dry-run
벤치 데이터 형식
| 파일 | 키 | task |
|---|---|---|
sft_1k_bench_raw.jsonl |
prompt, response |
sft |
dpo_1k_bench_raw.jsonl |
prompt, chosen, rejected |
preference |
eulerforge eval (스텁)
퍼플렉시티 평가 (미구현).
eulerforge grid
Optuna 기반 하이퍼파라미터 grid / random / Bayesian search. 상세: 아래 eulerforge grid 섹션 참조.
훈련 타입 (training.type)
| 타입 | 설명 | 데이터 포맷 | 레퍼런스 모델 |
|---|---|---|---|
sft |
Supervised Fine-Tuning (기본값) | {input_ids, attention_mask, labels} |
불필요 |
dpo |
Direct Preference Optimization | chosen/rejected 쌍 (DPO 포맷) | adapter disable |
orpo |
Odds Ratio Preference Optimization | chosen/rejected 쌍 (DPO 포맷) | 불필요 |
rm |
Reward Model (Bradley-Terry) | chosen/rejected 쌍 (DPO 포맷) | 불필요 |
ppo |
PPO/RLHF | 프롬프트 전용 + 리워드 모델 | adapter disable |
공통 훈련 설정
| 키 | 별칭 | 기본값 | 설명 |
|---|---|---|---|
max_train_steps |
max_steps |
10000 |
최대 훈련 스텝 수 (micro-step 기준 = forward/backward 횟수). optimizer step = max_train_steps / grad_accum_steps |
batch_size |
— | 4 |
배치 크기 |
grad_accum_steps |
— | 1 |
그래디언트 축적 스텝. optimizer step = max_train_steps / grad_accum_steps |
lr |
— | 1e-5 |
학습률 |
weight_decay |
— | 0.01 |
Weight decay |
warmup_steps |
— | 500 |
워밍업 스텝 수 (micro-step 단위, 내부에서 optimizer step으로 자동 변환) |
max_grad_norm |
— | 1.0 |
그래디언트 클리핑 최대 노름 |
log_steps |
— | 100 |
로깅 주기 (micro-step) |
save_steps |
— | 1000 |
체크포인트 저장 주기 (micro-step) |
val_steps |
— | save_steps 값 |
검증 실행 주기 (micro-step). 미설정 시 save_steps와 동일 |
참고:
max_train_steps와max_steps는 동일한 의미입니다. 둘 다 지정한 경우max_steps가 우선합니다. LR 스케줄링: cosine decay는optimizer step = max_train_steps / grad_accum_steps단위로 동작합니다.warmup_steps도 micro step 단위로 지정하되, 내부에서 자동 변환됩니다. 프리셋에서는max_train_steps가 표준 키입니다.스텝 용어: - Micro-step: 매 배치 forward/backward가 1 micro-step.
max_steps는 micro-step 기준. - Optimizer step:grad_accum_steps배치마다 1회. 총 optimizer step =max_steps / grad_accum_steps. - Effective batch:batch_size × grad_accum_steps. 실질적으로 1 optimizer step에 처리되는 샘플 수.
ORPO 옵션
training:
type: orpo
orpo_lambda: 1.0 # ORPO 항 가중치 (필수, 양수)
RM 옵션
training:
type: rm
# RewardHead가 자동 생성됨 (hidden_size → 1)
PPO 옵션
training:
type: ppo
ppo:
clip_range: 0.2 # PPO 클리핑 범위
kl_coef: 0.1 # KL 페널티 계수
epochs: 4 # 배치당 PPO 업데이트 에폭 수
max_gen_len: 64 # 최대 생성 길이
temperature: 1.0 # 샘플링 온도
reward_model:
model_name: "path/to/model" # 리워드 모델 경로
checkpoint_path: "" # 체크포인트 (선택)
모델 로드 정밀도 (model.load_precision)
모델 로드 시 정밀도와 양자화 옵션을 YAML로 선언합니다.
model:
load_precision:
mode: int4 # fp32 | fp16 | bf16 | int8 | int4
compute_dtype: bf16 # int8/int4 연산 dtype (fp16 | bf16)
quant_type: nf4 # int4 전용: nf4 | fp4
double_quant: true # int4 전용
dequantize_on_train: true # base_ffn trainable 시 자동 dequantize
mode별 동작
| mode | torch_dtype | BitsAndBytes | 용도 |
|---|---|---|---|
fp32 |
float32 | — | CPU/디버그 |
fp16 |
float16 | — | GPU 메모리 절감 |
bf16 |
bfloat16 | — | GPU 기본값 (Ampere+) |
int8 |
— | load_in_8bit |
8bit 양자화 |
int4 |
— | load_in_4bit |
4bit 양자화 (QLoRA) |
Phase Dequantize 정책
dequantize_on_train=true (기본값)이고 phase 전환 시 base_ffn이 trainable이 되면,
양자화 모듈을 nn.Linear로 교체하고 가중치를 compute_dtype으로 복원합니다.
| mode | 교체 대상 | dequant 방식 |
|---|---|---|
| int4 | Linear4bit → nn.Linear |
dequantize_4bit() |
| int8 | Linear8bitLt → nn.Linear |
int8_vectorwise_dequant() |
| bf16/fp16/fp32 | 교체 없음 | 직접 requires_grad 설정 |
교체는 set_trainable_by_groups() 내부에서 requires_grad=True 설정 직전에 자동 수행됩니다.
양자화 모듈의 forward()가 int8/int4 데이터를 재할당하므로, param cast만으로는 부족하며
모듈 자체를 교체해야 합니다.
target_layers 자동 스코핑: base_ffn이 활성이고 명시적 target_layers가 없으면, injection.start_layer/injection.num_layers에서 대상 레이어를 자동 추출합니다. MoE가 주입된 레이어만 dequantize/unfreeze합니다.
하위 호환
기존 training.quant_bits 사용 시 경고와 함께 자동 변환됩니다:
- quant_bits: 4 → mode: int4
- quant_bits: 8 → mode: int8
- quant_bits: 16 → mode: bf16
스펙 상세: docs/fixtures/specs/load_precision_spec.md
데이터 입력 (data 섹션)
EulerForge는 3종류의 데이터 태스크를 표준으로 지원합니다:
| 태스크 | Raw 스키마 | Processed 스키마 |
|---|---|---|
sft |
{text} 또는 {prompt, response} |
{input_ids, attention_mask, labels} |
preference |
{chosen, rejected} |
{chosen_input_ids, chosen_attention_mask, chosen_labels, rejected_input_ids, rejected_attention_mask, rejected_labels} |
prompted_preference |
{prompt, chosen, rejected} |
위 + {prompt_input_ids, prompt_attention_mask, prompt_len} |
설정 예시
# 방법 1: 이미 토큰화된 processed JSONL
data:
format: processed
path: data/sft_processed.jsonl
# 방법 2: raw JSONL (훈련 시 자동 전처리 → 캐시)
data:
format: raw
task: prompted_preference
path: data/dpo_10k_raw.jsonl
max_length: 512
# num_proc: 기본값 = CPU 코어 50% (자동)
# cache_dir: 기본값 = outputs/.cache (run 간 공유 캐시)
#
# 캐시 파일명 규칙: {입력파일명}_{task}_{모델명}_len{max_length}.jsonl
# 예: dpo_10k_raw_prompted_preference_qwen3.5-0.8b-base_len512.jsonl
# 동일 파라미터면 자동 재사용 (재전처리 없음)
# 방법 3 (레거시): processed_data_path 직접 지정
processed_data_path: data/sft_processed.jsonl
Labels 마스킹 정책
- SFT text-only:
labels = input_ids(전체 시퀀스 causal LM) - SFT prompt/response: prompt 토큰 구간
-100, response만 loss 반영 - Preference: chosen/rejected 각각 전체 시퀀스 labels
- Prompted-Preference: prompt 토큰
-100마스킹, completion만 loss/logp 반영
통합테스트 데이터 정책
- 통합테스트: 1k 데이터 (
sft_1k.jsonl,dpo_1k.jsonl) 사용 - 튜토리얼: 10k 데이터 (
sft_10k_raw.jsonl,dpo_10k_raw.jsonl,dpo_10k_raw.jsonl) 기준 - bench 테스트:
*_1k_bench_raw.jsonl사용
데이터 검증
Processed 데이터는 훈련 시작 전 첫 5줄을 검사하여 필수 키를 확인합니다. 누락 시 3줄 에러:
Data: processed dataset row 0 missing 'input_ids'
Fix: Run `eulerforge preprocess ...` or set data.format=raw with schema mapping
See: docs/tutorials/ko/00_data_preprocessing.md
data.task ↔ training.type 호환성
data.format=raw일 때 data.task와 training.type의 호환성을 자동 검증합니다:
| data.task | 호환 training.type |
|---|---|
sft |
sft, ppo |
preference |
dpo, orpo, rm |
prompted_preference |
dpo, orpo, rm |
prompt_only |
ppo |
불일치 시 에러:
Data Config: data.task='sft' is incompatible with training.type='dpo'. Task 'sft' produces data for sft, ppo training
Fix: Set --set training.type=sft or change data.task to match
See: docs/tutorials/ko/00_data_preprocessing.md
설정 오버라이드 메커니즘
--set으로 도트 경로 표기법을 사용하여 오버라이드합니다:
--set training.lr=2e-5
--set injection.lora_r=32
--set training.phases.1.step=100 # list 내 특정 인덱스 필드 업데이트 (sparse)
--set training.phases.0.trainable=[lora,attn_lora] # list 요소의 list 값
List 인덱스 오버라이드:
training.phases.N.field=value형식으로 list 내 N번째 요소의 필드만 업데이트 가능합니다. 나머지 요소와 해당 요소의 다른 필드는 preset 값이 보존됩니다. 범위 초과 시 명확한 에러가 발생합니다.
타입 추론
| 값 | 파싱 결과 |
|---|---|
true |
bool |
false |
bool |
null |
None |
42 |
int |
3.14 |
float |
2e-5 |
float |
hello |
str |
우선순위
CLI --set 오버라이드 > YAML 프리셋 값
출력 및 체크포인트
훈련 시 다음 디렉토리 구조가 생성됩니다:
outputs/run_YYYYMMDD_HHMMSS/
├── resolved_config.json # 전체 해석된 설정 (재현성)
├── checkpoint-latest/ # 최신 체크포인트
│ ├── model files...
│ ├── tokenizer files...
│ └── training_state.pt # 옵티마이저, 스케줄러, 스텝, best_val_loss
├── checkpoint-best/ # 최적 검증 손실 체크포인트
│ └── ...
└── final/ # 훈련 완료 후 최종 모델
└── ...
checkpoint-best는val_steps주기로,checkpoint-latest는save_steps주기로 독립적으로 저장됩니다. 예:val_steps=500,save_steps=1000→ step 500에서 best 저장 시도, step 1000에서 latest 저장.
훈련 자동 Resume
checkpoint-latest/training_state.pt가 존재하면 자동으로 해당 지점에서 이어서 훈련합니다:
- micro_step, optimizer_step, best_val_loss 복원
- LR scheduler fast-forward: resume 지점의 optimizer_step에 맞게 cosine schedule을 즉시 복원 (warmup부터 재시작하지 않음)
- ETA 계산: resume 이후 진행된 step 기준으로 남은 시간 추정
MoE Stability Validation
MoE 전략(mixture_lora, moe_expert_lora)을 사용할 때 validator가 자동으로 안정성을 검사합니다.
필수 파라미터
| 키 | 역할 | 권장값 | 근거 |
|---|---|---|---|
moe.router_z_loss_coef |
라우터 logit 안정화 | 0.001 |
ST-MoE: softmax overflow 방지 |
moe.load_balance.type |
부하 분산 정책 | aux_loss |
라우팅 붕괴 방지 |
moe.load_balance.aux_loss_coef |
보조 손실 가중치 | 0.01 |
type=aux_loss 시 필수 |
선택 파라미터
| 키 | 역할 | 기본값 | 권장 범위 |
|---|---|---|---|
moe.capacity_factor_train |
훈련 시 전문가 처리량 상한 | 모델 기본값 | 1.0~2.0 (ST-MoE: 1.25) |
moe.capacity_factor_eval |
평가 시 전문가 처리량 상한 | 모델 기본값 | train 이상 (ST-MoE: 2.0) |
moe.router_dtype |
라우터 연산 정밀도 | float32 |
float32 (float16/bfloat16은 수치 불안정) |
moe.load_balance.bias_update_speed |
전문가 bias 적응 속도 | — | type=aux_loss_free 시 필수 (0.001) |
에러 메시지 형식
MoE 검증 실패 시 3줄 포맷으로 출력됩니다:
MoE Config: moe.router_z_loss_coef is required for MoE strategies.
Fix: Set moe.router_z_loss_coef: 0.001 (ST-MoE recommended)
See: docs/tutorials/ko/09_moe_stability_and_validation.md
경고 (비치명적)
| 조건 | 의미 |
|---|---|
router_z_loss_coef = 0 |
z-loss 비활성화 — 대규모 훈련에서 불안정 가능 |
router_z_loss_coef > 0.1 |
비정상적으로 큰 값 — 라우터 제약 과도 |
load_balance.type = none |
부하 분산 없음 — 라우팅 붕괴 위험 |
aux_loss_coef = 0 |
실질적 부하 분산 비활성화 |
router_dtype = float16/bfloat16 |
라우터 softmax 수치 불안정 가능 |
capacity_factor_eval < train |
eval 시 토큰 드롭 증가 |
어떤 페이즈에도 router 없음 |
라우터 미훈련 — 데이터 적응 불가 |
Preflight 검사
--preflight는 모델 로드 후 런타임 검사를 수행합니다:
eulerforge train --preset PRESET.yml --preflight
| 검사 항목 | 설명 |
|---|---|
| 그룹 파라미터 수 | 페이즈가 참조하는 그룹의 파라미터가 0개인 경우 에러 |
| target_layers 범위 | 모델 레이어 수를 초과하는 인덱스 에러 |
상세: tutorials/09_moe_stability_and_validation.md
로깅 및 메트릭
훈련 루프는 2단계 메트릭 시스템을 통해 로깅합니다.
메트릭 레벨
| 레벨 | 기록 항목 |
|---|---|
minimal (기본) |
step, main_loss, total_loss, aux_loss, lr, grad_norm, throughput, tokens/samples, 훈련 타입별 메트릭 |
advanced |
minimal + MoE 라우팅 통계 (token_frac, entropy, importance_cv, router_logit_max 등) |
minimal 메트릭
| 태그 | 설명 |
|---|---|
train/main_loss |
주 손실 (SFT/DPO/ORPO/RM/PPO) |
train/total_loss |
총 손실 (main + aux * weight) |
train/aux_loss |
MoE 보조 손실 합계 |
train/learning_rate |
현재 학습률 |
train/grad_norm |
Global L2 그래디언트 노름 |
train/tokens_seen |
누적 학습 토큰 수 (labels != -100) |
train/samples_seen |
누적 처리 샘플 수 (preference: 쌍 기준) |
train/optimizer_step |
누적 옵티마이저 스텝 수 |
train/micro_step |
누적 마이크로 스텝 수 |
train/effective_batch |
유효 배치 크기 (batch_size x grad_accum_steps) |
DPO: train/reward_margin |
chosen-rejected 보상 차 |
ORPO: train/sft_loss, train/orpo_loss |
SFT/ORPO 개별 손실 |
PPO: train/kl, train/reward_mean |
KL divergence, 보상 평균 |
advanced 메트릭 (MoE 전용)
| 태그 | 설명 |
|---|---|
moe/token_frac_mean |
전문가별 토큰 비율 평균 |
moe/token_frac_std |
전문가별 토큰 비율 표준편차 |
moe/token_frac_max |
가장 많이 선택된 전문가 비율 |
moe/entropy_mean |
라우터 엔트로피 평균 |
moe/importance_cv |
중요도 변동계수 (불균형 감지) |
moe/aux_loss_total |
전체 aux loss 합계 |
moe/router_logit_max |
라우터 logit 최대값 (수치 폭주 감지) |
moe/num_moe_modules |
MoE 모듈 수 |
LoRA Handoff 로깅
lora_handoff 설정 시 훈련 로그에 다음 마일스톤 이벤트가 자동 출력됩니다:
| 이벤트 | 로그 메시지 | 시점 |
|---|---|---|
| 스케줄 초기화 | [Handoff] Schedule: expert_lora(step 4000→6000, ...) |
훈련 시작 시 |
| fade 시작 | [Handoff] expert_lora fade 시작 at step 4000 (curve=cosine, ...) |
start_step 도달 시 |
| fade 완료 | [Handoff] expert_lora fade 완료 at step 6000 (scale=0.0000) |
start_step + duration_steps 도달 시 |
| freeze | [Handoff] expert_lora frozen at step 6000 (scale=0.0000) |
end_action=freeze 시 |
| ramp 시작 | [Handoff] base_ffn_ramp 시작 at step 2000 (LR ×1.0→×3.0) |
ramp start_step 도달 시 |
| ramp 완료 | [Handoff] base_ffn_ramp 완료 at step 4000 (LR ×3.0) |
ramp end_step 도달 시 |
각 이벤트는 한 번만 출력됩니다 (one-shot). attn_lora도 동일 패턴입니다.
주기적 로그(log_steps)에는 handoff 상태가 자동 추가됩니다:
[Phase2] Step 400/600 (micro 4500/6000) | Loss: 0.1234 | LR: 1.00e-05 | ... | Handoff[expert_lora=0.75, attn_lora=0.80, ffn_lr_mult=2.50]
TensorBoard 통합
TensorBoard 기록은 선택적 의존성입니다:
pip install eulerforge[tb]
설정 예시:
logging:
metrics_level: advanced # "minimal" | "advanced"
tensorboard:
enabled: true # TensorBoard 기록 (기본: false)
log_dir: "outputs/tb" # 로그 디렉토리
log_interval: 50 # N 스텝마다 TensorBoard 기록
max_experts_log: 16 # advanced에서 상위 N 전문가 상세 로그
CLI로 메트릭 레벨 오버라이드:
eulerforge train --preset PRESET.yml --metrics-level advanced
tensorboard 미설치 시 경고만 출력하고 훈련은 정상 진행됩니다.
상세: tutorials/10_metrics_monitoring.md
eulerforge grid
기본 사용법
# spec 검증만 (dry-run)
eulerforge grid configs/grid/sft_random_search.yml --dry-run
# 실제 실행
eulerforge grid configs/grid/sft_random_search.yml
# project root 명시
eulerforge grid configs/grid/sft_random_search.yml --project-root /path/to/project
옵션
| 옵션 | 기본값 | 설명 |
|---|---|---|
spec |
(필수) | Grid search YAML spec 파일 경로 |
--dry-run |
false | Spec 검증만 수행, 학습 미실행 |
--project-root DIR |
cwd | 상대 경로 기준 디렉토리 |
Optuna 의존성
pip install eulerforge[hpo]
optuna 미설치 시 pip install eulerforge[hpo] 안내 메시지 출력 후 종료합니다.
method별 Optuna 샘플러
| method | 샘플러 | 비고 |
|---|---|---|
grid |
GridSampler |
이산 공간만 지원 (categorical / choices) |
random |
RandomSampler |
연속/이산 모두 지원 |
bayes |
TPESampler |
연속/이산 모두 지원 |
method: "grid"+type: "float"+low/high조합은 오류입니다. Grid에서 연속 실수를 탐색하려면choices: [값1, 값2]형식을 사용하세요.
출력
<output_root>/
├── trial_0000/
│ ├── metrics.jsonl # 스텝별 지표 (train/total_loss 등)
│ └── checkpoint-latest/
├── trial_0001/
│ └── ...
├── summary.json # 전체 결과 (best_trial + all_trials)
└── summary.csv
spec 형식 상세: docs/fixtures/specs/grid_search_spec.md
Python API: eulerforge.loader
EulerForge로 훈련한 체크포인트를 Python에서 직접 로드하는 공용 API.
from eulerforge import load_model
load_model(path, *, checkpoint, device, dtype, load_precision) → LoadedModel
| 파라미터 | 기본값 | 설명 |
|---|---|---|
path |
(필수) | run_dir 또는 checkpoint_dir 경로 |
checkpoint |
"final" |
run_dir일 때 체크포인트 선택: final | best | latest |
device |
"auto" |
"auto" | "cpu" | "cuda" | "cuda:0" 등 |
dtype |
"auto" |
"auto" | "float32" | "bfloat16" 등 |
load_precision |
None |
로드 정밀도: None | "fp32" | "fp16" | "bf16" | "int8" | "int4" |
반환 타입
@dataclass
class LoadedModel:
model: nn.Module # eval 모드
tokenizer: PreTrainedTokenizer
metadata: ModelMetadata
@dataclass
class ModelMetadata:
strategy: str # "dense_lora" | "moe_expert_lora" | "mixture_lora" | "none"
backbone: str # "qwen3" | "llama" | "gemma3" | ""
path_type: str # "run_dir" | "checkpoint_dir"
checkpoint_dir: str # 실제 체크포인트 디렉토리 경로
lora_config: dict | None # {"lora_r": int, "lora_alpha": float}
structure_preserved: bool # MoE/MixtureLoRA 구조 보존 여부
load_precision: str | None # "fp32" | "fp16" | "bf16" | "int8" | "int4" | None
경로 자동 분류
| 경로 유형 | 판별 기준 | 동작 |
|---|---|---|
run_dir |
resolved_config.json 존재 |
checkpoint 파라미터로 서브디렉토리 해석 |
checkpoint_dir |
config.json 존재 |
직접 로드 |
사용 예제
from eulerforge import load_model
# 1. 학습 출력 디렉토리에서 로드 (final 체크포인트)
result = load_model("outputs/run_20260311_163425")
print(result.metadata.strategy) # "moe_expert_lora"
print(result.metadata.backbone) # "qwen3"
# 2. best 체크포인트 로드
result = load_model("outputs/run_20260311_163425", checkpoint="best")
# 3. 체크포인트 디렉토리 직접 지정
result = load_model("outputs/run_20260311_163425/final", device="cuda:0")
# 4. 양자화 로딩 (int4/int8)
result = load_model("outputs/run_20260311_163425", load_precision="int4")
result = load_model("outputs/run_20260311_163425", load_precision="bf16")
# 5. 추론
messages = [{"role": "user", "content": "안녕하세요"}]
text = result.tokenizer.apply_chat_template(messages, tokenize=False, add_generation_prompt=True)
inputs = result.tokenizer(text, return_tensors="pt").to(result.model.device)
with torch.no_grad():
out = result.model.generate(**inputs, max_new_tokens=128)
print(result.tokenizer.decode(out[0], skip_special_tokens=True))
# 6. 메타데이터 활용
if result.metadata.structure_preserved:
print("MoE 구조가 보존된 체크포인트입니다")
if result.metadata.lora_config:
print(f"LoRA r={result.metadata.lora_config['lora_r']}")
로딩 전략
| strategy | 로드 방식 | 구조 보존 |
|---|---|---|
dense_lora |
LoRA 병합 → dense 모델 | No |
moe_expert_lora |
MoE 아키텍처 재구성 (expert+router) | Yes |
mixture_lora |
MixtureLoRA 아키텍처 재구성 | Yes |
none |
from_pretrained() 직접 로드 |
N/A |
참고:
moe_expert_lora와mixture_lora는resolved_config.json이 필요합니다. 없으면 expert 평균 → dense 모델로 fallback됩니다 (WARNING 출력).
eulerforge export-hf
EulerForge 체크포인트를 HuggingFace Transformers 호환 모델로 내보냅니다.
기본 사용법
# dense_lora → merged HF 모델
eulerforge export-hf --checkpoint outputs/run_20260311_163425 --output ./exported
# MoE → custom_moe HF 모델 (trust_remote_code=True로 로드)
eulerforge export-hf --checkpoint outputs/run_moe --output ./exported_moe
# dry-run (계획만 출력)
eulerforge export-hf --checkpoint outputs/run --output ./out --dry-run
# validate-only (검증만)
eulerforge export-hf --checkpoint outputs/run --output ./out --validate-only
옵션
| 옵션 | 기본값 | 설명 |
|---|---|---|
--checkpoint |
(필수) | run_dir 또는 checkpoint_dir 경로 |
--output |
(필수) | export 출력 디렉토리 (이미 존재하면 에러) |
--format |
auto |
auto | merged | custom_moe |
--select-checkpoint |
final |
final | best | latest |
--dtype |
auto |
auto | fp32 | fp16 | bf16 |
--safe-serialization |
True |
safetensors 사용 여부 (--no-safe-serialization으로 비활성화) |
--copy-tokenizer |
True |
tokenizer 복사 여부 (--no-copy-tokenizer로 비활성화) |
--dry-run |
False |
계획만 출력, 실제 export 없음 |
--validate-only |
False |
검증만 수행 |
--skip-diversity-check |
False |
Expert diversity check 건너뛰기 (경량 훈련 시 expert 미분화) |
전략별 Export 포맷
| 전략 | format=auto 시 | 결과 | HF 로드 |
|---|---|---|---|
dense_lora |
merged |
표준 dense HF 모델 | from_pretrained(path) |
mixture_lora |
custom_moe |
base+router+N LoRA experts | from_pretrained(path, trust_remote_code=True) |
moe_expert_lora |
custom_moe |
N expert FFN+router | from_pretrained(path, trust_remote_code=True) |
핵심:
moe_expert_lora/mixture_lora전략을merged로 export하면 expert 구조가 파괴됩니다.format=merged+MoE → ValueError.
스펙 상세: docs/fixtures/specs/export_hf_spec.md
eulerforge pretrain (Plugin)
Plugin 명령:
pretrain은 plugin 방식으로 제공됩니다.eulerforge.plugins.pretrain_plugin모듈이 존재할 때만 CLI에 등록됩니다. 공개 배포판에서 이 모듈을 제외하면 명령이 자동 비활성화됩니다.
EulerStack 등 외부 도구가 HuggingFace 형식으로 export한 모델을 raw text 데이터로 스크래치 사전훈련합니다. 기존 train 명령어(LoRA/MoE 인젝션)와 완전히 분리된 전체 파라미터 causal LM 훈련입니다.
eulerforge pretrain [OPTIONS]
| 옵션 | 설명 |
|---|---|
--preset PATH |
pretrain YAML 프리셋 경로 (필수) |
--set KEY=VALUE |
설정 오버라이드 (반복 가능) |
--output-dir DIR |
출력 디렉토리 |
--validate-only |
설정 검증만, 훈련 없음 |
pretrain vs train 차이
| 항목 | train (파인튜닝) |
pretrain (스크래치) |
|---|---|---|
| 모델 로드 | from_pretrained (기존 가중치) |
from_pretrained (초기화된 가중치) |
| 인젝션 | LoRA/MoE 적용 | 없음 (전체 파라미터 학습) |
| 페이즈 스케줄 | freeze/unfreeze 제어 | 없음 (전부 trainable) |
| 데이터 | instruction/preference 형식 | raw text (packed chunking) |
| 금지 키 | — | injection, moe, backbone → 에러 |
pretrain YAML 프리셋 구조
# 디바이스
device: "cuda:0" # cuda:0, cuda:1, cpu
# 모델 (EulerStack export 디렉토리)
model_dir: "outputs/full_hybrid_moe"
trust_remote_code: true
# 토크나이저 (model_dir에 없으면 별도 지정)
tokenizer: "gpt2"
# 데이터
data:
path: "data/dolma_10k.jsonl"
text_column: "text" # JSONL의 텍스트 키
max_length: 1024
packing: true # packed chunking (텍스트 연결 → 고정 길이 분할)
# 훈련
training:
max_steps: 500
batch_size: 2
grad_accum_steps: 4
lr: 3.0e-4
weight_decay: 0.1
warmup_steps: 50
max_grad_norm: 1.0
log_steps: 10
save_steps: 250
dtype: "float32" # Hybrid 모델(Hyena/RetNet)은 float32 필수
amp: false # FFT 연산 bf16 미지원 → 비활성화
seed: 42
사용 예
# 기본 실행
eulerforge pretrain --preset configs/presets/pretrain/eulerstack_hybrid_moe.yml
# 설정 오버라이드
eulerforge pretrain --preset ... --set training.max_steps=1000 --set training.lr=1e-4
# 검증만
eulerforge pretrain --preset ... --validate-only
# 출력 디렉토리 지정
eulerforge pretrain --preset ... --output-dir outputs/my_pretrain
출력 구조
outputs/pretrain_YYYYMMDD_HHMMSS/
├── pretrain_config.json # 설정 스냅샷
├── metrics.jsonl # 스텝별 loss, lr 기록
├── checkpoint-250/ # 중간 체크포인트
│ ├── config.json
│ ├── model.safetensors
│ └── tokenizer files...
└── final/ # 최종 모델
├── config.json
├── model.safetensors
└── tokenizer files...
pretrain 완료 후 final/ 디렉토리를 eulerforge train의 model_name으로 지정하면 LoRA 파인튜닝이 가능합니다.