当前位置: 首页 > news >正文

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

作者: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 模型以及最终完成图像嵌入生成的分步指南。 然后,你将能够使用自然语言搜索图像 —— 无需关键字。 

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

相关文章:

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

作者&#xff1a;Radovan Ondas&#xff0c;Bernhard Suhm 在本系列博文的第一部分中&#xff0c;我们介绍了图像相似度搜索&#xff0c;并回顾了一种可以降低复杂性并便于实施的高级架构。 此博客解释了实现图像相似性搜索应用程序所需的每个组件的基本概念和技术注意事项。 学…...

【CVPR2022】Class Re-Activation Maps for Weakly-Supervised Semantic Segmentation

论文标题&#xff1a;Class Re-Activation Maps for Weakly-Supervised Semantic Segmentation收录&#xff1a;CVPR 2022paper: https://arxiv.org/abs/2203.00962code: https://github.com/zhaozhengChen/ReCAM解读&#xff1a;https://zhuanlan.zhihu.com/p/478133151https:…...

PMP项目管理项目运行环境

目录1 概述2 事业环境因素和组织过程资产3 组织系统3.1 概述3.2 组织治理框架3.2.1 治理框架3.2.2 项目治理3.3 管理要素3.4 组织结构类型3.4.1 组织结构类型3.4.2 项目管理办公室1 概述 项目所处的环境可能对项目的开展产生有利或不利的影响&#xff0c;这些影响的两大主要来…...

Vue 3.0 渲染函数 【Vue3 从零开始】

Vue 推荐在绝大多数情况下使用模板来创建你的 HTML。然而在一些场景中&#xff0c;你真的需要 JavaScript 的完全编程的能力。这时你可以用渲染函数&#xff0c;它比模板更接近编译器。 让我们深入一个简单的例子&#xff0c;这个例子里 render 函数很实用。假设我们要生成一些…...

西电软件体系结构核心考点汇总(期末真题+核心考点)

文章目录前言一、历年真题二、核心考点汇总2.1 什么是软件体系架构?(软件体系结构的定义)2.2 架构风格优缺点2.3 质量属性2.4 质量评估前言 主要针对西安电子科技大学《软件体系结构》的核心考点进行汇总。 【期末期间总结资料如下】 针对西电计科院软件工程专业大三《软件体…...

SRS源码分析-SDP内容解析

前言 在学习SRS的RTC模块之前&#xff0c;首先来分析下SRS在将rtmp推流转成rtc流&#xff0c;通过浏览器拉取webrtc流场景下产生的SDP内容 SDP格式介绍 SDP数据是文本格式&#xff0c;由多个 <key><value> 表达式构成&#xff0c;<key>的值只能是一个字符…...

HTML 颜色

HTML 颜色 HTML 颜色采用的是 RGB 颜色&#xff0c;是通过对红 (R)、绿 (G)、蓝 (B) 三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的&#xff0c;RGB 即是代表红、绿、蓝三个通道的颜色。 Color Values HTML 颜色由一个十六进制符号来定义&#xff0c;这个符…...

MySQL高可用架构之InnoDB Cluster部署

MySQL高可用架构之InnoDB Cluster部署InnoDB Cluster适用场景准备工作安装MySQL Shell使用MySQL Shell搭建InnoDB Cluster初始化第一个实例创建InnoDB Cluster添加副本实例创建相关用户MySQL Router部署安装MySQL Router引导MySQL Router启动MySQL Router环境准备 主机名IPOS版…...

Linux安装minio单机版

说明&#xff1a;因为前面记录了一下minio的使用&#xff0c;这里说一下minio的安装&#xff0c;只是单机版哦 环境准备&#xff1a;Linux系统 说明图&#xff1a; 1.创建文件夹命令 我的是安装在/usr/local 文件夹下面的创建文件夹命令 #进入目标文件夹 cd /usr/local#创建…...

网络总结知识点(网络工程师必备)四

♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放,树高千尺,落叶归根人生不易,人间真情 目录 前言 71.NAPT有什么特点? 72.ARP欺骗解决方法...

数据结构——第三章 栈与队列(5)

共用栈和双队列1.共用栈2.双端队列栈与队列的本章小节1.共用栈 在实际应用中&#xff0c;有时一个应用程序需要多个栈&#xff0c;但这些栈的数据元素类型相同。假设每个栈都采用顺序栈&#xff0c;由于每个栈的使用情况不尽相同&#xff0c;势必会造成存储空间的浪费。若让多…...

CSDN竞赛第33期题解

CSDN竞赛第33期题解 1、题目名称&#xff1a;奇偶排序 给定一个存放整数的数组&#xff0c;重新排列数组使得数组左边为奇数&#xff0c;右边为偶数。&#xff08;奇数和偶数的顺序根据输入的数字顺序排 列&#xff09; #include<bits/stdc.h> using namespace std; t…...

农产品销售系统的设计与实现

技术&#xff1a;Java、JSP等摘要&#xff1a;这篇文章主要描述的是农产品蔬菜在线销售系统的设计与实现。主要应用关于JSP网站开发技术&#xff0c;并联系到网站所处理的数据的结构特点和所学到的知识&#xff0c;应用的主要是Mysql数据库系统。系统实现了网站的基本功能&…...

C语言-基础了解-08-C判断

C判断 一、C判断 判断结构要求程序员指定一个或多个要评估或测试的条件&#xff0c;以及条件为真时要执行的语句&#xff08;必需的&#xff09;和条件为假时要执行的语句&#xff08;可选的&#xff09;。 C 语言把任何非零和非空的值假定为 true&#xff0c;把零或 null 假…...

用数组名作函数参数的详解,以及形参实参采用数组名,形参实参采用指针变量的几种情况解析

