Elasticsearch:图片相似度搜索的 5 个技术组成部分

news2024/10/6 10:32:40

作者:Radovan Ondas,Bernhard Suhm

在本系列博文的第一部分中,我们介绍了图像相似度搜索,并回顾了一种可以降低复杂性并便于实施的高级架构。 此博客解释了实现图像相似性搜索应用程序所需的每个组件的基本概念和技术注意事项。 学习更多关于:

  1. 嵌入模型:机器学习模型生成应用向量搜索所需数据的数值表示
  2. 推理端点:用于将嵌入模型应用于 Elastic 中的数据的 API
  3. 矢量搜索:相似性搜索如何与最近邻搜索一起工作
  4. 生成图像嵌入:将数字表示的生成扩展到大型数据集
  5. 应用逻辑:交互前端如何与后端矢量搜索引擎通信

深入研究这五个组件,你可以了解如何在 Elastic 中应用矢量搜索来实现更直观的搜索体验。

1. 嵌入模型

要将相似性搜索应用于自然语言或图像数据,你需要机器学习模型将数据转换为其数值表示,也称为矢量嵌入。 在这个例子中:

  • NLP “transformer” 模型将自然语言转化为矢量。
  • OpenAI CLIP(对比语言 - 图像预训练)模型对图像进行矢量化。

Transformer 模型是经过训练以各种方式处理自然语言数据的机器学习模型,例如语言翻译、文本分类或命名实体识别。 他们接受了极大的带注释文本数据集的训练,以学习人类语言的模式和结构。

图像相似性应用程序根据文本、自然语言描述找到匹配的图像。 要实现这种相似性搜索,你需要一个在文本和图像上都经过训练并且可以将文本查询转换为矢量的模型。 然后可以使用它来查找相似图像。

详细了解如何在 Elasticsearch 中上传和使用 NLP 模型 >>

CLIP 是 OpenAI 开发的一种可以处理文本和图像的大规模语言模型。给定一小段文本作为输入,该模型被训练来预测图像的文本表示。 这涉及学习以允许模型做出准确预测的方式对齐图像的视觉和文本表示。

CLIP 的另一个重要方面是它是一个 “零样本” 模型,允许它执行没有经过专门训练的任务。 例如,它可以在训练期间从未见过的语言之间进行翻译,或者将图像分类到以前从未见过的类别中。 这使得 CLIP 成为一个非常灵活和通用的模型。

你将使用 CLIP 模型对你的图像进行矢量化处理,使用 Elastic 中的推理端点(如下所述)并对大量图像执行推理(如下文第 3 节所述)。

2. 推理端点

一旦将 NLP 模型加载到 Elasticsearch 中,你就可以处理实际的用户查询。 首先,你需要使用 Elasticsearch _infer 端点将查询文本转换为矢量。 该端点提供了一种在 Elastic 中原生使用 NLP 模型的内置方法,不需要查询外部服务,从而显着简化了实施。

POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
  "docs" : [
    {"text_field": "A mountain covered in snow"}
    ]
}

3. 向量(相似度)搜索

在使用矢量嵌入对查询和文档进行索引后,相似文档是嵌入空间中查询的最近邻居。 实现该目标的一种流行算法是 k 最近邻 (kNN),它找到与查询向量最近的 k 个向量。 但是,对于你通常在图像搜索应用程序中处理的大型数据集,kNN 需要非常高的计算资源,并可能导致执行时间过长。 作为一种解决方案,近似最近邻 (ANN) 搜索牺牲了完美的准确性,以换取在高维嵌入空间中大规模高效执行。

在 Elastic 中,_search 端点支持精确和近似最近邻搜索。 使用下面的代码进行 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>
  }
}

要了解有关 Elastic 中 kNN 的更多信息,请参阅我们的文档:k-nearest neighbor (kNN) search | Elasticsearch Guide [8.6] | Elastic.

4. 生成图像嵌入

上面提到的图像嵌入对于图像相似性搜索的良好性能至关重要。 它们应该存储在一个单独的索引中,该索引包含图像嵌入,在上面的代码中称为 your-image-index。 该索引由每个图像的文档以及上下文字段和图像的密集矢量(图像嵌入)解释组成。 图像嵌入表示低维空间中的图像。 相似的图像被映射到这个空间中的附近点。 原始图像可能有几 MB 大,具体取决于其分辨率。

