テキストからナレッジ グラフを構築することは、長い間、魅力的な研究分野でした。大規模言語モデル (LLM) の出現により、この分野はより主流の注目を集めるようになりました。ただし、LLM は非常にコストがかかる場合があります。代替アプローチは、より小さなモデルを微調整することです。これは学術研究によってサポートされており、より効率的なソリューションを生み出します。今日は、ローマ ラ サピエンツァ大学の NLP グループによって開発された、超高速で軽量な情報抽出モデルを実行するためのフレームワークであるRelikについて説明します。
LLM を使用しない典型的な情報抽出パイプラインは次のようになります。
この画像は、「Tomaz はブログ記事を書くのが好きです。彼は特に図を描くことに興味があります」というテキストを含む入力データから始まる情報抽出パイプラインを示しています。プロセスは、共参照解決から始まり、「Tomaz」と「彼」を同じエンティティとして識別します。次に、名前付きエンティティ認識 (NER) が「Tomaz」、「ブログ」、「図」などのエンティティを識別します。
エンティティ リンクは NER に続くプロセスで、認識されたエンティティがデータベースまたはナレッジ ベース内の対応するエントリにマッピングされます。たとえば、「Tomaz」は「Tomaz Bratanic (Q12345)」にリンクされ、「Blog」は「Blog (Q321)」にリンクされますが、「Diagram」はナレッジ ベース内に一致するものがありません。
関係抽出は、システムが認識されたエンティティ間の意味のある関係を識別して抽出する次のステップです。この例では、「Tomaz」が「Blog」と「WRITES」で特徴付けられる関係を持っていることが識別され、これは Tomaz がブログを書いていることを示しています。さらに、「Tomaz」が「Diagram」と「INTERESTED_IN」で特徴付けられる関係を持っていることが識別され、これは Tomaz が図表に興味を持っていることを示しています。
最後に、エンティティとその関係を含むこの構造化された情報はナレッジ グラフに保存され、整理されたアクセス可能なデータが提供され、さらに分析や取得が可能になります。
従来、LLM の力がなければ、このプロセス全体は、共参照の解決から関係の抽出まで、それぞれが特定のタスクを処理する一連の特殊なモデルに依存していました。これらのモデルを統合するには、より多くの労力と調整が必要ですが、コストの削減という大きな利点があります。タスク固有の小さなモデルを微調整することで、システムの構築と保守にかかる全体的な費用を抑えることができます。
コードはGitHubで入手できます。
依存関係を少しいじる必要があるため、 Google Colabなどの別の Python 環境を使用することをお勧めします。モデルは GPU で高速化されるため、Pro バージョンをお持ちの場合は GPU 搭載のランタイムを使用できます。
さらに、抽出した情報を保存するために、ネイティブ グラフ データベースである Neo4j を設定する必要があります。データベース インスタンスを設定する方法は多数ありますが、Google Colab ノートブックから簡単にアクセスできる無料のクラウド インスタンスを提供するNeo4j Aura を使用することをお勧めします。
Neo4j Aura – フルマネージドクラウドソリューション
データベースが作成されたら、LlamaIndex を使用して接続を定義できます。
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 )
以前Diffbot API経由で取得したニュース データセットを使用します。データセットは GitHub で簡単に利用できるので、再利用できます。
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)
パイプラインの最初のステップは、共参照解決モデルです。共参照解決とは、テキスト内のすべての表現が同じエンティティを参照していることを識別するタスクです。
私の知る限り、共参照解決に利用できるオープンソース モデルは多くありません。 maverick-coref を試しましたが、テストでは spaCy のCoreferee の方がうまく機能したので、これを使用します。 Coreferee を使用する唯一の欠点は、依存関係地獄に対処しなければならないことです。これはノートブックで解決されますが、ここでは説明しません。
次のコードを使用して、spaCy に共参照モデルをロードできます。
import spacy, coreferee coref_nlp = spacy.load('en_core_web_lg') coref_nlp.add_pipe('coreferee')
Coreferee モデルは、同じエンティティを参照する表現のクラスターを検出します。これらのクラスターに基づいてテキストを書き換えるには、独自の関数を実装する必要があります。
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
モデルと依存関係が適切に設定されていることを確認するために関数をテストしてみましょう。
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
この例では、モデルは「Tomaz」と「He」が同じエンティティを参照していることを識別しました。coref_text 関数を使用して、「He」を「Tomaz」に置き換えます。
クラスター内のエンティティに対して単純な置換ロジックを使用するため、書き換えによって必ずしも文法的に正しい文が返されるわけではないことに注意してください。ただし、ほとんどのシナリオではこれで十分です。
ここで、ニュース データセットに共参照解決を適用し、結果を LlamaIndex ドキュメントとしてラップします。
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 は、エンティティ リンク (EL) と関係抽出 (RE) のモデルを備えたライブラリであり、この 2 つを組み合わせたモデルもサポートしています。エンティティ リンクでは、テキスト内のエンティティを百科事典内の対応するエントリにマッピングするためのターゲット ナレッジ ベースとして Wikipedia が使用されます。
一方、関係抽出では、テキスト内のエンティティ間の関係を識別して分類し、非構造化データから構造化情報を抽出できるようにします。
無料の Colab バージョンを使用している場合は、関係抽出のみを実行する relik-ie/relik-relation-extraction-small モデルを使用します。Pro バージョンをお持ちの場合、またはより強力なローカル マシンで使用する場合は、エンティティ リンクと関係抽出を実行する relik-ie/relik-cie-small モデルをテストできます。
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"} # )
さらに、エンティティを埋め込むために使用される埋め込みモデルと、質問応答フローの LLM を定義する必要があります。
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")
グラフ構築中は LLM は使用されないことに注意してください。
これで準備がすべて整ったので、PropertyGraphIndex をインスタンス化し、ニュース ドキュメントをナレッジ グラフへの入力データとして使用できます。
さらに、関係を抽出するには、relik モデルを kg_extractors 値として渡す必要があります。
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, )
グラフを構築したら、Neo4j ブラウザを開いてインポートしたグラフを検証できます。次の Cypher ステートメントを実行すると、同様の視覚化が得られるはずです。
MATCH p=(:__Entity__)--(:__Entity__) RETURN p LIMIT 250
結果
LlamaIndex を使用すると、質問への回答が簡単に実行できるようになりました。デフォルトのグラフ リトリーバーを使用するには、次のように簡単な質問をすることができます。
query_engine = index.as_query_engine(include_text=True) response = query_engine.query("What happened at Ryanair?") print(str(response))
ここで、定義された LLM と埋め込みモデルが役立ちます。もちろん、精度をさらに高めるためにカスタム リトリーバーを実装することもできます。
LLM に依存せずにナレッジ グラフを構築することは、実現可能であるだけでなく、コスト効率と効率も優れています。Relik フレームワークなどの小規模なタスク固有のモデルを微調整することで、検索拡張生成 (RAG) アプリケーションで高性能な情報抽出を実現できます。
このプロセスの重要なステップであるエンティティ リンクにより、認識されたエンティティがナレッジ ベース内の対応するエントリに正確にマッピングされ、ナレッジ グラフの整合性と有用性が維持されます。
Relik などのフレームワークや Neo4j などのプラットフォームを使用すると、LLM の導入に通常伴う高額なコストをかけずに、複雑なデータ分析や取得タスクを容易にする高度なナレッジ グラフを構築できます。この方法は、強力なデータ処理ツールをより利用しやすくするだけでなく、情報抽出ワークフローの革新と効率化も促進します。
Relik ライブラリに必ずスターを付けてください。コードはGitHubで入手できます。
このトピックについて詳しく知るには、11 月 7 日に開催されるインテリジェント アプリ、ナレッジ グラフ、AI に関する無料の仮想開発者会議 NODES 2024 にご参加ください。今すぐ登録してください。