콘텐츠로 이동

Source: report/version7/exp-expert/v7_stage05_engineer_contract.md

Engineer Contract — v7_runner.py 신규 MLflow Param 로깅

본 문서는 critic C2 대응으로 v7_runner.py에 추가해야 할 MLflow param 명세다. smoke_analysis.py의 Gate 2 / Gate 6 은 이 param들을 엄격하게 요구한다 (cycle 2/2에서 soft fallback 제거 완료). 누락 시 Gate 2/6 FAIL.

맥락

  • smoke_analysis.py 측 수정은 완료: Gate 2 WARNING→FAIL, Gate 6 ERROR→FAIL.
  • v7_runner.py 측은 contract 맞추기만 하면 됨.
  • 기존 scaler_space_signature (unified) 은 backward compatibility 위해 유지 가능.

Contract Spec

P1. pape_definition_hash (이미 존재 — 확인만)

  • 위치: v7_runner.py line 1643 이미 mlflow.log_params({..., "pape_definition_hash": PAPE_DEFINITION_HASH, ...}).
  • 변경 없음. 단, 본 cycle 에서 prereg 스크립트를 pape_definition_hash 로 통일했음을 인지.

P2. vq_input_unit + dlinear_output_unit (신규)

  • allowed values: {"standardized", "kW", "kWh_per_h"} — 정확 문자열 일치.
  • 언제 로깅:
  • dlinear_output_unit: 모든 cell 에서 필수 로깅 (VQ·non-VQ 무관).
  • vq_input_unit: VQ cell (spec.use_vq == True) 에서만 로깅. non-VQ cell에서는 로깅 금지(None 취급).
  • 값 결정 규칙:
  • 현재 create_household_dataloaders 는 z-score 표준화 후 train_data 반환. → VQ 입력과 DLinear 출력 모두 "standardized" 로 기록해야 함.
  • 만약 inverse-transform 된 scale로 예측을 출력한다면 "kW" 로 전환 (하지만 현재 구조는 normalized 상태에서 loss/metric 계산).
  • 로깅 위치 예시 (line 1625~1646의 mlflow.log_params 블록 내부):
    mlflow.log_params({
        # 기존 field들 유지
        ...
        "pape_definition_hash": PAPE_DEFINITION_HASH,
        # ↓ 신규
        "dlinear_output_unit": "standardized",  # 모든 cell
        **({"vq_input_unit": "standardized"} if spec.use_vq else {}),
    })
    

P3. vq_scaler_space_signature + dlinear_output_scaler_space_signature (신규)

  • 현재 상태: line 1676 에 scaler_space_signature 하나만 로깅.
  • 변경 내용: 해당 unified signature 를 2개로 분리하여 로깅.
  • 값 결정 규칙:
  • VQ와 DLinear가 동일 split 으로부터 scaler 를 유도하므로 두 값은 동일해야 함.
  • 현재 scaler_sig = compute_scaler_space_signature(mean_std) 반환값을 두 param 모두에 재사용 가능:
    mlflow.log_params({
        "scaler_space_signature": scaler_sig,  # backward-compat 유지
        "dlinear_output_scaler_space_signature": scaler_sig,  # 전 cell
        **({"vq_scaler_space_signature": scaler_sig} if spec.use_vq else {}),
    })
    

