콘텐츠로 이동

v7 Peak-Aware FL Experiment Design

0. 배경 및 목적

v6 track-e v3의 patchwork(Tier 1a/1b 분할, provisional/final Branch, 5분기 자동 분류)를 폐기하고, 다음 초록의 검증에만 집중하는 clean restart phase.

대상 초록 (2026-04-19 사용자 수정판)

Accurate peak load forecasting is critical to power system operation, but household-level forecasting remains difficult due to load variability. Since consumption data are privacy-sensitive, federated learning (FL) offers a natural framework for collaborative modeling without centralized data collection.

We propose a peak-aware FL framework with two components: (i) a peak-weighted loss that emphasizes peak-time samples during training, and (ii) a dual-path architecture that combines a shared vector-quantized (VQ) codebook for federated pattern exchange with a lightweight DLinear residual for per-household personalization. We evaluate models using PAPE (Peak Absolute Percentage Error) and HR (Hit Rate), metrics tailored to peak-region accuracy.

Across a broad set of baselines, the proposed model achieves the best peak accuracy, reducing PAPE by 9.8% relative to local-only training. Notably, our light-weight model surpasses time-series foundation models, showing that loss design and personalization outweigh model scale for household peak forecasting under privacy constraints.

용도: 학술 논문 아님. 발표자료. 우선순위 = 속도 + 정확성.

환경: Umass HH 5가구 (Apt6, 15, 30, 51, 88), RTX 5070 Ti 16GB 단일, MLflow tracking.


1. 검증 대상 Claim 및 Rollback 규칙 (pre-registered)

# Claim 통과 기준 Rollback
C1 FL + privacy motivation 서술 없음
C2 peak-weighted loss 효과 A1 vs A0 paired Wilcoxon p<0.05 "asymmetrically weighted"
C3 VQ codebook 기여 (federated pattern exchange) A3 vs A1 bootstrap 95% CI 하한 > 0 "(ii)" 구절 재구성
C4 DLinear residual 기여 (personalization) A3 vs A4 paired Wilcoxon p<0.05 "local adaptation head"
C5 best across baselines A3 vs {B0,B1,B2,B3,B4} Wilcoxon + Bonferroni 다수 PASS "competitive peak accuracy"
C6 PAPE 9.8% reduction vs local-only (B0 − A3) / B0 bootstrap 95% CI 하한 > 5% 실측 CI median % 교체
C7 light-weight surpasses TSFM 단계 6 Chronos + TimeMoE zero-shot 평가 후 disclosure 비교 자체 유지 + param 비율 명기

원칙: 결과 확인 즉시 자동 rollback 적용. orchestrator override 금지.


2. 사전 등록 사항 (단계 0, override 금지)

2.1 실험 단위

  • Seed set: {42, 123, 456, 789, 2024} (5-seed paired)
  • 가구: Apt6, 15, 30, 51, 88
  • Tin/Tout: 96h → 24h
  • Train/Val/Test split: 시계열 순서 고정 (v6 split 계승)

2.2 Metric 정의 (단일 코드 경로 강제)

단일 소스: src/peak_analysis/v7/metrics.py. 모든 v7 스크립트는 이 모듈을 import해야 한다 (stage-0 v7_0419_stage0_preregistration.py, stages 1~4 v7_runner.py 공통). 정의 drift 발생 시 definition_hash() 값이 바뀌며, pre-registration 시점과 불일치하면 fail-fast 트리거.

PAPE_v7: - 대상 시점: 실제값 ≥ Q90 (각 가구 train+val 분포의 90 percentile) - 계산: mean(|y_true − y_pred| / y_true × 100) (대상 시점만) - Degenerate case: y_true의 std < 1e-8이면 NaN 반환 (G2 policy) - 대상 시점이 없거나 y_true 모두 0에 가까우면 NaN

HR_v7 (Hit Rate): - K = 12 (일 24시간 중 상위 50%, 단일 값 고정) - 계산: |argsort_K(y_true) ∩ argsort_K(y_pred)| / K per day, mean across days and households

Golden tensor 5쌍 (stage-0 2026-04-19 v2 pre-registered, 단계 1~4 전 코드 경로 sanity):

ID y_true y_pred expected PAPE expected HR 비고
G1 [1,2,10,3] [1,2,8,3] 20.000000 1.000000 toy; Q90=7.9 trigger 1개
G2 [5,5,5,5] [4,5,6,5] NaN NaN degenerate-variance (std=0) → NaN by policy
G3 Apt6 test 첫 7일 (168h, start=0) y_pred = y_true (perfect) 0.000000 1.000000 q90=2.918
G4 Apt6 test 첫 7일 (168h, start=0) const = mean(block) = 1.088576 67.342534 0.619048 q90=2.918
G5 Apt15 test 첫 14일 (336h, start=384, hits≥12) uniform(min(train+val), max(train+val)), seed=42 64.279282 0.511905 q90=1.721; 14d로 n_hits=2→13 (seed 편차 44% 감소)

