2026년 4월 25일 | 개발 일기
sample_collab 하나로 읽던 structural variant 역할을 bipartite graph에 다시 올려 보니, 직전 글에서 제일 또렷해 보였던 해석이 꽤 빠르게 흔들렸다. sample_collab에서는 reduced+degree가 seed 다섯 개 전부에서 test AUC 0.75로 맞춰지며 가장 평평한 판처럼 보였고, reduced+closed_triplets는 mean test AUC를 0.80까지 끌어올렸다. 그런데 삼각형이 아예 없는 12노드 bipartite 그래프에 같은 비교판을 그대로 얹으니, 평균이 가장 잘 버티는 설정과 hardest split 바닥이 덜 무너지는 설정이 다시 갈라졌다.
이번 반복에서 내가 붙인 건 거창한 새 encoder가 아니다. bipartite_bridge_graph라는 작은 샘플 그래프 하나를 추가했고, 기존 structural variant 비교를 sample_collab + bipartite 두 데이터셋에 같이 올려 보는 multi-dataset report를 만들었다. 핵심은 점수를 더 높이는 것보다, 내가 지난 글에서 붙인 역할 이름들, 이를테면 degree는 stabilizer, closed_triplets는 mean booster 같은 해석이 데이터셋 밖에서도 유지되는지 먼저 확인하는 데 있었다.
1. 이번에 추가한 것
코드 쪽 변경은 비교축을 넓히는 데만 썼다. run_multidataset_structural_variant_experiment()를 추가해서 여러 데이터셋의 structural variant 결과를 한 번에 모으고, 각 설정별로 dataset mean, worst dataset floor, gap 요약을 다시 계산하게 했다. 데이터는 12개 노드, 18개 edge를 가진 bipartite 샘플을 새로 넣었다. 테스트는 smoke run까지 포함해 다시 돌렸고 현재는 10개 테스트가 전부 통과한다.
- 새 데이터셋: bipartite_bridge_graph.csv
- 새 runner: run_multidataset_structural_variant_experiment()
- 새 산출물: single-dataset JSON 1개, multi-dataset report JSON 1개, 비교 figure 3개
- 검증: pytest 10 passed, GNN 프로젝트 저장소 커밋 및 원격 push 완료
실행 경로도 아주 단순하게 남겼다. 기존 structural_variants 실험을 bipartite 쪽에 한 번 더 돌리고, 그 다음에 두 데이터셋 경로를 묶어 report를 생성하는 흐름이다.
from pathlib import Path
from gnn_lab.experiment import run_multidataset_structural_variant_experiment
root = Path('/mnt/d/MyProject/Tistory_paper/project/gnn')
run_multidataset_structural_variant_experiment(
dataset_paths=[
root / 'data/sample_collab_graph.csv',
root / 'data/bipartite_bridge_graph.csv',
],
seeds=[5, 7, 11, 13, 17],
output_path=root / 'experiments/multidataset_structural_variant_report.json',
)
2. sample_collab에서는 보였던 역할 구분
먼저 출발점인 sample_collab을 다시 보면 지난 글의 읽기 자체는 틀리지 않았다. reduced+closed_triplets는 mean test AUC가 0.8000으로 제일 높고, reduced+degree는 hardest split AUC가 0.7500으로 제일 높다. 반대로 hybrid_reduced는 mean validation-test gap이 0.1167로 제일 작다. 그래서 sample_collab 하나만 놓고 읽으면, triad 계열은 평균을 밀어 올리고, degree는 바닥을 평평하게 만들고, reduced core는 generalization 흔적을 가장 깔끔하게 남긴다고 정리하기 쉬웠다.
| config | mean test AUC | hardest split AUC | mean validation-test gap |
|---|---|---|---|
| hybrid_full | 0.7500 | 0.5000 | 0.1611 |
| reduced+closed_triplets | 0.8000 | 0.5000 | 0.1556 |
| reduced+degree | 0.7500 | 0.7500 | 0.1611 |
| hybrid_reduced | 0.7500 | 0.5000 | 0.1167 |
| propagation_only | 0.6500 | 0.5000 | 0.2389 |
문제는 이 역할 구분이 너무 sample_collab 친화적일 수 있다는 점이었다. 작은 그래프 하나에서 잘 읽히는 설명은 쉽게 이름이 붙고, 이름이 붙는 순간 다음 실험에서도 같은 역할을 기대하게 된다. 내가 이번에 확인하고 싶었던 건 바로 그 관성이다.
3. bipartite에서는 triad 해석이 바로 약해졌다
새로 만든 bipartite_bridge_graph에서는 그림이 확 달라졌다. 구조적으로 삼각형이 없기 때문에, 이 그래프와 그 하위 split들에서는 closed_triplets와 clustering이 사실상 죽은 축이다. 그래서 sample_collab에서 mean booster처럼 보였던 triad 계열이 여기서는 같은 방식으로 읽히지 않는다. 실제로 reduced+closed_triplets와 hybrid_reduced의 mean test AUC는 둘 다 0.4667이다.
흥미로운 건 degree 쪽도 완전히 같은 이야기를 반복하지 않는다는 점이다. bipartite에서 reduced+degree는 mean test AUC가 0.6000으로 제일 높지만, hardest split AUC는 0.1111까지 내려간다. 즉 sample_collab에서 보였던 flat 0.75를 그대로 안정성 규칙으로 옮기면 과해진다. 반대로 propagation_only는 mean은 낮아도 hardest split AUC가 0.2222까지 버틴다.
| config | mean test AUC | hardest split AUC | mean validation-test gap |
|---|---|---|---|
| hybrid_full | 0.4000 | 0.1111 | 0.1556 |
| reduced+closed_triplets | 0.4667 | 0.2222 | 0.1556 |
| reduced+degree | 0.6000 | 0.1111 | 0.1556 |
| hybrid_reduced | 0.4667 | 0.0000 | 0.1333 |
| propagation_only | 0.4889 | 0.2222 | 0.1778 |
4. 평균과 바닥은 다른 질문이었다
두 데이터셋을 합쳐 놓고 보면 이번 반복에서 제일 크게 배운 건 이 점이다. 가장 높은 평균과 데이터셋 밖에서도 덜 무너지는 바닥은 같은 질문이 아니다. aggregate summary에서 reduced+degree는 mean of dataset mean AUC가 0.6750으로 제일 높고, min dataset mean AUC도 0.6000으로 가장 낫다. 그런데 worst dataset hardest-split AUC는 0.1111로 낮다.
반대로 reduced+closed_triplets와 propagation_only는 aggregate mean이 가장 높지는 않지만, worst dataset hardest-split AUC가 둘 다 0.2222로 더 높다. 그리고 hybrid_reduced는 gap이 가장 작게 남으면서도 worst dataset hardest-split AUC가 0.0000까지 내려간다. 이 장면을 보고 나니 이제는 strongest config를 하나로 고르기보다, mean winner, floor defender, cleanest gap을 따로 적는 편이 맞겠다고 느꼈다.
| config | mean of dataset mean AUC | min dataset mean AUC | min dataset hardest-split AUC |
|---|---|---|---|
| hybrid_full | 0.5750 | 0.4000 | 0.1111 |
| reduced+closed_triplets | 0.6334 | 0.4667 | 0.2222 |
| reduced+degree | 0.6750 | 0.6000 | 0.1111 |
| hybrid_reduced | 0.6083 | 0.4667 | 0.0000 |
| propagation_only | 0.5695 | 0.4889 | 0.2222 |
5. 이번 반복에서 남은 질문
지금 단계에서 바로 결론을 닫고 싶지는 않다. 데이터셋이 둘뿐이라 우연을 걷어냈다고 말하기 어렵고, bipartite는 삼각형이 전혀 없어서 structural feature 해석을 극단적으로 바꿔 버리는 샘플이기도 하다. 그래도 이번 반복 덕분에 다음 질문은 훨씬 분명해졌다.
- triangle-rich vs triangle-free를 먼저 나눈 뒤 structural feature를 읽어야 하는가
- reduced+degree의 높은 평균과 약한 worst-case floor가 어떤 split에서 갈리는가
- hardest split edge 묶음을 따로 저장해 failure-case report를 남겨야 하는가
내가 이번에 얻은 가장 큰 수확은 새 최고점을 찍었다는 사실보다, 작은 그래프 하나에서 붙인 역할 이름을 너무 빨리 일반화하지 말아야 한다는 감각이다. 이제 GNN 트랙의 다음 비교는 "무슨 설정이 제일 높았나"보다, 어떤 그래프 family에서 어떤 structural 신호가 아직 살아 있는가를 먼저 묻는 쪽으로 넘어가는 게 맞아 보인다.
'[AI 실험실] > [개인 프로젝트] GNN' 카테고리의 다른 글
| GNN | Structural variant의 edge별 실패 분석 (0) | 2026.04.28 |
|---|---|
| GNN | Structural variant failure-case report (0) | 2026.04.27 |
| GNN | Hybrid structural 축 ablation (0) | 2026.04.20 |
| GNN | Propagation feature correlation 진단 추가 (0) | 2026.04.14 |
| GNN 프로젝트: Propagated Cosine과 전파 깊이 비교 (0) | 2026.04.06 |