Elasticsearch向量检索需要的数据集以及768维向量生成

Elasticsearch8.17.0在mac上的安装

Kibana8.17.0在mac上的安装

Elasticsearch检索方案之一:使用from+size实现分页

快速掌握Elasticsearch检索之二:滚动查询(scrool)获取全量数据(golang)

Elasticsearch检索之三:官方推荐方案search_after检索实现(golang)

1、面临的首要问题

对于elasticsearch的向量检索的学习,我打算做一个图片检索的方案,图片检索在自动驾驶、ai识图、搜索都有广泛的应用,因此就借着学习elasticsearch的机会,设计一个mvp版本的图像搜索方案,以供有需要的各位小伙伴参考。

在学习向量检索之前,数据是基石,从哪里找上几千张图片,而且还有有一定的代表性,又如何将这些图片转化成向量,都是首先要解决的问题。

2、寻找数据集

12月中旬去阿里参加了elastic的线下meetup,当时阿里同学分享了一个向量测试的性能数据,我对这个数据印象非常深刻,于是在问答环节,请教了这个性能数据测试使用了多大的数据量,索引大小多少等问题,当时说到了一个数据集:ANN_GIST1M 960维,我们可以从这里下载到它:

http://corpus-texmex.irisa.fr/

下载解压后:

这些文件数据,需要使用matlab读取,咱也不太懂,还是找找图片的吧,再用模型跑一下就能出向量。

之后搜索了一些公开的图片数据集,找到了一个小猫、小狗数据集,这个挺有意思,小猫1000张图片,小狗1000张图片,除了训练集还有200张评测集,就用它了,我将数据集上传到了github上,点击查看icon-default.png?t=O83Ahttps://github.com/liupengh3c/career/tree/main/cats_and_dogs_v2需要的同学可以自取。

 这样数据集的问题就解决了,接下来解决抽取图像特征的问题。

3、寻找开源模型,抽取图像特征

本想着网上找个免费的api,输入图片,返回图片768维的特征向量,最后没有找到,只好求助于团队内算法同学,他给推荐了一个openai的开源模型:

https://hf-mirror.com/openai/clip-vit-large-patch14/tree/main

这里所有的文件都需要下载下来:

并汇总放到一个文件夹下,之后编写python代码,用此模型抽取图片特征:

import torch
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
import numpy as np
# 加载预训练的CLIP模型和处理器
model = CLIPModel.from_pretrained("/Users/liupeng/Downloads/clip-vit-large-patch14")
processor = CLIPProcessor.from_pretrained("/Users/liupeng/Downloads/clip-vit-large-patch14")
# 加载图像并进行预处理
image = Image.open("/Users/liupeng/Downloads/dog.11001.jpg")  # 替换为你的图像路径
inputs = processor(images=image, return_tensors="pt")
# 提取图像特征
with torch.no_grad():image_features = model.get_image_features(**inputs)
print("shape:",image_features.shape)
# 对图像特征进行 L2 归一化
# 使用 .norm() 计算 L2 范数并进行归一化
image_features_normalized = image_features / image_features.norm(p=2, dim=-1, keepdim=True)
numpy_array = image_features_normalized.numpy()
# 打印归一化后的特征和特征的模长(应该为 1)
print("归一化后的图像特征:", numpy_array[0])
print("归一化后的模长:", image_features_normalized.norm(p=2, dim=-1))  # 应该接近 1

上面代码实现了单张图片特征提取,后面根据需求再完善。

4、向量索引设计

向量检索,最大的机器瓶颈就是内存,因此我们在设计索引时,应该最大限度的保证内存的占用最低,即使牺牲掉部分精度。

而检索算法:KNN(最近邻检索),它的原理是:计算待查询向量与数据库中所有向量之间的距离,然后按照距离从小到大排序,选择距离最近的 K 个向量作为查询结果。KNN 算法的优点是可以保证精确的结果,但是效率较低,不是elastic的默认检索算法,大家可以参考这篇文章:

ElasticSearch向量检索技术方案介绍,

为了提升向量检索的效率、降低机器内存占用,elastic采用HNSW算法支持向量检索,HNSW是一种近似紧邻检索,牺牲了一定的精度,但是大大提升了检索的效率。

对于向量索引,我们只设计3个字段:

name:本张图片小动物名称,猫or狗
IFV:本章图片向量
path:图片路径或地址

其中检索算法采用hnsw,并使用int8量化,以减少内存占用,这样会牺牲一定的精度,同时磁盘占用量会增加25%左右,向量距离计算逻辑为欧氏距离: 

PUT /vector_search_202412
{"mappings": {"properties": {"name": {"type": "keyword","ignore_above": 256},"path": {"type": "keyword","ignore_above": 256},"IFV": {"type": "dense_vector","index": true,"dims": 768,"similarity": "l2_norm","index_options": {"type": "int8_hnsw"}}}}
}

