En este blog, construiremos la búsqueda de imágenes en vivo y la interrogaremos con el lenguaje natural. Por ejemplo, puede buscar "un elefante", o un "animal bonito" con una lista de imágenes como entrada.
Vamos a usar el modelo de incorporación multimodal para comprender y incorporar la imagen, y construir un índice vectorial para una recuperación eficiente. Vamos a usar CocoIndex para construir el flujo de indexación, es un marco de transformación de datos en tiempo real de alto rendimiento. Durante la ejecución, puede agregar nuevos archivos a la carpeta y sólo procesará archivos cambiados y se indexarán en un minuto.
significaría mucho para nosotros si pudieras lanzar una estrella enCocoIndex en GitHubSi este tutorial es útil.
Tecnologías
CocoIndex
CocoIndexEs un marco de transformación de datos en tiempo real para la IA.
Clásico ViT-L/14
Clásico ViT-L/14Es un poderoso modelo de lenguaje de visión que puede entender tanto imágenes como textos. Se ha entrenado para alinear las representaciones visuales y textuales en un espacio de embalaje compartido, lo que lo hace perfecto para nuestro caso de uso de búsqueda de imagen.
En nuestro proyecto, utilizamos CLIP para:
- Generar incorporaciones de las imágenes directamente
- Convertir las consultas de búsqueda de lengua natural en el mismo espacio de embalaje
- Permite la búsqueda semántica comparando las incorporaciones de consultas con las incorporaciones de subtítulos
Quirón
Quirónes una base de datos vectorial de alto rendimiento. la usamos para almacenar y consultar las incorporaciones.
Rápido
Rápidoes un moderno, rápido (de alto rendimiento), marco web para la construcción de APIs con Python 3.7+ basado en las pistas de tipo estándar de Python.
Precondiciones
- Instalar Postgres. CocoIndex utiliza Postgres para mantener el seguimiento de la línea de datos para el procesamiento incremental.
- Instalación de Qdrant.
Definición del flujo de indexación
Diseño de flujo
El diagrama de flujo ilustra cómo procesaremos nuestra base de código:
- Leer archivos de imagen del sistema de archivos local
- Utilice CLIP para comprender y incorporar la imagen
- Almacenar las incorporaciones en una base de datos vectorial para la recuperación
1 Incorporar las imágenes.
@cocoindex.flow_def(name="ImageObjectEmbedding")
def image_object_embedding_flow(flow_builder: cocoindex.FlowBuilder, data_scope: cocoindex.DataScope):
data_scope["images"] = flow_builder.add_source(
cocoindex.sources.LocalFile(path="img", included_patterns=["*.jpg", "*.jpeg", "*.png"], binary=True),
refresh_interval=datetime.timedelta(minutes=1) # Poll for changes every 1 minute
)
img_embeddings = data_scope.add_collector()
flow_builder.add_source
se creará una tabla con subcampos (filename
, decontent
), podemos referirnos a laDocumentaciónPara más detalles.
Procesar cada imagen y recopilar la información.
2.1 Incorporar la imagen con CLIP
@functools.cache
def get_clip_model() -> tuple[CLIPModel, CLIPProcessor]:
model = CLIPModel.from_pretrained(CLIP_MODEL_NAME)
processor = CLIPProcessor.from_pretrained(CLIP_MODEL_NAME)
return model, processor
El@functools.cache
En este caso, garantiza que solo cargamos el modelo CLIP y el procesador una vez.
@cocoindex.op.function(cache=True, behavior_version=1, gpu=True)
def embed_image(img_bytes: bytes) -> cocoindex.Vector[cocoindex.Float32, Literal[384]]:
"""
Convert image to embedding using CLIP model.
"""
model, processor = get_clip_model()
image = Image.open(io.BytesIO(img_bytes)).convert("RGB")
inputs = processor(images=image, return_tensors="pt")
with torch.no_grad():
features = model.get_image_features(**inputs)
return features[0].tolist()
embed_image
Es una función personalizada que utiliza el modelo CLIP para convertir una imagen en una incorporación vectorial.Acepta datos de imagen en formato de bytes y devuelve una lista de números de puntos flotantes que representan la incorporación de la imagen.
La función soporta el cache a través de lacache
Parámetro. Cuando está habilitado, el ejecutor almacenará los resultados de la función para su reutilización durante el procesamiento, lo que es particularmente útil para operaciones computacionalmente intensivas. Para obtener más información sobre los parámetros de la función personalizada, consulteDocumentación.
Luego vamos a procesar cada imagen y recoger la información.
with data_scope["images"].row() as img:
img["embedding"] = img["content"].transform(embed_image)
img_embeddings.collect(
id=cocoindex.GeneratedField.UUID,
filename=img["filename"],
embedding=img["embedding"],
)
2.3 Colectar los engranajes
Exportar las incorporaciones a una mesa en Qdrant.
img_embeddings.export(
"img_embeddings",
cocoindex.storages.Qdrant(
collection_name="image_search",
grpc_url=QDRANT_GRPC_URL,
),
primary_key_fields=["id"],
setup_by_user=True,
)
Quiero el índice
Incorporar la consulta con CLIP, que mapea tanto el texto como las imágenes en el mismo espacio de incorporación, permitiendo la búsqueda de similitud entre modos.
def embed_query(text: str) -> list[float]:
model, processor = get_clip_model()
inputs = processor(text=[text], return_tensors="pt", padding=True)
with torch.no_grad():
features = model.get_text_features(**inputs)
return features[0].tolist()
Definición de un punto final/search
Realizar una búsqueda semántica de imagen.
@app.get("/search")
def search(q: str = Query(..., description="Search query"), limit: int = Query(5, description="Number of results")):
# Get the embedding for the query
query_embedding = embed_query(q)
# Search in Qdrant
search_results = app.state.qdrant_client.search(
collection_name="image_search",
query_vector=("embedding", query_embedding),
limit=limit
)
Esto busca la base de datos de vectores de Qdrant para inserciones similares. Devuelve la parte superiorlimit
Resultados
# Format results
out = []
for result in search_results:
out.append({
"filename": result.payload["filename"],
"score": result.score
})
return {"results": out}
Este punto final permite la búsqueda de imágenes semánticas donde los usuarios pueden encontrar imágenes describiéndolas en lenguaje natural, en lugar de usar coincidencias exactas de palabras clave.
Aplicación
Fuego rápido
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Serve images from the 'img' directory at /img
app.mount("/img", StaticFiles(directory="img"), name="img")
Instalación de aplicaciones FastAPI con middleware CORS y archivos estáticos que sirven La aplicación está configurada para:
- Permitir solicitudes cruzadas de cualquier origen
- Servir archivos de imagen estáticos desde el directorio 'img'
- Gestionar los endpoints de API para la funcionalidad de búsqueda de imagen
@app.on_event("startup")
def startup_event():
load_dotenv()
cocoindex.init()
# Initialize Qdrant client
app.state.qdrant_client = QdrantClient(
url=QDRANT_GRPC_URL,
prefer_grpc=True
)
app.state.live_updater = cocoindex.FlowLiveUpdater(image_object_embedding_flow)
app.state.live_updater.start()
El gestor de eventos de inicio inicia la aplicación cuando se inicia por primera vez.Aquí está lo que hace cada parte:
- load_dotenv(): Carga variables de entorno de un archivo .env, que es útil para la configuración como claves de API y URL
- cocoindex.init(): Inicializa el marco de CocoIndex, configurando los componentes y configuraciones necesarios
- Qdrant Client Setup:
- Creates a new
QdrantClient
instance - Configures it to use the gRPC URL specified in environment variables
- Enables gRPC preference for better performance
- Stores the client in the FastAPI app state for access across requests
- Creates a new
- Live Updater Setup:
- Creates a
FlowLiveUpdater
instance for theimage_object_embedding_flow
- This enables real-time updates to the image search index
- Starts the live updater to begin monitoring for changes
- Creates a
Esta inicialización asegura que todos los componentes necesarios se configuran correctamente y se ejecuten cuando se inicia la aplicación.
Frente
Puedes comprobar el código frontalAquíIntentamos mantenerlo simple y minimalista para centrarnos en la funcionalidad de búsqueda de imágenes.
¡Hora de divertirse!
-
Create a collection in Qdrant
curl -X PUT 'http://localhost:6333/collections/image_search' \ -H 'Content-Type: application/json' \ -d '{ "vectors": { "embedding": { "size": 768, "distance": "Cosine" } } }'
-
Setup indexing flow
cocoindex setup main.py
It is setup with a live updater, so you can add new files to the folder and it will be indexed within a minute.
-
Run backend
uvicorn main:app --reload --host 0.0.0.0 --port 8000
-
Run frontend
cd frontend npm install npm run dev
Vaya ahttp://localhost:5174de la búsqueda.
Añade otra imagen en elimg
Por ejemplo, en el folio, estedulce escarabajoEsperar un minuto para que la nueva imagen sea procesada e indexada.
Si desea monitorear el progreso de la indexación, puede verlo en CocoInsightcocoindex server -ci main.py
.
Finally - we are constantly improving, and more features and examples are coming soon. If you love this article, please give us a star ⭐ at GitHub to help us grow. Thanks for reading!
GitHub