Die Erstellung von Wissensgraphen aus Texten ist schon seit einiger Zeit ein faszinierendes Forschungsgebiet. Mit dem Aufkommen großer Sprachmodelle (LLMs) hat dieses Feld mehr Aufmerksamkeit in der breiten Öffentlichkeit erlangt. Allerdings können LLMs recht kostspielig sein. Ein alternativer Ansatz besteht darin, kleinere Modelle zu optimieren, was durch akademische Forschung unterstützt wird und zu effizienteren Lösungen führt. Heute werden wir Relik erkunden, ein Framework zum Ausführen blitzschneller und leichtgewichtiger Informationsextraktionsmodelle, das von der NLP-Gruppe der Sapienza-Universität in Rom entwickelt wurde.
Eine typische Informationsextraktionspipeline ohne LLM sieht wie folgt aus:
Das Bild zeigt eine Informationsextraktionspipeline, die mit Eingabedaten beginnt, die aus dem Text „Tomaz schreibt gern Blogbeiträge. Er ist besonders daran interessiert, Diagramme zu zeichnen“ bestehen. Der Prozess beginnt mit der Koreferenzauflösung, um „Tomaz“ und „Er“ als dieselbe Entität zu identifizieren. Die benannte Entitätserkennung (Named Entity Recognition, NER) identifiziert dann Entitäten wie „Tomaz“, „Blog“ und „Diagramm“.
Entity Linking ist der Prozess, der auf NER folgt, bei dem erkannte Entitäten entsprechenden Einträgen in einer Datenbank oder Wissensdatenbank zugeordnet werden. Beispielsweise ist „Tomaz“ mit „Tomaz Bratanic (Q12345)“ und „Blog“ mit „Blog (Q321)“ verknüpft, aber „Diagram“ hat keine Entsprechung in der Wissensdatenbank.
Die Extraktion von Beziehungen ist der nächste Schritt, bei dem das System sinnvolle Beziehungen zwischen den erkannten Entitäten identifiziert und extrahiert. Dieses Beispiel zeigt, dass „Tomaz“ eine Beziehung zu „Blog“ hat, die durch „SCHREIBT“ gekennzeichnet ist, was darauf hinweist, dass Tomaz Blogs schreibt. Darüber hinaus zeigt es, dass „Tomaz“ eine Beziehung zu „Diagramm“ hat, die durch „INTERESSIERT_AN“ gekennzeichnet ist, was darauf hinweist, dass Tomaz an Diagrammen interessiert ist.
Schließlich werden diese strukturierten Informationen, einschließlich der Entitäten und ihrer Beziehungen, in einem Wissensgraphen gespeichert, sodass organisierte und zugängliche Daten für weitere Analysen oder Abrufe bereitgestellt werden.
Traditionell, ohne die Leistungsfähigkeit von LLMs, basiert dieser gesamte Prozess auf einer Reihe spezialisierter Modelle, von denen jedes eine bestimmte Aufgabe von der Koreferenzauflösung bis zur Beziehungsextraktion übernimmt. Die Integration dieser Modelle erfordert zwar mehr Aufwand und Koordination, bietet aber einen erheblichen Vorteil: geringere Kosten. Durch die Feinabstimmung kleinerer, aufgabenspezifischer Modelle können die Gesamtkosten für den Aufbau und die Wartung des Systems in Grenzen gehalten werden.
Der Code ist auf GitHub verfügbar.
Ich schlage vor, dass Sie eine separate Python-Umgebung wie Google Colab verwenden, da wir ein wenig mit Abhängigkeiten herumspielen müssen. Die Modelle sind auf GPU schneller, sodass Sie eine GPU-gestützte Laufzeit verwenden können, wenn Sie die Pro-Version haben.
Zusätzlich müssen wir Neo4j, eine native Graphdatenbank, einrichten, um die extrahierten Informationen zu speichern. Es gibt viele Möglichkeiten, Ihre Datenbankinstanz einzurichten . Ich empfehle jedoch die Verwendung von Neo4j Aura , das eine kostenlose Cloud-Instanz bereitstellt, auf die problemlos von einem Google Colab-Notebook aus zugegriffen werden kann.
Neo4j Aura – Vollständig verwaltete Cloud-Lösung
Nachdem die Datenbank erstellt wurde, können wir mit LlamaIndex eine Verbindung definieren:
from llama_index.graph_stores.neo4j import Neo4jPGStore username="neo4j" password="rubber-cuffs-radiator" url="bolt://54.89.19.156:7687" graph_store = Neo4jPGStore( username=username, password=password, url=url, refresh_schema=False )
Wir werden einen Nachrichtendatensatz verwenden, den ich vor einiger Zeit über die Diffbot-API erhalten habe. Der Datensatz ist bequem auf GitHub verfügbar, damit wir ihn wiederverwenden können:
import pandas as pd NUMBER_OF_ARTICLES = 100 news = pd.read_csv( "https://raw.githubusercontent.com/tomasonjo/blog-datasets/main/news_articles.csv" ) news = news.head(NUMBER_OF_ARTICLES)
Der erste Schritt in der Pipeline ist ein Koreferenzauflösungsmodell. Bei der Koreferenzauflösung geht es darum, alle Ausdrücke in einem Text zu identifizieren, die auf dieselbe Entität verweisen.
Meines Wissens sind nicht viele Open-Source-Modelle für die Koreferenzauflösung verfügbar. Ich habe maverick-coref ausprobiert, aber in meinen Tests hat Coreferee von spaCy besser funktioniert, also werden wir das verwenden. Der einzige Nachteil bei der Verwendung von Coreferee ist, dass wir uns mit der Abhängigkeitshölle herumschlagen müssen, die im Notebook gelöst ist, aber wir werden hier nicht darauf eingehen.
Sie können das Koreferenzmodell in spaCy mit dem folgenden Code laden:
import spacy, coreferee coref_nlp = spacy.load('en_core_web_lg') coref_nlp.add_pipe('coreferee')
Das Coreferee-Modell erkennt Ausdruckscluster, die sich auf dieselbe Entität oder dieselben Entitäten beziehen. Um den Text basierend auf diesen Clustern neu zu schreiben, müssen wir unsere eigene Funktion implementieren:
def coref_text(text): coref_doc = coref_nlp(text) resolved_text = "" for token in coref_doc: repres = coref_doc._.coref_chains.resolve(token) if repres: resolved_text += " " + " and ".join( [ t.text if t.ent_type_ == "" else [e.text for e in coref_doc.ents if t in e][0] for t in repres ] ) else: resolved_text += " " + token.text return resolved_text
Testen wir die Funktion, um sicherzustellen, dass die Modelle und Abhängigkeiten richtig eingerichtet sind:
print( coref_text("Tomaz is so cool. He can solve various Python dependencies and not cry") ) # Tomaz is so cool . Tomaz can solve various Python dependencies and not cry
In diesem Beispiel hat das Modell erkannt, dass „Tomaz“ und „Er“ sich auf dieselbe Entität beziehen. Mithilfe der coref_text-Funktion ersetzen wir „Er“ durch „Tomaz“.
Beachten Sie, dass das Umschreiben aufgrund der Verwendung einer einfachen Ersetzungslogik für Entitäten innerhalb des Clusters nicht immer grammatikalisch korrekte Sätze zurückgibt. Für die meisten Szenarien sollte dies jedoch ausreichend sein.
Nun wenden wir die Koreferenzauflösung auf unseren Nachrichtendatensatz an und verpacken die Ergebnisse als LlamaIndex-Dokumente:
from llama_index.core import Document news["coref_text"] = news["text"].apply(coref_text) documents = [ Document(text=f"{row['title']}: {row['coref_text']}") for i, row in news.iterrows() ]
Relik ist eine Bibliothek mit Modellen für Entity Linking (EL) und Relationship Extraction (RE) und unterstützt auch Modelle, die beides kombinieren. Beim Entity Linking wird Wikipedia als Zielwissensbasis verwendet, um Entitäten im Text ihren entsprechenden Einträgen in der Enzyklopädie zuzuordnen.
Bei der Beziehungsextraktion hingegen geht es darum, die Beziehungen zwischen Entitäten innerhalb eines Textes zu identifizieren und zu kategorisieren, wodurch die Extraktion strukturierter Informationen aus unstrukturierten Daten ermöglicht wird.
Wenn Sie eine kostenlose Colab-Version verwenden, verwenden Sie das Modell relik-ie/relik-relation-extraction-small, das nur Beziehungsextraktion durchführt. Wenn Sie eine Pro-Version haben oder diese auf einem leistungsstärkeren lokalen Computer verwenden, können Sie das Modell relik-ie/relik-cie-small testen, das Entitätsverknüpfung und Beziehungsextraktion durchführt.
from llama_index.extractors.relik.base import RelikPathExtractor relik = RelikPathExtractor( model="relik-ie/relik-relation-extraction-small" ) # Use on Pro Collab with GPU # relik = RelikPathExtractor( # model="relik-ie/relik-cie-small", model_config={"skip_metadata": True, "device":"cuda"} # )
Zusätzlich müssen wir das Einbettungsmodell definieren, das zum Einbetten von Entitäten und des LLM für den Frage-Antwort-Fluss verwendet wird:
import os from llama_index.embeddings.openai import OpenAIEmbedding from llama_index.llms.openai import OpenAI os.environ["OPENAI_API_KEY"] = "sk-" llm = OpenAI(model="gpt-4o", temperature=0.0) embed_model = OpenAIEmbedding(model_name="text-embedding-3-small")
Beachten Sie, dass das LLM bei der Graphenkonstruktion nicht verwendet wird.
Da nun alles an seinem Platz ist, können wir einen PropertyGraphIndex instanziieren und die Nachrichtendokumente als Eingabedaten für einen Wissensgraphen verwenden.
Zusätzlich müssen wir das Relikt-Modell als kg_extractors-Wert übergeben, um die Beziehungen zu extrahieren:
from llama_index.core import PropertyGraphIndex index = PropertyGraphIndex.from_documents( documents, kg_extractors=[relik], llm=llm, embed_model=embed_model, property_graph_store=graph_store, show_progress=True, )
Nachdem Sie das Diagramm erstellt haben, können Sie den Neo4j-Browser öffnen, um das importierte Diagramm zu validieren. Sie sollten eine ähnliche Visualisierung erhalten, indem Sie die folgende Cypher-Anweisung ausführen:
MATCH p=(:__Entity__)--(:__Entity__) RETURN p LIMIT 250
Ergebnisse
Mit LlamaIndex ist es jetzt ganz einfach, Fragen zu beantworten. Wenn Sie die Standard-Graph-Retriever verwenden, können Sie ganz einfache Fragen stellen:
query_engine = index.as_query_engine(include_text=True) response = query_engine.query("What happened at Ryanair?") print(str(response))
Hier kommen das definierte LLM und das Einbettungsmodell ins Spiel. Natürlich können Sie auch benutzerdefinierte Retriever implementieren, um möglicherweise eine bessere Genauigkeit zu erzielen.
Die Erstellung von Wissensgraphen ohne LLMs ist nicht nur machbar, sondern auch kostengünstig und effizient. Durch die Feinabstimmung kleinerer, aufgabenspezifischer Modelle, wie denen im Relik-Framework, können Sie eine leistungsstarke Informationsextraktion für Ihre Retrieval-Augmented Generation (RAG)-Anwendungen erreichen.
Die Entitätsverknüpfung, ein entscheidender Schritt in diesem Prozess, stellt sicher, dass erkannte Entitäten genau den entsprechenden Einträgen in einer Wissensdatenbank zugeordnet werden, wodurch die Integrität und Nützlichkeit des Wissensgraphen gewahrt bleibt.
Durch die Verwendung von Frameworks wie Relik und Plattformen wie Neo4j ist es möglich, erweiterte Wissensgraphen zu erstellen, die komplexe Datenanalyse- und -abrufaufgaben erleichtern – und das alles ohne die hohen Kosten, die normalerweise mit der Bereitstellung von LLMs verbunden sind. Diese Methode macht nicht nur leistungsstarke Datenverarbeitungstools zugänglicher, sondern fördert auch Innovation und Effizienz in Arbeitsabläufen zur Informationsextraktion.
Geben Sie der Relik-Bibliothek unbedingt einen Stern . Der Code ist auf GitHub verfügbar.
Um mehr über dieses Thema zu erfahren, besuchen Sie uns am 7. November bei NODES 2024, unserer kostenlosen virtuellen Entwicklerkonferenz zu intelligenten Apps, Wissensgraphen und KI. JETZT registrieren !