从文本构建知识图谱长期以来一直是一个令人着迷的研究领域。随着大型语言模型 (LLM) 的出现,该领域获得了更多主流关注。然而,LLM 的成本可能相当高。另一种方法是微调较小的模型,这种方法得到了学术研究的支持,可以产生更有效的解决方案。今天,我们将探索Relik ,这是一个用于运行超快且轻量级的信息提取模型的框架,由罗马 Sapienza 大学的 NLP 小组开发。
没有 LLM 的典型信息提取流程如下所示:
该图展示了一个信息提取流程,从包含提及“Tomaz 喜欢写博客文章。他对绘制图表特别感兴趣”的文本的输入数据开始。该过程从共指解析开始,以将“Tomaz”和“他”识别为同一实体。然后,命名实体识别 (NER) 识别诸如“Tomaz”、“博客”和“图表”之类的实体。
实体链接是 NER 之后的过程,其中识别的实体被映射到数据库或知识库中的相应条目。例如,“Tomaz”链接到“Tomaz Bratanic (Q12345)”,“Blog”链接到“Blog (Q321)”,但“Diagram”在知识库中没有匹配项。
关系提取是后续步骤,系统在此步骤中识别并提取已识别实体之间的有意义关系。此示例识别出“Tomaz”与“博客”之间存在关系,其特征为“WRITES”,表明 Tomaz 写博客。此外,它还识别出“Tomaz”与“图表”之间存在关系,其特征为“INTERESTED_IN”,表明 Tomaz 对图表感兴趣。
最后,这些结构化信息(包括实体及其关系)存储在知识图谱中,以便对数据进行组织和访问,以便进一步分析或检索。
传统上,如果没有 LLM 的强大功能,整个过程将依赖于一套专门的模型,每个模型都处理从共指解析到关系提取的特定任务。虽然整合这些模型需要更多的努力和协调,但它具有一个显著的优势:降低成本。通过微调较小的、特定于任务的模型,可以控制构建和维护系统的总体费用。
该代码可在GitHub上获取。
我建议您使用单独的 Python 环境,例如Google Colab ,因为我们将不得不尝试一些依赖项。模型在 GPU 上运行速度更快,因此如果您拥有 Pro 版本,则可以使用 GPU 驱动的运行时。
此外,我们需要设置原生图形数据库 Neo4j 来存储提取的信息。设置数据库实例的方法有很多种。不过,我建议使用Neo4j Aura ,它提供了一个免费的云实例,可以从 Google Colab 笔记本轻松访问。
创建数据库后,我们可以使用 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) 模型的库,它还支持将两者相结合的模型。在实体链接中,维基百科被用作目标知识库,将文本中的实体映射到百科全书中的相应条目。
另一方面,关系提取涉及识别和分类文本中实体之间的关系,从而能够从非结构化数据中提取结构化信息。
如果您使用的是免费的 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 所需的高昂成本。这种方法不仅使强大的数据处理工具更易于访问,而且还促进了信息提取工作流程的创新和效率。
要了解有关此主题的更多信息,请参加 11 月 7 日举行的 NODES 2024,这是我们关于智能应用、知识图谱和 AI 的免费虚拟开发者会议。立即注册!