利用Embedding优化搜索功能

我们继续用Gemini学习LLM编程之旅。

Embedding是一种自然语言处理 (NLP) 技术,可将文本转换为数值向量。Embedding捕获语义含义和上下文,从而导致具有相似含义的文本具有更接近的Embedding。例如,句子“我带我的狗去看兽医”和“我带我的猫去看兽医”在向量空间中的Embedding会比较接近,因为它们都描述了相似的上下文。

Gemini 接口中的嵌入服务(models/embedding-001)可为单词、短语和句子生成embedding,然后生成的embedding可用于 NLP 任务,例如语义搜索、文本分类和聚类等。

本期文章参考徐文浩老师的《语义检索,利用Embedding优化你的搜索功能》(https://time.geekbang.org/column/article/644795) ,学习如何用embedding优化搜索,即通过语义来搜索(在给定一段输入文本的情况下检索语义相似的文本),而非传统的基于关键词分词的搜索。徐文浩老师的课程中用OpenAI的text-davinci-003模型生成淘宝产品标题,用text-embedding-ada-002生成Embedding。

由于gemini-pro对中文支持不好,models/embedding-001甚至完全不支持中文,我们会用gemini-pro生成Amazon的英文产品标题,用models/embedding-001生成Embedding。

一开始没留意谷歌的models/embedding-001不支持中文(文档没提),只是奇怪计算出来的余弦相似度很多一样,还以为自己的代码错了。后面用代码具体测试,才发现它生成的中文embedding一模一样。

human = genai.embed_content(model="models/embedding-001", content='人类', task_type="retrieval_query",
)['embedding']
mouse = genai.embed_content(model="models/embedding-001", content='鼠标', task_type="retrieval_query",
)['embedding']# 比较两个嵌入向量列表是否相同
embeddings_are_equal = human == mouse
print(f"人类和鼠标的嵌入向量是否相同: {embeddings_are_equal}")

得到的结果是:

人类和鼠标的嵌入向量是否相同: True

设置环境

先参考《免费使用谷歌Gemini模型学习LLM编程》(https://juejin.cn/post/7315009908302331923)获取API Key,设置环境变量。

import osimport google.generativeai as genai
import pandas as pd
from dotenv import find_dotenv, load_dotenv
import numpy as np_ = load_dotenv(find_dotenv())  # read local .env fileGOOGLE_API_KEY = os.getenv('GOOGLE_API_KEY')
genai.configure(api_key=GOOGLE_API_KEY)model = genai.GenerativeModel("gemini-pro")

通过Gemini Pro生成实验数据

一般可以从网上下载或者直接用机器学习软件包自带的数据集来做实验,现在大语言模型来了,我们也可以直接让大语言模型帮我们生成实验数据。只要不是用于训练大模型,直接使用没有任何问题。

(参考字节跳动账户被封禁)

data = model.generate_content(" Please generate 50 product titles from Amazon, each about 50 characters long. The category is 3C digital products. The title often contains some promotional information, one per line.").text
digital_product_names = data.strip().split('\n')
digital_df = pd.DataFrame({'product_name': digital_product_names})
digital_df.product_name = digital_df.product_name.apply(lambda x: x.split('.')[1].strip())
digital_df.head()

让gemini-pro生成amazon的3C类别的产品标题,按行分隔,并加载到panda的DataFrame。注意,大模型返回的结果里面带了标号,通过这行代码去掉了:digital_df.product_name = digital_df.product_name.apply(lambda x: x.split('.')[1].strip())

输出结果:

All-in-One 4K UHD Smart TV with Built-in Streaming Apps and Voice Control
High-Performance Gaming PC with RGB Lighting and Liquid Cooling
Ultra-Thin Laptop with Long Battery Life and Fast Charging
Premium Noise-Canceling Headphones with Hi-Res Audio and Multipoint Connectivity
Powerful Wireless Router with Mesh Technology for Whole-Home Coverage

为了让实验数据多样化,再让模型生成女士的衣服、箱包类的商品标题。

clothes_data = model.generate_content("""Please generate 50 product titles from Amazon, each about 50 characters long. The category is women’s clothing, bags, etc. The title often contains some promotional information, one per line.""").text
clothes_product_names = clothes_data.strip().split('\n')
clothes_df = pd.DataFrame({'product_name': clothes_product_names})
clothes_df.product_name = clothes_df.product_name.apply(lambda x: x.split('.')[1].strip())
clothes_df.head()

输出结果:

Women’s Lightweight Summer Maxi Dress with Pockets: Flattering Flowy Beach Style
Crossbody Bag for Women: Durable Leather with Adjustable Strap and Multiple Compartments
“Women’s Designer Handbag Set: Tote, Crossbody, and Clutch Bag in One”
Vegan Leather Backpack for Women: Convertible to Tote or Shoulder Bag
Women’s Casual Shift Dress with Ruffle Sleeves: Comfortable and Stylish

再把两个DataFrame拼接起来作为我们最终的实验数据:

df = pd.concat([digital_df, clothes_df], axis=0)
df = df.reset_index(drop=True)
df

输出结果:
在这里插入图片描述

通过 Embedding 进行语义搜索

传统的搜索主要有两种:一种是数据库,不管是关系型数据库还是NoSQL数据库,都提供like类型的搜索,这种方式是直接查找某个字段是否包含某个关键词;另外一种是像ElasticSearch之类的全文检索,通过倒排索引的方式,先建立关键词到具体文档的映射,在搜索的时候,匹配上关键词,再返回对应的文档列表。

这两种方式具体到细节,当然都有很多可以优化的地方,但是本质上,都是通过关键词匹配,你的关键词选错了,就找不到对应的商品、文档等。所以,很多电商的商家,在将产品上架的时候,会在系统允许的范围内将商品的标题填上各种各样的关键词,目的就是为了尽可能匹配上关键词,获得更多搜索的流量。后台也会提供类似“买家搜索词”之类的工具,方便商家了解用户可能用什么关键词来搜索。这种“人工”智能比较费人工,但是关键词堆多了,也能有比较好的效果。

这个策略最大的缺点就是如果产品没有包含那个关键词,即使是同义词,语义上很接近,也搜索不到。

现在有了Embedding 的接口,就可以把一段文本的语义表示成一段向量。而向量之间是可以计算距离的。我们可以把用户的搜索也通过 Embedding 接口变成向量,然后把它和所有的商品的标题向量计算一下点积或者余弦距离,找出离我们搜索词最近的几个向量。最近的几个向量,其实就是语义和这个商品相似的,而并不需要相同的关键词。

下面来看一下具体的步骤。

保存文档的Embedding

首先,我们要把随机生成的所有商品标题,都计算出它们的Embedding,然后保存下来。

product_names_list = df.product_name.tolist()
#Note: Specifying a title for RETRIEVAL_DOCUMENT provides better quality embeddings for retrieval.
embeddings = (genai.embed_content(model="models/embedding-001", content=product_names_list, task_type="retrieval_document", title="amazon product names"))['embedding']
print(f"embeddings len:{len(embeddings)}")
df["embedding"] = embeddings
df.to_parquet("data/amazon_product_title.parquet", index=False)
df.to_csv("data/amazon_product.csv", index=False)
df

注意谷歌生成embedding和其他的不太一样,有一个task_type,可能是针对不同的应用场景做了优化。

这里我们是用来做文档检索,而且现在是建立文档的“数据库”,所以task_type设置为retrieval_document,针对retrieval_document,还可以设置一个可选的title;等下查询的时候task_type要设为retrieval_query。

谷歌的models/embedding-001生成embedding还是很方便的,传入字符串列表就可以直接生成向量列表。

Task TypeDescription
RETRIEVAL_QUERYSpecifies the given text is a query in a search/retrieval setting.
RETRIEVAL_DOCUMENTSpecifies the given text is a document in a search/retrieval setting.
SEMANTIC_SIMILARITYSpecifies the given text will be used for Semantic Textual Similarity (STS).
CLASSIFICATIONSpecifies that the embeddings will be used for classification.
CLUSTERINGSpecifies that the embeddings will be used for clustering.

搜索产品

接下来我们定义一个 search_product 的搜索函数,接受三个参数:df 代表用于搜索的数据源, query 代表用于搜索的搜索词,n 代表搜索返回多少条记录。

而这个函数做了这三件事情:

  • 调用谷歌的接口将搜索词转换成 Embedding。
  • 将这个 Embedding 和 DataFrame 里的每一个 Embedding 都计算一下点积。
  • 根据点积去排序,返回点积最大的 n 个标题。

点积的值可以在 -1 和 1 之间(包含 -1 和 1)。如果两个向量之间的点积为 1,则这两个向量的方向相同。如果点积值为 0,则这些向量彼此正交或不相关。最后,如果点积为 -1,则向量指向相反方向并且彼此不相似。

def search_product(df, query, n=5, pprint=True):product_embedding = genai.embed_content(model="models/embedding-001", content=query, task_type="retrieval_query")['embedding']df["dot_products"] = df.embedding.apply(lambda x: np.dot(x, product_embedding))results = (df.sort_values("dot_products", ascending=False).head(n).loc[:, ["product_name", "dot_products"]])if pprint:for index, row in results.iterrows():print(f"{row['product_name']} - dot_products: {row['dot_products']}")return resultsresults = search_product(df, "elegant dress for summer for beach vacations", n=3)

我们搜索 elegant dress for summer for beach vacations 得到结果:

Women's Lightweight Summer Maxi Dress with Pockets: Flattering Flowy Beach Style - dot_products: 0.6860313467181551
Women's Mini Dress: Sexy and Elegant, Perfect for a Night Out - dot_products: 0.6560099266011095
Women's Floral Print Wrap Dress: Flattering Design for Any Occasion - dot_products: 0.6244976428038793

搜索英文的结果还可以。

注意事项

在实际项目中使用这种方式优化的时候,或者是使用向量数据库来找匹配的文档的时候,要注意的是,返回的文档只是库里和你的查询最相似的。但是即使相差十万八千里,向量的距离也不太可能是0或者-1。以我们这次实验的数据为例,“elegant dress for summer for beach vacations”和”VR Gaming Controller with Haptic Feedback and Motion Controls”是最不相关的,点积也有0.415979671305287。所以,可能要根据具体的项目,低于某个数值就认为是不相干的,就不要返回了。

参考

  1. https://time.geekbang.org/column/article/644795
  2. https://ai.google.dev/docs/embeddings_guide?hl=en
  3. https://ai.google.dev/examples/doc_search_emb

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/596536.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LeetCode---378周赛

题目列表 2980. 检查按位或是否存在尾随零 2981. 找出出现至少三次的最长特殊子字符串 I 2982. 找出出现至少三次的最长特殊子字符串 II 2983. 回文串重新排列查询 一、检查按位或是否存在尾随零 这题和位运算有关,不是很难,题目要求至少有两个数的…

案例073:基于微信小程序的智慧旅游平台开发

文末获取源码 开发语言:Java 框架:SSM JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序…

用贪心算法编程求解任务安排问题

题目:用贪心算法编程求解以下任务安排问题 一个单位时间任务是恰好需要一个单位时间完成的任务。给定一个单位时间任务的有限集S。关于S的一个时间表用于描述S中单位时间任务的执行次序。时间表中第1个任务从时间0 开始执行直至时间1 结束,第2 个任务从时…

20240104确认AIO-3399J的开发板适配ov13850摄像头不支持4K分辨率录像

20240104确认AIO-3399J的开发板适配ov13850摄像头不支持4K分辨率录像 2024/1/4 13:23 开发板:Firefly的AIO-3399J【RK3399】 SDK:rk3399-android-11-r20211216.tar.xz【Android11】 Android11.0.tar.bz2.aa【ToyBrick】 Android11.0.tar.bz2.ab Android1…

人工智能如何重塑金融服务业

在体验优先的世界中识别金融服务业中的AI使用场景 人工智能(AI)作为主要行业的大型组织的重要业务驱动力,持续受到关注。众所周知,传统金融服务业在采用新技术方面相对滞后,一些组织使用的还是上世纪50年代和60年代发…

Android Jetpack学习系列——Navigation

写在前面 Google在2018年就推出了Jetpack组件库,但是直到今天我才给重视起来,这真的不得不说是一件让人遗憾的事。过去几年的空闲时间里,我一直在尝试做一套自己的组件库,帮助自己快速开发,虽然也听说过Jetpack&#…

Android如何正确使用 Canvas 的 save() 和 restore() 方法

如何正确使用 Canvas 的 save() 和 restore() 方法 在Android的绘图API中,Canvas类提供了一系列强大的功能来绘制自定义视图。为了更高效地管理绘图状态和变换,Canvas类提供了save()和restore()方法。正确使用这些方法是高效绘图和避免常见错误的关键。 …

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义 流程图 流程图中各种图形的含义及用法解析 连接线符号 连接各要素,表示流程的顺序或过程的方向。 批注符号 批注或说明,也可以做条件叙述。 子流程 流程中一部分图形的逻辑…

机器人动力学一些笔记

动力学方程中,Q和q的关系(Q是sita) Q其实是一个向量,q(Q1,Q2,Q3,Q4,Q5,Q6)(假如6个关节) https://zhuanlan.zhihu.com/p/25789930 举个浅显易懂的例子,你在房…

Windows内核理论基础学习

文章目录 前言Windosw内核 理论基础Windows体系结构CPU权限级别内存空间布局Windows内核结构硬件抽象层(HAL)内核层执行体层设备驱动程序文件系统/存储管理网络 Windows子系统窗口管理图形设备接口 系统线程和系统进程 内核基本概念处理器模式内存管理进…

项目框架构建之5:日志的构建

本文是“项目框架构建”系列之5,本文介绍日志的构建。 为了做出通用的公共日志模块,我们需要使用微软的Microsoft.Extensions.Logging日志管理模块,该模块提供了灵活且可扩展的日志记录机制,它为整个.net应用程序提供了一致统一的…

02-微服务-Eureka注册中心

Eureka注册中心 假如我们的服务提供者user-service部署了多个实例,如图: 大家思考几个问题: order-service在发起远程调用的时候,该如何得知user-service实例的ip地址和端口?有多个user-service实例地址,…

每日一道算法题day-one(备战蓝桥杯)

从今天开始博主会每天做一道算法题备战蓝桥杯,并分享博主做题的思路,有兴趣就加入我把! 算法题目: 有一个长度为 N 的字符串 S ,其中的每个字符要么是 B,要么是 E。 我们规定 S 的价值等于其中包含的子…

牛客网面试题知识点记录-03

1.题目讲解重写后子类调用父类的方法总结:当子类重写了父类方法A,父类方法直接调用被重写的父类方法后,调用的是子类的重写的父类方法A。 class Test {public static void main(String[] args) {System.out.println(new B().getValue());}st…

在线负公差测径仪 生产场景智能化

在线负公差测径仪是专为负公差轧制而研发的精密仪器,除检测的外径尺寸外,还能对负公差信息进行展示。让操作工对生产更加得心应手。 负公差测径仪同样采用八轴测头进行非接触式的在线检测,以实现全方位的尺寸检测,并将截面图实时展…

申请域名SSL证书并自动推送至阿里云 CDN

近期国外SSL证书厂商调整了免费证书的续签规则,一年期的证书全部取消,现在只能申请90天有效期的免费证书。普通web站点可以通过宝塔面板或部署acme.sh等证书自动管理工具来实现自动化申请和部署,但是阿里云之类的CDN服务就只能通过手动或Open…

初步认识API安全

一、认识API 1. 什么是API API(应用程序接口):是一种软件中介,它允许两个不相关的应用程序相互通信。它就像一座桥梁,从一个程序接收请求或消息,然后将其传递给另一个程序,翻译消息并根据 API 的程序设计执行协议。A…

利用阿里云的尖端数据库解决方案增强游戏数据管理

在快节奏和动态的游戏世界中,对于努力为玩家提供无缝体验的公司来说,管理大量数据是一项关键挑战。阿里云是亚太地区的主要参与者,也是全球公认的运营数据库管理系统领导者,提供量身定制的创新解决方案,以应对游戏公司…

C# 全屏label控件实现的贪吃蛇。

C# 全屏label控件实现的贪吃蛇。 using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; using stat…

案例074:基于微信小程序的儿童预防接种预约管理系统

文末获取源码 开发语言:Java 框架:springboot JDK版本:JDK1.8 数据库:mysql 5.7 开发软件:eclipse/myeclipse/idea Maven包:Maven3.5.4 小程序框架:uniapp 小程序开发软件:HBuilder …