前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >在 Elasticsearch 中实施图片相似度搜索

在 Elasticsearch 中实施图片相似度搜索

原创
作者头像
点火三周
修改2023-05-19 17:29:24
1.7K0
修改2023-05-19 17:29:24
举报
文章被收录于专栏:Elastic Stack专栏

本文将帮助你了解如何快速在 Elastic 中实施图像相似度搜索。你仅需要:要创建应用程序环境,然后导入 NLP 模型,最后针对您的图像集完成嵌入的生成工作。就这么简单!

整体了解 Elastic 图像相似度搜索 >> 

如何创建环境

第一步是为您的应用程序创建环境。一般要求包括:

  • Git
  • Python 3.9
  • Docker
  • 数百张图像

为了确保实现最好效果,需要使用数百张图像,这一点十分重要。

前往工作文件夹并查看所创建的存储库代码。然后导航至存储库文件夹。

代码语言:javascript
复制
$ git clone https://github.com/radoondas/flask-elastic-image-search.git
$ cd flask-elastic-image-search

因为要使用 Python 来运行代码,您需要确保所有条件均已满足且环境已准备就绪。现在创建虚拟环境并安装所有依赖项。

代码语言:javascript
复制
$ python3 -m venv .venv
$ source .venv/bin/activate
$ pip install -r requirements.txt

Elasticsearch 集群和嵌入模型

登录您的账号并快速创建一个 Elasticsearch 集群。使用下列参数创建一个小型集群:

  • 一个 2GB 内存的热节点
  • 一个 4GB 内存的 ML (Machine Learning) 节点(该节点的大小很重要,因为您将要导入到 Elasticsearch 中的 NLP 模型就要占用 ~1.5GB 内存。)

您的部署准备完毕之后,前往 Kibana 并检查您的 Machine Learning 节点的容量。在此视图中,您将会看到有一个 Machine Learning 节点。此时尚未加载模型。

使用 Eland 库上传来自 OpenAI 的 CLIP 嵌入模型。Eland 是一个 Python Elasticsearch 客户端,可用来在 Elasticsearch 中探索和分析数据,并且能够同时处理文本和图像。您将会使用此模型来基于文本输入生成嵌入并查询匹配的图像。更多详情请参见 Eland 库的文档

对于下一步,您将需要 Elasticsearch 终端。您可以从部署详情部分内的 Elasticsearch 云控制台获取此终端。

使用终端 URL,在存储库的根目录中执行下列命令。Eland 客户端将会连接至 Elasticsearch 集群并将模型上传到 Machine Learning 节点中。您可以使用 –url 参数来引用自己的实际集群 URL,例如下方代码中“image-search.es.europe-west1.gcp.cloud.es.io”便是集群 URL。

代码语言:javascript
复制
--url https://elastic:<password>@image-search.es.europe-west1.gcp.cloud.es.io:443

输入 Eland 导入命令。

代码语言:javascript
复制
$ eland_import_hub_model --url https://elastic:<password>@<URL>:443 \
  --hub-model-id sentence-transformers/clip-ViT-B-32-multilingual-v1 \
  --task-type text_embedding --ca-certs app/conf/ess-cloud.cer \
  --start

输出将类似于以下内容:

代码语言:javascript
复制
2022-12-12 13:40:52,308 INFO : Establishing connection to Elasticsearch
2022-12-12 13:40:52,327 INFO : Connected to cluster named 'image-search-8.6.1' (version: 8.5.3)
2022-12-12 13:40:52,328 INFO : Loading HuggingFace transformer tokenizer and model 'sentence-transformers/clip-ViT-B-32-multilingual-v1'
2022-12-12 13:41:03,032 INFO : Creating model with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'
2022-12-12 13:41:03,050 INFO : Uploading model definition
100%|█████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████████| 129/129 [00:42<00:00,  3.01 parts/s]
2022-12-12 13:41:45,902 INFO : Uploading model vocabulary
2022-12-12 13:41:46,120 INFO : Starting model deployment
2022-12-12 13:41:52,825 INFO : Model successfully imported with id 'sentence-transformers__clip-vit-b-32-multilingual-v1'

