이 장은 그래프와 ML의 교차점을 다룬다. ML 기법이 기존 지식 그래프를 자동으로 보강하는 법, 그리고 지식 그래프에서 피처를 채굴해 정확한 예측 모델을 만드는 법을 본다. 6장에서 익힌 GDS·Cypher·Python 기술 위에, 지식 그래프를 살찌우는 모델을 만드는 그래프 네이티브 머신러닝을 도구 상자에 추가한다.
ML은 거대한 연구·실무 영역이지만, 가장 추상적인 수준에서는 데이터로부터 프로그램을 도출하는 일이다 — 그리고 지식 그래프는 물론 훌륭한 데이터다. 전통적으로 소프트웨어 대부분은 입력을 받아 함수를 적용해 출력 데이터를 만들도록 작성되었다. 그 함수는 도메인을 깊이 이해하는 전문가 인간이 작성하며, 대개 전문가 팀이 만들고 유지해야 하는 정교한 프로그램이다 — 출력 품질을 유지하려면 모델의 모든 잠재적 엣지 케이스와 세부를 다뤄야 한다.
어떤 모델을 고를지는 전문가의 결정이지만, 그 ML에 지식 그래프를 연료로 공급하는 것은 대개 좋은 선택이다. 그래프와 ML을 통합하는 방식은 두 가지다.
지식 그래프가 시간에 따라 어떻게 진화할지 예측한다. 그래프가 자기 자신 위에서 계산하여 누락된 관계·노드 레이블·속성을 추가할 기회를 찾는다.
지식 그래프에서 피처를 추출해 고품질의 외부 예측 모델을 구축한다. 그래프에는 데이터만이 아니라 위상(topology)이 있으므로 더 많고 대개 더 좋은 피처를 뽑을 수 있다.
어느 방식을 쓰든, ML 모델과 지식 그래프를 둘러싼 시스템은 종종 피드백 루프로 배열된다 — 모델의 사용이 궁극적으로 지식 그래프를 풍요롭게 하고, 그 그래프가 다시 모델을 개선하는 데 쓰인다.
인그래프 머신러닝은 지식 그래프가 자기 자신 위에서 계산하여 스스로를 보강하는 기법들의 모음이다(이 능력은 Neo4j GDS 라이브러리에 들어 있으며 학습 목적으로는 Neo4j Desktop으로 쉽게 설치된다). 그래프 네이티브 ML로는 지식 그래프의 위상과 데이터를 사용하는 알고리즘을 실행해 인사이트를 얻는다.
Neo4j 내장 영화 지식 그래프를 기반으로 즉시 위상적 링크 예측 알고리즘을 돌려 볼 수 있다.
빈 데이터베이스에서 Neo4j Browser를 열고 :play movie graph를 입력하면 영화·배우·
감독의 작은 지식 그래프를 만드는 내장 튜토리얼이 시작된다. Keanu Reeves를 중심으로 그래프를 둘러보면 그가
Matrix 전편 출연을 포함해 바쁜 경력을 보냈음을 알 수 있다(그림 7-1).
현실의 지식 그래프는 불완전하다 — 일부 데이터는 누락되고, 일부는 잘못 다뤄졌고, 일부는 아직 알지도 못한다. 불완전한 지식 그래프도 유용하지만, 데이터 품질을 끌어올리는 도구가 있다면 가치 있다. 위상적 링크 예측을 시연하려면 존재한다고 아는 관계를 지우고, 알고리즘이 그 재생성을 권하는지 지켜보면 된다.
MATCH (:Person {name:'Keanu Reeves'}) -[r:ACTED_IN]-> (:Movie {title:'The Matrix'}) DELETE r
MATCH (Keanu:Person {name:'Keanu Reeves'}) MATCH (TheMatrix:Movie {title:'The Matrix'}) RETURN gds.alpha.linkprediction.preferentialAttachment (Keanu, TheMatrix, {relationshipQuery: "ACTED_IN"}) AS score // → score: 28.0
Keanu Reeves와 The Matrix 사이의 ACTED_IN 관계는 존재 확률이 높아야 한다 — 방금 우리가 지웠으니까! 이는 Barabási와 Albert의 선호적 연결(preferential attachment) 같은 위상적 링크 예측 알고리즘으로 쉽게 검증된다. 실행 결과 점수는 28.0 — 관계가 존재해야 한다는 좋은 신호지만 단정적(emphatic)이지는 않다. 그래프의 성격에 따라 다른 위상적 링크 예측 알고리즘이 점수를 개선할 수 있고, (계산 시간을 대가로) 더 큰 그래프를 쓰는 것도 방법이다. 그러나 또 하나의 탐구 노선은 ML 파이프라인을 훈련·사용해 링크 예측 문제를 푸는 것이다.
ML 파이프라인으로 옮겨 가면 링크 예측(그리고 레이블·속성 예측도)을 잠재적으로 개선할 수 있다. 이를 위해서는 파이프라인이 피처를 추출해 예측 모델을 훈련할 수 있는, 상당히 큰 관련 훈련 데이터 집합이 필요하다.
피처 엔지니어링은 ML 모델 훈련에 쓸 유용한 데이터를 식별하는 활동이다. 전통적으로 피처는 관계형 데이터베이스의 컬럼 — age, gender, postal code 같은 — 에서 왔다. 그래프 피처 엔지니어링은 지식 그래프에서 데이터를 식별·추출해 ML 모델에 통합하는 일이다. 지식 그래프에는 데이터와 함께 위상이 있으므로, 다른 방법보다 더 많고 대개 더 높은 품질의 피처를 추출할 수 있다.
피처는 종종 그래프 알고리즘 실행으로 생성된다 — 각 노드의 PageRank나 커뮤니티를 계산해 피처로 쓰는 식이다. 마찬가지로 노드 임베딩(node embedding)으로 그래프의 위상을 (인간이 읽을 수 없는) 피처로 직접 인코딩할 수도 있다. 어느 쪽이든 ML에 쓸 피처의 수와 품질이 늘어나 더 좋은 성능의 예측 모델로 이어질 수 있다.
전통 ML에서는 상당한 데이터 엔지니어링이 필요할 수 있다. 그러나 Neo4j가 지식 그래프를 호스팅한다면, 약간의 데이터 랭글링만으로 ML 파이프라인을 선언하여 존재하게(declare into existence) 할 수 있다. 링크 예측 파이프라인의 구축은 아홉 단계다 — 본능적으로 많은 수고처럼 보이지만, 필요한 기능이 이미 Neo4j에 내장되어 있으므로 직접 구현하는 것이 아니라 파이프라인의 구성만 선언하면 된다.
기저 지식 그래프에서 프로젝션을 만든다 gds.graph.project
파이프라인을 존재하게 선언한다 gds.beta.pipeline.linkPrediction.create
그래프의 관계에 대한 계산(예: 그래프 알고리즘 실행)의 결과에만 기반한 값을 프로젝션의 노드에 속성으로 추가한다 addNodeProperty
앞 단계의 속성을 결합기(combiner)로 묶어 노드 쌍마다 피처 벡터를 만든다 addFeature
그래프를 서로소(disjoint) 집합으로 나눈다 configureSplit
예: 로지스틱 회귀 addLogisticRegression
머신의 메모리가 충분한지 확인한다 train.estimate
훈련된 모델의 품질을 판단할 평가 지표를 포함해 훈련한다 train + metrics
지표상 충분히 좋다고 판단되면 모델을 프로덕션으로 밀어 넣는다
영화 지식 그래프는 교육용의 작은 그래프지만, 과거에 누구와 함께 일했는지를 근거로 잘 어울릴
배우를 추천하는 예측 모델을 만들기에 충분히 현실적이다. 첫 단계는 약간의 데이터 랭글링이다 — 같은 영화에
출연한 배우 쌍을 매치해 ACTED_WITH 관계로 연결한다(방향은 중요하지 않다).
훈련 전 랭글링은 이것이 전부이며, 보다시피 단순하다.
MATCH (a:Person)-[:ACTED_IN]->(:Movie) <-[:ACTED_IN]-(b:Person) MERGE (a)-[:ACTED_WITH]->(b)
CALL gds.graph.project( 'actors-graph', { Person: {} }, // 노드 레이블 + 속성(없음) { ACTED_WITH: { orientation: 'UNDIRECTED' } } ) CALL gds.beta.pipeline.linkPrediction.create( 'actors-pipeline')
ACTED_WITH로 보강된 그래프는 Browser에서 함께 일한 배우들의 네트워크로 쉽게 시각화된다(그림 7-2). 이제 훈련에 쓸 노드 속성을 생각해야 한다 — 기저 그래프의 기존 속성을 고르거나, 알고리즘 실행으로 새 속성을 만들 수 있다. 여기서는 그림 7-2의 위상 자체가 중요하므로, 위상을 파이프라인의 ML 단계가 읽을 수 있는 노드 속성으로 인코딩해야 한다. 노드의 국소 위상을 수치로 인코딩하는 노드 임베딩 알고리즘이 좋은 선택이다 — GDS에는 Node2Vec, FastRP 등 후보가 몇 가지 있다.
CALL gds.beta.pipeline.linkPrediction.addNodeProperty( 'actors-pipeline', 'fastRP', { mutateProperty: 'embedding', embeddingDimension: 256, randomSeed: 42 }) // 파이프라인 실행 시 각 노드가 위상 내 위치의 // 수치 인코딩으로 보강된다
CALL gds.beta.pipeline.linkPrediction.addFeature( 'actors-pipeline', 'cosine', { nodeProperties: ['embedding'] }) YIELD featureSteps // embedding 속성들의 코사인 유사도 — // 벡터가 충분히 가까우면 연결된 것으로 간주. // 대안: Hadamard product, L2. // 이 소규모 사례에서는 실험 결과 cosine이 최선
링크 피처(link feature)는 노드 쌍을 하나로 묶는 단일 피처로, 위상적 ML의 필수 요소다. 링크 피처 단계는 훈련 시점에도, 모델이 예측하는 프로덕션 시점에도 실행된다. 다음은 예측 모델의 훈련·테스트를 위한 긍정·부정 예제의 공급인데, 이는 도구가 자동화한다 — 사용자는 테스트에 쓸 그래프의 비율과, 테스트 여집합(테스트에 쓰이지 않은 데이터) 중 훈련에 쓸 비율만 지정하면 된다. 직접 튜닝하고 싶지 않으면 이 설정을 생략하고 기본값을 쓰면 된다.
CALL gds.beta.pipeline.linkPrediction.configureSplit( 'actors-pipeline', { testFraction: 0.25, trainFraction: 0.6, validationFolds: 3 })
// 집필 시점의 모델 후보: 로지스틱 회귀 · // 랜덤 포레스트 · 다층 퍼셉트론 CALL gds.beta.pipeline.linkPrediction .addLogisticRegression(actors-pipeline) CALL gds.alpha.pipeline.linkPrediction .configureAutoTuning(actors-pipeline, {maxTrials: 100}) // maxTrials = 최적 매개변수 선택 전 모델당 // 최대 튜닝 반복 횟수. 이 규모에선 계산 시간이 // 무시할 수준이지만, 큰 파이프라인에서는 // 반복당 수 분이 걸릴 수 있다
파이프라인은 이제 훈련 준비가 되었다. 다만 프로덕션 규모의 데이터셋으로 훈련하기 전에, 훈련 메모리 요구량을 확인하고 필요하면 메모리가 충분한 머신에서 훈련하는 것이 좋다 — 이 역시 단순한 프로시저 호출이다.
CALL gds.beta.pipeline.linkPrediction.train.estimate( 'actors-graph', { pipeline: 'actors', modelName: 'actors-model', targetRelationshipType: 'ACTED_WITH' }) YIELD requiredMemory
CALL gds.beta.pipeline.linkPrediction.train( 'actors-graph', { pipeline: 'actors-pipeline', modelName: 'actors-model', metrics: ['AUCPR'], targetRelationshipType: 'ACTED_WITH', randomSeed: 73 }) YIELD modelInfo, modelSelectionStats RETURN modelInfo.bestParameters AS winningModel, modelInfo.metrics.AUCPR.train.avg AS avgTrainScore, modelInfo.metrics.AUCPR.outerTrain AS outerTrainScore, modelInfo.metrics.AUCPR.test AS testScore, [cand IN modelSelectionStats.modelCandidates | cand.metrics.AUCPR.validation.avg] AS validationScores
Example 7-9는 앞서 제공한 구성으로 파이프라인을 인스턴스화하고 훈련 국면을 실행하여 actors-model이라는 모델을 산출한다. 훈련 국면에 대한 지표들도 함께 산출되어, 데이터 과학자가 모델 품질을 추론하는 데 쓸 수 있다.
훈련된 모델로 예측을 하려면, 모델이 실행될 그래프 프로젝션을 공급하는 데서 출발한다. 입력 그래프
actors-input-graph-for-prediction은 원본 영화 그래프에 약간의 교란 — 합성 배우 몇
명 추가와 ACTED_IN 관계 몇 개 삭제라는 단순한 Cypher 문장 — 을 가한 것이다. 프로덕션 시나리오라면
실제 지식 그래프를 대신 쓰면 된다.
CALL gds.graph.project( 'actors-input-graph-for-prediction', { Person: {} }, { ACTED_WITH: { orientation: 'UNDIRECTED' } } )
CALL gds.beta.pipeline.linkPrediction.predict.mutate( 'actors-input-graph-for-prediction', { modelName: 'actors-model', relationshipTypes: ['ACTED_WITH'], mutateRelationshipType: 'SHOULD_ACT_WITH', topN: 20, threshold: 0.4 }) YIELD relationshipsWritten, samplingStats
매개변수는 자명한 편이다 — 입력 그래프 프로젝션, Example 7-9가 산출한 훈련 모델
actors-model, 처리 대상을 ACTED_WITH로 한정하는
relationshipTypes, 확신 수준을 충족하면 프로젝션에
SHOULD_ACT_WITH 관계를 되쓰는 mutateRelationshipType,
필요한 추천 수 topN, 그리고 그 아래로는 추천을 폐기하는 확신 수준
threshold다. 여기서는 임계값이 낮다 — 즉각적인 인간 최종 사용자(배역
캐스팅 담당자)가 있는 소규모 문제이기 때문이다. 실제 프로덕션 시스템은 저품질 예측이 과다 생산되는 것을
막기 위해 더 높은 임계값을 쓸 가능성이 크다.
모델의 추천을 영속화하고 싶지 않다면 그러지 않아도 된다.
predict.mutate를 predict.stream으로 바꾸고
mutateRelationshipType 매개변수를 빼면, 결과가 프로젝션을 보강하지 않고 사용자에게 직접 스트리밍된다.
Example 7-11 실행 후에는 보강된 프로젝션만 남고, 추천은 아직 지식 그래프에 쓰이지 않았다. 영속화하려면 프로젝션에서 SHOULD_ACT_WITH 관계를 스트리밍한 뒤, 스트리밍된 관계의 소스·타깃 ID를 Cypher로 받아 기저 지식 그래프에 MERGE한다.
CALL gds.beta.graph.relationships.stream( 'actors-input-graph-for-prediction', ['SHOULD_ACT_WITH'] ) YIELD sourceNodeId, targetNodeId WITH gds.util.asNode(sourceNodeId) AS source, gds.util.asNode(targetNodeId) AS target MERGE(source)-[:SHOULD_ACT_WITH]->(target)
// SHOULD_ACT_WITH는 대칭이므로 쌍방 중 하나면 충분 MATCH (a:Person)-[:SHOULD_ACT_WITH]->(b:Person) -[d:SHOULD_ACT_WITH]->(a) // a가 먼저, b가 나중에 매치되어 모든 관계가 // 지워지는 것을 방지 WHERE id(a) > id(b) DELETE d // 보강 완료 — 추천 조회는 단순한 Cypher면 된다 MATCH (a:Person)-[:SHOULD_ACT_WITH]->(b:Person) RETURN a.name, b.name
| # | a.name | b.name |
|---|---|---|
| 0–4 | Naomie Harris | Emile Hirsch · John Goodman · Susan Sarandon · Matthew Fox · Christina Ricci |
| 5–10 | Danny DeVito | Demi Moore · Noah Wyle · Kevin Pollak · James Marshall · Christopher Guest · Aaron Sorkin |
| 11–16 | John C. Reilly | Demi Moore · Noah Wyle · Kevin Pollak · James Marshall · Christopher Guest · Aaron Sorkin |
| 17 | Ed Harris | Sam Rockwell |
| 18 | Lori Petty | Julia Roberts |
추천이 지식 그래프에 영속화되었으므로 — ML이 만든 것임에도 — 재사용하고 다른 질의와 결합할 수 있다. 사용 사례의 요구에 따라 데이터를 신선하게 유지하려면 이 과정을 주기적으로(시간·일·월 단위) 반복해야 한다. 그리고 이것은 출발점일 뿐이다 — 진짜 시간은 모델의 매개변수, 특히 속성·피처·평가 지표의 최적화에 쓰인다. 오토 ML이 도울 수 있지만, 인공 지능을 부트스트랩하는 데는 여전히 인간 지능이 필요하다!
인그래프 ML 파이프라인의 범위가 부족하면 언제든 TensorFlow, PyTorch, scikit-learn 같은 외부 도구나 Google Vertex AI, Amazon SageMaker, Microsoft Azure Machine Learning 같은 클라우드 호스팅 시스템으로 물러설 수 있다. 두 영역 사이의 다리는 지식 그래프에서 추출한 피처 벡터 집합으로, 외부 호스팅 모델의 훈련·테스트 입력이 된다. (자동이든 수동이든) 실험과 반복을 통해 이 도구·플랫폼들의 더 큰 깊이로 더 나은 ML 모델을 만들 수 있을지 모른다 — 다만 구현 복잡도, 특히 외부 시스템의 결과로 지식 그래프를 보강하는 일의 복잡도가 대가다.
책의 이 지점에서, 지식 그래프 구축에 유능해지기에 충분한 기술적 세부를 다뤘다. 지식 그래프의 생성과 질의부터 그래프 알고리즘의 적용, 그리고 마지막으로 그래프 ML로 데이터를 보강하는 것까지 — 상당한 기초 기술을 소화했다. 여기까지 온 것은 결코 작은 일이 아니다. 이제부터는 기술적 역량을 구체적인 지식 그래프 사용 사례에 적용한다.
ML은 책임의 역전이다. 데이터와 과거 출력이 입력이 되고 프로그램(모델)이 출력이 된다. 그래프×ML의 두 통합 방식 — 인그래프 ML(그래프 진화 예측)과 그래프 피처 엔지니어링(외부 모델용 피처) — 은 피드백 루프로 서로를 강화한다.
위상적 링크 예측은 즉시 실행 가능하다. 지운 Keanu–Matrix 관계에 선호적 연결(Barabási-Albert)이 28.0을 주었다 — 좋은 신호지만 단정적이지 않다. 개선 경로는 다른 알고리즘, 더 큰 그래프, 그리고 ML 파이프라인이다.
파이프라인은 구현이 아니라 선언이다. 프로젝션 → 파이프라인 생성 → FastRP 임베딩(addNodeProperty) → cosine 링크 피처(addFeature) → 분할 → 모델 후보(로지스틱 회귀 등 3종) + 오토 튜닝 → 메모리 추정 → AUCPR 훈련 → 프로덕션의 9단계가 모두 프로시저 호출이다.
mutate → stream → MERGE의 영속화 동선. predict.mutate는 프로젝션만 보강하므로, relationships.stream으로 꺼내 기저 그래프에 MERGE하고 대칭 중복을 정규화한다. 임계값은 사용 맥락(인간 사용자 vs 자동 시스템)이 결정한다.
인간 지능이 인공 지능을 부트스트랩한다. 진짜 시간은 속성·피처·지표 최적화에 들며, 주기적 재실행으로 신선도를 유지한다. 인그래프 범위가 부족하면 피처 벡터를 다리 삼아 TensorFlow/PyTorch/scikit-learn이나 Vertex AI/SageMaker/Azure ML로 확장한다.
여기서부터는 기술 역량을 구체적 사용 사례에 적용한다. 첫 번째는 엔터프라이즈 데이터의 지도 그리기 — 데이터의 형태와 위치, 처리 시스템, 소비자를 기록하고 연결하여 데이터의 계보(provenance)를 명시적으로 만드는 메타데이터 지식 그래프(8장, Mapping Data with Metadata Knowledge Graphs)다.