5、全部数据集抽取特征并入库

首先调整我们抽取特征脚本,增加遍历文件夹所有图片+写入es部分:

import torch
from PIL import Image
from transformers import CLIPProcessor, CLIPModel
import numpy as np
import os
from elasticsearch import Elasticsearch, helpers
# Elasticsearch服务器地址和端口
host = 'https://localhost:9200'
# 用户名和密码
username = 'elastic'
password = 'xpE4DQGWE9bCkoj7WXYE'# 创建Elasticsearch客户端实例,并提供用户名和密码
es = Elasticsearch(hosts=[host], http_auth=(username, password), verify_certs=False,ca_certs="/Users/liupeng/Documents/study/elasticsearch-8.17.0/config/certs/http_ca.crt")
# 检查连接是否成功
if not es.ping():print("无法连接到Elasticsearch")exit()
else:print("成功连接到Elasticsearch")
# 现在你可以使用es变量来与Elasticsearch进行交互了
# 加载预训练的CLIP模型和处理器
model = CLIPModel.from_pretrained("/Users/liupeng/Documents/career/clip-vit-large-patch14")
processor = CLIPProcessor.from_pretrained("/Users/liupeng/Documents/career/clip-vit-large-patch14")
# 加载图像并进行预处理
# folder = "/Users/liupeng/Documents/career/cats_and_dogs_v2/train/cats"
folder = "/Users/liupeng/Documents/career/cats_and_dogs_v2/train/dogs"
for root, dirs, files in os.walk(folder):index_id = 1000for file in files:index_id += 1print(os.path.join(root, file))image = Image.open(os.path.join(root, file))  inputs = processor(images=image, return_tensors="pt")# 提取图像特征with torch.no_grad():image_features = model.get_image_features(**inputs)print("shape:",image_features.shape)# 对图像特征进行 L2 归一化# 使用 .norm() 计算 L2 范数并进行归一化image_features_normalized = image_features / image_features.norm(p=2, dim=-1, keepdim=True)numpy_array = image_features_normalized.numpy()# 打印归一化后的特征和特征的模长(应该为 1)# print("归一化后的图像特征:", numpy_array[0])# print("归一化后的模长:", image_features_normalized.norm(p=2, dim=-1))  # 应该接近 1documents = [{"name": "cat_"+str(index_id), "IFV": numpy_array[0].tolist(),"path":file},]helpers.bulk(es, [{"_index": "vector_search_202412","_id": index_id,"_source": doc}for doc in documents])

上面代码,由于数据集中小猫和小狗是两个不同的文件夹,所以需要跑2次,小猫和小狗各一次。

同时代码都已上传到github上: 

https://github.com/liupengh3c/career/blob/main/features/main.py

推理过程很耗费资源,mac的风扇呼呼的转呀。

占用的空间大小35M:

 到这里向量数据就全部入库完成了。

新的一年。就让我们对过去所有开心的事做个总结,对不开心的所有事也做个了结,微笑着迎接属于我们所有人的2025年,祝我可爱的小伙伴们新年快乐。 

天亮了,去跑个20.25km迎接新一年的到来~~~~~~~~~~~~~

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

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

相关文章

CSS2笔记

一、CSS基础 1.CSS简介 2.CSS的编写位置 2.1 行内样式 2.2 内部样式 2.3 外部样式 3.样式表的优先级 4.CSS语法规范 5.CSS代码风格 二、CSS选择器 1.CSS基本选择器 通配选择器元素选择器类选择器id选择器 1.1 通配选择器 1.2 元素选择器 1.3 类选择器 1.4 ID选择器 1.5 基…

Prometheus 专栏 —— Prometheus安装、配置

配置文件基本结构 global: 全局配置 scrape_interval: 抓取目标指标的频率,默认为 1minevaluation_interval: 评估告警规则的频率,默认为 1minscrape_timeout: 抓取目标指标数据拉取超时,默认为 10s,如果出现 context deadline exceeded 错误时需要在特定的 job 下配置该字…

基于AT89C51单片机的可暂停八路抢答器设计

点击链接获取Keil源码与Project Backups仿真图: https://download.csdn.net/download/qq_64505944/90196607?spm1001.2014.3001.5503 C15 部分参考设计如下: 摘要 随着社会进步和科技发展,电子设备在各类活动中的应用日益普遍&#xff0c…

【python】unittest单元测试

文章目录 基本使用不同启动方式的区别 基本使用 下面是根据文档写的一个demo,主要的内容基本都包含了,使用时导入自己的业务类测试类中的方法就行。 import unittest# 测试类不强制test开头,仅作为规范。但必须继承unittest.TestCase class…

MySQL实用SQL示例