上传过程可能会耗时几分钟,具体取决于您的网络连接。完成后,在 Machine Learning Kibana 页面上查看所训练模型的列表:Menu(菜单)-> Analytics(分析)-> Machine Learning -> Model management(模型管理)-> Trained models(所训练模型)。确认 NLP CLIP 模型处于 ‘started’(已开始)状态。

如果您在屏幕上收到一条消息——需要同步 ML 作业和所训练模型——则点击链接以对模型完成同步。

如何创建图像嵌入

创建 Elasticsearch 集群并导入嵌入模型后,您需要对图像数据进行矢量化并为您数据集中的每一张图像创建图像嵌入。

要创建图像嵌入,可使用简单的 Python 脚本。您可以在此处找到脚本:create-image-embeddings.py。此脚本会遍历您图像所在的目录并生成单独的图像嵌入。它将会创建带名称和相对路径的文档,并使用所提供的映射将其存到 Elasticsearch 索引 ‘my-image-embeddings’ 中。

将您的所有图像(照片)放到文件夹 ‘app/static/images’ 中。使用带子文件夹的目录结构来确保图像井然有序。所有图像都准备就绪后,使用几个参数执行脚本。

至为关键的一点是至少要有数百张图像,才能实现比较合理的效果。图像数量太少会导致结果达不到您的期望,因为您将要搜索的空间会特别狭小,而且到搜索向量的距离会特别接近。 在文件夹 image_embeddings 中,运行脚本并针对变量使用您的值。

代码语言:javascript
复制
$ cd image_embeddings
$ python3 create-image-embeddings.py \
  --es_host='https://image-search.es.europe-west1.gcp.cloud.es.io:443' \
  --es_user='elastic' --es_password=<password> \
  --ca_certs='../app/conf/ess-cloud.cer'

这一任务会需要一定时间才能完成,具体取决于图像数量、图像大小、您的 CPU 以及您的网络连接。先用较少的图像进行实验,然后再尝试处理完整的数据集。 脚本运行完毕之后,您可以使用 Kibana 开发工具验证索引 my-image-embeddings 是否存在并拥有相对应的文档。

代码语言:javascript
复制
GET _cat/indices/my-image-embeddings?v

health status index               uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   my-image-embeddings vfA3wOheT1C79R-PceDyXg   1   1       1222            0     24.4mb         12.2mb

看一下这些文档,您会发现特别相似的 JSON 对象(就像这个示例)。您会看到图像名称、图像 id,以及在 images 文件夹内的相对路径。搜索时,前端应用程序会使用这一路径来正确显示图像。 JSON 文档中最重要的部分是 ‘image_embedding’,因为其中包含 CLIP 模型所生成的密集矢量。当应用程序搜索图像或相似图像时,会用到这一矢量。

代码语言:javascript
复制
{
   "_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"
   }
}阅读更少

使用 Flask 应用程序搜索图像

现在您的环境已经完全创建完毕,您可以进行下一步了,亦即使用自然语言实际搜索图像并寻找相似图像,不妨使用我们所提供的 Flask 应用程序作为概念验证。该网络应用程序具有简单的 UI,可简化图像搜索。您可以在此 GitHub 存储库中获取原型 Flask 应用程序。

该应用程序会在后台执行两项任务。您将搜索字符串输入到搜索框中之后,应用程序将会使用 Machine Learning _infer 终端对文本进行矢量化。然后,会使用矢量来针对索引 my-image-embeddings 执行带有您的密集矢量的查询。 您可以在这个示例中看到那两个查询。第一个 API 调用使用了 _infer 终端,结果是一个密集矢量。

代码语言:javascript
复制
POST _ml/trained_models/sentence-transformers__clip-vit-b-32-multilingual-v1/deployment/_infer
{
  "docs" : [
    {"text_field": "endless route to the top"}
    ]
}

在第二个任务(即搜索查询)中,我们将会使用密集矢量并按照分数将图像排序。

代码语言:javascript
复制
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
}了解详情

为了配置 Flask 应用程序并让它正常运行,导航至存储库的根文件夹及并配置 .env 文件。会使用配置文件中的值来连接至 Elasticsearch 集群。您需要为下列变量插入值。这些是在图像嵌入生成过程中用到的同一批值。

  • ES_HOST='URL:PORT'
  • ES_USER='elastic'
  • ES_PWD='password'