关于地址&#xff0c;指针&#xff0c;指针变量可以参考我的这篇文章&#xff1a; 地址&#xff0c;指针&#xff0c;指针变量是什么&#xff1f;他们的区别&#xff1f;符号&#xff08;*&#xff09;在不同位置的解释&#xff1f;_juechen333的博客-CSDN博客https://blog.csd…...

k8s中的PV和PVS

前言&#xff1a;容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重启它&#xff0c;但是容器中的文件将丢失——容器以干净的状态&#xff08;镜像最初的状态&#xff09;…...

【云原生】Gateway网关选型

网关一般分为流量网关和业务网关&#xff0c;流量网关负责接入所有的流量&#xff0c;并分发给不同的子系统&#xff0c;那在具体的业务接入之前&#xff0c;还有一层业务网关。流量网关提供全局性的、与后端业务应用无关的策略&#xff0c;例如 HTTPS证书卸载、Web防火墙、全局…...

QML Button详解

1.Button简介 Button表示用户可以按下或单击的按钮控件。按钮通常用于执行一个动作&#xff0c;或回答一个问题。典型的按钮有确定、应用、取消、关闭、是、否和帮助。 Button继承自AbstractButton&#xff0c;提供了以下几种信号。 void canceled() //当按…...

【编程实践】什么是好/坏代码?非程序员的示例

What is good/bad code? An illustrated example for non-programmers 什么是好/坏代码?非程序员的示例 目录 What is good/bad code? An illustrated example for non-programmers什么是好/坏代码?非程序员的示例 So what is ‘Bad Code’, as a layperson?那么,作为…...

一个简单的Sublime设置

问题 如果读者熟悉我&#xff0c;应该会发现我经常使用 VSCode 作为主力编辑器&#xff0c;但随着我安装的 VSCode 的插件逐渐增加&#xff0c;我发现对于部分较小的任务使用 VSCode 过于笨重&#xff0c;比如简单的 Markdown 文件编辑工作。 在经过一系列寻找后&#xff0c;…...

c语言经典例题-选择结构程序设计进阶

(创作不易&#xff0c;感谢有你&#xff0c;你的支持&#xff0c;就是我前行的最大动力&#xff0c;如果看完对你有帮助&#xff0c;请留下您的足迹&#xff09; 目录 快递费用计算&#xff1a; 题目&#xff1a; 代码思路&#xff1a; 代码表示&#xff1a; 计算一元二…...

NOI 2023春季测试 游记

怎么说&#xff0c;没遇到大波折即幸运。 Day 0 睡到下午三点&#xff0c;然后列了一堆复习计划&#xff0c;大概是左偏树等一些早就忘没的科技。 但是沉迷打块&#xff0c;最后基本什么计划也没完成。 白天睡多了&#xff0c;晚上睡不着&#xff0c;大概半梦半醒过了一整夜…...

【VC 7/8】vCenter Server 基于文件的备份和还原Ⅱ——使用 FTP 协议备份 VC(VAMI 英文)

目录2. 备份 vCenter Server2.1 使用 FTP 协议备份 VC&#xff08;1&#xff09;登录 vCenter Server 管理界面&#xff08;2&#xff09;进入Backup页面&#xff08;3&#xff09;配置 Backup Schedule&#xff08;4&#xff09;开始备份&#xff08;5&#xff09;备份成功&am…...

Python基础—文件操作(二)

Python基础—文件操作(二) CSV格式文件 逗号分隔值&#xff0c;以纯文本形式存储表格数据 由任意数目的记录组成&#xff0c;记录间以换行符分隔 每条记录由字段组成&#xff0c;字段间用逗号或制表符分隔 每条记录都有同样的字段序列 如有列名&#xff0c;位于文件第一行 每条…...

学校的班级个数【并查集基础应用,Java实现】

题目描述 现有一个学校&#xff0c;学校中有若干个班级&#xff0c;每个班级中有若干个学生&#xff0c;每个学生只会存在于一个班级中。如果学生A和学生B处于一个班级&#xff0c;学生B和学生C处于一个班级&#xff0c;那么我们称学生A和学生C也处于一个班级。 现已知学校中共…...

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

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

pygame9 扫雷游戏2

一、响应鼠标左键事件 pygame.MOUSEBUTTONDOWN 表示鼠标事件发生&#xff0c; pygame.mouse.get_pressed()[0] 确认是鼠标左键被按下 pygame.mouse.get_pos() 获取到鼠标按下时的坐标值。 因此&#xff0c;我们可以在事件逻辑中例用此三个函数判断鼠标事件及对应的坐标&#x…...

逻辑电路代数运算(上)

逻辑代数L是一个封闭的代数系统&#xff0c;由一个逻辑变量集K&#xff0c;常量0和1&#xff0c;以及与或非三种基本运算构成。 参与逻辑运算的变量叫逻辑变量&#xff0c;用字母A&#xff0c;B……表示。每个变量的取值非0 即1。 0、1不表示数的大小&#xff0c;而是代表两种不…...

Rabbit快速入门

入门案例 需求&#xff1a;使用简单模式完成消息传递 步骤&#xff1a; 创建工程&#xff08;生成者、消费者&#xff09; 分别添加依赖 编写生产者发送消息 编写消费者接收消息 3.1.2. 添加依赖 往heima-rabbitmq的pom.xml文件中添加如下依赖&#xff1a; <dependenc…...

【react+ts- forwardRef】

reactts- forwardRef1. 学习资料2. 普通input透传2.1 TS版本2.2 JS版本3. TS-Antd-Form组价透传引用传递&#xff08;Ref forwading&#xff09;是一种通过组件向子组件自动传递 引用ref 的技术。对于应用者的大多数组件来说没什么作用。但是对于有些重复使用的组件&#xff0c…...