Dinov2 + Faiss 图片检索

MetaAI的DINOv2模型在包含1.42亿张图像的数据集上训练出通用特征,应用于图像和像素级视觉任务。Faiss库被用于高效处理和搜索这些特征,包括GPU加速。文章介绍了如何使用DINo2模型提取COCO数据集的图像特征,并演示了Faiss在检索过程中的性能。
该文章已生成可运行项目,

MetaAI 通过开源 DINOv2,在计算机视觉领域取得了一个显着的里程碑,这是一个在包含1.42 亿张图像的令人印象深刻的数据集上训练的模型。产生适用于图像级视觉任务(图像分类、实例检索、视频理解)以及像素级视觉任务(深度估计、语义分割)的通用特征。
Dinov2网站

Faiss是一个用于高效相似性搜索和密集向量聚类的库。它包含的算法可以搜索任意大小的向量集,甚至可能无法容纳在 RAM 中的向量集。

Faiss安装
可以选择 GPU 或 CPU 版本,这里选GPU版本

pip install faiss-gpu

embedding的预处理
使用 Faiss 时的一个重要考虑因素是它需要 Numpy 格式的embedding。因此,我们需要在将它们添加到索引之前对其进行转换。

处理embedding的步骤:

1.Detach the tensor并将其转换为 numpy 数组
2.转换为 numpy float 32 数组
3.使用 Faiss 使用 L2 归一化对 numpy 数组进行归一化

def add_vector_to_index(embedding, index):
    vector = embedding.detach().cpu().numpy()
    vector = np.float32(vector)
    faiss.normalize_L2(vector)
    index.add(vector)

存储 Faiss 索引
计算embedding然后存储它们。
这里以COCO数据集的val2017为例。
把每个图片的feature保存在index里面。

import torch
from transformers import AutoImageProcessor, AutoModel
from PIL import Image
import faiss
import numpy as np
import os
import matplotlib.pyplot as plt
import cv2

device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
#你可以换成dinov2-base/large/giant模型
processor = AutoImageProcessor.from_pretrained('./dinov2_small')
model = AutoModel.from_pretrained('./dinov2_small').to(device)

data_folder = './coco/val2017'
images = []
for root,dirs,files in os.walk(data_folder):
    for file in files:
        if file.endswith('jpg'):
            images.append(root + '/' + file)

#feature dim 是384维,所以建立dim=384的index,type是FlatL2
index = faiss.IndexFlatL2(384)
#t0 = time.time()
for image_path in images:
    img = Image.open(image_path).convert('RGB')
    with torch.no_grad():
        inputs = processor(images=img,return_tensors='pt').to(device)
        outputs = model(**inputs)
    features = outputs.last_hidden_state
    add_vector_to_index(features.mean(dim=1), index)

#print('Extraction done in: ', time.time() - t0)
faiss.write_index(index, 'coco.index')

下面以这张图片为例来检索图片。

请添加图片描述

先提取图片的特征,转为Faiss要求的格式。

image = Image.open('ski.jpg')
#Extract the features
with torch.no_grad():
    inputs = processor(images=image, return_tensors="pt").to(device)
    outputs = model(**inputs)

#Normalize the features before search
embeddings = outputs.last_hidden_state
embeddings = embeddings.mean(dim=1)
vector = embeddings.detach().cpu().numpy()
vector = np.float32(vector)
faiss.normalize_L2(vector)

用之前保存的index, 检索top3相似的图片。

index = faiss.read_index("coco.index")
d,i = index.search(vector,3)
print('distances:', d, 'indexes:', i)

#images[[i][0][k]]为检索到的图片,k为0,1,2

检索效果
请添加图片描述
Faiss本身检索速度很快,GPU下COCO数据集检索仅需0.7ms,
但Dinov2提取特征需要时间。

参考资料