재현 규칙 요약: - 첫 블록 선택: extract_first_block(test_vals, q90, block_hours, min_hits) — 24h-aligned 슬라이딩, q90-hit≥min_hits인 첫 블록 - G3/G4: min_hits=1, block_hours=168 - G5: min_hits=12, block_hours=336 (critic M1 대응, n=2 대신 n≥12 샘플) - G5 RNG: np.random.default_rng(42).uniform(low, high, shape); low/high는 train+val min/max - Gate 1 assertion: atol=1e-6 - y_true / y_pred ndarray는 stage-0 run의 artifact golden_tensors/{G3,G4,G5}_y_{true,pred}.npy로 freeze됨

정의 해시: definition_hash() = sha256(이 모듈 소스 || DEFINITION_HASH_PAYLOAD JSON) 상위 16 hex. 2026-04-19 v2 기준 = 8be2bd2f691deed0. 단계 1~4 모든 MLflow run은 이 해시를 param으로 로깅하며 불일치 시 fail-fast.

2.3 통계 방법론

  • Paired Wilcoxon signed-rank test (각 5-seed paired)
  • Bootstrap 95% CI (1000 resamples)
  • Bonferroni correction (k = claim 수)
  • Primary metric = PAPE / Secondary = HR

2.4 Fail-fast Threshold (per-run hook, 7-metric) — v2 2026-04-19 critic-revised

설계 원칙 전환 (critic C3 대응): v1의 "v6 historical max × 1.5"는 accepted 표본이 n=4 (그중 3개는 2-epoch prototype)이라 대표성 없음. v2는 per-run val divergence + static train ceiling 조합으로 전환.

Metric Threshold 근거 / 구현
final_train_loss > 3.0 (static sanity ceiling) v6 converged runs (MIN_STEPS≥10) max=0.541 × ~5.5배; catastrophic divergence 차단 목적
nan_step_count > 0 학습 중 NaN 발생 즉시 fail
final_val_loss / initial_val_loss (epoch 5+ moving avg ratio) > 1.5 per-run silent divergence 탐지. run-local 기준이라 표본 편향 무관
n_nan_predictions > 0 예측 단계 NaN 즉시 fail
final_codebook_util (VQ cell만) < 0.05 WARNING (FAIL 아님), v6 near-collapse 3~6% 기준
pape_definition_hash mismatch 단일 코드 경로 강제, 정의 drift 차단
scaler_space_signature mismatch normalization leakage 차단

v6 stage-0 재산출 통계 요약 (MIN_STEPS≥10 converged filter 적용, n=22): - final_train_loss 분포 (n=3, track-e-tier0은 2-epoch proto로 대부분 탈락): p50=0.324, p95=0.520, max=0.541 - final_val_loss 분포 (n=22): p50=0.336, p95=0.353, max=0.403, min=0.278 - final_val_loss / initial_val_loss 분포 (n=22): p50=0.929, p95=1.001, max=1.001 → 관찰: v6 converged runs은 val loss가 초기 대비 완만하게만 개선된다. 1.5× 임계는 "명확한 divergence"만 포착 (보수적 설계). - Gate 5 metric 근거 (§3 단계 0.5 참조, 2026-04-20 redesign): 위 final_val_loss / initial_val_loss 분포(p50=0.929)는 "divergence 여부"를 가리는 §2.4 지표로만 쓰이며, Gate 5 convergence 판정에는 쓰이지 않는다. Gate 5는 새 rel_decrease = (mean(vl[:3]) − mean(vl[-3:])) / mean(vl[:3]) 지표를 사용하며, v6 n=22 back-test 결과 p10=0.0017 / p05=−0.0005 / p50=0.0350로부터 PASS/WARNING/FAIL cutoff가 empirical하게 도출된다. 두 지표는 상호 보완적이며 중복되지 않는다.

기각된 대안: - Option A (P95 × 1.5): n=3 표본, 기각. - Option C (v6 historical max × 1.5 = 2.63): v1 사용, 2-epoch prototype epoch-1 loss에 근거하여 대표성 없음, 기각.

2.5 MLflow 로깅 의무 (전 실험 공통)

  1. per-epoch/round train_loss, val_loss (mlflow.log_metric(step=))
  2. best checkpoint (mlflow.log_artifact)
  3. test y_true.npy + y_pred.npy (mlflow.log_artifact)
  4. 가구별 + avg PAPE, HR, MSE, MAE (mlflow.log_metric)
  5. 7-metric fail-fast 지표 (mlflow.log_metric)
  6. config 전체 (mlflow.log_params) — pape_definition_hash, scaler_space_signature 포함