如何生成这些嵌入的具体细节可能会有所不同。 一般来说,这个过程涉及从图像中提取特征,然后使用数学函数将它们映射到低维空间。 该函数通常在大量图像数据集上进行训练,以学习在低维空间中表示特征的最佳方式。 生成嵌入是一项一次性任务。

在此博客中,我们将为此目的使用 CLIP 模型。 它由 OpenAI 分发,提供了一个很好的起点。 你可能需要为专门的用例训练自定义嵌入模型以实现所需的性能,具体取决于你要分类的图像类型在用于训练 CLIP 模型的公开可用数据中的表现程度。

Elastic 中的嵌入生成需要在摄取时发生,因此在搜索外部的过程中发生,步骤如下:

  1. 加载 CLIP 模型。
  2. 对于每个图像:
    1. 加载图像。
    2. 使用模型评估图像。
    3. 将生成的嵌入保存到文档中。
    4. 将文档保存到数据存储/Elasticsearch 中。

如下的伪代码使这些步骤更加具体,你可以在示例存储库中访问完整代码。

...
img_model = SentenceTransformer('clip-ViT-B-32')
...
for filename in glob.glob(PATH_TO_IMAGES, recursive=True):
    doc = {}
    image = Image.open(filename)
    embedding = img_model.encode(image)
    doc['image_name'] = os.path.basename(filename)
    doc['image_embedding'] = embedding.tolist()
    lst.append(doc)
...

或者参考下图作为说明:

处理后的文档可能如下所示。 关键部分是存储密集向量表示的字段 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"
   }
}

5. 应用逻辑

在这些基本组件的基础上,你最终可以将所有部分组合在一起并通过逻辑来实现交互式图像相似性搜索。 让我们从概念上开始,了解当你想要以交互方式检索与给定描述匹配的图像时需要发生的事情。

对于文本查询,输入可以简单到像 "roses" 这样的单个词,也可以是更广泛的描述,如 “a mountain covered in snow”。 或者你也可以提供一张图片并要求提供与你拥有的图片相似的图片。

尽管你使用不同的模式来制定查询,但两者都是在底层矢量搜索中使用相同的步骤序列执行的,即对由其嵌入(作为 “dense” 矢量)表示的文档使用查询 (kNN)。 我们在前面的部分中描述了使 Elasticsearch 能够对大型图像数据集执行非常快速和可扩展的矢量搜索的机制。 请参阅此文档以了解有关在 Elastic 中调整 kNN 搜索以提高效率的更多信息。

  • 那么如何实现上述逻辑呢? 在下面的流程图中,你可以看到信息是如何流动的:用户发出的查询,作为文本或图像,由嵌入模型矢量化 —— 取决于输入类型: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": "A mountain covered in snow"}
    ]
}

对于图像,你可以使用以下简化代码使用 CLIP 模型处理单个图像,你需要提前将其加载到 Elastic 机器学习节点中:

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 中最匹配的图像。

下面的流程图总结了交互式应用程序在处理用户查询时所经历的步骤:

  1. 加载交互式应用程序,它的前端。
  2. 用户选择他们感兴趣的图像。
  3. 你的应用程序通过应用 CLIP 模型将图像矢量化,并将生成的嵌入存储为密集矢量。
  4. 应用程序在 Elasticsearch 中启动 kNN 查询,它获取嵌入并返回其最近的邻居。
  5. 你的应用程序处理响应并呈现一个(或多个)匹配图像。

现在你已经了解了实现交互式图像相似性搜索所需的主要组件和信息流,你可以浏览本系列的最后一部分,了解如何实现它。 你将获得有关如何设置应用程序环境、导入 NLP 模型以及最终完成图像嵌入生成的分步指南。 然后,你将能够使用自然语言搜索图像 —— 无需关键字。 

开始设置图片相似度搜索 >>

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

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

相关文章

