使用火山云搜索ESCloud服务构建图文检索应用(以文搜图/以图搜图)

图文检索在生活中具有广泛的应用,常见的图片检索包括基于文本内容搜索和基于图片内容搜索。用户通过输入文字描述或上传图片就可以在海量的图片库中快速找到同款或者相似图片,这种搜索方式被广泛应用于电商、广告、设计以及搜索引擎等热门领域。

本文基于火山引擎云搜索服务 ESCloud 和图文特征提取模型 CLIP,快速搭建一套以图搜图,以文搜图的端到端解决方案。

原理介绍

图片搜索技术,以文本描述和图片作为检索对象,分别对 image 和 text 进行特征提取,并在模型中对文本和图片建立相关联系,然后在海量图片数据库进行特征向量检索,返回与检索对象最相关的记录集合。其中特征提取部分采用 CLIP 模型,向量检索使用火山引擎云搜索服务在海量图片特征中进行快速的搜索。

 

环境依赖准备

1.登录火山引擎云搜索服务,创建实例集群,集群版本选择 7.10。

2.Python Client 关键依赖准备

pip install -U sentence-transformers # 模型相关 pip install -U elasticsearch7==7.10.1 # ES向量数据库相关 pip install -U pandas #分析splash的csv

数据集准备

我们选择 Unsplash 作为图片数据集,详细介绍请参考:https://unsplash.com/data。在此示例中,我们选择下载 Lite 数据集,其中包含约 25,000 张照片。下载完成后会获得一个压缩文件,其中包含描述图片的 CSV 文件。通过使用 Pandas 读取 CSV 文件,我们将获得图片的 URL 地址。

def read_imgset(): path = '${下载的数据集所在路径}' documents = ['photos', 'keywords', 'collections', 'conversions', 'colors'] datasets = {} for doc in documents: files = glob.glob(path + doc + ".tsv*") subsets = [] for filename in files: # pd 分析csv df = pd.read_csv(filename, sep='\t', header=0) subsets.append(df) datasets[doc] = pd.concat(subsets, axis=0, ignore_index=True) return datasets

模型选型

本文选取clip-ViT-B-32作为 以图搜图、以文搜图的模型,这个模型是基于 OpenAI 2021 论文的模型训练出来的,模型 CLIP 能将图片和文字联系在一起,目标是得到一个能同时表达图片和文字的模型。

ESCloud Mapping 准备

PUT image_search { "mappings": { "dynamic": "false", "properties": { "photo_id": { "type": "keyword" }, "photo_url": { "type": "keyword" }, "describe": { "type": "text" }, "photo_embedding": { "type": "knn_vector", "dimension": 512 } } }, "settings": { "index": { "refresh_interval": "60s", "number_of_shards": "3", "knn.space_type": "cosinesimil", "knn": "true", "number_of_replicas": "1" } } }

ESCloud 数据库操作

连接

登录火山引擎云搜索服务,选择刚刚创建好的实例,选择复制公网访问地址(如关闭,可选择开启):

# 连接云搜索实例 cloudSearch = CloudSearch("https://{user}:{password}@{ES_URL}", verify_certs=False, ssl_show_warn=False)

写入

from sentence_transformers import SentenceTransformer from elasticsearch7 import Elasticsearch as CloudSearch from PIL import Image import requests import pandas as pd import glob from os.path import join # We use the original clip-ViT-B-32 for encoding images img_model = SentenceTransformer('clip-ViT-B-32') text_model = SentenceTransformer('clip-ViT-B-32-multilingual-v1') # Construct request for es def encodedataset(photo_id, photo_url, describe, image): encoded_sents = { "photo_id": photo_id, "photo_url": photo_url, "describe": describe, "photo_embedding": img_model.encode(image), } return encoded_sents # download images def load_image(url_or_path): if url_or_path.startswith("http://") or url_or_path.startswith("https://"): return Image.open(requests.get(url_or_path, stream=True).raw) else: return Image.open(url_or_path) # 从unsplash的csv文件解出图片url,然后下载图片, # 下载完了后用model 生成embedding,并构造成ES的请求进行写入 def get_imgset_and_bulk(): datasets = read_imgset() datasets['photos'].head() kwywords = datasets['keywords'] docs = [] #遍历CSV, 根据photo_url 去download photo for idx, row in datasets['photos'].iterrows(): print("Process id: ", idx) # 获取CSV 中的url photo_url = row["photo_image_url"] photo_id = row["photo_id"] image = load_image(photo_url) # 找到photo_id 且 suggested true 对应的图片描述 filter = kwywords.loc[(kwywords['photo_id'] == photo_id) & (kwywords['suggested_by_user'] == 't')] text = ' '.join(set(filter['keyword'])) # 封装写入ES的请求 one_document = encodedataset(photo_id=photo_id, photo_url=photo_url, describe=text, image=image) docs.append({"index": {}}) docs.append(one_document) if idx % 20 == 0: # 20条一组进行写入 resp = cloudSearch.bulk(docs, index='image_search') print(resp) docs = [] return docs if __name__ == '__main__': docs = get_imgset_and_bulk() print(docs)

