wip: phase_z2 evidence 파이프라인 + matching 실험(phase2~26) + 프론트 trace 패널 진행분 스냅샷
- src: phase_z2 composition/mapper/pipeline/placement_planner/retry, ai_fallback(prompts/schema/validate), mdx_text_atoms 신규 - Front: PipelineTracePanel 신규, FramePanel/SlideCanvas/Home/designAgentApi 등 갱신 + 테스트 4종 추가 - templates/phase_z2: catalog(component_expansion_registry, node_slot_mapping 신규), frames, families, slide_base 갱신 - tests/matching: phase2~26 매칭 실험 스크립트·리포트·온톨로지 전체 (미커밋 진행분) - tests: b4_v4 evidence, task5~28.5 시리즈, regression(imp95 baseline) 등 신규 테스트 대량 추가 - docs/reference: MDX 구조 인벤토리, MDX→Frame 구조 계약 문서 - scripts: mdx 계약/parity/coverage/viewport 체크, gitea comment, run sync 유틸 - .gitignore: tmp*.json, chromedriver, .orchestrator, *.pkl, Front_test* 등 임시/스냅샷 제외 미완성 작업의 보존용 스냅샷 커밋 (2026-07-02) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,134 @@
|
||||
"""Pipeline Step 15 (Logistic Regression) — TARGET 4 로 가중치 학습.
|
||||
|
||||
방법:
|
||||
1. TARGET 4 섹션 × 32 프레임 = 128 샘플
|
||||
2. Feature: (standalone_score, group_score, related_score) — 각 [0, 1]
|
||||
3. Label: 1 if 정답 프레임 else 0 (정답 4, 오답 124)
|
||||
4. Logistic Regression + Linear Regression 두 가지 fit
|
||||
5. 학습 가중치를 sum=1 로 정규화 → 현재 0.30/0.50/0.20 와 비교
|
||||
6. 학습 가중치로 예측 시 TARGET 정답률 검증
|
||||
"""
|
||||
from pathlib import Path
|
||||
import numpy as np
|
||||
import yaml
|
||||
from sklearn.linear_model import LogisticRegression, LinearRegression
|
||||
|
||||
HERE = Path(__file__).parent
|
||||
TARGET_SIDS = ['01-2', '02-2.2', '03-1', '03-2']
|
||||
|
||||
|
||||
def main():
|
||||
v1 = yaml.safe_load((HERE / 'mdx_matching_result.yaml').read_text(encoding='utf-8'))
|
||||
auto = yaml.safe_load((HERE / 'auto_anchor_candidates.yaml').read_text(encoding='utf-8'))
|
||||
|
||||
answer_map = v1['meta']['answer_map']
|
||||
frame_num = {fid: info['frame_number'] for fid, info in auto['frame_stats'].items()}
|
||||
|
||||
# ─── 데이터 구성 ───
|
||||
rows = [] # (sid, frame_id, frame_num, s, g, r, label)
|
||||
for sid in TARGET_SIDS:
|
||||
sec = v1['mdx_sections'][sid]
|
||||
answer = answer_map[sid]
|
||||
for frame_id, detail in sec['per_frame_detail'].items():
|
||||
s = detail['standalone']['score']
|
||||
g = detail['keyword_group'].get('score_avg', 0)
|
||||
r = detail['related']['score']
|
||||
label = 1 if frame_num[frame_id] == answer else 0
|
||||
rows.append((sid, frame_id, frame_num[frame_id], s, g, r, label))
|
||||
|
||||
X = np.array([[r[3], r[4], r[5]] for r in rows])
|
||||
y = np.array([r[6] for r in rows])
|
||||
|
||||
print('=' * 75)
|
||||
print(f'데이터: {len(y)} 샘플 (정답 {y.sum()}, 오답 {len(y)-y.sum()}) — TARGET 4 × 32 frames')
|
||||
print('=' * 75)
|
||||
print()
|
||||
|
||||
# ─── Logistic Regression ───
|
||||
clf = LogisticRegression(penalty='l2', C=1.0, fit_intercept=True, max_iter=2000)
|
||||
clf.fit(X, y)
|
||||
w_lr = clf.coef_[0]
|
||||
bias_lr = clf.intercept_[0]
|
||||
w_lr_norm = w_lr / w_lr.sum()
|
||||
|
||||
print(f'[Logistic Regression (L2, C=1.0)]')
|
||||
print(f' raw weights: standalone={w_lr[0]:+.3f} group={w_lr[1]:+.3f} related={w_lr[2]:+.3f}')
|
||||
print(f' bias: {bias_lr:+.3f}')
|
||||
print(f' 정규화 (sum=1): standalone={w_lr_norm[0]:.3f} group={w_lr_norm[1]:.3f} related={w_lr_norm[2]:.3f}')
|
||||
print()
|
||||
|
||||
# ─── Linear Regression (OLS, no intercept) ───
|
||||
ols = LinearRegression(fit_intercept=False)
|
||||
ols.fit(X, y)
|
||||
w_ols = ols.coef_
|
||||
w_ols_norm = w_ols / w_ols.sum()
|
||||
|
||||
print(f'[Linear Regression (OLS, no intercept)]')
|
||||
print(f' raw weights: standalone={w_ols[0]:+.3f} group={w_ols[1]:+.3f} related={w_ols[2]:+.3f}')
|
||||
print(f' 정규화 (sum=1): standalone={w_ols_norm[0]:.3f} group={w_ols_norm[1]:.3f} related={w_ols_norm[2]:.3f}')
|
||||
print()
|
||||
|
||||
# ─── 현재 vs 학습 가중치 비교 ───
|
||||
print('[비교]')
|
||||
print(f' standalone group related')
|
||||
print(f' 현재 (수동): 0.300 0.500 0.200')
|
||||
print(f' Logistic: {w_lr_norm[0]:.3f} {w_lr_norm[1]:.3f} {w_lr_norm[2]:.3f}')
|
||||
print(f' OLS: {w_ols_norm[0]:.3f} {w_ols_norm[1]:.3f} {w_ols_norm[2]:.3f}')
|
||||
print()
|
||||
|
||||
# ─── 학습 가중치로 TARGET 정답률 검증 ───
|
||||
def evaluate(w_normalized, name):
|
||||
hits = 0
|
||||
for sid in TARGET_SIDS:
|
||||
sec = v1['mdx_sections'][sid]
|
||||
answer = answer_map[sid]
|
||||
scores = {}
|
||||
for fid, detail in sec['per_frame_detail'].items():
|
||||
s = detail['standalone']['score']
|
||||
g = detail['keyword_group'].get('score_avg', 0)
|
||||
r = detail['related']['score']
|
||||
scores[fid] = w_normalized[0]*s + w_normalized[1]*g + w_normalized[2]*r
|
||||
top_fid = max(scores, key=scores.get)
|
||||
if frame_num[top_fid] == answer:
|
||||
hits += 1
|
||||
return hits
|
||||
|
||||
hits_current = evaluate([0.30, 0.50, 0.20], '현재')
|
||||
hits_lr = evaluate(w_lr_norm, 'Logistic')
|
||||
hits_ols = evaluate(w_ols_norm, 'OLS')
|
||||
|
||||
print('[TARGET 4 정답률 (학습 가중치로 재예측)]')
|
||||
print(f' 현재 (0.30/0.50/0.20): {hits_current}/4')
|
||||
print(f' Logistic Regression: {hits_lr}/4')
|
||||
print(f' OLS Linear Regression: {hits_ols}/4')
|
||||
print()
|
||||
|
||||
# ─── LOOCV (Leave-One-Out Cross-Validation) — 과적합 체크 ───
|
||||
print('[LOOCV — 과적합 확인]')
|
||||
print(' 각 TARGET 을 hold-out, 나머지 3개로 학습 후 테스트')
|
||||
loocv_hits = 0
|
||||
for hold_out_idx, hold_out_sid in enumerate(TARGET_SIDS):
|
||||
train_X = np.array([[r[3], r[4], r[5]] for r in rows if r[0] != hold_out_sid])
|
||||
train_y = np.array([r[6] for r in rows if r[0] != hold_out_sid])
|
||||
clf_cv = LogisticRegression(penalty='l2', C=1.0, fit_intercept=True, max_iter=2000)
|
||||
clf_cv.fit(train_X, train_y)
|
||||
w_cv = clf_cv.coef_[0] / clf_cv.coef_[0].sum()
|
||||
|
||||
sec = v1['mdx_sections'][hold_out_sid]
|
||||
answer = answer_map[hold_out_sid]
|
||||
scores = {}
|
||||
for fid, detail in sec['per_frame_detail'].items():
|
||||
s = detail['standalone']['score']
|
||||
g = detail['keyword_group'].get('score_avg', 0)
|
||||
r = detail['related']['score']
|
||||
scores[fid] = w_cv[0]*s + w_cv[1]*g + w_cv[2]*r
|
||||
top_fid = max(scores, key=scores.get)
|
||||
correct = frame_num[top_fid] == answer
|
||||
if correct:
|
||||
loocv_hits += 1
|
||||
print(f' hold-out {hold_out_sid}: weights={w_cv.round(3)} 정답? {"✓" if correct else "✗"}')
|
||||
print(f' LOOCV 정답률: {loocv_hits}/4')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user