3. 실험 단계

단계 0 — 사전 등록 (D+0, ~0.5h)

  • 위 §2 전체 항목을 코드/문서 양쪽에 확정 기록
  • Golden tensor 5쌍 expected 값 표 작성 (실제 값 채움)
  • v6 historical loss range 추출 → fail-fast threshold 확정

단계 0.5 — Vertical Slice Smoke Test (D+0~1, 12 runs, ~2h)

  • 호출: uv run python -m experiments.federated.v7_runner --mode=smoke --households=Apt6,Apt_max --cells=B0,B2,A3 --seeds=42,43,123
  • 가구: Apt6 + Apt88 (Apt_max_load). Stage-0 v2 (2026-04-19) 기준: 5개 peak-load metric (daily_max_mean, daily_max_median, daily_max_p95, overall_max, overall_p95) 모두에서 Apt88이 1위 (critic M2 민감도 검증 통과). variability(std, CV)는 Apt51이 1위지만 "extreme high-load"와는 다른 축이라 plurality vote에서 제외.
  • Cells: B0 (Local), B2 (Ditto λ — 가장 risky regularization), A3 (full proposed)

6 Critical Gates (모두 PASS/WARNING 시 단계 1 진입; FAIL 1개라도 있으면 HOLD): 1. PAPE/HR 정의 코드 경로 동일 (hash + golden tensor expected 값 assertion) 2. VQ + DLinear scaler space 일치 (std ratio ∈ [0.5, 2.0] + unit assertion) 3. MLflow artifact 완전성 (best.ckpt, y_true.npy, y_pred.npy, per-epoch loss, 7-metric 모두 기록) 4. Figure가 mlflow.search_runs() 직접 query로 그려지고 PNG EXIF에 run_id 임베드 5. 수렴성 — monotonic-decrease metric (2026-04-20 v3 redesign): rel_decrease = (mean(val_loss[:3]) − mean(val_loss[-3:])) / mean(val_loss[:3]) - PASS: rel_decrease ≥ 0.0017 (v6 n=22 converged-run P10; TPR 86.4% on v6) - WARNING: 0.0 ≤ rel_decrease < 0.0017 (borderline, v6 P05~P10 구간) - FAIL: rel_decrease < 0.0 (net increase — 수렴 방향 반대) - 전제: len(val_loss) ≥ 6. 미만이면 ERROR 처리. - smoke / full 공통 metric. Block size=3은 smoke 최소 10 rounds에서 초기/말미 각 3개를 안정적으로 분리. - 근거: outputs/v7_stage05/v6_gate5_backtest.json (2026-04-20). Legacy moving/initial < 0.5는 v6 n=22 중 0건 PASS(false-positive rate 1.0)로 사실상 불가능한 임계였으며 폐기. 6. Paired 구조 sanity (동일 seed의 모든 cell이 동일 train/val/test split data hash)

FAIL 처리: Q2 정책에 따라 자동 engineer 호출 + 사용자 알림 동시. 수정 후 단계 0.5 재실행. 재smoke 사이클 최대 2회.

§2.4 val-divergence와 Gate 5의 관계 (중복·충돌 없음): - §2.4 final_val_loss / initial_val_loss > 1.5 = divergence detector (per-run hook, 1회 판정). - §3 Gate 5 rel_decrease = convergence verifier (smoke aggregate, 3-tier). - 두 지표는 서로 다른 끝단(발산 vs 정체)을 보호. 한 쪽이 다른 쪽을 대체하지 못한다. 예: rel_decrease = 0 + ratio = 1.0은 §2.4에서는 PASS이지만 §3 Gate 5는 WARNING.

단계 1 — Baseline 5종 × 5-seed (D+1~2, 25 runs, ~3h 병렬)

ID 방법 하이퍼파라미터
B0 Local DLinear fixed default
B1 FedAvg + DLinear fixed default
B2 FedProx + DLinear μ = 0.01
B3 FedRep (shared encoder + local head) fixed default
B4 Ditto λ = 0.1
  • 호출: v7_runner.py --mode=main --phase=baseline --cells=B0,B1,B2,B3,B4 --seeds=42,123,456,789,2024 --households=all
  • 2-way 병렬 (DLinear-only + Fed methods)
  • Early checkpoint: B0 5-seed 완료 시 자동 점검. 5/5 PASS면 B1~B4 진행. NaN 1개 발생 시 Q1 정책(Option A) — 동일 seed 재실행 1회. 재실행 후에도 5/5 미달 시 stop-and-wait + 부분 분석 보고서 자동 생성.

