在我的以前的文章中,我写了关于如何将知识图谱与 RAGs 结合使用,以及如何使用图技术进行自适应标记化以构建更具上下文意识的LLMs。在本文中,我很高兴地介绍了我结合文本嵌入和知识(图)嵌入进行实验以及对RAG性能的观察。
我将首先独立解释文本和知识嵌入的概念,使用简单的开放框架,然后,我们将看到如何在RAG应用中同时使用两者。
这是一篇相当长的文章,我故意不想分成多个部分来写,所以你们都可以按照我下面分享的顺序来阅读和尝试。
作者创建的以域为中心的语料库
我将深入研究,并按照以下列出的四个部分来介绍我的工作。
- 第一部分:什么是文本嵌入(TE)?它们是如何在RAG实现中存储和使用的?
- 第二部分:知识(图)嵌入是什么,它们是如何存储的?
- 第三部分:知识(图)嵌入与文本嵌入有何不同,并分析它们在RAG中的使用是否互补
- 结论: 在 RAGs 中结合文本和知识嵌入的好处以及总体摘要
第一部分:文本嵌入和 1001 实现
如果您尝试进入自然语言处理(NLP),您可能在探索语言模型和机器学习时遇到了“文本嵌入”这个术语。那么,文本嵌入到底是什么,它是如何工作的呢?让我以更易理解的方式来解释一下。
文本嵌入介绍
文本嵌入是单词或短语的数值表示,能有效地捕捉它们的含义和上下文。将其视为单词的唯一标识符-简洁的向量,能捕捉所代表单词的含义。
这些嵌入允许计算机增强他们对文本的理解和处理,使它们能够在各种自然语言处理任务中表现出色,如文本分类、情感分析和机器翻译。
我们利用预训练模型,如 Word2Vec、GloVe 或 BERT 来生成文本嵌入。这些模型已经在大量文本数据上进行了广泛训练,并已获得了编码有关单词及其关系的语义信息的能力。
- 令牌化[决定我们将使用哪种算法来生成令牌。 [基于单词(如下所选),基于字符,基于子词等)请参阅我关于使用图技术进行高级令牌化的文章
- 将令牌编码为向量(如字节对编码等)。
现在,让我们探讨使用简单的 Python 代码片段(word2vec)生成文本嵌入的过程:
# Code Implementation: Generating Text Embeddings
import numpy as np
from gensim.models import Word2Vec
# Sample sentences
sentences = [
["I", "love", "natural", "language", "processing"],
["Text", "embeddings", "are", "fascinating"],
["NLP", "makes", "computers", "understand", "language"]
]
# Train Word2Vec model
model = Word2Vec(sentences, vector_size=5, window=5, min_count=1, sg=1)
# Get embeddings for words
word_embeddings = {}
for word in model.wv.index_to_key:
word_embeddings[word] = model.wv[word]
# Print embeddings
for word, embedding in word_embeddings.items():
print(f"Embedding for '{word}': {embedding}")
在这段代码中,我们通过对一组样本句子进行训练,开发了一个 Word2Vec 模型。然后模型为每个单词生成嵌入。这些嵌入捕捉了句子中单词之间的语义关系。
代码片段生成文本嵌入的输出如下:
Embedding for 'I': [-0.01978252 0.02348454 -0.0405227 -0.01806103 0.00496107]
Embedding for 'love': [ 0.01147135 -0.00716509 -0.02319919 0.03274594 -0.00713439]
Embedding for 'natural': [ 0.03319094 0.02570618 0.02645341 -0.00284445 -0.01343429]
Embedding for 'language': [-0.01165106 -0.02851446 -0.01676577 -0.01542572 -0.02357706]
Embedding for 'processing': [-0.00205235 0.01240269 -0.03660049 -0.0240654 -0.03612582]
Embedding for 'Text': [ 0.02553515 0.03493764 0.01932768 -0.02028572 0.02185934]
Embedding for 'embeddings': [ 0.01769094 0.02836292 -0.02720205 -0.01580047 -0.0323391 ]
Embedding for 'are': [ 0.01449668 0.0178032 0.02154245 -0.02403528 -0.03612522]
Embedding for 'fascinating': [ 0.0389471 0.00991404 0.0198368 -0.02466156 -0.03446501]
Embedding for 'NLP': [ 0.00828243 -0.02125732 0.01082581 0.02250805 0.02270168]
Embedding for 'makes': [ 0.01696491 0.0151721 -0.02186292 -0.01510419 -0.02021307]
Embedding for 'computers': [ 0.00983663 -0.02679762 0.03002482 -0.02373362 -0.01307139]
Embedding for 'understand': [-0.0326019 0.01835899 0.01538064 -0.01008516 0.01717436]
在上述输出中:
- 每一行对应一个单词的嵌入向量。
- 每行以单词开头,后跟其嵌入向量,表示为一系列数值的列表。
- 例如,“爱”这个词的嵌入:[-0.01978252 0.02348454 -0.0405227 -0.01806103 0.00496107]。
在RAG中实施文本嵌入技术
既然我们已经掌握了生成文本嵌入的过程,让我们来探索它们在检索增强生成模型中的应用(RAG)。
结合检索式和生成式方法,RAGs 利用文本嵌入来把握输入查询的上下文,并在自然语言处理任务的检索阶段提取相关信息。
文本嵌入流程 作者
步骤 1:标记化和编码。
让我们现在尝试利用预训练模型,如 BERT,对输入查询进行标记化和编码。这将把查询转换为一个捕捉其语义含义和上下文的数值表示。
# Code Implementation: Tokenization and Encoding
from transformers import BertTokenizer, BertModel
# Initialize BERT tokenizer and model
tokenizer = BertTokenizer.from_pretrained('bert-base-uncased')
model = BertModel.from_pretrained('bert-base-uncased')
# Tokenize and encode the input query
query = "What is the capital of France?"
input_ids = tokenizer.encode(query, add_special_tokens=True, return_tensors="pt")
在这里,我们使用 BERT 对输入查询进行标记化和编码,转换为数字 ID。由于 BERT 模型的初始化和标记化过程涉及加载一个大型预训练模型,标记化和编码步骤的输出包括以下组件:
- 输入 ID:这些是输入查询中标记的数字表示形式。每个标记都转换为一个 ID,该 ID 对应于其在 BERT 词汇表中的索引。
- 关注蒙版:这是一个二进制蒙版,指示哪些标记是实际词汇(1),哪些是填充标记(0)。它确保模型在处理过程中只关注真实标记。
- 令牌类型 ID(适用于 BERT 等模型):这表明在多个段落的情况下,每个令牌属于哪个部分或句子。对于单句输入,所有令牌类型 ID 通常设置为 0。
输出是一个包含这些组件的字典,可以作为输入传递给 BERT 模型进行进一步处理。
这是输出将包括的一个例子:
{
'input_ids': tensor([[ 101, 2054, 2003, 1996, 3007, 1997, 2605, 1029, 102, 0]]),
'attention_mask': tensor([[1, 1, 1, 1, 1, 1, 1, 1, 1, 0]]),
'token_type_ids': tensor([[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]])
}
在这个例子中:
input_ids
包含了输入查询中令牌的数字 ID。attention_mask
表示哪些 token 是实际的单词(1),哪些是填充的(0)。token_type_ids
表示每个标记所属的段落或句子(在这种情况下为第一个句子)。
第二步:检索和相似度匹配
接下来,我们根据编码的查询从语料库中检索相关段落。我们使用余弦相似度计算查询嵌入和段落嵌入之间的相似性分数。
# Code Implementation: Retrieval and Similarity Matching
from sklearn.metrics.pairwise import cosine_similarity
# Retrieve passages and compute similarity scores
query_embedding = model(input_ids)[0].mean(dim=1).detach().numpy()
passage_embeddings = ... # Retrieve passage embeddings
similarity_scores = cosine_similarity(query_embedding, passage_embeddings)
在这里,我们选择具有最高相似度分数的段落,并将其与相似度分数一起输出。
由于检索和相似性匹配步骤涉及计算查询嵌入和段落嵌入之间的相似性分数,我可以提供一个例子,展示相似性分数可能是什么样子的。
让我们假设我们有三个样本段落,并计算查询嵌入和这些段落的嵌入之间的余弦相似度分数。以下是输出结果可能看起来的例子:
similarity_scores = [0.75, 0.82, 0.65]
在这个例子中:
- 相似度为 0.75 的分数表明查询和第一段之间存在适度的相似性。
- 相似度得分为 0.82,表示查询与第二段落之间具有高度相似性。
- 相似度得分为 0.65,表示查询和第三段之间的相似度较低。
相似度分数表示每个段落与输入查询之间的相似程度,分数越高表示相似度越强。在RAG模型中,得分最高的段落被视为最相关的,用于进一步处理。
第三步:扩展上下文
最后,我们将具有最高相似度分数的段落指定为最相关的段落。这段文字为模型的生成阶段提供了相关信息。
# Select passage with highest similarity score
max_similarity_index = np.argmax(similarity_scores)
selected_passage = passages[max_similarity_index]
# Output selected passage and similarity score
print("Selected Passage:")
print(selected_passage)
print("Similarity Score:", similarity_scores[0][max_similarity_index])\
假设第二段具有最高的相似度分数(0.82),被选为最相关的段落。以下是输出可能会是这样的一个例子:
Selected Passage:
"Barack Obama served as the 44th president of the United States."
Similarity Score: 0.82
在这个例子中:
- 巴拉克·奥巴马担任美国第 44 任总统。
- 相似度得分为 0.82,表明此段与输入查询之间存在很高的相似性。
文本嵌入是自然语言处理(NLP)领域中非常强大的工具,使计算机能够有效地理解和处理文本信息。
它们对于回答问题、生成文本和分析情感等各种任务都有重大影响。
通过在先进模型中利用文本嵌入,如RAG,我们可以显著提高它们的性能和精度,从而产生更敏锐和上下文适当的响应。
随着您在自然语言处理的探索中的进步,获得文本嵌入的专业知识将对释放语言模型的全部能力和推动自然语言处理的进步至关重要。
第二部分:知识(图)嵌入与实现
让我们现在转向先进知识图谱的世界,看看如何定义和实施知识嵌入,表示从非结构化数据中构建的结构域。
知识(图)与嵌入简介
知识图谱是一种高效的组织信息的方式,以有意义的方式连接实体及其关系。这些图谱作为信息的良好组织的仓库,捕捉现实世界对象及其连接的含义。
然而,这个过程并不仅仅止步于知识图谱的开发。探索知识图谱嵌入领域对于充分发挥其潜力至关重要。
让我们使用一个包含各种实体及其相互关系的简单文本来探索知识图嵌入,或简称为知识嵌入。从提取数据到生成嵌入,并以紧凑的向量捕捉文本的真实含义。
获取这些嵌入的目标是为了便于对图元素(实体、关系)进行各种预测任务的操作,例如实体分类、链接预测或推荐系统。
我们保持知识图谱的基本结构,并优化知识图谱组件的利用。在将知识图谱元素表示为嵌入向量之后,我们使用评分函数来评估三元组的可信度,例如“Tim”、“是”、“艺术家”。
以下是实施知识(图)嵌入的步骤:
知识嵌入流经作者
第一步:三重提取和处理
给定一个非结构化的文本,我们首先使用斯坦福的 OpenIE 框架提取关键实体、关系和属性。一旦三元组被提取出来,我们将对它们进行清理和协调。
夏威夷是美国的一个州。巴拉克·奥巴马曾任美国第 44 任总统。卢浮宫位于法国的巴黎。
from openie import StanfordOpenIE
text = "Hawaii is a state in the United States. Barack Obama served as the 44th president of the United States. The Louvre Museum is located in Paris, France."
with StanfordOpenIE() as client:
triples = client.annotate(text)
for triple in triples:
print(triple)
cleaned_triples = [(subject.lower(), relation.lower(), object.lower()) for (subject, relation, object) in triples]
print("Cleaned Triples:", cleaned_triples)
以上代码的输出是
('Hawaii', 'is', 'a state in the United States')
('Barack Obama', 'served as', 'the 44th president of the United States')
('The Louvre Museum', 'is located in', 'Paris, France')
Cleaned Triples: [('hawaii', 'is', 'a state in the united states'), ('barack obama', 'served as', 'the 44th president of the united states'), ('the louvre museum', 'is located in', 'paris, france')]
我们现在准备使用这些信息并创建知识图谱
第 2 步:知识图谱构建
使用 NetworkX 框架,我们将使用上述清理过的三元组,构建一个具有实体→节点和关系→边的知识图。以下是实现:
import networkx as nx
# Create a directed graph
knowledge_graph = nx.DiGraph()
# Add nodes and edges from cleaned triples
for (subject, relation, object) in cleaned_triples:
knowledge_graph.add_edge(subject, object, relation=relation)
# Visualize the knowledge graph
nx.draw(knowledge_graph, with_labels=True)
输出是下面看到的一个图表:
作者示例图输出
第三步:实体解析和归属
实体解析在各种自然语言处理应用中发挥着关键作用,包括信息提取、问答、知识图谱构建等。
通过准确地将文本中的实体提及与结构化知识表示中的相应实体进行关联,实体解析使机器能够更有效地理解和推理自然语言,从而促进各种下游任务和应用。
基本上,实体解析关注的是自然语言中的歧义和多变性的挑战。
在日常语言使用中,诸如人物、地点、组织和概念等实体通常会用不同的名字、同义词、缩写或变体来指代。例如,“巴拉克·奥巴马”可能被提及为“奥巴马”、“美国前总统”,或简单地称为“他”。此外,有类似名字或属性的实体可能存在,导致潜在的混淆或歧义。例如,“巴黎”可能指的是法国的首都,也可能是另一个同名地点。
让我们逐个介绍实体解析技术,并根据所使用的文本提供例子:
- 精确匹配:在文本中,“夏威夷”一词可以直接与图中标记为“夏威夷”的节点相匹配,因为它们完全匹配。
- 部分匹配:如果文本提到“美国”而不是“美利坚合众国”,部分匹配算法可能会认识到两者之间的相似性,并将提及链接到图中标有“美利坚合众国”的节点。
- 命名实体识别(NER):使用 NER,系统可以在文本中识别“巴拉克·奥巴马”作为一个人物实体。然后可以将这个提及与图中标记为“巴拉克·奥巴马”的相应节点相连。
- 指代消解:如果文本提到“他担任总统”,指代消解可以将“他”与先前文本中提到的“巴拉克·奥巴马”关联起来,然后将其与图中标记为“巴拉克·奥巴马”的相应节点关联起来。
- 消歧义:假设文本提到“巴黎”,但没有指明是指法国的城市还是其他地点。
消歧技术可能会考虑上下文信息或外部知识源,以确定它指的是“法国巴黎”,并将其链接到图中相应的节点。
一旦确定了正确的实体链接,文本中的提及将与知识库或知识图中的相应实体进行链接。
实体解析系统的性能是通过使用精确率、召回率和 F1 得分等指标来进行评估的,将预测的实体链接与真实结果或黄金标准进行比较。下面是对上述构建的图进行的样本实体解析。
灰色圆圈表示给定实体的类类型解析。
实体解析示例由作者创建
步骤 4:知识(图形)嵌入生成
作为最后一步,我们现在将为实体和关系生成嵌入。有几种模型,但在这个练习中,我们将使用 TransE。
from pykeen.pipeline import pipeline
# Define pipeline configuration
pipeline_config = {
"dataset": "nations",
"model": {
"name": "TransE",
"embedding_dim": 50
},
"training": {
"num_epochs": 100,
"learning_rate": 0.01
}
}
# Create and run pipeline
result = pipeline(
**pipeline_config,
random_seed=1234,
use_testing_data=True
)
# Access trained embeddings
entity_embeddings = result.model.entity_embeddings
relation_embeddings = result.model.relation_embeddings
# Print embeddings
print("Entity Embeddings:", entity_embeddings)
print("Relation Embeddings:", relation_embeddings)
这是输出:
Entity Embeddings: [Embedding dimension: (120, 50)]
Relation Embeddings: [Embedding dimension: (120, 50)]
知识嵌入的向量如下所示:
实体嵌入:
- “夏威夷”:[0.1, -0.2, 0.5, …]
- “美国”:[0.3, 0.4, -0.1, …]
- “巴拉克·奥巴马”: [-0.2,0.6,0.2,…]
- "卢浮宫博物馆": [-0.5, 0.1, 0.7, …]
关系嵌入:
- “是一个国家”: [0.2, -0.3, 0.1, …]
- "担任为": [0.4, 0.2, -0.5, …]
- “位于”: [-0.1, 0.5, 0.3, …]
第三部分:合并文本和知识(图形)嵌入
在我们尝试合并嵌入之前,让我们首先了解这些嵌入所带来的价值,并验证它们是否互补。
文本嵌入和知识嵌入在自然语言处理(NLP)中具有不同的目的,代表语言和语义信息的不同方面。让我们根据提供的输出来比较和对比这两种嵌入类型:
比较和对比文本和知识嵌入——作者
实施结合文本和知识嵌入
这段代码通过将文本嵌入和知识嵌入结合到单一嵌入空间中,然后根据查询和段落的组合嵌入之间的余弦相似度,从知识库中检索相关段落。
输出显示了相关段落以及它们与查询的相似度分数。
import numpy as np
from sklearn.metrics.pairwise import cosine_similarity
# Sample knowledge embeddings
knowledge_embeddings = { } #initialise the above knowledge embeddgings output
# Sample text embeddings
text_embeddings = { } #initialise the above text embeddgings output
# Consider passages from knowledge base
knowledge_base = {
"Passage 1": "Hawaii is a state in the United States.",
"Passage 2": "Barack Obama served as the 44th president of the United States.",
# Add more passages as needed
}
# Function to combine text and knowledge embeddings
def combine_embeddings(text_emb, know_emb):
combined_emb = {}
for entity, t_emb in text_emb.items():
if entity in know_emb:
combined_emb[entity] = np.concatenate([t_emb, know_emb[entity]])
else:
combined_emb[entity] = t_emb
return combined_emb
# Function to retrieve relevant passages using combined embeddings
def retrieve_passages(query_emb, knowledge_base_emb):
similarities = {}
for passage, kb_emb in knowledge_base_emb.items():
sim = cosine_similarity([query_emb], [kb_emb])[0][0]
similarities[passage] = sim
sorted_passages = sorted(similarities.items(), key=lambda x: x[1], reverse=True)
return sorted_passages
# Example usage
combined_embeddings = combine_embeddings(text_embeddings, knowledge_embeddings)
query = "query"
relevant_passages = retrieve_passages(combined_embeddings[query], knowledge_embeddings)
# Print relevant passages
for passage, similarity in relevant_passages:
print("Passage:", passage)
print("Similarity:", similarity)
print()
输出的相似度如下:
Passage: Passage 1
Similarity: 0.946943628930774
Passage: Passage 2
Similarity: 0.9397945401928656
我们可以实施其他相似性框架,并选择最适合业务背景的一个。
结论
同时在检索增强生成(RAG)模型中同时使用文本嵌入和知识嵌入可以在多个方面增强模型的性能和能力:
- 全面理解:文本嵌入捕捉单词或短语的语义含义,而知识嵌入捕捉实体之间的明确关系。
通过整合这两种嵌入方式,RAG 模型对输入文本和知识图中存储的组织信息实现了更全面的掌握。 - 文本嵌入:通过分析输入文本中的词共现,文本嵌入提供有价值的上下文见解,而知识嵌入则通过检查知识图中实体之间的关系提供上下文相关性。
通过结合不同类型的嵌入,RAG 模型能够生成既在语义上与输入文本相关,又在上下文中与结构化知识一致的响应。 - 改进的答案检索:在RAG模型中利用结构化知识可以显著提高答案选择,这要归功于在检索组件中集成知识嵌入。
利用知识嵌入技术对知识库进行索引和检索相关段落,RAG模型能够检索出更准确、更具信息量的响应。 - 增强的答案生成:文本嵌入增强了RAG模型的生成组件,将广泛的语言特征和语义细微差别纳入其中。
通过在答案生成过程中融合文本嵌入和知识嵌入,RAG模型能够生成具有语言流畅性、语义相关性和结构化知识基础的回答。 - 对歧义的鲁棒性:通过利用文本嵌入和知识嵌入,RAG模型在自然语言中更具有抵抗歧义和变异的能力。
文本嵌入捕捉了无结构文本中存在的变化性和模糊性,而知识嵌入提供明确的语义关系,以增强和澄清模型的理解。 - 有效的知识整合:知识嵌入使得模型能够无缝地将来自知识图或知识库的结构化知识整合到生成过程中。
通过知识嵌入和文本嵌入的整合,RAG 模型实现了结构化知识和非结构化文本的无缝融合,从而产生更具信息性和上下文相关性的响应。
总的来说,文本嵌入和知识嵌入一起在一个RAG模型中,可以更全面和具有上下文丰富的表示输入文本和结构化知识。
该集成提高了模型在答案检索、答案生成、对模棱两可的鲁棒性和有效结合结构化知识等方面的性能,最终实现更准确、更丰富的回答。
参考文献和文章
我在本文中使用了以下参考资料,以加深我的理解,并分享了上述的经验。
- EAGER: 嵌入式辅助的知识图谱实体解析 — 2021
- 知识图谱嵌入简介
- 《检索增强生成模型用于知识密集型自然语言处理任务》(作者:Lewis, P., Neumann, M.,等,2020)
- “KagNet:知识感知图网络用于常识推理”由胡 Z.等人 (2021)
- 使用图神经网络在信息检索中学习查询意图表示,崔等人(2020 年)。
- 《基于知识增强上下文嵌入的开放领域问答改进》作者:杨某某等(2020 年)
广告:
我正在「大语言模型和知识图谱」和朋友们讨论有趣的话题,你⼀起来吧?
https://t.zsxq.com/zDX10
配置优惠券:
https://wx.zsxq.com/dweb2/dashboard/28885842155521/operation_coupon?source=fasongyouhuiquan