使用embedding实现简单的内容查找

本文介绍了如何使用langchain框架结合HuggingFace和Qianfan模型,通过embedding技术将文本转换为张量进行内容查找。作者分享了实现过程,包括文本预处理、模型加载和使用API查询,以及模型在实际应用中的局限性。
摘要由CSDN通过智能技术生成

介绍

近两天学习了一点深度学习的内容。学的比较浅,想将自己的收获和理解记录下来,本文是基于langchain框架使用embedding实现简单的内容查找。话入正题。
embedding在深度学习中通常用于NLP(自然语言处理)。其作用是将文本处理成一个张量。

思路

通过将一个待查找文本使用分词器划分,然后使用embedding处理成张量。询问者输入问题也被处理一个张量此时进行匹配,程序将相似文本返回。

在embedding将文本处理为一个张量步骤中,产生的张量的好坏对程序的性能起决定性作用。自己电脑肯定是难以训练好一个embedding模型的,因此本次使用embedding模型是m3e-base,该模型在hungface中下载,当然模型的使用也是需要一定算力的,如果电脑无法使用该模型也可以使用市面上一些大模型的api。本文以百度的千帆大模型为例。

实现

程序通过langchain框架结合hungface模型简单实现。主要需要下载的包是langchain包

pip install langchain

如果是调用千帆接口还需要安装qianfan库

pip install qianfan

使用的库

from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma
from langchain.embeddings.huggingface import HuggingFaceEmbeddings
from langchain.embeddings.baidu_qianfan_endpoint import QianfanEmbeddingsEndpoint
import os

这些库分别是:

  • langchain中的分词器
  • langchain的chroma作用是作为一个数据库,存储通过embedding得到的张量
  • 第三和第四个分别是加载hungface模型的库和百度千帆大模型的embedding调用库,这两个库只需要调用一个,如果想要使用本地下载的模型就使用第一个,想要使用大模型api就会使用第四个
  • os库这个是python自带的库,在此处目的主要是为了设置环境变量

加载文本内容

此处是为了加载需要查找的目标文本。这里我随便找了一个网页将该网页内容直接复制到data.txt文件中

f=pen('data.txt','r',encoding='utf-8')	#以读模式编码为utf-8打开文件
state_of_the_union = f.read()			#读取文件内容
f.close()								#关闭文件

使用分词器对文本划分

#划分器对象,第一个参数是通过回车符号划分,第二个参数是划分长度是60,最后参数是重叠个数
text_splitter = CharacterTextSplitter(separator="\n",chunk_size=60, chunk_overlap=2)
#通过划分器划分文件,并将结果返回
texts = text_splitter.split_text(state_of_the_union)

划分器同也是十分重要。其结果也一定程度关系到后面的结果好坏。就像是汉语的标点符号,划分错误可能会曲解原意。

加载模型对象

#下载的模型保存路径
m = r"m3e"
#加载模型对象
embeddings = HuggingFaceEmbeddings(model_name=m)

上面使用的是下载模型如果不想使用该模型可以直接调用千帆的api,当然也可以使用openai等大模型的api。这里只是作为一个示例。
二者各有优劣,使用本地模型好处是免费,缺点是如果模型的规模太大家用电脑可能无法带动,并且运算速度上无法比拟企业的服务器。调用企业大模型的api好处是速度快不需要太多的本地算力,坏处是这是付费的,不过好在费用不算太高。
这里以调用千帆的embedding为例

#将api的appkey添加到环境变量
os.environ['QIANFAN_AK']='yourak'
#将api的serectkey添加到环境变量
os.environ['QIANFAN_SK']='yoursk'
#使用千帆大模型的embedding
embeddings = QianfanEmbeddingsEndpoint()

部署数据

这里使用的是chorma作为数据库

#将划分后的文本和embedding作为参数构造数据库
docesearch = Chroma.from_texts(texts, embeddings)

查询内容

在以下代码中查询数据中返回的是多个数据,这些数据以概率排序,第一个是程序认为最大可能是答案的。这些数据存储在一个个列表中(元素类型不是字符串而是一个documen对象),如果只想要第一个数据可以直接用索引输出第一个数据。

