大约一个月前,矢量数据库Weaviate在B系列资金中获得了5000万美元。大约三周前,只有5K星的开源项目Chroma为其嵌入数据库筹集了1800万,大约两周前,Pinecone DB宣布了1亿美元的B系列投资,以7.5亿美元的估值。自然,出现一个问题,什么是矢量数据库?
要谈论向量数据库,我们首先需要知道矢量是什么。向量只是数字数量。但是,它们可以在连续的高维空间中表示更复杂的对象,例如单词,句子,图像或音频文件。
嵌入式映射单词的语义含义或几乎任何其他数据类型中的类似功能。然后,这些嵌入可以用于推荐系统,搜索引擎,甚至是文本生成(例如ChatGpt)。但是,一旦您嵌入了嵌入,真正的问题就变成了:您在哪里存储它们以及如何查询它们?
这就是矢量数据库的来源。在关系数据库中,您有行和列。在文档数据库中,您有文档和集合。但是,在矢量数据库中,您的数字数组基于相似性聚集在一起,后来可以使用超低延迟来查询,这是AI驱动的应用程序的理想选择。
诸如PostgreSQL之类的关系数据库具有诸如PGVECTOR之类的工具来支持此类型的功能,REDIS还具有其一级向量支持,例如REDISEARZEREARZ。一堆新的本地矢量数据库也弹出了。编织和Milvus是GO编写的开源选项。基于引擎盖下的Clickhouse的Chroma也是另一种开源选项。另一个非常受欢迎的选择是PineconedB,但不是开源的。
让我们跳入一些代码,看看它的外观。我将使用PineconedB和Python。使用官方指南,我将使用ELI5 BART模型来实施抽象的问答程序。抽象问题回答着重于开放式问题的多句答案的产生。通常,它可以通过搜索大量文档存储以获取相关信息,然后使用此信息合成生成答案。
我们的源数据将从Wiki Sippets数据集中获取,该数据集包含Wikipedia的1700万通道。我们将仅利用5,000段内容,其中包括“截面标题”列中的“历史记录” (由于内存问题,您可以在需要的情况下使用完整的数据集;官方指南使用了50,000段落)。<<<<<<<<< br>
import pandas as pd
# create a pandas dataframe with the documents we extracted
df = pd.DataFrame(docs)
df.head()
要构建我们的向量索引,我们必须首先与Pinecone建立联系。然后,我们创建一个新索引。索引是Pinecone中向量数据的最高组织单位。它接受并存储向量,在其包含的向量上提供查询,并在其内容上进行其他向量操作。我们将度量类型指定为“余弦”和尺寸为768,因为我们用来生成上下文嵌入的回收器已针对余弦相似性进行了优化,并输出768二维向量。其他指标是“ Euclidean”和“ Dotproduct”。
import pinecone
# connect to pinecone environment
pinecone.init(
api_key="YOUR_API_KEY",
environment="us-central1-gcp"
)
index_name = "abstractive-question-answering"
# check if the abstractive-question-answering index exists
if index_name not in pinecone.list_indexes():
# create the index if it does not exist
pinecone.create_index(
index_name,
dimension=768,
metric="cosine"
)
# connect to abstractive-question-answering index we created
index = pinecone.Index(index_name)
我们将使用基于Microsoft MPNET作为我们的猎犬的句子词构造模型。另外,我们将使用ELI5 BART进行生成器,该生成器是一个使用“ Infiment Islike I i ime 5”(ELI5)数据集训练的序列到序列模型。序列到序列模型可以将文本序列作为输入,并产生不同的文本序列作为输出。您可以从Huggingface hub下载这些模型。
import torch
from sentence_transformers import SentenceTransformer
# set device to GPU if available
device = 'cuda' if torch.cuda.is_available() else 'cpu'
# load the retriever model from huggingface model hub
retriever = SentenceTransformer("flax-sentence-embeddings/all_datasets_v3_mpnet-base", device=device)
retriever
from transformers import BartTokenizer, BartForConditionalGeneration
# load bart tokenizer and model from huggingface
tokenizer = BartTokenizer.from_pretrained('vblagoje/bart_lfqa')
generator = BartForConditionalGeneration.from_pretrained('vblagoje/bart_lfqa').to(device)
接下来,我们应该使用
index.upsert()
命令将数据上传到Pinecone数据库。如果操作成功,则应看到以下输出。
然后,让我们正确一些助手功能以从Pinecone索引检索上下文段落,并以生成器期望输入的方式格式化查询。
def query_pinecone(query, top_k):
# generate embeddings for the query
xq = retriever.encode([query]).tolist()
# search pinecone index for context passage with the answer
xc = index.query(xq, top_k=top_k, include_metadata=True)
return xc
def format_query(query, context):
# extract passage_text from Pinecone search result and add the <P> tag
context = [f"<P> {m['metadata']['passage_text']}" for m in context]
# concatinate all context passages
context = " ".join(context)
# contcatinate the query and context passages
query = f"question: {query} context: {context}"
return query
query = "when was the first electric power system built?"
result = query_pinecone(query, top_k=1)
result
最后,我们将写一个给定查询的答案的辅助函数。
from pprint import pprint
def generate_answer(query):
# tokenize the query to get input_ids
inputs = tokenizer([query], max_length=1024, return_tensors="pt")
# use generator to predict output ids
ids = generator.generate(inputs["input_ids"], num_beams=2, min_length=20, max_length=40)
# use tokenizer to decode the output ids
answer = tokenizer.batch_decode(ids, skip_special_tokens=True, clean_up_tokenization_spaces=False)[0]
return pprint(answer)
我们使用此功能测试不同的查询。
请注意,答案还不完整,因为我们只使用了5,000段段落。您可以调整段落的数量并观察结果。
这些数据库现在很热的真正原因是它们可以通过长期内存扩展LLM。您从OpenAI的GPT-4,Meta的Llama或Google的LAMDA等通用模型开始,然后在矢量数据库中提供您自己的数据。当用户发出提示时,您可以从您自己的数据库中查询相关文档,以更新上下文,以自定义最终响应,并且还可以检索历史数据以提供AI长期内存。他们还与将多个LLMS组合在一起的Langchain之类的工具集成在一起。
从Fireship的视频转录的某些部分:矢量数据库现在很热。 wtf是吗?
官方的抽象问题 - 问题指南:https://docs.pinecone.io/docs/abstractive-question-answering