5. 학습 데이터 준비
⚠️ 범위 경고 — 이것은 EulerStack 의 주 목적이 아닙니다
EulerStack 은 아키텍처 설계 언어 (ADL) 입니다 — 훈련 프레임워크도, 데이터 파이프라인도 아닙니다. 이 장에서 소개하는
eulerstack.data.prepare는 "아키텍처가 스스로 무너지지 않았는지" 를 빠르게 확인하기 위한 개발용 Sanity 헬퍼입니다.
구체적으로 이 모듈이 하는 것 과 하지 않는 것 을 분명히 해둡니다.
| EulerStack 이 하는 일 | EulerStack 이 하지 않는 일 |
|---|---|
| YAML 스펙 validate / compile | 실전 데이터 정제 (dedup, quality filter, PII 제거 등) |
| HF PreTrainedModel 로 export | 멀티-소스 혼합·샘플링 비율 조정 |
| 아키텍처 회귀 검증용 작은 샘플 을 토큰화 | 스트리밍 / 샤딩 / 분산 I/O |
tokenize_jsonl 결과를 캐시 저장 |
토크나이저 훈련 / 어휘 확장 |
실전 LLM 프로젝트에서 데이터 파이프라인은 반드시 전용 도구를 쓰세요. 이 헬퍼는 "새 mixer 를 추가하고 20 step 짜리 sanity 를 돌리는" 용도에만 맞습니다.
실전 훈련 데이터 준비에 권장하는 도구
EulerStack YAML 로 export 한 HF 모델은 아래 어떤 도구와도 그대로 연동됩니다.
| 사용 사례 | 권장 도구 | 왜 |
|---|---|---|
| 대규모 사전학습 데이터 큐레이션 | dolma (AI2), datatrove (HF) |
중복 제거, 품질 필터, PII 제거, dedup 가 production-grade |
| 일반 HF Datasets 스트리밍 / 샤딩 | datasets + streaming=True |
수 TB 스케일 스트리밍, caching, mapping 표준 |
| Fine-tune / SFT 데이터 | Axolotl / LLaMA-Factory / torchtune | 채팅 템플릿, 패킹, 멀티-태스크 샘플링 포함 |
| RLHF / 선호도 데이터 | TRL, OpenRLHF | PPO / DPO / GRPO 레시피에 맞춘 포맷팅 |
| HPC 분산 사전학습 | MosaicML Composer, Megatron-LM, TorchTitan | 수십억 토큰/GPU 처리량, stream-from-S3 |
이 중 어떤 파이프라인의 출력도 AutoModelForCausalLM.from_pretrained(
"./my_eulerstack_export", trust_remote_code=True) 로 로드한 모델에 그대로
투입됩니다. EulerStack 은 "모델 정의 레이어" 로서 위 도구들과 직교적으로
결합됩니다. 자세한 포지셔닝은 튜토리얼 0: EulerStack 의 자리
참조.
이 장이 설명하는 것 — 내부 Sanity 헬퍼
이하의 내용은 이 저장소의 테스트와 sanity 루프에서만 쓰이는 최소 헬퍼를 정의합니다. 본 훈련용이 아닙니다. 그래도 필요한 이유는 다음 한 가지:
새 mixer / 새 primitive 를 추가했을 때, "loss 가 감소하는 기본 구조" 인지 몇 초 안에 확인하는 CPU-friendly 회귀 테스트 를 EulerStack 자체 CI 에서 돌려야 하기 때문.
따라서 이하에서 설명하는 tokenize_jsonl / TokenizedDataset 은:
- 한 번에 ~1,000 문서 이하의 매우 작은 샘플용
- 캐시는
data/.cache/에 작은.pt파일로만 저장 - 멀티-파일 / 스트리밍 / 샤딩 미지원
- 실제 프로덕션 품질의 dedup / PII 제거 / quality filter 없음
이 제약을 이해한 상태에서 아래 섹션을 읽으세요.
데이터 소스의 두 가지 종류
EulerStack 은 두 종류의 소스를 지원합니다.
로컬 JSONL 파일
가장 단순하고 재현성이 높은 방식입니다. 각 줄이 하나의 JSON 객체이고, text 필드에
해당 문서의 원시 텍스트가 들어있는 형식입니다.
{"text": "예시 문서 내용입니다.", "source": "example"}
{"text": "또 다른 문서 내용입니다.", "source": "example"}
저장소에는 이미 data/dolma_10k.jsonl 파일이 포함되어 있습니다. 이는 Dolma 코퍼스
(Soldaini et al., 2024) 에서 추출한 영어 일반 텍스트 10,000 개 문서 로, 다운로드
없이 바로 사용할 수 있는 안정적인 테스트 데이터입니다. 이 튜토리얼과 대부분의
sanity/integration 테스트가 이 파일을 기본 데이터로 사용합니다.
HuggingFace Datasets
표준 벤치마크(wikitext, c4 등)를 쓰고 싶다면 HF Datasets 에서 받아올 수 있습니다.
from eulerstack.data.prepare import download_and_tokenize
dataset = download_and_tokenize(
tokenizer_name="gpt2",
max_seq_len=512,
dataset_name="wikitext",
dataset_config="wikitext-2-raw-v1",
num_rows=10000,
)
인터넷 접근이 필요하며, 다운로드 결과는 HF cache (기본 ~/.cache/huggingface/) 에
저장됩니다.
토큰화 파이프라인의 사용법
로컬 JSONL 을 토큰화하는 가장 일반적인 호출 형태는 다음과 같습니다.
from eulerstack.data.prepare import tokenize_jsonl
dataset = tokenize_jsonl(
jsonl_path="data/dolma_10k.jsonl",
tokenizer_name="gpt2",
max_seq_len=512,
num_rows=1000, # 앞에서 1,000 개 문서만 사용
cache_dir="data/.cache",
)
print(f"청크: {len(dataset)}, 시퀀스 길이: 512")
인자의 의미는 다음과 같습니다.
jsonl_path: 읽을 JSONL 파일 경로tokenizer_name: HF 토크나이저 이름 (예:"gpt2","meta-llama/Llama-2-7b-hf")max_seq_len: 각 청크의 토큰 길이num_rows: 앞에서 몇 개의 문서를 읽을지. 작게 잡으면 토큰화가 빠릅니다.cache_dir: 캐시 저장 위치. 같은 인자로 재호출하면 캐시 히트로 즉시 로드됩니다.
내부 동작 단계
tokenize_jsonl 은 내부적으로 다음 단계를 수행합니다.
- JSONL 읽기 — 각 줄을 파싱해
text필드를 추출합니다. - 토큰화 — 지정된 HF 토크나이저로 각 문서를 토큰 ID 리스트로 변환합니다. 기본적으로 BOS/EOS 특수 토큰을 각 문서 경계에 추가합니다.
- 이어붙이기(concatenation) — 모든 문서의 토큰을 하나의 긴 스트림으로 연결합니다.
- 청킹(chunking) —
max_seq_len단위로 잘라 고정 길이 시퀀스 배열을 만듭니다. 이때 패딩도 truncation 도 쓰지 않습니다. 스트림 끝에서 길이가 모자라는 마지막 조각은 버립니다. 이런 방식을 "packed chunking" 이라고 부르며, GPU 활용률을 극대화하는 표준 기법입니다. - 캐시 저장 — 결과를
.pt파일과.meta.json파일로 저장합니다. 같은 인자로 다시 호출하면 토큰화를 건너뛰고 곧바로 로드합니다.
캐시 키의 구성
재호출 시 캐시를 재사용할지 결정하는 키는 다음 요소의 해시로 만들어집니다.
tokenizer_namemax_seq_lenjsonl_path(절대 경로)num_rows- BOS/EOS 사용 여부
이 중 하나라도 달라지면 캐시는 무효화되고 새로 토큰화됩니다. 캐시 파일의 위치는 다음과 같습니다.
data/.cache/tokenized_<hash>.pt
data/.cache/tokenized_<hash>.meta.json
.meta.json 에는 토큰화에 쓴 인자들이 모두 기록되어 있어, 나중에 이 캐시가 어떤
조건으로 만들어졌는지 추적할 수 있습니다.
Vocab 크기 클램프
이 단계는 토크나이저와 모델의 vocab 크기가 다를 때 반드시 거쳐야 하는 과정입니다.
예를 들어 GPT-2 토크나이저는 50,257 개의 토큰 ID 를 가지지만, EulerStack 의
기본 프리셋은 vocab_size=32000 으로 설정되어 있습니다. 이 상태로 토큰화한 결과를
모델에 그대로 넣으면 index out of bounds 에러 가 발생합니다.
해결책은 TokenizedDataset 래퍼로 감싸 모델의 vocab 크기로 클램프하는 것입니다.
from eulerstack.data.prepare import TokenizedDataset
# 캐시에서 원시 토큰 로드
raw_dataset = tokenize_jsonl(...)
# 모델의 vocab_size 로 클램프
safe_dataset = TokenizedDataset(raw_dataset.input_ids, vocab_size=32000)
TokenizedDataset 은 __getitem__ 시점에 input_ids 와 labels 를 모두 [0, vocab_size)
범위로 클램프합니다. 이 방식은 데이터 자체를 수정하지 않으므로 캐시가 오염되지
않으며, 모델별로 다른 vocab_size 를 써도 같은 캐시를 재활용할 수 있습니다.
Sanity 루프와의 통합 (내부 테스트 전용)
토큰화한 샘플은 다음 장의 sanity 루프 — 역시 내부 테스트 전용 — 에 직접 투입 가능합니다. 다시 한 번, 이것은 프로덕션 훈련이 아닙니다.
from eulerstack.training.sanity import run_e2e_training, build_model_from_ir
from eulerstack.ir.normalizer import normalize_to_ir
import yaml, torch
# 프리셋 로드 및 IR 생성
with open("configs/presets/arch_beginner_llama.yml") as f:
ir = normalize_to_ir(yaml.safe_load(f))
# 데이터 준비 (토큰화 + vocab 클램프) — 이 저장소 CI 용 샘플 규모
raw = tokenize_jsonl(
jsonl_path="data/dolma_10k.jsonl",
tokenizer_name="gpt2",
max_seq_len=512,
num_rows=1000,
cache_dir="data/.cache",
)
dataset = TokenizedDataset(raw.input_ids, vocab_size=ir.model.vocab_size)
# 모델 빌드 및 20-step sanity 훈련 (structural smoke test 용)
model = build_model_from_ir(ir, device="cuda:0", dtype=torch.bfloat16)
result = run_e2e_training(
model, dataset, batch_size=2, max_steps=20, device="cuda:0",
)
print(result.summary())
이 20-step 결과는 "코드가 안 깨졌다" 만 알려줍니다. 실제 훈련 품질 · 다운스트림 점수 · reward 학습 · multi-GPU scaling 등은 위 §"권장 도구" 표의 전용 프레임워크 가 측정합니다.
실전 데이터 준비 체크리스트 (외부 도구 사용 시)
전용 데이터 파이프라인 도구로 넘어갈 때 다음을 점검하세요.
- 데이터 크기 vs 모델 크기 — Chinchilla 스케일링 법칙 기준 1B 파라미터당 ~20B
토큰. EulerStack 이 아니라
datatrove/dolma가 이 규모를 다룹니다. - 품질 필터 — 반복 감지, URL 블랙리스트, perplexity filter.
datatrove/dolma내장. - 중복 제거 (dedup) — 문서 수준 + n-gram 수준. prod 사전학습의 필수 단계.
- Tokenizer-vocab 일관성 —
tokenizer.vocab_size == model.config.vocab_size일치 (위 §"Vocab 크기 클램프" 는 일치시키지 못할 때 의 임시 우회). max_seq_len≤ 모델의max_seq_len— 초과 시 position overflow.- 샤딩과 스트리밍 — 수십 GB 이상이면
datasetsstreaming, WebDataset tar, Mosaic MDS 중 선택.
이 단계들은 EulerStack 의 범위 밖입니다 — 모델 정의 레이어는 "데이터가 어떻게 오든 일관된 모델" 을 보장할 뿐입니다.
다음 단계
이 저장소 안에서 계속 학습
- 튜토리얼 6: Sanity 훈련 — 이것도 내부 테스트용. 아키텍처가 기본 구조상 loss 감소 가능한지 CI 가능한 초소형 체크.
실전 훈련으로 넘어가는 경로
- 튜토리얼 0: EulerStack 의 자리 — 왜 훈련은 다른 도구가 맡는지 긴 설명.
- 튜토리얼 4: 컴파일과 설명 — HF 디렉토리로 export 하는 법. 이후 단계는 외부 트레이너: Axolotl / LLaMA-Factory / torchtune / TRL / HF Trainer / TorchTitan / Megatron-LM 중 목적에 맞는 것을 고르세요.