本文章已经生成可运行项目
<think>我们正在构建一个包含前端和后端的文本检索应用,使用m3e作为嵌入模型,Faiss作为向量数据库。目标是通过Docker快速部署整个应用。 项目架构设计: 1. 前端:使用Vue.js或React等框架构建,提供用户界面。 2. 后端:使用FastAPI或Flask构建API服务,处理文本检索请求。 3. 向量数据库:使用Faiss,由于Faiss是一个库,我们需要将其集成到后端服务中,或者单独作为一个服务(但通常Faiss是嵌入到应用中的)。 4. 嵌入模型:使用m3e模型生成文本嵌入。 考虑到Faiss通常作为库使用,我们将其集成到后端服务中。因此,整个项目可以分为两个主要部分:前端和后端(包含Faiss和m3e模型)。 项目结构示例: ``` text-search-app/ ├── frontend/ # 前端项目 │ ├── Dockerfile # 前端Dockerfile │ └── ... # 前端代码(Vue项目) ├── backend/ # 后端项目 │ ├── Dockerfile # 后端Dockerfile │ ├── requirements.txt # Python依赖 │ └── ... # 后端代码(FastAPI应用,包含Faiss操作和m3e模型加载) ├── docker-compose.yml # 使用docker-compose编排多个容器 └── ... # 其他配置文件 ``` 部署步骤: 1. 构建前端镜像:将前端项目构建成静态文件,并使用Nginx提供服务。 2. 构建后端镜像:包含Python环境、依赖、Faiss库、m3e模型以及后端代码。 3. 使用docker-compose同时启动前端和后端服务。 详细设计: 1. 前端Dockerfile(位于frontend目录): 以Vue项目为例,使用多阶段构建: ```dockerfile # 构建阶段 FROM node:16 as build-stage WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build # 生产阶段 FROM nginx:stable-alpine as production-stage COPY --from=build-stage /app/dist /usr/share/nginx/html EXPOSE 80 CMD ["nginx", "-g", "daemon off;"] ``` 2. 后端Dockerfile(位于backend目录): 使用Python镜像,安装Faiss等依赖,注意Faiss的安装可能需要从源码编译或使用预编译版本。 由于Faiss的安装可能比较复杂,我们可以使用预编译的faiss-cpu或faiss-gpu包(通过pip安装)。 ```dockerfile FROM python:3.9-slim WORKDIR /app # 安装系统依赖(Faiss可能需要) RUN apt-get update && apt-get install -y build-essential libopenblas-dev libomp-dev && rm -rf /var/lib/apt/lists/* # 复制依赖文件并安装 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制后端代码 COPY . . # 暴露端口(假设后端服务运行在8000端口) EXPOSE 8000 # 启动命令 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] ``` 注意:requirements.txt中需要包含faiss-cpu(或faiss-gpu)、fastapi、uvicorn、m3e模型所需的库(如transformers、sentence-transformers)等。 3. docker-compose.yml(位于项目根目录): ```yaml version: '3.8' services: frontend: build: ./frontend ports: - "80:80" depends_on: - backend networks: - app-network backend: build: ./backend ports: - "8000:8000" environment: - MODEL_NAME=m3e-base # 环境变量示例 # 如果需要,可以挂载模型文件或者数据卷 # volumes: # - ./backend/data:/app/data networks: - app-network networks: app-network: driver: bridge ``` 4. 启动应用: 在项目根目录下执行: ```bash docker-compose up -d ``` 5. 访问应用: 前端:http://localhost 后端API:http://localhost:8000 注意事项: - 模型文件:m3e模型文件可能需要提前下载并放入backend目录,或者在构建镜像时下载(注意镜像大小)。 - Faiss索引:如果需要持久化Faiss索引,可以将索引文件存储到挂载的卷中(如上文注释的volumes部分)。 - 性能:Faiss对CPU指令集有要求,如果使用预编译的faiss-cpu,可能无法发挥最佳性能。可以考虑使用官方提供的Docker镜像(如faiss官方镜像)或者自行编译。 针对Faiss的优化:如果对性能要求较高,可以考虑使用GPU版本的Faiss,但需要安装GPU驱动和faiss-gpu库,并且使用支持GPU的Docker环境。 相关问题: 1. 如何优化Faiss索引的构建和搜索性能? 2. 在Docker中如何管理大型模型文件(如m3e)以减少镜像体积? 3. 如何为前端和后端服务配置反向代理(如Nginx)? 4. 如何实现前后端分离架构下的跨域请求(CORS)? 5. 如何扩展后端服务以实现负载均衡? 引用说明: - 参考了引用[1]中关于FastAPI架构和API封装的经验。 - 参考了引用[2]中docker-compose多容器编排的示例。 - 参考了引用[3]中关于使用向量数据库进行文本检索的思路。 因此,在回答中我们可以添加引用标识[^1][^2][^3]。</think>### 基于M3E+Faiss的文本检索应用Docker化部署架构设计 #### 项目架构设计 ```mermaid graph TD A[前端] --> B[Nginx反向代理] B --> C[后端API服务] C --> D[Faiss向量数据库] C --> E[M3E嵌入模型] D --> F[持久化存储] E --> G[模型文件] ``` 1. **前端服务** - Vue/React单页应用 - 通过Nginx提供静态文件服务 - 与后端API交互实现搜索功能 2. **后端服务** (FastAPI架构参考[^1]) - RESTful API接口 - 请求处理流程: ```mermaid sequenceDiagram 前端->>+后端: 搜索请求 后端->>+M3E模型: 文本向量化 后端->>+Faiss: 相似度检索 后端-->>-前端: JSON结果 ``` - 支持高并发设计(异步IO+连接池) 3. **Faiss向量数据库** - 内存索引加速查询 - 定期快照持久化到卷 - 支持IVF、HNSW等索引算法 4. **M3E嵌入模型** - 中文优化文本嵌入模型 - 支持动态加载多模型版本 - 模型文件挂载外部存储 #### Docker部署方案 **目录结构** ``` m3e-faiss-app/ ├── frontend/ # 前端代码 │ ├── Dockerfile │ └── ... ├── backend/ # 后端服务 │ ├── Dockerfile │ ├── app/ # FastAPI代码 │ └── requirements.txt ├── docker-compose.yml # 多容器编排 └── data/ # 持久化数据 ├── models/ # M3E模型文件 └── faiss_index/ # Faiss索引 ``` **1. 后端Dockerfile** ```dockerfile FROM python:3.10-slim-buster # 安装Faiss依赖 RUN apt-get update && apt-get install -y \ libopenblas-dev \ libomp-dev WORKDIR /app # 安装Python依赖 COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt # 复制应用代码 COPY . . # 挂载点声明 VOLUME ["/app/data/models", "/app/data/faiss_index"] CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] ``` **2. 前端Dockerfile** ```dockerfile FROM node:18 as builder WORKDIR /app COPY package*.json ./ RUN npm install COPY . . RUN npm run build FROM nginx:alpine COPY --from=builder /app/dist /usr/share/nginx/html COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80 ``` **3. docker-compose.yml** (参考[^2]) ```yaml version: '3.8' services: frontend: build: ./frontend ports: - "80:80" depends_on: - backend backend: build: ./backend ports: - "8000:8000" environment: - FAISS_INDEX_PATH=/app/data/faiss_index/default.faiss - M3E_MODEL_PATH=/app/data/models/m3e-base volumes: - ./data/models:/app/data/models - ./data/faiss_index:/app/data/faiss_index deploy: resources: limits: memory: 8g # 可选:添加Redis缓存 redis: image: redis:alpine ports: - "6379:6379" ``` #### 部署流程 1. **准备依赖** ```bash # 下载M3E模型 mkdir -p data/models wget -P data/models https://huggingface.co/moka-ai/m3e-base/resolve/main/pytorch_model.bin # 初始化Faiss索引 python backend/init_faiss.py ``` 2. **构建镜像** ```bash docker-compose build ``` 3. **启动服务** ```bash docker-compose up -d ``` 4. **验证部署** ```bash curl http://localhost:8000/healthcheck ``` #### 性能优化技巧 1. **Faiss索引优化** - 使用`IndexIVFFlat`减少内存占用 - 开启多线程查询:`faiss.omp_set_num_threads(8)` - 定期重建索引(参考[^3]) 2. **模型加载加速** ```python # 后端启动时预加载模型 from sentence_transformers import SentenceTransformer model = SentenceTransformer('/app/data/models/m3e-base') ``` 3. **缓存策略** - Redis缓存常见查询结果 - 使用LRU内存缓存高频向量 4. **水平扩展** ```yaml # docker-compose扩展示例 backend: image: my-backend deploy: replicas: 3 environment: - SHARED_REDIS=redis://redis:6379/0 ``` #### 常见问题解决方案 1. **模型文件过大** - 使用`.dockerignore`排除非必要文件 - 通过卷挂载而非构建进镜像 2. **Faiss索引更新** ```python # 后端热重载接口 @app.post("/reload_index") def reload_index(): global faiss_index faiss_index = faiss.read_index(INDEX_PATH) ``` 3. **跨域问题** ```python # FastAPI配置 from fastapi.middleware.cors import CORSMiddleware app.add_middleware(CORSMiddleware, allow_origins=["*"]) ``` --- ### 相关问题 1. 如何优化Faiss在大规模数据集上的查询性能? 2. 在Docker环境中如何实现模型的热更新? 3. 如何监控Docker化文本检索服务的性能指标? 4. 怎样设计API限流机制防止服务过载? 5. 在Kubernetes中如何部署此类应用? [^1]: 参考FastAPI架构设计经验 [^2]: 基于多容器编排实践优化 [^3]: 借鉴混合查询架构思路
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蓝羽飞鸟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值