创建数据库 CREATE DATABASE zq-cloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;创建表 CREATE TABLE regulatory_firm_category (category_id int NOT NULL AUTO_INCREMENT COMMENT 分类id,自增主键,parent_id int NOT NULL COMMENT 父级id,category_…

从0入门自主空中机器人-4-【PX4与Gazebo入门】

前言: 从上一篇的文章 从0入门自主空中机器人-3-【环境与常用软件安装】 | MGodmonkeyの世界 中我们的机载电脑已经安装了系统和常用的软件,这一篇文章中我们入门一下无人机常用的开源飞控PX4,以及ROS中无人机的仿真 1. PX4的安装 1.1 PX4固件代码的下载…

数据结构与算法之动态规划: LeetCode 674. 最长连续递增序列 (Ts版)

最长连续递增序列 https://leetcode.cn/problems/longest-continuous-increasing-subsequence/description/ 描述 给定一个未经排序的整数数组,找到最长且 连续递增的子序列,并返回该序列的长度连续递增的子序列 可以由两个下标 l 和 r(l …

SqlSession的线程安全问题源码分析

🎮 作者主页:点击 🎁 完整专栏和代码:点击 🏡 博客主页:点击 文章目录 SqlSession 是线程安全的吗?为什么说是线程不安全的?事务管理问题 数据库连接的共享问题 一级缓存线程安全问题…

Unity Mesh生成Cube

1. 配置一个Cube的每个面的数据 一共是6个面,每个面包含的数据包括4个顶点的相对顶点坐标(Cube的中心为原点),法线方向,UV坐标,顶点渲染顺序,以及这个面用到的材质,因为这里是Top&am…

小程序组件 —— 22 组件案例 - 轮播区域绘制

这一节我们实现轮播图最外层的盒子,也就是把轮播图的最外层搭好,先不给轮播图添加图片,因为图片属于新的组件,组件里面有一些知识点,需要单独分开讲; 回顾一下,在进行传统网页开发时&#xff0…

【文献精读笔记】Explainability for Large Language Models: A Survey (大语言模型的可解释性综述)(二)

****非斜体正文为原文献内容(也包含笔者的补充),灰色块中是对文章细节的进一步详细解释! 3.1.2 基于注意力的解释(Attention-Based Explanation) 注意力机制可以揭示输入数据中各个部分之间的关系&#…

【centos8 镜像修改】centos8 镜像修改阿里云

要将 CentOS 8 的镜像源修改为阿里云镜像,你需要编辑 /etc/yum.repos.d/ 目录下的 .repo 文件。以下是具体的步骤: 备份原始的 .repo 文件: 在编辑之前,建议备份原始的 .repo 文件,以便在出现问题时可以恢复。 sudo cp…

git reset --hard(重置到当前提交,所有未提交的更改都会被永久丢弃)

git reset --hard 是一个强大的命令,它会将你的工作目录、暂存区和当前分支的 HEAD 指针重置到指定的提交状态,所有未提交的更改都会被永久丢弃。因此,使用这个命令时需要非常小心。 基本用法 重置到当前提交(丢弃所有未提交的更…

WebRTC的三大线程

WebRTC中的三个主要线程: signaling_thread,信号线程:用于与应用层交互worker_thread,工作线程(最核心):负责内部逻辑处理network_thread,网络线程:负责网络数据包的收发…

25考研总结

11408确实难,25英一直接单科斩杀😭 对过去这一年多备考的经历进行复盘,以及考试期间出现的问题进行思考。 考408的人,政治英语都不能拖到最后,408会惩罚每一个偷懒的人! 政治 之所以把政治写在最开始&am…

linux ext4文件系统

Ext4(第四扩展文件系统,简称为 EXT4)是Linux操作系统中广泛使用的日志文件系统。它是Ext3文件系统的后继者,提供了更多的特性和改进,以适应更大的存储设备和更复杂的文件系统操作。以下是Ext4文件系统的一些主要特点&a…

Singleton: WebRTC中ThreadManager中的单例模式

1. 什么是单例模式: 旨在确保一个类只有一个实例,并提供全局访问点。 应用场景:需要一个全局唯一的实例,避免资源浪费。 2. 单例模式的实现: Lazy Initialization(懒汉式)(延迟初…

人工智能:变革时代的核心驱动力

求各位观众老爷看一看 先声明一下,该内容由于篇幅过长,可能会有一些地方存在一些小问题请大家谅解 观众老爷们,点个免费的赞和关注呗,您们的支持就是我最大的动力~ 人工智能:变革时代的核心驱动力 一、引言 在当今…

单元测试入门和mockup

Java 新手入门:Java单元测试利器,Mock详解_java mock-CSDN博客 这个是典型的before when assert三段式,学一下单测思路 这个没有动态代理,所以是直接class(对比下面) Jmockit使用笔记_增加代码覆盖率_覆盖try catch_使用new Mock…

数组方法 | vue修改数组

数组方法 修改原数组 push() 方法(在数组结尾处)向数组添加一个新的元素 var list["数学","历史"]; list.push("英语"); ["数学","历史","英语"]unshift() 方法(在开头&…