查询

以文搜图:文本向量化,执行 knn 查询

def extract_text(text): # 文搜图 res = cloudSearch.search( body={ "size": 5, "query": {"knn": {"photo_embedding": {"vector": text_model.encode(text), "k": 5}}}, "_source": ["describe", "photo_url"], }, index="image_search2", ) return res fe = FeatureExtractor() @app.route('/', methods=['GET', 'POST']) def index(): # ... resp = fe.extract_text(text) return render_template('index.html', query_text=text, scores=resp['hits']['hits']) # ...

搜 sunset 打印结果

 

以图搜图:图片向量化,执行 knn 查询

def extract(img): # 图搜图 res = cloudSearch.search( body={ "size": 5, "query": {"knn": {"photo_embedding": {"vector": img_model.encode(img), "k": 5}}}, "_source": ["describe", "photo_url"], }, index="image_search2", ) return res fe = FeatureExtractor() @app.route('/', methods=['GET', 'POST']) def index(): # ... # Save query image img = Image.open(file.stream) # PIL image uploaded_img_path = "static/uploaded/" + datetime.now().isoformat().replace(":", ".") + "_" + file.filename img.save(uploaded_img_path) # Run search resp = fe.extract(img) return render_template('index.html', query_path=uploaded_img_path, scores=resp['hits']['hits']) # ...

搜海豹图片 打印结果

 


火山引擎云搜索服务 ESCloud 兼容 Elasticsearch、Kibana 等软件及常用开源插件,提供结构化、非结构化文本的多条件检索、统计、报表,可以实现一键部署、弹性扩缩、简化运维,快速构建日志分析、信息检索分析等业务能力。

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

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

相关文章

TCP三次握手四次挥手

