作者:朱杰、奚悦、黄宇
AI 和搜索的整合已成为下一代搜索引擎的发展趋势,技术革新的浪潮下,你是否想抓住搜索领域的新机会,增强 AI 产品力与技术竞争力?
想学习搜索引擎技术的你,是否面临这样的困惑:
- 初学实操搭建,缺少指导解惑,刚起步就困在原地
- 对基础搜索不够了解,怎样构建更高阶的搜索应用
- 自学搜索引擎难度大,工作中也没有实操的机会
- 向量检索、多模态搜索、混合搜索,只听过没用过,不知从哪入手
加入 Elasticsearch 训练营,从全文检索到向量检索,搭建高频业务场景,构建进阶向量检索应用。带你拓展技术视野,晋升 Elasticsearch 搜索实战派。
立即学习 搜文本搜位置搜图片,玩转Elasticsearch-阿里云开发者社区-阿里云
学习专属权益
- 基础学习环境:新用户免费试用阿里云检索分析服务 Elasticsearch 版一个月
- 打卡拿周边:完成指定打卡任务,可获得Elastic社区周边
- 结业赢好礼:完成参营学习任务,赢阿里云开发者社区定制礼品
循序渐进的场景实战
- Elasticsearch 基础检索
包含业务场景中高频应用的【全文检索】,同时可拓展学习【多语言检索】和【地理位置查询】
- 基于 Elasticsearch 向量检索的以文搜图
实现图片和文本的跨模态相似性比对检索,搭建基于向量检索的以文搜图的搜索服务原型
【以文搜图】实验课程先览
1. 以文搜图的实现原理
区别于传统的文本关键词搜索,现代的文本语义搜索、相似图片搜索、还有文本搜索图片的跨模态搜索普遍采用向量相似搜索的方式来实现。基本原理是将文本、图片通过深度学习模型映射到一个高纬度的向量空间,然后通过衡量向量的相似程度就可以找到最相关的文本或者图片。
下面就分 5 个方面详细讲解文本搜索图片、图片搜索图片应用所需的每个组件的基本概念和技术细节:
- 嵌入模型:把要搜索的数据转化为向量的机器学习模型
- 推理API:Elastic 中调用模型进行推理的 API
- 生成图像嵌入:调用嵌入模型将图像转化为向量
- 向量搜索:通过向量最近邻搜索实现相似性搜索
- 应用逻辑:前端程序与后端向量搜索引擎 Elasticsearch 通信
嵌入模型
要将相似性搜索应用于自然语言或图像数据,你需要使用机器学习模型将数据转换为数值表示,也称为向量嵌入(embeddings)。在这个例子中:
- NLP “transformer” 模型将自然语言转化为向量。
- OpenAI CLIP(对比语言-图像预训练)模型对图像进行向量化。
NLPTransformer 模型是经过训练处理自然语言数据的机器学习模型,例如语言翻译、文本分类或命名实体识别。他们接受了大量的带注释文本数据集的训练,以学习人类语言的模式和结构。
图像相似性应用程序根据文本、自然语言描述找到匹配的图像。要实现这种相似性搜索,你需要一个在文本和图像上都经过训练并且可以将文本查询转换为向的模型。
CLIP 是 OpenAI 开发的一种可以处理文本和图像的大规模语言模型。给定一小段文本作为输入,该模型被训练来预测图像的文本表示。这涉及到将图像的视觉
和文本表示关联起来的学习过程,然后才能进行准确的预测。
CLIP 的另一个重要方面是它是一个“零样本”模型,允许它执行没有经过专门训练的任务。例如,它可以对训练期间从未见过的语言进行翻译,或者将图像分类到以前从未见过的类别中。这使得 CLIP 成为一个非常灵活和通用的模型。
推理 API
一旦将 NLP 模型加载到 Elasticsearch 中,你就可以处理实际的用户查询。首先,你需要使用 Elasticsearch_infer API 将查询文本转换为向量。该 API 提供了一种在 Elastic 中原生使用 NLP 模型的内置方法,不需要查询外部服务,从而显著简化了实施。
POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
"docs": [
{
"text_field": "A mountain covered in snow"
}
]
}
生成图像嵌入
上面提到的图像嵌入对于图像相似性搜索的效果至关重要。它们应该存储在一个单独的索引中,该索引包含图像向量,在上面的代码中称为 your-image-index。
该索引由每个图像的文档以及上下文字段和图像的密集向量组成。图像向量表示低维空间中的图像。相似的图像被映射到这个空间中的附近点。原始图像可能有几 MB 大,具体取决于其分辨率。
如何生成这些向量的具体细节可能会有所不同。一般来说,这个过程涉及从图像中提取特征,然后使用数学函数将它们映射到低维空间。该函数通常在大量图数据集上进行训练,以学习在低维空间中表示特征的最佳方式。生成向量是一项一次性任务。
在这个项目中我们将使用 CLIP 模型。你可能需要为专门的用例训练自定义嵌入模型以实现所需的性能,具体取决于你要分类的图像类型在用于训练 CLIP 模型的公开可用数据中的表现程度。
Elastic 中的嵌入生成需要在数据写入时发生,步骤如下:
- 加载 CLIP 模型。
- 对于每个图像:
- 加载图像。
- 使用模型评估图像。
- 将生成的向量保存到文档中。
- 将文档保存到 Elasticsearch 中。
处理后的文档如下所示。关键部分是存储密集向量表示的字段 image_embedding:
{
"_index":"my-image-embeddings",
"_id":"_g9ACIUBMEjlQge4tztV",
"_score":6.703597,
"_source":{
"image_id":"IMG_4032",
"image_name":"IMG_4032.jpeg",
"image_embedding":[
-0.3415695130825043,
0.1906963288784027,
.....
-0.10289803147315979,
-0.15871885418891907
],
"relative_path":"phone/IMG_4032.jpeg"
}
}
向量相似度搜索
在使用嵌入模型对查询和文档进行向量化后,相似文档是向量空间中查询的最近邻居。实现该目标的一种流行算法是 k 最近邻 (kNN),它找到与查询向量最近
的k个向量。但是,对于你通常在图像搜索应用程序中处理的大型数据集,kNN 需要非常高的计算资源,并可能导致执行时间过长。作为一种解决方案,近似最近邻 (ANN) 搜索牺牲了完美的准确性,以换取在大规模高维向量空间中高效地执行。
在 Elastic 中,_search API 支持精确和近似最近邻搜索。使用下面的代码进行 kNN 搜索。它假定 your-image-index 中所有图像的向量都在 image_embedding 字段中。
# Run kNN search against<query-embedding> obtained above
POST <your-image-index>/_search
{
"fields":[...],
"knn":{
"field":"image_embedding",
"k":5,
"num_candidates":10,
"query_vector":<query-embedding>
}
}
应用逻辑
在这些基本组件的基础上,你最终可以将所有部分组合在一起来实现交互式图像相似性搜索。让我们从概念上开始,了解当你想要以交互方式检索匹配的图像时
需要发生的事情。
对于文本查询,输入可以简单到像 "roses" 这样的单个词,也可以是更广泛的描述,如 “a mountain covered in snow”。或者你也可以提供一张图片并要求提供与你图片相似的图片。
尽管你使用不同的模式来查询,但两者在底层向量搜索中都是使用相同的步骤执行,即对密集向量表示的文档使用 kNN 查询。我们在前面的部分中描述了使 Elasticsearch 能够对大型图像数据集执行非常快速和可扩展的向量搜索的机制。
那么如何实现上述逻辑呢?在下面的流程中,你可以看到信息是如何流动的:用户发出的查询,作为文本或图像,由嵌入模型向量化——取决于输入类型:NLP
模型用于文本描述,而 CLIP 模型用于图像。两者都将输入转换为它们的向量表示,并将结果存储为 Elasticsearch 中的密集向量类型([number, number,
number...])。
然后在 kNN 搜索中使用向量表示来查找相似的向量(图像),这些向量作为结果返回。
推理:用户查询向量化
后台的应用程序会向Elasticsearch中的推理API发送请求。对于文本输入,是这样的:
POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
"docs": [
{
"text_field": "Amountaincoveredinsnow"
}
]
}
对于图像,你可以使用以下简化代码使用 CLIP 模型处理单个图像
model = SentenceTransformer('clip-ViT-B-32')
image = Image.open(file_path)
embedding = model.encode(image)
你将得到一个 512 长的 Float32 值数组,如下所示:
{
"predicted_value": [
-0.26385045051574707,
0.14752596616744995,
0.4033305048942566,
0.22902603447437286,
-0.15598160028457642,
...
]
}
搜索:寻找相似的图片
对于两种类型的输入,搜索工作相同。将带有kNN搜索定义的查询发送到带有图像向量 my-image-embeddings 的索引。放入先前查询的密集向量 (”query_vector": [...]) 并执行搜索
GET my-image-embeddings/_search
{
"knn":{
"field":"image_embedding",
"k":5,
"num_candidates":10,
"query_vector":[
-0.19898493587970734,
0.1074572503566742,
-0.05087625980377197,
...
0.08200495690107346,
-0.07852292060852051
]
},
"fields":["image_id","image_name","relative_path"],
"_source":false
}
Elasticsearch 的响应将根据我们的 kNN 搜索查询为你提供存储在 Elasticsearch 中最匹配的图像。
下面的流程总结了交互式应用程序在处理用户查询时所经历的步骤:
- 加载交互式应用程序,它的前端。
- 用户选择他们感兴趣的图像。
- 你的应用程序通过应用 CLIP 模型将图像向量化,并将生成的向量存储为密集向量类型。
- 应用程序在 Elasticsearch 中启动 kNN 查询,它获取向量并返回其最近的邻居。
- 你的应用程序处理响应并呈现一个(或多个)匹配图像。
2. 课程实验详情
本实验将阿里云 Elasticsearch 作为支持向量近邻搜索的向量查询引擎,结合在 Elasticsearch 实例部署开源模型,将查询文本的语义特征向量化的方式,将文本和图片映射到同一个向量空间,实现图片和文本的跨模态相似性比对检索,搭建基于向量检索的以文搜图的搜索服务原型,并使用阿里云 Serverless 应用引擎 SAE 实现了前端 web 应用 demo。
说明:本实验由阿里云与Elastic公司合作创作,实验原始代码来源于 flask-elastic-nlp 项目,点击查看 Github 项目地址。
2.1 领取实验产品资源
本实验场景使用的实验资源和配置,说明如下:
- 资源规格说明:本示例遵循最小原则,使用满足场景需求的最小资源。
- 免费试用说明:首购客户可以免费试用 Serverless 应用引擎 SAE、传统型负载均衡 CLB 可以使用免费试用资源。
- 付费说明:本实验推荐使用阿里云 Elasticsearch 4C8G 规格的按量付费资源,
- 计费标准 3.7 元起/时(不同地域价格略有差异);如果用户没有 SAE 免费试用领取资格,推荐使用 SAE2C4G 规格的按量付费资源,计费标准为单实例0.0074074 元/min。
具体配置项说明和资源领取步骤,请参见 搜文本搜位置搜图片,玩转Elasticsearch-阿里云开发者社区-阿里云
2.2 实验步骤
2.2.1 创建配置 Elasticsearch 部分
1. 进入控制台,找到 Elasticsearch 所在的地域,从实例列表页找到实验需要使用 ES 的实例:
2. 点击实例 ID 或 “管理”,进入实例详情页,可查看ES的实例所在的专有网络、私网地址、私网端口等信息;
3. 进入安全配置,确认 VPC 私网访问白名单是否包含 ES 实例所在的专有网络的全部网段:
专有网络网段可以进入专有网络列表页查看:阿里云登录 - 欢迎登录阿里云,安全稳定的云计算服务平台
4. 进入可视化控制,在修改配置页修改 Kibana 公网访问白名单为本机 IP:
5. 点击公网入口进入 Kibana,正确输入用户名密码后,即可登录。用户名默认为:elastic;密码为实例创建时输入的自定义密码。
6. 左侧菜单栏 “Management” 进入 “开发工具”
7. 通过快照恢复方式将数据集和模型导入到 ES 实验实例中:
1)创建快照仓库并指定公共读的阿里云 OSS bucket 作为源存储库
代码:
PUT _snapshot/my_backup/
{
"type": "oss",
"settings": {
"endpoint": "http://oss-rg-china-mainland.aliyuncs.com",
"bucket": "es-image-search",
"base_path": "snapshot/",
"readonly": true,
"access_key_id": "xxxx",
"secret_access_key":"xxxx",
"region": "oss-rg-china-mainland"
}
}
说明:“access_key_id” 和 “secret_access_key” 字段的具体信息,请进入课程学习钉群(群号:28810034388)在群公告处获取。
2)从公共读的 OSS 中恢复快照到当前实验实例中:
代码:
POST /_snapshot/my_backup/snapshot_1/_restore
{
"indices": "image-embeddings",
"feature_states": [
"machine_learning"
],
"ignore_unavailable": true,
"include_global_state": false
}
3)确认数据已同步完毕:
左侧菜单栏 “Management” 进入 “Stack Management”的“ 索引管理”模块,确认 “image-embeddings” 和 ".ml-inference-native-000001" 大小和下图一致:
8. 左侧菜单栏 “Analytics” 进入 “Machine Learning” 中 “同步模型” 后进入 “模型管理-已训练模型” 并部署
tips:如遇以下网络返回超时报错可忽略,关闭报错窗口并刷新,模型状态能正常更新为 “started” 即可。
9. 测试模型,输入词组或短句,该模型可以将文本数据转换成向量数据:
该模型支持中英文的文本转换,成功转化为向量后,说明模型部署成功。
2.2.2 创建和配置 SAE 部分
本步骤仅介绍关键配置项,其余配置项保持默认即可。
1. 登录 SAE 控制台。
2.(可选)在左侧导航栏,单击命名空间(环境),在顶部菜单栏选择华北2(北京)地域,然后在命名空间页面,单击创建命名空间,在创建命名空间面板,配置相关信息,单击确定。
配置项 | 教程配置 |
---|---|
命名空间名称 | 自定义,例如输入 demo。 |
命名空间 ID | 自定义,例如输入 demo。 |
描述 | 自定义,例如输入测试。 |
说明:如果跳过该步骤,在创建应用时(步骤4)选择默认命名空间,则应用创建成功后,需要切换 VPC,修改为与 Elasticsearch 实例配置一致的 VPC。
3. 在左侧导航栏,选择应用管理>应用列表,然后在应用列表页面,单击创建应用。
4. 在创建应用页面,配置相关信息。
a.在应用基本信息配置向导,配置相关信息,然后单击下一步:应用部署配置。
配置项 | 教程配置 |
---|---|
应用名称 | 自定义,例如输入 demo。 |
专有网络配置 | 选择自定义配置。 |
命名空间 |
|
vSwitch | 选择与 Elasticsearch 实例配置一致的虚拟交换机。 |
安全组 | 选择与 Elasticsearch 实例配置一致的 VPC 绑定的安全组。更多信息,请参见创建安全组。 |
应用实例数 | 1 |
VCPU | 2Core |
内存 | 4GiB |
2. 在应用部署配置配置向导,配置相关信息,然后单击下一步:确认规格。
配置项 | 教程配置 |
---|---|
技术栈语言 | 选择 Python。 |
应用部署方式 | 选择镜像。 |
配置镜像 | 在配置镜像区域,单击Demo镜像页签,选择SAE提供的版本为nlp的镜像Demo。完整的镜像地址如下:registry-vpc.cn-beijing.aliyuncs.com/sae-serverless-demo/python-demo:nlp |
环境变量设置 | 展开环境变量设置区域,选择类型为自定义,新增3对键值对,格式如下:
|
注意事项如下:
- ES_HOST 可在阿里云 Elasticsearch 控制台的实例基本信息页面获取 ES 实例的私网地址
- 请注意格式为:http://es-cn-vxxxxx.elasticsearch.aliyuncs.com:9200
- ES_USER 和 ES_PWD 为开通 Elasticsearch 时填写的的账户名和密码
4. 页面会跳转至创建完成配置向导,你可以单击应用详情页进入基本信息页面。
2.2.3 为 SAE 应用绑定负载均衡 CLB
SAE 支持绑定的 SLB,为传统型负载均衡 CLB(Classic Load Balancer),属于阿里云负载均衡 SLB(Server Load Balancer)支持的负载均衡类型之一
1) 在应用的基本信息页面的应用访问设置区域,单击添加公网 SLB 访问。
2. 在添加公网访问 SLB 对话框,从请选择 SLB 下拉列表中,选择复用已创建的免费试用 CLB 资源(优先),或者新建 SLB 资源(如果没有 CLB 领取资格需要额外付费),然后在 HTTP 协议页签,HTTP 端口输入 80,容器端口输入 5001,单击确认。
注意:如果你复用已创建的 SLB,且需要确保 HTTP 端口和容器端口均未被占用。更多信息,请参见 CLB 按量付费。
3. 添加完成后,n 可以在公网访问地址栏看到该公网 SLB 的 IP 地址和端口。
4. 在浏览器地址栏中输入上一步获得的 SLB 的 IP 地址:端口,并回车访问公网。在如下界面中,我们可以在搜索框中输入文字搜索图片,或者在图片结果列的“搜索相似图片”按钮,搜索相似图片。下图红色框的内容展现了搜索相似图片的实现原理。
原文:基于 Elasticsearch 向量检索的以文搜图-阿里云开发者社区