Python采集本地二手房,一键知晓上万房源信息

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 所以今天教大家用Python来采集本地房源数据&#xff0c;帮助大家筛选好房。 话不多说&#xff0c;让我们开始愉快的旅程吧~ 更多精彩内容、资源皆可点击文章下方名片获取此处跳转 本文涉及知识点 采集基本流程 requests 发送…

【Java】Spring Boot整合WebSocket

【Java】Spring Boot整合WebSocket WebSocket简介 WebSocket是一种协议&#xff0c;用于实现客户端和服务器之间的双向通信。它可以在单个TCP连接上提供全双工通信&#xff0c;避免了HTTP协议中的请求-响应模式&#xff0c;从而实现更高效的数据交换。WebSocket协议最初由HTM…

【计算几何】贝塞尔曲线 B样条曲线简介及其离散化 + Python C++ 代码实现

文章目录一、贝塞尔曲线二、B样条曲线三、Python 代码实现B样条曲线离散化四、C 代码实现B样条曲线离散化4.1 主要代码4.2 其余类4.3 离散效果展示&#xff08;在CAD中展示&#xff09;本文只做简介&#xff0c;关于贝塞尔曲线和B样条曲线的详细介绍&#xff0c;请参考&#xf…

unity UGUI系统梳理 - 基本布局

偷懒了&#xff0c;部分节选unity API API 1、矩形工具 为了便于布局&#xff0c;每个 UI 元素都表示为矩形。可使用工具栏中的__矩形工具 (Rect Tool)__ 在 Scene 视图中操纵此矩形。矩形工具既可用于 Unity 的 2D 功能&#xff0c;也可用于 UI&#xff0c;实际上甚至还可用…

C/C++开发,无可避免的多线程(篇三).协程及其支持库

一、c20的协程概念 在c20标准后&#xff0c;在一些函数中看到co_await、co_yield、co_return这些关键词&#xff0c;这是c20为协程实现设计的运算符。 协程是能暂停执行以在之后恢复的函数。原来我们调用一个功能函数时&#xff0c;只要调用了以后&#xff0c;就要完整执行完该…

【Kettle-佛系总结】

Kettle-佛系总结Kettle-佛系总结1.kettle介绍2.kettle安装3.kettle目录介绍4.kettle核心概念1.转换2.步骤3.跳&#xff08;Hop&#xff09;4.元数据5.数据类型6.并行7.作业5.kettle转换1.输入控件1.csv文件输入2.文本文件输入3.Excel输入4.XML输入5.JSON输入6.表输入2.输出控件…

百度Apollo规划算法——轨迹拼接

百度Apollo规划算法——轨迹拼接引言轨迹拼接1、什么是轨迹拼接&#xff1f;2、为什么要进行轨迹拼接&#xff1f;3、结合Apollo代码为例理解轨迹拼接的细节。参考引言 在apollo的规划算法中&#xff0c;在每一帧规划开始时会调用一个轨迹拼接函数&#xff0c;返回一段拼接轨迹…

Kubernetes之服务发布

学了服务发现后&#xff0c;svc的IP只能被集群内部主机及pod才可以访问&#xff0c;要想集群外的主机也可以访问svc&#xff0c;就需要利用到服务发布。 NodePort Nodeport服务是外部访问服务的最基本方式。当我们创建一个服务的时候&#xff0c;把服务的端口映射到kubernete…

【大数据AI人工智能】常见的归一化函数有哪些?分别用数学公式详细介绍

常见的归一化函数有哪些?分别用数学公式详细介绍一下。 常见的归一化函数 常见的归一化函数包括: Min-Max 归一化Z-Score 归一化Log 归一化Sigmoid 归一化下面分别介绍这些归一化函数以及它们的数学公式。 1. Min-Max 归一化 Min-Max 归一化是将原始数据线性映射到 [0,1]…

dp模型——状态机模型C++详解

状态机定义状态机顾名思义跟状态有关系&#xff0c;但到底有什么关系呢。在实际解决的时候&#xff0c;通常把状态想成节点&#xff0c;状态的转换想成有向边的有向图&#xff0c;我们来举个例子。相信大家都玩过类似枪战的游戏&#xff08;没玩过的也听说过吧&#xff09;&…

4.创建和加入通道相关(network.sh脚本createChannel函数分析)[fabric2.2]

