> EulerForge > 튜토리얼 > 0. 데이터 전처리

0. 데이터 전처리

이 튜토리얼을 가장 먼저 실행하세요. data/ 디렉토리의 원본 데이터를 EulerForge 표준 raw JSONL로 변환합니다. 이후 모든 튜토리얼은 변환된 파일을 data.format=raw로 사용합니다.


1. EulerForge 표준 raw 포맷

EulerForge는 3종의 표준 raw JSONL을 지원합니다:

task 표준 raw 스키마 용도
sft {"prompt": "...", "response": "..."} 또는 {"text": "..."} SFT, PPO
preference {"chosen": "...", "rejected": "..."} Preference (프롬프트 없음)
prompted_preference {"prompt": "...", "chosen": "...", "rejected": "..."} DPO, ORPO, RM

data.format=raw를 사용하면 훈련 시작 시 자동으로 토큰화(processed 변환)됩니다.


2. 제공 데이터 파일

data/ 디렉토리에는 원본 파일과 변환 완료된 _raw 파일이 있습니다.

파일 목록

파일 설명 크기
sft_10k.jsonl SFT 원본 (messages 중첩 구조) 10k
sft_10k_raw.jsonl 표준 SFT raw (변환 완료) 10k
sft_1k.jsonl SFT 원본 (TDD/테스트용) 1k
sft_1k_bench_raw.jsonl SFT bench용 (변환 완료) 1k
dpo_10k.jsonl DPO 원본 (중첩 구조) 10k
dpo_10k_raw.jsonl 표준 prompted_preference raw (변환 완료) 10k
dpo_1k.jsonl DPO 원본 (TDD/테스트용) 1k
dpo_1k_bench_raw.jsonl DPO bench용 (변환 완료) 1k
dpo_10k.jsonl DPO 선호 데이터 (이미 표준에 가까움) 10k
dpo_10k_raw.jsonl 표준 prompted_preference raw (변환 완료) 10k
dpo_1k.jsonl DPO 선호 데이터 (TDD/테스트용) 1k
dpo_1k_bench_raw.jsonl SHP bench용 (변환 완료) 1k

명명 규칙

튜토리얼은 모두 10k 데이터를 전제로 합니다. _raw 파일이 이미 변환 완료되어 있으므로 대부분의 튜토리얼에서 convert 단계는 건너뛸 수 있습니다.


3. 데이터 변환 (eulerforge convert)

eulerforge convert의 기본 철학은 --map 기반 매핑입니다. 내장 레시피(--recipe)는 자주 쓰이는 구조의 편의 기능입니다.

필드 탐색 (--print-sample-flat)

변환 전 입력 파일의 필드 구조를 확인합니다:

eulerforge convert --task sft --input data/sft_10k.jsonl --print-sample-flat
# 출력 예시:
# --- row 0 flat keys ---
#   'json_record.messages'                          (list)  [{'role': 'system', ...}]

(A) sft_10k.jsonl → 표준 SFT raw

sft_10k.jsonl은 messages 배열 구조입니다. 두 가지 방법 중 선택:

방법 1: 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

방법 2: --map 모드 (커스텀 flat 필드)

커스텀 데이터에 instruction, output 같은 flat 필드가 있다면:

eulerforge convert \
    --task sft \
    --input data/custom.jsonl \
    --output data/out_raw.jsonl \
    --map prompt=instruction \
    --map response=output

검증:

head -1 data/sft_10k_raw.jsonl | python3 -c "import sys,json; row=json.loads(sys.stdin.readline()); print(list(row.keys()))"
# 출력: ['prompt', 'response']

(B) dpo_10k.jsonl → 표준 prompted_preference raw

dpo_10k.jsonl은 중첩 {instruction.value, chosen.value, rejected.value} 구조입니다:

방법 1: --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

방법 2: Recipe 모드

eulerforge convert \
    --task prompted_preference \
    --input data/dpo_10k.jsonl \
    --output data/dpo_10k_raw.jsonl \
    --recipe dpo_nested_v1

검증:

head -1 data/dpo_10k_raw.jsonl | python3 -c "import sys,json; row=json.loads(sys.stdin.readline()); print(list(row.keys()))"
# 출력: ['prompt', 'chosen', 'rejected']

(C) dpo_10k.jsonl → 표준 prompted_preference raw

dpo_10k.jsonl은 이미 표준에 가까운 {prompt, chosen, rejected} 구조입니다. 변환된 dpo_10k_raw.jsonl이 이미 제공되어 있으며, 스키마 검증:

eulerforge convert --task prompted_preference --input data/dpo_10k_raw.jsonl --validate
# 출력: [Validate] 10000/10000 valid rows (0 invalid)

멀티 CPU 변환

대용량 데이터의 경우 --num-proc으로 병렬 처리:

eulerforge convert \
    --task sft \
    --input data/sft_10k.jsonl \
    --output data/sft_10k_raw.jsonl \
    --recipe sft_messages \
    --messages-expr json_record.messages \
    --num-proc 4 \
    --overwrite

4. 변환 결과 요약

변환 후 파일 task 사용 튜토리얼
data/sft_10k_raw.jsonl sft 01~04 (SFT 전략별), 08 (PPO)
data/dpo_10k_raw.jsonl prompted_preference 05 (DPO)
data/dpo_10k_raw.jsonl prompted_preference 06 (ORPO), 07 (RM)

5. 훈련에서 raw 데이터 사용

CLI --set 오버라이드

# SFT 훈련 (raw)
eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_sft.yml \
    --set data.format=raw \
    --set data.task=sft \
    --set data.path=data/sft_10k_raw.jsonl \
    --set data.max_length=512

# DPO 훈련 (raw)
eulerforge train --preset configs/presets/qwen3.5_0.8b_moe_expert_lora_dpo.yml \
    --set data.format=raw \
    --set data.task=prompted_preference \
    --set data.path=data/dpo_10k_raw.jsonl \
    --set data.max_length=512

# ORPO/RM 훈련 (raw)
eulerforge train --preset configs/presets/qwen3.5_0.8b_dense_lora_orpo.yml \
    --set data.format=raw \
    --set data.task=prompted_preference \
    --set data.path=data/dpo_10k_raw.jsonl \
    --set data.max_length=256

YAML 설정 파일

data:
  format: raw
  task: sft
  path: data/sft_10k_raw.jsonl
  max_length: 512
  # cache_dir: 기본값 outputs/.cache (모든 run이 공유, 명시하면 오버라이드)
  # num_proc: 기본값 CPU 코어 50% (명시하면 오버라이드)

6. 오프라인 전처리 (eulerforge preprocess)

자동 전처리 대신 미리 토큰화하려면:

# SFT (--num-proc 생략 시 CPU 코어 50% 자동 사용)
eulerforge preprocess \
  --task sft \
  --input data/sft_10k_raw.jsonl \
  --output data/sft_10k_processed.jsonl \
  --model-name Qwen/Qwen3.5-0.8B-Base

# Prompted-Preference
eulerforge preprocess \
  --task prompted_preference \
  --input data/dpo_10k_raw.jsonl \
  --output data/dpo_10k_processed.jsonl \
  --model-name Qwen/Qwen3.5-0.8B-Base \
  --max-length 256

# 워커 수 명시 지정
eulerforge preprocess \
  --task sft --input data/sft_10k_raw.jsonl --output data/sft_processed.jsonl \
  --model-name Qwen/Qwen3.5-0.8B-Base --num-proc 8

--num-proc > 1 사용 시 EulerForge가 자동으로 TOKENIZERS_PARALLELISM=false를 설정합니다. 기본값은 CPU 코어 수의 50%이며, 단일 코어를 강제하려면 --num-proc 1을 지정하세요.


7. Labels 마스킹 정책

모드 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 반영

8. 흔한 에러와 해결

Data: processed dataset row 0 missing 'input_ids'

Data: processed dataset row 0 missing 'input_ids'
Fix: Run `eulerforge preprocess ...` or set data.format=raw with schema mapping
See: docs/tutorials/00_data_preprocessing.md

원인: raw JSONL을 processed로 지정했거나, 전처리가 안 된 파일을 사용 해결: data.format=raw로 변경하거나 eulerforge preprocess로 전처리

Data Config: data.task is required for raw format

원인: data.format=raw인데 data.task 미지정 해결: data.tasksft, preference, prompted_preference 중 하나로 설정

Data Config: data.task='sft' is incompatible with training.type='dpo'

원인: data.tasktraining.type이 호환되지 않음. 예: DPO 프리셋(training.type=dpo)에 SFT 데이터(data.task=sft)를 지정 해결: --set training.type=sft로 훈련 타입도 함께 오버라이드하거나, data.task를 훈련 타입에 맞게 변경

data.task 호환 training.type
sft sft, ppo
preference dpo, orpo, rm
prompted_preference dpo, orpo, rm

Data: raw sft data row 0 missing column 'text'

원인: 데이터에 text 컬럼이 없음 (prompt/response 형식인 경우) 해결: 컬럼이 자동 감지됨. prompt+response 컬럼이 있으면 정상 동작