一、TCP三次握手四次挥手 1.三次握手: 第一次握手:客户端发送syn包(seqx)到服务器,并进入SYN_SEND(发送)状态,等待服务器确认; 第二次握手:服务器收到syn包,必须确认客户的SYN(ac…

redis五种数据类型介绍

、string(字符串) 它师最基本的类型,可以理解为Memcached一模一样的类型,一个key对应一个value。 注意:一个键最大能存储 512MB。 特性:可以包含任何数据,比如jpg图片或者序列化的对象,一个键最大能存储512…

计划管理与项目管理:有何区别?

简而言之,是的。尽管它们经常互换使用并对全局产生影响,但它们是完全不同的。 在本文中,我们将了解计划和项目管理之间的差异,提供每个示例,并向您展示如何使计划和项目管理工作更有效地实现您的业务目标。 计划管理与…

程序员面试金典17.*

文章目录 17.01 不用加号的加法17.04 消失的数字17.05字母与数字17.06 2出现的次数17.07 婴儿名字17.08 马戏团人塔17.09 第k个数17.10 主要元素17.11 单词距离17.12 BiNode17.13 恢复空格(未做,字典树dp)17.14 最小K个数17.15 最长单词17.16…

python爬虫-加速乐cookie混淆解析实例小记

注意!!!!某XX网站逆向实例仅作为学习案例,禁止其他个人以及团体做谋利用途!!! 第一步:抓包工具第一次请求页面,得到响应。本次我使用的fiddle进行抓包&#…

网易云音乐扫码登录

简介 尚硅谷的网易云音乐项目无法登录,因为目前网易修改了接口使用手机号和密码登录的话需要先通过认证才可以,所以目前无法使用手机号登录,只能使用二维码登录,接下来我就教大家如何使用 二维码进行登录 实现步骤 1.获取nodejs接…

【1.4】Java微服务:服务注册和调用(Eureka和Ribbon实现)

✅作者简介:大家好,我是 Meteors., 向往着更加简洁高效的代码写法与编程方式,持续分享Java技术内容。 🍎个人主页:Meteors.的博客 💞当前专栏: 微服务 ✨特色专栏: 知识分享 &#x…

排序八卦炉之选择、堆排

文章目录 1.选择排序1.1代码实现1.2复杂度 2.堆排序2.1代码实现2.2复杂度 1.选择排序 1.1代码实现 // 当数据趋于有序或随机(可能部分有序) 插排更有优势 O(N)~O(N^2) //选择排序:O(N^2) O(N^2)~O(N^2) void …

【shell】获取ping的时延数据并分析网络情况及常用命令学习

文章目录 获取ping的时延数据并分析网络情况|、||、&、&&辨析teetailkillall 获取ping的时延数据并分析网络情况 网络情况经常让我们头疼,每次都需要手动在终端ping太麻烦了,不如写个脚本ping并将数据带上时间戳存入文件,然后也…

如何克服看到别人优于自己而感到的焦虑和迷茫?

文章目录 每日一句正能量前言简述自己的感受怎么做如何调整自己的心态后记 每日一句正能量 行动是至于恐惧的良药,而犹豫、拖延,将不断滋养恐惧。 前言 虽然清楚知识需要靠时间沉淀,但在看到自己做不出来的题别人会做,自己写不出的…

软件测试缺陷报告

缺陷报告是描述软件缺陷现象和重现步骤地集合。软件缺陷报告Software Bug Report(SBR)或软件问题报告Software Problem Report(SPR) 作用:缺陷报告是软件测试人员的工作成果之一,体现软件测试的价值缺陷报…

Pytorch深度学习-----神经网络之线性层用法

系列文章目录 PyTorch深度学习——Anaconda和PyTorch安装 Pytorch深度学习-----数据模块Dataset类 Pytorch深度学习------TensorBoard的使用 Pytorch深度学习------Torchvision中Transforms的使用(ToTensor,Normalize,Resize ,Co…

<van-empty description=““ /> 滚动条bug

使用 <van-empty description"" /> 时&#xff0c;图片出现了个滚动条&#xff0c;图片可以上下滑动。 代码如下&#xff1a; <block wx:if"{{courseList.length < 0}}"><van-empty description"" /> </block> <…

python与深度学习(十):CNN和cifar10二

目录 1. 说明2. cifar10的CNN模型测试2.1 导入相关库2.2 加载数据和模型2.3 设置保存图片的路径2.4 加载图片2.5 图片预处理2.6 对图片进行预测2.7 显示图片 3. 完整代码和显示结果4. 多张图片进行测试的完整代码以及结果 1. 说明 本篇文章是对上篇文章训练的模型进行测试。首…

主流开源监控系统一览

减少故障有两个层面的意思&#xff0c;一个是做好常态预防&#xff0c;不让故障发生&#xff1b;另一个是如果故障发生&#xff0c;要能尽快止损&#xff0c;减少故障时长。而监控的典型作用&#xff0c;就是帮助我们发现及定位故障&#xff0c;这两个环节对于减少故障时长至关…

LeetCode面向运气之Javascript—第2500题-删除每行中的最大值-93.51%

LeetCode第2500题-删除每行中的最大值 题目要求 一个 m x n 大小的矩阵 grid &#xff0c;由若干正整数组成。 执行下述操作&#xff0c;直到 grid 变为空矩阵&#xff1a; 从每一行删除值最大的元素。如果存在多个这样的值&#xff0c;删除其中任何一个。 将删除元素中的最…

Kafka的零拷贝

传统的IO模型 如果要把磁盘中的某个文件发送到远程服务器需要经历以下几个步骤 (1) 从磁盘中读取文件的内容&#xff0c;然后拷贝到内核缓冲区 (2) CPU把内核缓冲区的数据赋值到用户空间的缓冲区 (3) 在用户程序中调用write方法&#xff0c;把用户缓冲区的数据拷贝到内核下面…

面向对象程序三大特性一:多态(超详细)

目录 1.重写 1.1基本语法规则 1.2规则深化 1.3重写与重载的区别 2.向上转型 2.1简单介绍 2.3向上转型的作用 3.向下转型 3.1介绍 3.2instanceof 基本介绍 4.多态 4.1多态实现条件 4.2避免在构造方法中调用重写的方法 1.重写 重写 (override) &#xff1a;也称为覆…

容器技术:Docker搭建(通俗易懂)

目录 Docker搭建环境准备Docker安装1、查看服务器是否安装Docker2、卸载Docker3、安装Dokcer依赖环境4、配置Docker国内阿里云镜像5、安装Docker6、查看Docker信息7、配置阿里云镜像加速8、镜像安装10、运行实例11、查看实例状态12、测试 Docker命令集合 Docker搭建 环境准备 …

剑指Offer 05.替换空格

剑指Offer 05.替换空格 目录 剑指Offer 05.替换空格05.替换空格题目代码&#xff08;容易想到的&#xff09;利用库函数的方法题解&#xff08;时间复杂度更低&#xff09;面试&#xff1a;为什么java中String类型是不可变的 05.替换空格 题目 官网题目地址 代码&#xff08;…