fabric的test-network例子有一个orderer组织、两个peer组织、每个组织一个节点&#xff0c;只有系统通道&#xff08;system-channel&#xff09;&#xff0c;没有其他应用通道。我们可以使用./network.sh createChannel命令来创建一个名为mychannel的应用通道。 一、主要概念 …

【Java开发】JUC进阶 04:线程池详解

1 线程池介绍由于频繁创建销毁线程要调用native方法比较消耗资源&#xff0c;为了保证内核的充分利用&#xff0c;所以引入了线程池的概念。&#x1f4cc; 线程池优点降低资源消耗提高响应速度方便管理&#x1f4cc; 创建线程池使用Executors创建使用ThreadPoolExecutor创建&am…

Git图解-为啥是Git?怎么装?

目录 零、学习目标 一、版本控制 1.1 团队开发问题 1.2 版本控制思想 1.2.1 版本工具 二、Git简介 2.1 简介 2.2 Git环境的搭建 三、转视频版 零、学习目标 掌握git的工作流程 熟悉git安装使用 掌握git的基本使用 掌握分支管理 掌握IDEA操作git 掌握使用git远程仓…

【教程】记录Typecho Joe主题升级与Joe魔改版

目录 升级Joe 其他魔改版 Joe主题挺好看的&#xff0c;很早之前我就装了。后来官方升级了主题&#xff0c;但没有给升级教程。这里记录一下我的升级过程&#xff0c;供大家参考。 Joe Github&#xff1a;GitHub - HaoOuBa/Joe: A Theme of Typecho 升级站点&#xff1a;小锋学…

WSL2使用Nvidia-Docker实现CUDA版本自由切换

众所周知&#xff0c;深度学习的环境往往非常麻烦&#xff0c;经常不同的项目所依赖的 torch、tensorflow 包对 CUDA 的版本也有不同的要求&#xff0c;Linux 下进行 CUDA 的管理比较麻烦&#xff0c;是一个比较头疼的问题。 随着 WSL2 对物理机显卡的支持&#xff0c;Nvidia-…

用二极管和电容过滤电源波动,实现简单的稳压 - 小水泵升压改装方案

简而言之&#xff0c;就是类似采样保持电路&#xff0c;当电源电压因为电机启动而骤降时&#xff0c;用二极管避免电容电压跟着降低&#xff0c;从而让电容上连接的低功耗芯片有一个比较稳定的供电电压。没什么特别的用处&#xff0c;省个LDO 吧&#xff0c;电压跌幅太大的时候…

最详细Sql语句优化大汇总 面试必问 含解释

欢迎补充和纠正&#xff01;&#xff01;&#xff01; 目录 欢迎补充和纠正&#xff01;&#xff01;&#xff01; 基础知识 相关索引的创建 一条sql语句的执行过程 sql语句关键字的执行顺序 SQL优化 使用explain来分析Sql语句 尽量用varchar代替char 使用数值代替字符…

Vector - CAPL - 定时器函数和使用

定时器在C语言中的使用我想学习过C编程的都不会陌生&#xff0c;它能够提供延时&#xff0c;完成等待一定的时间&#xff1b;它也可以实现多线程的操作&#xff0c;并行实行某些软件功能。那在CAPL中&#xff0c;定时器又能做哪些工作呢&#xff1f;又是怎么使用的呢&#xff1…

SPringCloud:Nacos快速入门及相关属性配置

目录 一、Nacos快速入门 1、在父工程中添加spring-cloud-alilbaba的管理依赖 2、如果有使用eureka依赖&#xff0c;将其注释 3、添加nacos的客户端依赖 4、修改yml文件&#xff0c;注释eureka配置 5、启动测试 二、Nacos相关属性配置 1、Nacos服务分级存储 2、根据集群…

ELasticsearch基本使用——基础篇

1.初识elasticsearch1.1.了解ES1.1.1.elasticsearch的作用elasticsearch是一款非常强大的开源搜索引擎&#xff0c;具备非常多强大功能&#xff0c;可以帮助我们从海量数据中快速找到需要的内容例如&#xff1a;在GitHub搜索代码在电商网站搜索商品在谷歌搜索答案在打车软件搜索…