A method to convert any text corpus into a Knowledge Graph using Mistral 7B
https://towardsdatascience.com/how-to-convert-any-text-into-a-graph-of-concepts-110844f22a1a
몇 달 전만 해도 지식 기반 질의응답(KBQA)은 생소했습니다. 이제 검색 증강 생성(RAG)이 포함된 KBQA는 모든 AI 애호가에게 식은 죽 먹기입니다. LLM으로 인해 자연어 처리의 가능성의 영역이 이렇게 빠르게 확장된 것을 보는 것은 매우 흥미롭습니다. 그리고 날이 갈수록 더 좋아지고 있습니다.
지난 글에서는 대규모 텍스트 코퍼스를 기반으로 복잡한 쿼리에 답하기 위해 멀티홉 추론으로 QnA를 구현하는 재귀적 RAG 접근 방식을 공유했습니다.
많은 분들이 직접 사용해보고 피드백을 보내주셨습니다. 피드백을 보내주신 모든 분들께 감사드립니다. 이후 이러한 의견을 취합하고 원래 구현의 몇 가지 문제를 해결하기 위해 코드를 몇 가지 개선했습니다. 이에 대해서는 별도의 글을 작성할 계획입니다.
이 글에서는 재귀적 RAG와 결합했을 때 슈퍼 리서치 에이전트를 만드는 데 도움이 될 수 있는 또 다른 아이디어를 공유하고자 합니다. 이 아이디어는 더 작은 LLM을 사용한 재귀적 RAG 실험과 Medium에서 읽은 몇 가지 다른 아이디어, 특히 지식 그래프 증강 세대라는 아이디어에서 떠올랐습니다.
요약
지식 그래프(KG) 또는 모든 그래프는 노드와 에지로 구성됩니다. KG의 각 노드는 개념을 나타내고 각 에지는 이러한 개념 쌍 사이의 관계를 나타냅니다. 이 글에서는 텍스트 코퍼스를 개념 그래프로 변환하는 방법을 공유하겠습니다. 저는 여기서 데모하는 내용을 더 잘 설명하기 위해 '개념 그래프'(GC)라는 용어를 KG라는 용어와 혼용해서 사용하고 있습니다.
이 구현에 사용한 모든 구성 요소는 로컬에서 설정할 수 있으므로 이 프로젝트는 개인용 컴퓨터에서 쉽게 실행할 수 있습니다. 저는 소규모 오픈 소스 모델을 믿기 때문에 여기서는 무-GPT 접근 방식을 채택했습니다. 저는 환상적인 Mistral 7B Openorca instruct와 Zephyr 모델을 사용하고 있습니다. 이 모델들은 Ollama로 로컬에서 설정할 수 있습니다.
Neo4j와 같은 데이터베이스를 사용하면 그래프 데이터를 쉽게 저장하고 검색할 수 있습니다. 여기서는 간단하게 하기 위해 인메모리 Pandas 데이터 프레임과 NetworkX Python 라이브러리를 사용하고 있습니다.
여기서 우리의 목표는 모든 텍스트 코퍼스를 개념 그래프(GC)로 변환하여 이 글의 멋진 배너 이미지처럼 시각화하는 것입니다. 노드와 에지를 이동하고, 확대 및 축소하고, 그래프의 물리학을 원하는 대로 변경하여 네트워크 그래프와 상호 작용할 수도 있습니다. 다음은 우리가 만들고 있는 결과물을 보여주는 Github 페이지 링크입니다.
하지만 먼저 KG의 기본 개념과 왜 필요한지 자세히 알아봅시다. 이 개념에 이미 익숙하다면 다음 섹션을 건너뛰셔도 됩니다
Knowledge Graph
다음 텍스트를 살펴보세요.
마리아에게 어린 양 한 마리가 있었습니다,
여러분은 이 이야기를 들어본 적이 있을 것입니다;
하지만 그녀가 접시를 넘겼다는 사실을 알고 계셨나요?
그리고 조금 더 먹었죠!
(아이들이 이 글을 읽지 않았으면 좋겠어요 😝)
다음은 텍스트를 KG로 표현할 수 있는 한 가지 방법입니다.
IBM의 다음 문서에서 지식 그래프의 기본 개념을 적절하게 설명합니다.
기사에서 발췌한 내용을 인용하여 아이디어를 요약합니다:
시맨틱 네트워크라고도 하는 지식 그래프는 사물, 이벤트, 상황 또는 개념과 같은 실제 실체의 네트워크를 나타내며 이들 간의 관계를 보여줍니다. 이 정보는 일반적으로 그래프 데이터베이스에 저장되고 그래프 구조로 시각화되어 지식 "그래프"라는 용어로 불립니다.
Why Knowledge Graph?
지식 그래프는 다양한 방식으로 유용합니다. 그래프 알고리즘을 실행하고 모든 노드의 중심성을 계산하여 개념(노드)이 업무에서 얼마나 중요한지 파악할 수 있습니다. 연결 및 단절된 개념 집합을 분석하거나 개념의 커뮤니티를 계산하여 주제에 대한 심층적인 이해를 도모할 수 있습니다. 단절된 것처럼 보이는 개념 사이의 연결 고리를 이해할 수 있습니다.
또한 지식 그래프를 사용해 그래프 검색 증강 생성(GRAG 또는 GAG)을 구현하고 문서와 채팅할 수 있습니다. 이렇게 하면 몇 가지 단점이 있는 기존 RAG 버전보다 훨씬 더 나은 결과를 얻을 수 있습니다. 예를 들어, 단순한 의미론적 유사성 검색으로 쿼리와 가장 관련성이 높은 문맥을 검색하는 것이 항상 효과적인 것은 아닙니다. 특히 쿼리의 실제 의도에 대한 충분한 컨텍스트가 제공되지 않거나 컨텍스트가 대규모 텍스트 코퍼스에서 단편적인 경우 더욱 그렇습니다.
예를 들어 다음 질문을 생각해 보세요.
'백 년의 고독'이라는 책에 나오는 호세 아르카디오 부엔디아의 가계도에 대해 말해 주세요.
이 책에는 호세 아르카디오 부엔디아의 7대에 걸친 가계도가 기록되어 있으며, 등장인물의 절반이 호세 아르카디오 부엔디아라는 이름을 가지고 있습니다. 간단한 RAG 파이프라인을 사용하여 쿼리에 답하는 것은 가능하더라도 상당히 어려울 것입니다.
RAG의 또 다른 단점은 무엇을 질문해야 하는지 알려주지 못한다는 것입니다. 답을 얻는 것보다 올바른 질문을 하는 것이 더 중요한 경우가 많습니다.
그래프 증강 생성(GAG)은 이러한 RAG의 단점을 어느 정도 해결할 수 있습니다. 더 좋은 점은 그래프 증강 검색 증강 생성 파이프라인을 혼합하여 구축함으로써 두 가지 장점을 모두 얻을 수 있다는 것입니다.
이제 그래프가 흥미롭고 매우 유용할 뿐만 아니라 보기에도 아름답다는 것을 알게 되었습니다.
Creating the Graph of Concepts
- 주어진 텍스트로부터 지식 그래프를 만드는 방법을 GPT에 묻는다면 다음과 같은 프로세스를 제안할 수 있습니다.
- 본문에서 개념과 개체를 추출합니다. 이것이 노드입니다.
- 개념 간의 관계를 추출합니다. 이것이 에지입니다.
- 그래프 데이터 구조 또는 그래프 데이터베이스에 노드(개념)와 에지(관계)를 채웁니다.
- 예술적 만족감을 위해 시각화합니다.
- 3단계와 4단계는 이해할 수 있을 것 같습니다. 하지만 1단계와 2단계는 어떻게 달성할 수 있을까요?
다음은 주어진 텍스트 코퍼스에서 개념 그래프를 추출하기 위해 제가 고안한 방법의 흐름도입니다. 위의 방법과 비슷하지만 몇 가지 사소한 차이점이 있습니다.
텍스트 코퍼스를 청크로 분할합니다. 각 청크에 chunk_id를 할당합니다.
모든 텍스트 청크에 대해 LLM을 사용하여 개념과 그 의미 관계를 추출합니다. 이 관계에 가중치 W1을 할당해 보겠습니다. 동일한 개념 쌍 사이에는 여러 개의 관계가 있을 수 있습니다. 이러한 모든 관계는 한 쌍의 개념 사이의 에지입니다.
동일한 텍스트 청크에서 발생하는 개념은 문맥적 근접성에 의해서도 관련되어 있다고 생각해 보세요. 이 관계에 가중치 W2를 할당해 보겠습니다. 동일한 개념 쌍이 여러 청크에 나타날 수 있다는 점에 유의하세요.
유사한 쌍을 그룹화하고 가중치를 합산한 다음 관계를 연결합니다. 이제 서로 다른 개념 쌍 사이에는 하나의 에지만 있습니다. 이 에지에는 특정 가중치와 관계 목록이 이름으로 지정됩니다.
이 방법의 구현은 이 글에서 공유한 GitHub 리포지토리에서 Python 코드로 확인할 수 있습니다. 다음 몇 섹션에서 구현의 핵심 아이디어를 간략하게 살펴보겠습니다.
여기서는 이 방법을 시연하기 위해 크리에이티브 커먼즈 저작자표시 라이선스 조건에 따라 PubMed/Cureus에 게시된 다음 리뷰 기사를 사용하고 있습니다. 이 글의 끝에는 저자에 대한 크레딧이 나와 있습니다.
The Mistral and the Prompt
이 모델들은 모두 시스템 프롬프트와 사용자 프롬프트가 있는 명령어 조정 모델입니다. 이 모델들은 모두 지시를 잘 따르고 우리가 지시하면 대답을 JSON으로 깔끔하게 형식화하는 데 꽤 능숙합니다.
몇 차례의 히트와 시험 끝에 마침내 다음과 같은 프롬프트가 있는 Zephyr 모델로 수렴했습니다.
SYS_PROMPT = (
"You are a network graph maker who extracts terms and their relations from a given context. "
"You are provided with a context chunk (delimited by ```) Your task is to extract the ontology "
"of terms mentioned in the given context. These terms should represent the key concepts as per the context. \n"
"Thought 1: While traversing through each sentence, Think about the key terms mentioned in it.\n"
"\tTerms may include object, entity, location, organization, person, \n"
"\tcondition, acronym, documents, service, concept, etc.\n"
"\tTerms should be as atomistic as possible\n\n"
"Thought 2: Think about how these terms can have one on one relation with other terms.\n"
"\tTerms that are mentioned in the same sentence or the same paragraph are typically related to each other.\n"
"\tTerms can be related to many other terms\n\n"
"Thought 3: Find out the relation between each such related pair of terms. \n\n"
"Format your output as a list of json. Each element of the list contains a pair of terms"
"and the relation between them, like the follwing: \n"
"[\n"
" {\n"
' "node_1": "A concept from extracted ontology",\n'
' "node_2": "A related concept from extracted ontology",\n'
' "edge": "relationship between the two concepts, node_1 and node_2 in one or two sentences"\n'
" }, {...}\n"
"]"
)
USER_PROMPT = f"context: ```{input}``` \n\n output: "
If we pass our (not fit for) nursery rhyme with this prompt, here is the result.
[
{
"node_1": "Mary",
"node_2": "lamb",
"edge": "owned by"
},
{
"node_1": "plate",
"node_2": "food",
"edge": "contained"
}, . . .
]
텍스트 청크에 명시적으로 언급되지 않은 '음식'을 개념으로 추측한 것도 주목할 만합니다. 정말 놀랍지 않나요!
예제 기사의 모든 텍스트 청크에 대해 이 작업을 실행하고 json을 Pandas 데이터 프레임으로 변환하면 다음과 같이 표시됩니다.
여기서 모든 행은 한 쌍의 개념 간의 관계를 나타냅니다. 각 행은 그래프에서 두 노드 사이의 에지이며, 동일한 개념 쌍 사이에는 여러 개의 에지 또는 관계가 있을 수 있습니다. 위 데이터 프레임의 개수는 제가 임의로 4로 설정한 가중치입니다.
Contextual Proximity
텍스트 말뭉치에서 서로 가깝게 나타나는 개념은 서로 연관되어 있다고 가정합니다. 이 관계를 '문맥적 근접성'이라고 부르겠습니다.
문맥 근접성 에지를 계산하기 위해 데이터 프레임을 녹여 node_1과 node_2가 하나의 열로 축소되도록 합니다. 그런 다음 chunk_id를 키로 사용하여 이 데이터프레임의 자체 조인을 생성합니다. 따라서 동일한 chunk_id를 가진 노드는 서로 쌍을 이루어 행을 형성합니다.
그러나 이것은 또한 각 개념이 그 자체와도 쌍을 이룬다는 것을 의미합니다. 이를 셀프 루프라고 하며, 에지는 동일한 노드에서 시작하고 끝납니다. 이러한 자체 루프를 제거하기 위해 데이터 프레임에서 node_1이 node_2와 동일한 모든 행을 삭제합니다.
In the end, we get a dataframe very similar to our original dataframe.
여기서 count 열은 node_1과 node_2가 함께 발생하는 청크의 수입니다. chunk_id 열은 이러한 모든 청크의 목록입니다.
이제 우리는 텍스트에 언급된 개념들 사이의 의미론적 관계와 문맥적 근접 관계를 가진 두 개의 데이터 프레임을 갖게 되었습니다. 이를 결합하여 네트워크 그래프 데이터 프레임을 구성할 수 있습니다.
이제 텍스트에 대한 개념 그래프 구축이 끝났습니다. 하지만 이 시점에서 끝내는 것은 상당히 불만족스러운 작업이 될 것입니다. 우리의 목표는 이 글의 시작 부분에 있는 추천 이미지와 같은 그래프를 시각화하는 것이며, 목표에 얼마 남지 않았습니다.
Creating a Network of Concepts
NetworkX는 그래프를 매우 쉽게 다룰 수 있는 Python 라이브러리입니다. 아직 이 라이브러리에 익숙하지 않다면 아래 로고를 클릭하여 자세히 알아보세요.
Adding our dataframe to a NetworkX graph is just a few lines of code.
G = nx.Graph()
## Add nodes to the graph
for node in nodes:
G.add_node(str(node))
## Add edges to the graph
for index, row in dfg.iterrows():
G.add_edge(
str(row["node_1"]),
str(row["node_2"]),
title=row["edge"],
weight=row['count']
)
This is where we can start harnessing the power of Network Graph. NetworkX provides a plethora of network algorithms out of the box for us to use. Here is a link to the list of algorithms we can run on our Graph.
여기서는 커뮤니티 감지 알고리즘을 사용하여 노드에 색상을 추가합니다. 커뮤니티는 그래프의 나머지 부분보다 서로 더 긴밀하게 연결된 노드 그룹입니다. 개념 커뮤니티는 본문에서 논의된 광범위한 주제에 대한 좋은 아이디어를 제공할 수 있습니다.
지르반 뉴먼 알고리즘은 우리가 작업 중인 리뷰 글에서 17개의 개념 커뮤니티를 감지했습니다. 다음은 그러한 커뮤니티 중 하나입니다.
[
'digital technology',
'EVIN',
'medical devices',
'online training management information systems',
'wearable, trackable technology'
]
이를 통해 검토 논문에서 논의된 광범위한 건강 기술 주제에 대한 아이디어를 즉시 얻을 수 있으며, RAG 파이프라인으로 답변할 수 있는 질문을 할 수 있습니다. 대단하지 않나요?
그래프에서 각 개념의 정도도 계산해 보겠습니다. 노드의 차수는 노드와 연결된 에지의 총 개수입니다. 따라서 이 경우 개념의 차수가 높을수록 텍스트의 주제에 더 중심이 되는 개념입니다. 이 차수를 시각화에서 노드의 크기로 사용하겠습니다.
Graph Visualisation
시각화는 이 연습에서 가장 재미있는 부분입니다. 시각화에는 예술적 만족감을 주는 특정 품질이 있습니다.
저는 대화형 그래프를 만들기 위해 PiVis 라이브러리를 사용하고 있습니다. 파이비스는 네트워크를 시각화하기 위한 Python 라이브러리입니다. 다음은 이 라이브러리의 편리함과 강력한 성능을 보여주는 미디엄 기사입니다.
파이비스에는 NetworkX 그래프를 파이비스 오브젝트로 변환하는 NetworkX 헬퍼가 내장되어 있습니다. 따라서 더 이상 코딩할 필요가 없습니다.... 야호!!
우리는 이미 에지의 두께에 대한 각 에지의 가중치, 색상에 대한 노드의 커뮤니티, 크기에 대한 각 노드의 정도를 계산했음을 기억하세요.
이 모든 과정을 거쳐 완성한 그래프는 다음과 같습니다.
대화형 그래프 링크: https://rahulnyk.github.io/knowledge_graph/
원하는 대로 확대 및 축소하고 노드와 가장자리를 이동할 수 있습니다. 또한 페이지 하단에 슬라이더 패널이 있어 그래프의 물리학을 변경할 수 있습니다. 그래프가 어떻게 올바른 질문을 하고 주제를 더 잘 이해하는 데 도움이 되는지 살펴보세요!
그래프가 어떻게 그래프 증강 검색을 구축하는 데 도움이 되는지, 그리고 그래프가 어떻게 더 나은 RAG 파이프라인을 구축하는 데 도움이 되는지에 대해 더 논의할 수 있습니다. 하지만 다음 기회로 미루는 것이 좋을 것 같습니다. 이 글의 목표는 이미 달성했으니까요!
기여와 제안을 환영합니다.
제 코드의 데모에는 다음 문서를 사용했습니다.
Saxena S G, Godfrey T (2023년 6월 11일) 의료 분야의 인적 자원 문제를 해결할 수 있는 인도의 기회. 큐레우스 15(6): e40274. DOI 10.7759/cureus.40274
훌륭한 저작물을 크리에이티브 커먼즈 저작자표시 라이선스에 따라 공개해 주신 저자분들께 감사드립니다.
About me
I am a learner of architecture (not the buildings… the tech kind). In the past, I have worked with Semiconductor modelling, Digital circuit design, Electronic Interface modelling, and the Internet of Things. Currently, I am working with Data Interoperability and data warehouse architectures for Health and Wellness, at Walmart Health and Wellness.
댓글