> EulerForge > 튜토리얼 > 15. 모델 로딩

15. 모델 로딩

개요

eulerforge.load_model()은 EulerForge로 훈련한 체크포인트를 한 줄로 로드할 수 있는 공용 API입니다. 훈련 전략(plain LoRA, MoE, MixtureLoRA)을 자동 감지하고, 적절한 로딩 방식을 선택합니다.


사전 요구 사항


1. 기본 사용법

from eulerforge import load_model

result = load_model("outputs/run_20260311_163425")

# 반환값
result.model       # nn.Module (eval 모드)
result.tokenizer   # PreTrainedTokenizer
result.metadata    # ModelMetadata

load_model()은 경로 유형을 자동 감지합니다:

경로 유형 판별 기준 예시
run_dir resolved_config.json 존재 outputs/run_20260311_163425
checkpoint_dir config.json 존재 outputs/run_20260311_163425/final

2. 체크포인트 선택

run_dir를 지정하면 checkpoint 매개변수로 체크포인트를 선택할 수 있습니다.

# final (기본값)
result = load_model("outputs/run_20260311_163425", checkpoint="final")

# best checkpoint
result = load_model("outputs/run_20260311_163425", checkpoint="best")

# latest checkpoint
result = load_model("outputs/run_20260311_163425", checkpoint="latest")
checkpoint 서브디렉토리
"final" {run_dir}/final/
"best" {run_dir}/checkpoint-best/
"latest" {run_dir}/checkpoint-latest/

checkpoint_dir를 직접 지정하면 checkpoint 매개변수는 무시됩니다:

result = load_model("outputs/run_20260311_163425/final")

3. 로드 정밀도 (양자화)

load_precision 매개변수로 모델의 로딩 정밀도를 지정할 수 있습니다.

# 4bit 양자화 (NF4 + double quantization)
result = load_model("outputs/run_20260311_163425", load_precision="int4")

# 8bit 양자화
result = load_model("outputs/run_20260311_163425", load_precision="int8")

# bfloat16 (Ampere 이상 GPU)
result = load_model("outputs/run_20260311_163425", load_precision="bf16")

지원 정밀도

설명 요구사항
None 모델 원본 정밀도 (기본)
"fp32" float32
"fp16" float16 GPU 권장
"bf16" bfloat16 Ampere+ GPU
"int8" 8bit 양자화 bitsandbytes
"int4" 4bit NF4 양자화 bitsandbytes

int4 양자화 설정

int4를 지정하면 다음 BitsAndBytesConfig가 자동 적용됩니다:

BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_compute_dtype=torch.bfloat16,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_use_double_quant=True,
)

4. 훈련 전략별 자동 로딩

load_model()은 체크포인트의 훈련 전략을 자동 감지하여 적절한 방식으로 로드합니다.

전략 로딩 방식 결과 모델
dense_lora LoRA 병합 → dense dense 모델
moe_expert_lora MoE 구조 재구성 MoE 모델 (구조 보존)
mixture_lora MixtureLoRA 재구성 MixtureLoRA 모델 (구조 보존)
none from_pretrained() 직접 로드 HF 모델

사용자 코드는 전략에 관계없이 동일합니다:

# dense_lora, moe_expert_lora, mixture_lora 모두 동일 코드
result = load_model("outputs/run_20260311_163425")
response = generate(result.model, result.tokenizer, "안녕하세요")

5. 메타데이터 검사

result = load_model("outputs/run_20260311_163425")
m = result.metadata

print(f"전략: {m.strategy}")             # "dense_lora"
print(f"백본: {m.backbone}")             # "qwen3"
print(f"경로 유형: {m.path_type}")        # "run_dir"
print(f"체크포인트: {m.checkpoint_dir}")   # 절대경로
print(f"구조 보존: {m.structure_preserved}")  # True/False
print(f"로드 정밀도: {m.load_precision}")    # "int4" 등 또는 None

if m.lora_config:
    print(f"LoRA r: {m.lora_config['lora_r']}")
    print(f"LoRA alpha: {m.lora_config['lora_alpha']}")

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 로드 정밀도

6. 추론 예제

6.1 채팅 생성

import torch
from eulerforge import load_model

result = load_model("outputs/run_20260311_163425", load_precision="int4")

messages = [{"role": "user", "content": "한국의 수도는?"}]

if getattr(result.tokenizer, "chat_template", None):
    text = result.tokenizer.apply_chat_template(
        messages, tokenize=False, add_generation_prompt=True
    )
else:
    text = "[USER]\n한국의 수도는?\n\n[ASSISTANT]\n"

inputs = result.tokenizer(text, return_tensors="pt")
inputs = {k: v.to(result.model.device) for k, v in inputs.items()}

with torch.no_grad():
    outputs = result.model.generate(
        **inputs,
        max_new_tokens=256,
        do_sample=True,
        temperature=0.7,
        pad_token_id=result.tokenizer.eos_token_id,
    )

input_len = inputs["input_ids"].shape[1]
response = result.tokenizer.decode(
    outputs[0][input_len:], skip_special_tokens=True
).strip()
print(response)

6.2 메모리 사용량 비교

from eulerforge import load_model

# 원본 정밀도
r1 = load_model("outputs/run_20260311_163425", load_precision="fp16")
mem1 = sum(p.nelement() * p.element_size() for p in r1.model.parameters())

# 4bit 양자화
r2 = load_model("outputs/run_20260311_163425", load_precision="int4")
mem2 = sum(p.nelement() * p.element_size() for p in r2.model.parameters())

print(f"fp16: {mem1 / 1024**2:.1f} MB")
print(f"int4: {mem2 / 1024**2:.1f} MB")
print(f"절약: {(1 - mem2/mem1) * 100:.0f}%")

7. 예제 스크립트

examples/ 디렉토리에 실행 가능한 예제가 포함되어 있습니다:

예제 설명 명령어
load_and_chat.py 기본 채팅 python examples/load_and_chat.py <path>
load_quantized.py 양자화 로딩 python examples/load_quantized.py <path> --precision int4
load_and_inspect.py 메타데이터 검사 python examples/load_and_inspect.py <path>
load_batch_inference.py 배치 추론 python examples/load_batch_inference.py <path>

8. API 레퍼런스

from eulerforge import load_model, LoadedModel, ModelMetadata

result: LoadedModel = load_model(
    path,                      # run_dir 또는 checkpoint_dir 경로
    *,
    checkpoint="final",        # "final" | "best" | "latest"
    device="auto",             # "auto" | "cpu" | "cuda" | "cuda:0"
    dtype="auto",              # "auto" | "float32" | "bfloat16"
    load_precision=None,       # None | "fp32" | "fp16" | "bf16" | "int8" | "int4"
)

에러 처리

모든 에러는 ValueError로 3줄 포맷을 사용합니다:

EulerForge 체크포인트를 식별할 수 없습니다: ...
Fix: 유효한 run_dir 또는 checkpoint_dir 경로를 지정하세요.
See: docs/tutorials/11_bench.md

참조