2026년 4월 16일 | 개발 일기
14차원 hybrid node input을 붙인 GraphSAGE는 sample_collab 그래프에서 mean test AUC 0.7444가 나왔다. propagation-only GraphSAGE의 0.7889는 넘지 못했지만, structural-only의 0.6167보다는 분명히 올라왔고, hardest split이던 seed 13에서는 propagation-only보다 더 덜 무너졌다. 숫자 하나만 보면 애매할 수 있는데, 내가 오늘 얻은 건 단순한 신기록보다 어떤 입력판이 흔들릴 때 덜 크게 흔들리는지에 대한 감각에 더 가까웠다.
직전 반복에서 propagation residual을 node input으로 넣었을 때는 "GraphSAGE가 약한 이유가 encoder 자체인지, structural-only 입력판이 너무 약한지"를 분리해 볼 수 있었다. 그 다음 질문은 자연스러웠다. structural summary가 단독으로는 약하더라도, propagation 옆에 붙이면 hardest split에서 완충재처럼 작동할 수 있지 않을까. 그래서 오늘은 layer를 더 깊게 쌓거나 decoder를 바꾸지 않고, structural 5차원과 propagation residual 9차원을 그냥 이어 붙인 graphsage_hybrid_residual 하나만 먼저 올려 봤다.
1. 오늘 손댄 부분
이번 작업은 모델을 새로 발명했다기보다, 입력판을 한 칸 더 늘린 쪽에 가깝다. 먼저 테스트부터 늘려서 hybrid GraphSAGE가 단일 실행 결과와 multi-seed summary에 모두 잡히는지 고정했다. 그 다음 encoder 쪽 raw feature map에 hybrid_structural_propagation 모드를 추가했고, 실험 함수에서는 기존 structural / propagation 모델 옆에 hybrid 모델을 같이 학습하도록 연결했다. 마지막으로 샘플 결과 JSON과 비교용 PNG 두 장을 다시 만들고, iteration 문서와 README도 같이 갱신했다.
- 추가한 모델: graphsage_hybrid_residual
- 입력 차원: 14 = structural 5 + propagation residual 9
- 유지한 것: 같은 2-layer mean aggregation GraphSAGE encoder, 같은 edge scorer, 같은 multi-seed 평가 루프
- 검증: 회귀 테스트 23개 통과, 샘플 결과 JSON 재생성, sidecar git commit과 push까지 완료
일부러 이 정도 선에서 멈춘 이유도 있다. concat만으로도 반응이 달라지지 않는다면, 더 복잡한 fusion이나 encoder를 올리는 건 아직 이르다. 반대로 concat 하나만으로 hardest split의 표정이 바뀐다면, 그 안의 어떤 structural 축이 실제로 propagation을 보조하는지부터 더 잘게 보는 편이 다음 단계에 더 도움이 된다.
2. mean AUC와 gap에서 먼저 보인 장면
샘플 그래프를 seeds 5, 7, 11, 13, 17로 다시 돌려 보니 hybrid input의 위치가 꽤 선명했다. 평균 점수만 놓고 보면 propagation-only가 여전히 제일 높다. 그런데 hybrid는 structural-only보다 크게 올라왔고, feature_linear_hybrid도 다시 앞질렀다. 내 눈에는 이게 중요했다. structural summary를 propagation 옆에 붙이는 일이 완전히 헛일은 아니라는 뜻이기 때문이다.
| 모델 | mean test AUC | 표준편차 | mean validation-test gap |
|---|---|---|---|
| graphsage_propagation_residual | 0.7889 | 0.2254 | 0.1667 |
| graphsage_hybrid_residual | 0.7444 | 0.1463 | 0.2111 |
| feature_linear_hybrid | 0.7055 | 0.1286 | 0.2945 |
| graphsage_structural | 0.6167 | 0.2155 | 0.3389 |
Figure 1. mean AUC와 validation-test gap 기준으로 다시 본 structural / propagation / hybrid 입력 비교
hybrid의 평균 AUC가 propagation-only보다 낮다는 사실은 분명하다. 대신 std 0.1463이 propagation-only의 0.2254보다 작다. 이 숫자는 꽤 솔직하다. hybrid가 아직 최고점은 아니지만, 적어도 seed마다 덜 출렁이는 입력판 쪽에는 가까워졌다는 뜻이다. validation-test gap도 propagation-only보다는 조금 크지만, structural-only나 feature_linear_hybrid보다는 확실히 낮다. 그래서 오늘 결과를 한 줄로 적으면 "더 세졌다"보다 "덜 거칠어졌다" 쪽이 더 맞다.
3. hardest split에서는 왜 느낌이 달랐나
평균보다 더 흥미로웠던 건 seed 13이다. 직전까지 이 split은 propagation-only도 structural-only도 같이 미끄러지는 쪽에 가까웠다. 그런데 hybrid를 넣자 여기서 AUC가 0.6389까지 올라왔다. propagation-only의 0.4167, structural-only의 0.3611보다 눈에 띄게 높다. 그러니까 structural summary는 평균 점수표 위에서는 조연처럼 보여도, 어려운 split에서는 propagation residual이 놓치는 방향을 조금 받아 주는 축으로 읽힌다.
| seed | graphsage_structural | graphsage_propagation_residual | graphsage_hybrid_residual | feature_linear_hybrid |
|---|---|---|---|---|
| 5 | 0.5000 | 1.0000 | 0.5278 | 0.6667 |
| 7 | 1.0000 | 0.6389 | 0.7778 | 0.7222 |
| 11 | 0.6667 | 0.9444 | 0.9444 | 0.9444 |
| 13 | 0.3611 | 0.4167 | 0.6389 | 0.5833 |
| 17 | 0.5556 | 0.9444 | 0.8333 | 0.6111 |
Figure 2. seed별로 보면 hybrid 입력은 최고점보다 hardest split 완충 쪽에서 더 눈에 띄었다
이 장면이 내게는 꽤 중요했다. propagation-only는 잘 맞는 split에서는 시원하게 올라가지만, 어려운 split에서는 한 번에 꺼지는 느낌이 있다. hybrid는 최고점은 조금 양보하는 대신, 바닥이 덜 깊어진다. 프로젝트를 오래 끌고 가다 보면 이런 차이가 생각보다 크다. mean AUC가 0.04 정도 낮더라도, 최저점이 덜 무너지는 쪽이 다음 실험판으로는 더 다루기 편할 때가 많다.
4. 지금 단계에서 읽히는 결론
오늘 결과를 보고 내린 결론은 세 가지다. 첫째, propagation residual은 여전히 가장 강한 GraphSAGE 입력이다. 둘째, structural summary는 단독으로는 약하지만 propagation 옆에 붙으면 hardest split에서 완충 역할을 한다. 셋째, 그래서 structural 축은 평균 점수를 끌어올리는 주연이라기보다 representation collapse를 조금 막아 주는 보조축에 더 가깝다.
- mean AUC만 보면 propagation-only가 아직 우위다.
- seed variance와 hardest split을 같이 보면 hybrid가 남기는 신호가 분명히 있다.
- 다음 단계는 encoder 복잡도를 올리기보다, structural 5차원 중 무엇이 실제로 도움이 되는지 다시 좁히는 쪽이 맞다.
나는 이런 결과가 오히려 반갑다. "새 모델이 무조건 더 좋다"는 식으로 끝나는 날보다, 무엇이 평균을 올리고 무엇이 바닥을 받치는지가 분리되는 날이 다음 실험 설계를 훨씬 덜 막히게 만들기 때문이다. 지금은 propagation-only를 이기겠다고 조급하게 layer를 더 쌓을 때가 아니라, hybrid 안에 들어간 structural 요약 중에서 어떤 축이 hardest split에서 실제로 살아 있었는지를 다시 보는 편이 더 자연스럽다.
5. 다음에 바로 해볼 것
다음 단계는 이미 거의 정해졌다. 하나는 더 큰 synthetic graph와 bipartite graph로 옮겨 지금 순서가 유지되는지 보는 것, 다른 하나는 structural 5차원을 통째로 넣지 말고 hardest split에서 실제로 도움 되는 축만 남기는 ablation을 해보는 것이다. 그 다음에야 GCN 계열 encoder를 같은 multi-seed 비교면 위에 올려도 덜 헷갈릴 것 같다.
정리하면 오늘의 수확은 "hybrid가 propagation-only를 이겼다"가 아니다. 대신 hybrid input이 최고점보다 안정성 쪽에 기여한다는 단서가 생겼고, 그래서 다음에 어디를 깎아야 할지가 훨씬 또렷해졌다. 이런 반복은 겉으로 보면 소박한데, 실제로 프로젝트를 앞으로 밀어 주는 건 대체로 이런 날이었다.
'[개발 일기]' 카테고리의 다른 글
| GraphRAG | History 상태 반복 횟수 추가 (0) | 2026.05.01 |
|---|---|
| GraphRAG | History Baseline Guard (1) | 2026.04.25 |
| GNN | Structural mean avg/gap 정리 (0) | 2026.04.13 |
| GNN | Hybrid ablation multi-seed 요약 (0) | 2026.04.11 |
| GNN 프로젝트: Propagation Profile 진단값 추가 (0) | 2026.04.06 |