假如你和我一样在预备24年的春招,在前端全栈外,再预备一些AI的内容是非常有必要的。24年是AI盈利年,AIGC+各种岗位大厂机会会多些,同意的请点赞。也欢迎朋友们加我微信shunwuyu, 一同交流。

前语

向量数据库是构建LLM运用程序架构的要害组成部分,特别是当咱们在构建RAG(检索增强生成)类运用的时候,本文咱们一同来学习Pinecone。

咱们将运用Pinecone来完成文本类似性查找、图画类似性查找、反常检测、推荐系统和混合查找等… 马上就要能完成图搜图了,小激动的。

语义查找 Semantic Search

在传统的词汇查找中,主要是字面或形式匹配,咱们会用数据库的like查询或ElasticSearch。LLM降低了语义查找的门槛, 咱们能够根据keyword的语义来进行查找。

自然语义是AIGC类运用的根底,它经过Embedding核算完成,Pinecone存储的便是Embedding向量。当咱们将用户输入的keyword也Embedding,就能够和Pinecone里的向量进行cosine类似度核算,然后完成Semantic Search。

简单的Semantic Search Demo

前端也能够这样零根底入门Pinecone

上图是一个Semantic Search的根本架构图。程序将Quora(问答社区) dataset (数据集),生成嵌入式向量(Embeding)后存入Pinecone。然后程序构建一个QAChain(LangChain),用户就能够向它提出上面的几个问题,得到回答。

  • 安装依赖
# HuggingFace 数据集, 
!pip install datasets
# pinecone 向量数据库
!pip install pinecone-client
# 命令行东西
!pip install tqdm
  • 引进warning模块,疏忽警告信息
import warnings
warnings.filterwarnings('ignore')
  • 引进相关依赖
# datasets 是由 HugggingFace 提供的数据库加载库,能够方便的加载社区的开源数据集,等下咱们会用它加载 quora dataset
from datasets import load_dataset
# sentence_transformers是根据pytorch的句子嵌入核算
from sentence_transformers import SentenceTransformer
# pinecone 向量数据库  Pinecone是数据库实例, ServerlessSpec是云端存储
from pinecone import Pinecone, ServerlessSpec
import os 
import time
# 开源的深度学习结构
import torch
# tqdm 是命令行进度条,实时表达当时进展
from tqdm.auto import tqdm
  • 下载数据集,并截取其间的一个子集
# train的意思是训练子会集的一部分
dataset = load_dataset('quora', split='train[240000-290000]')
# 取其间五条
dataset[:5]

前端也能够这样零根底入门Pinecone

前端也能够这样零根底入门Pinecone

  • 添加问题
# 预备问题空数组
questions = []
# 遍历dataset的questions 
for record in dataset['questions']:
    questions.extend(record['text'])
# list 表明有序的可变的数据调集,set去重
question = list(set(questions))
print('n'.join(questions[:10]))
print('-'*50)
print(f'Number of questions: {len(questions)}')

前端也能够这样零根底入门Pinecone

  • 嵌入模型的加载
# 查看gpu 能力,假如支撑,则gpu 核算,这儿数据集不大, 用cpu也行
device = 'cuda' if torch.cuda.is_available() else 'cpu'
if device != 'cuda':
    print('Sorry no cuda')
# 曾经用的是OpenAI, 这儿运用的是SentenceTransformer,模型是all-MiniLM-L6-v2
# `all-MiniLM-L6-v2`是一个根据Hugging Face的Sentence Transformers库中的预训练模型
model = SentenceTransformer('all-MiniLM-L6-v2', device=device)

前端也能够这样零根底入门Pinecone

这儿咱们没有用gpu能力,下载进度表表明all-MiniLM-L6-v2模型文件的下载

  • 测验一下嵌入
# 问题
query = 'Which city is the most populated in the world?'
# 编码 即嵌入
xq = model.encode(query)
# 将句子编码为一个384维的向量
xq.shape
(384,)

前端也能够这样零根底入门Pinecone

  • 实例化pinecone
# 实例化pinecone
pinecone=Pinecone(api_key='515c9a29-ebf3-4b0b-ab55-e67e50cf31cc')
# pinecone里的索引,能够相像为mysql里的table
INDEX_NAME = "dl-ai"
# pinecone.list_index() 会回来咱们的index列表  
if INDEX_NAME in (index.name for index in pinecone.list_index()):
    # 假如现已创建就删去
    pinecone.delete_index(INDEX_NAME)
# 创建索引
pinecone.create_index(
    name=INDEX_NAME, 
    # 维度 
    dimension=model.get_sentence_embedding_dimension(),
    # cosine 核算类似度
    metric='cosine',
    # serverless 的云服务 aws 亚马逊云  地区是 美国西部(俄勒冈)
    spec=ServerlessSpec(cloud='aws',region='us-west-2')
)
# 获得index 
index = pinecone.Index(INDEX_NAME)
打印index
index

前端也能够这样零根底入门Pinecone

前端也能够这样零根底入门Pinecone

  • 数据节片
# 一次处理200个数据
batch_size=200
# 向量上限为10000
vector_limit=10000
# 切片操作,要提取的数据是vector_limit
questions = question[:vector_limit]

前端也能够这样零根底入门Pinecone

  • 上传数据
# tqdm 是进度条东西, 下图显现进度条到60%, 已处理30批数据
# range 承受三个参数, 分别是起始方位,完毕值, 迭代值 总共要迭代10000/200 = 50
for i in tqdm(range(0, len(questions), batch_size)):
    # 当时最终一条 i的值for 时也会添加 0 200 400....
    # min 最终一页假如< batch_size 那就取len(questions)
    i_end = min(i+batch_size, len(questions))
    # 列表推导式  ids 的值 是 ['0', '1', '2', ....]
    ids = [str(x) for x in range(i, i_end)]
    # 数据放在metadatas中, 每一项的结构都是text:text
    metadatas=[{'text': text} for text in questions[i:i_end]]
    # 根据SentenceTransformer embedding 
    xc = model.encode(questions[i:i_end])
    #`zip`是 Python 内置函数,用于将多个可迭代目标(如列表、元组或其他序列)的元素打包成一个个元组,并回来一个 zip 目标
    records=zip(ids, xc, metadatas)
    # 添加数据
    index.upset(vectors=records)

前端也能够这样零根底入门Pinecone

pinecone 里寄存的是一个将ids数组、嵌入向量和metadatas 打包后的元组。从下图看,现已存好了。

前端也能够这样零根底入门Pinecone

咱们要理解下这边为啥会花那么多时刻, 一是数量量比较大,二是每次都要进行模型的运转,假如显卡好,就会快许多。我这儿花了3分16秒。

  • 打印查询内容
index.describe_index_stats()

存成功后,index的状况数据如下:

前端也能够这样零根底入门Pinecone

  • 检索器
def run_query(query):
  embedding = model.encode(query).tolist()
  results = index.query(vector=embedding, top_k=10, include_metadata=True, include_value=False)
  for result in results['matches']:
    print(f"{round(result['score'], 2)}:{result['metadata']['text']}")

这儿咱们定义了run_query函数, 根据输入调用index上的query方法,得到成果。

  • 查询
run_query("which city has the higest population in the world?")

前端也能够这样零根底入门Pinecone

总结

pinecone 的根本流程跑通了,结合huggingface,完美。

参考资料