P4. train_data_hash / val_data_hash / test_data_hash (신규)

  • 해시 정의 (unified scheme — per-household suffix 스킴 폐기):
    import hashlib, numpy as np
    def _data_hash(arr: np.ndarray) -> str:
        payload = arr.tobytes() + str(arr.shape).encode() + str(arr.dtype).encode()
        return hashlib.sha256(payload).hexdigest()[:16]
    
  • 입력 ndarray 규정: 전 household 의 데이터를 정렬된 household 순서로 concat 한 단일 ndarray 에 대해 계산. split 별로 한 번씩 해시.
  • train_concat = np.concatenate([loaders[hh][0].dataset.data for hh in sorted(households)], axis=0) 같은 방식 (실제 dataset 내부 구조에 맞춰 조정 필요).
  • 또는 TimeSeriesDataset 의 내부 numpy array 를 직접 hashing.
  • 언제 로깅: 모든 cell. VQ 유무 무관.
  • 왜 unified 인가: per-household suffix (train_data_hash_Apt6 등) 는 smoke_analysis.py 에서 dict-equality 비교로 가능하지만, "동일 seed × 다른 cell 모두 같은 split 데이터 사용" 이라는 불변식은 단일 hash triple 이 더 강한 검증이다 (cell 별로 hh 세트가 달라질 risk 차단).
  • 예시 (line 1676 근처):
    # After dataloader creation, before training:
    train_concat, val_concat, test_concat = _collect_split_tensors(loaders, households)
    mlflow.log_params({
        "train_data_hash": _data_hash(train_concat),
        "val_data_hash": _data_hash(val_concat),
        "test_data_hash": _data_hash(test_concat),
    })
    

P5. Gate 3 artifact 완전성 재확인 (변경 없으면 PASS)

  • 현재 line 1732-1733: _log_npy_artifact(..., f"{cell_id}_seed{seed}_y_true.npy") — smoke_analysis 가 y_true.npy / y_pred.npy suffix 매칭이므로 OK.
  • 현재 line 1756: _log_checkpoint_artifact(best_ckpt, f"{cell_id}_seed{seed}_best.pt") — smoke_analysis 는 checkpoints/*.pt 패턴 검색. checkpoints/ prefix 확인 필요.

확인 필요: _log_checkpoint_artifactcheckpoints/ 하위에 저장하는가? 아니라면 artifact_path="checkpoints" 를 지정하도록 수정.

테스트 요구사항

  • 기존 tests/test_v7_runner.pytests/test_v7_runner_training.py 전부 PASS 유지.
  • 신규 테스트 추가 (권장)tests/test_v7_runner_mlflow_params.py 또는 기존 test class 확장:
  • test_dlinear_output_unit_logged_in_allowed_whitelist
  • test_vq_input_unit_logged_only_for_vq_cell
  • test_vq_and_dlinear_signatures_match_when_vq_cell
  • test_train_val_test_data_hash_is_16hex
  • test_same_seed_different_cells_produce_identical_data_hash

검증 스크립트 (engineer 완료 후 재실행)

# 1) v7_runner 단위 테스트
uv run python -m pytest tests/test_v7_runner.py tests/test_v7_runner_training.py -v

# 2) smoke_analysis unit test 전체 (contract 검증용, 19 tests)
uv run python -m pytest tests/test_v7_stage05_smoke_analysis.py -v

# 3) 소규모 실 실행 — 2-seed × 2-cell 로 MLflow param 기록 확인
uv run python -m experiments.federated.v7_runner \
    --mode=smoke --phase=baseline --cells=B0,A3 --seeds=42,123 --households=Apt6
# → MLflow UI 에서 run 에 pape_definition_hash, dlinear_output_unit,
#   vq_input_unit (A3만), dlinear_output_scaler_space_signature,
#   vq_scaler_space_signature (A3만), train/val/test_data_hash 7~9개 신규
#   param 확인

위임 범위 (명시적 제한)

  • 본 contract 외 기능 변경 금지. 기존 테스트 회귀 없어야 함.
  • training loop 내부 로직 (model, loss, optim) 수정 금지.
  • ROOT_DIR, RANDOM_SEED 등 상수 변경 금지.
  • 기존 scaler_space_signature param 은 삭제 금지 (backward-compat).

완료 보고 포맷

engineer 완료 시 아래 포함해 보고: 1. 수정된 v7_runner.py 라인 범위 2. 신규/수정 테스트 결과 (pytest 출력 last 5 line) 3. 소규모 실 실행 (위 검증 스크립트 3번) MLflow run_id 하나와 해당 run 의 params 전체 JSON 덤프 (mlflow.search_runs 또는 gh-like fetch) 4. backward-compat 확인: scaler_space_signature param 여전히 존재


작성자: exp-expert | 작성 시점: v7 stage-0.5 cycle 2/2 revision | 2026-04-19