단계 2 — Ablation 5종 × 5-seed (D+2~3, 20 runs, ~7h)

ID peak loss VQ path DLinear path 검증
A0 SmoothL1 (= B1, dedup)
A1 peak-weighted C2 (peak-loss 기여)
A2 SmoothL1 C3 mid (no peak)
A3 peak-weighted full proposed
A4 peak-weighted ✗ (y_vq만) C4 (DLinear 기여)
  • 호출: v7_runner.py --mode=main --phase=ablation --cells=A1,A2,A3,A4 --seeds=...
  • Spot check: A1 첫 1 seed 완료 후 7-metric 점검 → PASS 시 잔여 진행

단계 4 — VQ 개선 3종 × 5-seed (D+3, 15 runs, ~5.5h)

본문 Method 섹션에 명시 (초록 변경 없음).

ID 기법
V1 A3 + EMA codebook update (γ=0.95)
V2 A3 + K-means init (warm-up round=5)
V3 A3 + EMA + K-means
  • 목적: codebook util이 v6의 3~6%에서 ≥ 20%로 개선되는지 검증
  • Spot check: V1 첫 1 seed 완료 후 점검

단계 5 — 통계 검증 + Claim Rollback (D+3~4, ~4h)

  • 단계 1+2+4 결과로 §1 Claim 표의 통과 기준 자동 평가
  • 미통과 claim은 즉시 rollback 문구 적용 (override 금지)
  • bootstrap CI median % 실측값으로 9.8% 교체 가능

단계 6 — TSFM 비교 + 발표자료 (D+4, ~8h)

  • Chronos zero-shot + TimeMoE zero-shot on 5가구 (training 없음, inference만)
  • C7 disclosure: 제안 모델 param 수 + TSFM param 수 비율 본문 명기
  • 발표자료 figure: 모든 plot은 MLflow run_id 직접 query (PNG EXIF run_id 임베드)
  • 산출: presentation slides + figure 폴더

4. 안전망 (3-layer)

  1. 단계 0.5 Vertical Slice Smoke (12 runs / ~2h) — 6 Critical Gate
  2. Per-run fail-fast hook (7-metric, 단계 1~4 전체 적용) — 이상 즉시 FAIL_AUTO 마킹 + 다음 run skip
  3. Cell-specific spot check (단계 1 early checkpoint + 단계 2/4 진입 시 첫 cell 1 seed)

5. 사용자 결정 (확정)

Q 채택안
Q1 NaN seed 처리 Option A — 동일 seed 1회 재실행. 재실행 후 5/5 미달 시 stop-and-wait
Q2 Gate FAIL 시 자동 engineer 호출 + 사용자 알림 동시
Q3 Early checkpoint FAIL stop-and-wait + 부분 분석 보고서 자동 생성

6. 단일 entry point 설계 (C-7 mitigation)

experiments/federated/v7_runner.py — 모든 단계가 동일 runner의 config flag로 호출:

v7_runner.py
  --mode={smoke,main}
  --phase={baseline,ablation,vq_improvement}
  --cells=B0,B1,B2,B3,B4,A1,A2,A3,A4,V1,V2,V3
  --seeds=42,123,456,789,2024
  --households=Apt6,Apt15,Apt30,Apt51,Apt88|all
  --golden-tensor-check (Gate 1 sanity)

별도 smoke 스크립트 작성 금지. smoke ↔ main 코드 경로 100% 공유.

7. Workload + 타임라인

단계 시간
0 사전 등록 0.5h
0.5 smoke (12 runs) 2h
1 baseline (25 runs, 병렬) 3h
2 ablation (20 runs) 7h
4 VQ 개선 (15 runs) 5.5h
5 통계 + 6 TSFM + 발표자료 12h
재smoke buffer (1 cycle) +2~4h
~32~34h ≈ 3-4일

8. Gate Check 요약

Gate 시점 통과 조건 실패 시
단계 0 사전등록 완료 D+0 golden tensor 표 작성 + threshold 확정 단계 0.5 진입 차단
단계 0.5 6-Gate D+0~1 모두 PASS 자동 engineer 호출, 재smoke 최대 2회
단계 1 early checkpoint D+1~2 B0 5-seed 5/5 PASS stop-and-wait + 부분 분석 보고서
단계 2 spot check D+2 A1 첫 1 seed 7-metric PASS stop-and-wait
단계 4 spot check D+3 V1 첫 1 seed PASS stop-and-wait
단계 5 통계 D+3~4 claim별 자동 rollback (override 금지)