就绪后,在主文件夹中运行 Flask 应用程序并等待直至它启动。

代码语言:javascript
复制
# In the main directory 
$ flask run --port=5001

如果应用程序启动,您将会看到类似下面的输出,在末尾显示您需要前往哪个 URL 以访问该应用程序。

代码语言:javascript
复制
flask run --port=5001
 * Serving Flask app 'flask-elastic-image-search.py' (lazy loading)
 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 * Running on http://127.0.0.1:5001
Press CTRL+C to quit

恭喜!您的应用程序现在应该已经配置完毕并运行了,可通过互联网浏览器在 http://127.0.0.1:5001 上访问。

导航至图像搜索选项卡并输入能够最确切地描述您的图像的文本。尝试使用非关键字或描述性文本。 在下面的示例中,输入的文本是“endless route to the top”(到达顶部的无尽头路径)。 显示的是来自我们数据集的结果。如果用户喜欢结果集中的某张特定图像,可以简单地点击旁边的按钮,相似的图像便会显示出来。用户可以无限次地进行这一操作,并通过图像数据集构建他们自己的路径。

也可以通过简单地上传图像来进行搜索。应用程序会将图像转换为矢量并在数据集中搜索相似的图像。如要搜索图像,请导航至第三个选项卡相似图像,从磁盘中上传图片,并点击搜索

由于我们在 Elasticsearch 中使用的 NLP (sentence-transformers/clip-ViT-B-32-multilingual-v1) 模型是多语言模型并支持以多种语言进行推理,所以请尝试用您自己的语言搜索图片。然后还可以使用英语文本对结果进行验证。

有很重要的一点需要注意:所使用的模型是通用模型,虽然相当准确,但您所得到的的结果可能会不同,具体取决于用例和其他因素。如果需要实现更高的准确度,您则必须对通用模型进行调整或开发您自己的模型——CLIP 模型仅旨在作为您的一个起始点。

代码摘要

您可以在 GitHub 存储库中找到完整代码。您还可以检查 routes.py 中的代码,此处的代码用来实施应用程序的主逻辑。除了显而易见的路径定义,您应该专注于用来定义 _infer 和 _search 终端(infer_trained_modelknn_search_images)的方法。负责生成图像嵌入的代码位于 create-image-embeddings.py 文件中。

总结

现在 Flask 应用已经设置完毕,您可以轻松搜索自己的图像集啦!Elastic 在平台内提供矢量搜索的原生集成,所以无需与外部进程进行通信。您能够灵活地开发和部署您使用 PyTorch 开发的定制嵌入模型。

相较于图像搜索的其他传统方式,语义图像搜索具有下列优点:

  • 更高的准确度:无须依赖图像的文本元描述,矢量相似度便能捕获上下文和关联。
  • 更好的用户体验:描述您正在查找什么,或者提供一张示例图片,而不再需要猜测哪个关键词可能相关。
  • 对图像数据库进行分类:无需担心如何为您的图像编制目录——相似度搜索无须整理图像就能从一堆图像中找到相关的那些。

如果您的用例更多地依靠文本数据,您可以查阅之前的博文详细了解如何实施语义搜索并将自然语言处理应用到文本。对于文本数据,将矢量相似度与传统关键字计分相结合能够让您同时收获这两种方法的优点。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 如何创建环境
  • Elasticsearch 集群和嵌入模型
  • 如何创建图像嵌入
  • 使用 Flask 应用程序搜索图像
    • 代码摘要
    • 总结
    相关产品与服务
    Elasticsearch Service
    腾讯云 Elasticsearch Service(ES)是云端全托管海量数据检索分析服务,拥有高性能自研内核,集成X-Pack。ES 支持通过自治索引、存算分离、集群巡检等特性轻松管理集群,也支持免运维、自动弹性、按需使用的 Serverless 模式。使用 ES 您可以高效构建信息检索、日志分析、运维监控等服务,它独特的向量检索还可助您构建基于语义、图像的AI深度应用。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档