#输入问题
question =input('usr:')
#查询数据
ans = docsearch.similarity_search(question)
#输出数据
print(ans) 

效果

usr:第一个手持计算机谁发明的
[Document(page_content='1972年,惠普(Hewlett-Packard)发明了第一个手持计算器。'), Document(page_content='1820年,法国人 查尔斯·泽维尔·托马斯·德·科尔马(Charles Xavier Thomas de Colmar)制作成功第一台成品机械式计算机。'), Document(page_content='1946年2月14日,美国人莫克利(JohnW.Mauchly)和艾克特(J.PresperEckert)在美国宾夕法尼亚大学研制成功世界上第一台通用电子计算机“ENIAC”。'), Document(page_content='1886年,美国芝加哥的多尔·菲尔特(Dorr Eugene Felt)制造了第一台用按键操作 的计算器。')]

需要注意的是该程序中,ai模型作用仅仅是作为embedding,作用是将文本转化为张量,最后的答案是程序通过对比数据库中张量和问题张量相似度得出,相似度越大是答案概率越大。因此如果询问一个和读入的文本数据毫不相关的问题,程序还是会按概率给出一个概率较高的答案,尽管该答案概率可能并不高,例如以下例子:

usr:1+1=[Document(page_content='1976年,Cray 1诞生。它是第一台商用超级计算机,集成了20万个晶体管,每秒进行1.5亿次浮点运算。'), Document(page_content='1939年11月,美国的约翰·阿塔那索夫(John V. Atanasoff)和他的学生克利福特·贝瑞(Clifford Berry) 完成了一台16位的加法器,这是第一台真空管计算机。'), Document(page_content='1642年 ,法国数学家 布莱士·帕斯卡(Blaise Pascal) 在计算尺的基础上加以改进,能进行八位计算。'), Document(page_content='1938年,德国柏林的康拉德·楚泽(Konrad Zuse)和 他的助手们完成了一个机械可编程二进制形式的计算机,并将其命名为Z1。')]
  • 22
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个使用numpy实现embedding使用余弦相似度的NTxent的示例代码: ``` python import numpy as np # 定义一些超参数 k = 10 # top-k正样本 T = 0.5 # 温度参数 # 假设我们有n个样本,每个样本有m维特征 n, m = 1000, 128 # 随机初始化嵌入向量 embeddings = np.random.randn(n, m) # 计算余弦相似度矩阵 norms = np.linalg.norm(embeddings, axis=1, keepdims=True) similarities = np.dot(embeddings, embeddings.T) / np.dot(norms, norms.T) # 对于每个样本i,选择top-k个正样本和一组负样本 pos_samples = np.zeros((n, k)) neg_samples = np.zeros((n, k)) for i in range(n): pos_samples[i] = np.argsort(similarities[i])[::-1][1:k+1] neg_samples[i] = np.random.choice(np.delete(np.arange(n), pos_samples[i]), k, replace=False) # 计算交叉熵损失 loss = 0 for i in range(n): pos_scores = np.sum(embeddings[i] * embeddings[pos_samples[i]], axis=1) / T neg_scores = np.sum(embeddings[i] * embeddings[neg_samples[i]], axis=1) / T scores = np.concatenate((pos_scores, neg_scores)) labels = np.zeros(k*2) labels[:k] = 1 loss += -np.mean(labels * np.log(np.exp(scores) / np.sum(np.exp(scores)))) print('NTxent loss:', loss) ``` 在这个示例中,我们首先随机初始化n个样本的m维嵌入向量,然后计算余弦相似度矩阵。接着,对于每个样本i,我们选择top-k个余弦相似度最大的样本作为正样本,随机选择一组与i余弦相似度较小的样本作为负样本。最后,我们计算每个样本i的交叉熵损失,并输出总的NTxent损失。 需要注意的是,这只是一个简单的示例,实际使用时需要根据具体情况进行调整和优化。此外,还需要对嵌入向量进行归一化处理,以保证余弦相似度的取值范围在[-1, 1]之间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值