Sistema de recomendação de moda usando FastEmbed, QDRANT


Os sistemas de recomendação estão por toda parte. Da Netflix e Spotify à Amazon. Mas e se você quisesse criar um mecanismo de recomendação visible? Um que olha para a imagem, não apenas o título ou as tags? Neste artigo, você criará um sistema de recomendação de moda masculina. Ele usará incorporações de imagem e o banco de dados de vetores QDRANT. Você irá de dados de imagem bruta para recomendações visuais em tempo actual.

Objetivo de aprendizagem

  • Como as incorporações de imagem representam conteúdo visible
  • Como usar o FastEmbbed para geração vetorial
  • Como armazenar e pesquisar vetores usando o QDRANT
  • Como construir um mecanismo de recomendação orientado a suggestions
  • Como criar uma interface de interface do simples

Caso de uso: recomendações visuais para camisetas e polos

Think about um usuário clica em uma camisa polo elegante. Em vez de usar tags de produto, seu sistema de recomendação de moda recomendará camisetas e polos que parecem semelhantes. Ele usa a própria imagem para tomar essa decisão.

Vamos explorar como.

Etapa 1: Compreendendo incorporações de imagem

O que são incorporações de imagem?

Um incorporação de imagem é um vetor. É uma lista de números. Esses números representam os principais recursos da imagem. Duas imagens semelhantes têm incorporações que estão juntas no espaço vetorial. Isso permite que o sistema mede a similaridade visible.

Por exemplo, duas camisetas diferentes podem parecer diferentes em pixels. Mas suas incorporações estarão próximas se tiverem cores, padrões e texturas semelhantes. Essa é uma capacidade essential para um sistema de recomendação de moda.

Sistema de recomendação de moda usando FastEmbed, QDRANT

Como as incorporações são geradas?

A maioria dos modelos de incorporação usa aprendizado profundo. CNNs (redes neurais convolucionais) extraem padrões visuais. Esses padrões se tornam parte do vetor.

No nosso caso, usamos o Fastembed. O modelo de incorporação usado aqui é: QDRANT/UNICOM-VIT-B-32

from fastembed import ImageEmbedding
from typing import Record
from dotenv import load_dotenv
import os

load_dotenv()
mannequin = ImageEmbedding(os.getenv("IMAGE_EMBEDDING_MODEL"))

def compute_image_embedding(image_paths: Record(str)) -> checklist(float):
    return checklist(mannequin.embed(image_paths))

Esta função leva uma lista de caminhos de imagem. Retorna vetores que capturam a essência dessas imagens.

Etapa 2: Obtendo o conjunto de dados

Usamos um conjunto de dados de cerca de 2000 imagens de moda masculina. Você pode encontrá -lo em Kaggle. Aqui está como carregamos o conjunto de dados:

import shutil, os, kagglehub
from dotenv import load_dotenv

load_dotenv()
kaggle_repo = os.getenv("KAGGLE_REPO")
path = kagglehub.dataset_download(kaggle_repo)
target_folder = os.getenv("DATA_PATH")

def getData():
    if not os.path.exists(target_folder):
        shutil.copytree(path, target_folder)

Este script verifica se a pasta de destino existe. Caso contrário, copia as imagens lá.

Etapa 3: Armazene e pesquise vetores com QDRANT

Depois de incorporar, precisamos armazená -los e pesquisar. É aqui que QDRANT vem. É um banco de dados vetorial rápido e escalável.

Aqui está como se conectar ao banco de dados de vetores QDrant:

from qdrant_client import QdrantClient

shopper = QdrantClient(
    url=os.getenv("QDRANT_URL"),
    api_key=os.getenv("QDRANT_API_KEY"),
)
That is the right way to insert the photographs paired with its embedding to a Qdrant assortment:
class VectorStore:
    def __init__(self, embed_batch: int = 64, upload_batch: int = 32, parallel_uploads: int = 3):
        # ... (initializer code omitted for brevity) ...

    def insert_images(self, image_paths: Record(str)):
        def chunked(iterable, dimension):
            for i in vary(0, len(iterable), dimension):
                yield iterable(i:i + dimension)

        for batch in chunked(image_paths, self.embed_batch):
            embeddings = compute_image_embedding(batch)  # Batch embed
            factors = (
                fashions.PointStruct(id=str(uuid.uuid4()), vector=emb, payload={"image_path": img})
                for emb, img in zip(embeddings, batch)
            )

            # Batch add every sub-batch
            self.shopper.upload_points(
                collection_name=self.collection_name,
                factors=factors,
                batch_size=self.upload_batch,
                parallel=self.parallel_uploads,
                max_retries=3,
                wait=True
            )

Esse código leva uma lista de caminhos de arquivo de imagem, transforma -os em incorporação em lotes e carrega essas incorporações para uma coleção QDRANT. Primeiro verifica se a coleção existe. Em seguida, ele processa as imagens em paralelo usando threads para acelerar as coisas. Cada imagem recebe um ID exclusivo e é envolvido em um “ponto” com sua incorporação e caminho. Esses pontos são então enviados para QDRANT em pedaços.

Pesquise imagens semelhantes

def search_similar(query_image_path: str, restrict: int = 5):
    emb_list = compute_image_embedding((query_image_path))
    hits = shopper.search(
        collection_name="fashion_images",
        query_vector=emb_list(0),
        restrict=restrict
    )
    return ({"id": h.id, "image_path": h.payload.get("image_path")} for h in hits)

Você dá uma imagem de consulta. O sistema retorna imagens visualmente semelhantes usando métricas de similaridade de cosseno.

Etapa 4: Crie o mecanismo de recomendação com suggestions

Agora vamos um passo adiante. E se o usuário gostar de algumas imagens e não gosta de outras? O sistema de recomendação de moda pode aprender com isso?

Sim. O QDRANT nos permite dar suggestions positivo e negativo. Em seguida, retorna resultados melhores e mais personalizados.

class RecommendationEngine:
    def get_recommendations(self, liked_images:Record(str), disliked_images:Record(str), restrict=10):
        beneficial = shopper.advocate(
            collection_name="fashion_images",
            constructive=liked_images,
            unfavourable=disliked_images,
            restrict=restrict
        )
        return ({"id": hit.id, "image_path": hit.payload.get("image_path")} for hit in beneficial)

Aqui estão as entradas desta função:

  • gostei_images: uma lista de IDs de imagem que representam itens que o usuário gostou.
  • Não gostei_Images: Uma lista de IDs de imagem que representam itens que o usuário não gostava.
  • LIMITE (OPCIONAL): Um número inteiro especificando o número máximo de recomendações a serem retornadas (padrão para 10).

Isso retornará roupas recomendadas usando a similaridade do vetor de incorporação apresentada anteriormente.

Isso permite que seu sistema se adapte. Aprende as preferências do usuário rapidamente.

Etapa 5: Construa uma interface do usuário com simplidade

Usamos o streamlit para criar a interface. É simples, rápido e escrito em Python.

Sistema de recomendação de moda 2
Sistema de recomendação de moda

Os usuários podem:

  • Navegue roupas
  • Gostar ou não gostar de itens
  • Veja novas recomendações melhores

Aqui está o código do streamlit:

import streamlit as st
from PIL import Picture
import os

from src.advice.engine import RecommendationEngine
from src.vector_database.vectorstore import VectorStore
from src.knowledge.get_data import getData

# -------------- Config --------------
st.set_page_config(page_title="🧥 Males's Vogue Recommender", format="vast")
IMAGES_PER_PAGE = 12

# -------------- Guarantee Dataset Exists (as soon as) --------------
@st.cache_resource
def initialize_data():
    getData()
    return VectorStore(), RecommendationEngine()

vector_store, recommendation_engine = initialize_data()

# -------------- Session State Defaults --------------
session_defaults = {
    "favored": {},
    "disliked": {},
    "current_page": 0,
    "recommended_images": vector_store.factors,
    "vector_store": vector_store,
    "recommendation_engine": recommendation_engine,
}

for key, worth in session_defaults.objects():
    if key not in st.session_state:
        st.session_state(key) = worth

# -------------- Sidebar Data --------------
with st.sidebar:
    st.title("🧥 Males's Vogue Recommender")

    st.markdown("""
    **Uncover trend types that fit your style.**  
    Like 👍 or dislike 👎 outfits and obtain AI-powered suggestions tailor-made to you.
    """)

    st.markdown("### 📦 Dataset")
    st.markdown("""
    - Supply: (Kaggle – virat164/fashion-database)(https://www.kaggle.com/datasets/virat164/fashion-database)  
    - ~2,000 trend photographs
    """)

    st.markdown("### 🧠 How It Works")
    st.markdown("""
    1. Photos are embedded into vector house  
    2. You present preferences by way of Like/Dislike  
    3. Qdrant finds visually comparable photographs  
    4. Outcomes are up to date in real-time
    """)

    st.markdown("### ⚙️ Applied sciences")
    st.markdown("""
    - **Streamlit** UI  
    - **Qdrant** vector DB  
    - **Python** backend  
    - **PIL** for picture dealing with  
    - **Kaggle API** for knowledge
    """)

    st.markdown("---")
# -------------- Core Logic Capabilities --------------
def get_recommendations(liked_ids, disliked_ids):
    return st.session_state.recommendation_engine.get_recommendations(
        liked_images=liked_ids,
        disliked_images=disliked_ids,
        restrict=3 * IMAGES_PER_PAGE
    )

def refresh_recommendations():
    liked_ids = checklist(st.session_state.favored.keys())
    disliked_ids = checklist(st.session_state.disliked.keys())
    st.session_state.recommended_images = get_recommendations(liked_ids, disliked_ids)

# -------------- Show: Chosen Preferences --------------
def display_selected_images():
    if not st.session_state.favored and never st.session_state.disliked:
        return

    st.markdown("### 🧍 Your Picks")
    cols = st.columns(6)
    photographs = st.session_state.vector_store.factors

    for i, (img_id, standing) in enumerate(
        checklist(st.session_state.favored.objects()) + checklist(st.session_state.disliked.objects())
    ):
        img_path = subsequent((img("image_path") for img in photographs if img("id") == img_id), None)
        if img_path and os.path.exists(img_path):
            with cols(i % 6):
                st.picture(img_path, use_container_width=True, caption=f"{img_id} ({standing})")
                col1, col2 = st.columns(2)
                if col1.button("❌ Take away", key=f"remove_{img_id}"):
                    if standing == "favored":
                        del st.session_state.favored(img_id)
                    else:
                        del st.session_state.disliked(img_id)
                    refresh_recommendations()
                    st.rerun()

                if col2.button("🔁 Change", key=f"switch_{img_id}"):
                    if standing == "favored":
                        del st.session_state.favored(img_id)
                        st.session_state.disliked(img_id) = "disliked"
                    else:
                        del st.session_state.disliked(img_id)
                        st.session_state.favored(img_id) = "favored"
                    refresh_recommendations()
                    st.rerun()

# -------------- Show: Advisable Gallery --------------
def display_gallery():
    st.markdown("### 🧠 Good Recommendations")

    web page = st.session_state.current_page
    start_idx = web page * IMAGES_PER_PAGE
    end_idx = start_idx + IMAGES_PER_PAGE
    current_images = st.session_state.recommended_images(start_idx:end_idx)

    cols = st.columns(4)
    for idx, img in enumerate(current_images):
        with cols(idx % 4):
            if os.path.exists(img("image_path")):
                st.picture(img("image_path"), use_container_width=True)
            else:
                st.warning("Picture not discovered")

            col1, col2 = st.columns(2)
            if col1.button("👍 Like", key=f"like_{img('id')}"):
                st.session_state.favored(img("id")) = "favored"
                refresh_recommendations()
                st.rerun()
            if col2.button("👎 Dislike", key=f"dislike_{img('id')}"):
                st.session_state.disliked(img("id")) = "disliked"
                refresh_recommendations()
                st.rerun()

    # Pagination
    col1, _, col3 = st.columns((1, 2, 1))
    with col1:
        if st.button("⬅️ Earlier") and web page > 0:
            st.session_state.current_page -= 1
            st.rerun()
    with col3:
        if st.button("➡️ Subsequent") and end_idx < len(st.session_state.recommended_images):
            st.session_state.current_page += 1
            st.rerun()

# -------------- Most important Render Pipeline --------------
st.title("🧥 Males's Vogue Recommender")

display_selected_images()
st.divider()
display_gallery()

This UI closes the loop. It turns a operate right into a usable product.

Conclusão

Você acabou de criar um sistema completo de recomendação de moda. Ele vê imagens, entende recursos visuais e faz sugestões inteligentes.

Usando o Fastembed, o QDRANT e o Streamlit, agora você tem um poderoso sistema de recomendação. Funciona para camisetas, polos e roupas masculinas, mas pode ser adaptado a outras recomendações baseadas na imagem.

Perguntas frequentes

Os números nas incorporações de imagem representam intensidades de pixel?

Não exatamente. Os números nas incorporações capturam recursos semânticos como formas, cores e texturas – não valores de pixels brutos. Isso ajuda o sistema a entender o significado por trás da imagem e não apenas os dados do Pixel.

Este sistema de recomendação requer treinamento?

Não. Ele aproveita a similaridade vetorial (como a similaridade de cosseno) no espaço de incorporação para encontrar itens visualmente semelhantes sem precisar treinar um modelo tradicional do zero.

Posso ajustar ou treinar meu próprio modelo de incorporação de imagem?

Sim, você pode. Os modelos de incorporação de imagem de treinamento ou de ajuste fino geralmente envolvem estruturas como Tensorflow ou Pytorch e um conjunto de dados rotulado. Isso permite personalizar incorporações para necessidades específicas.

É possível consultar incorporações de imagem usando texto?

Sim, se você usar um modelo multimodal que mapeie as imagens e o texto no mesmo espaço vetorial. Dessa forma, você pode pesquisar imagens com consultas de texto ou vice -versa.

Devo sempre usar o Fastembed para incorporações?

Fastembed é uma ótima opção para incorporações rápidas e eficientes. Mas existem muitas alternativas, incluindo modelos do OpenAI, Google ou Groq. A escolha depende do seu caso de uso e das necessidades de desempenho.

Posso usar bancos de dados vetoriais que não sejam QDRANT?

Absolutamente. As alternativas populares incluem Pinecone, Weaviate, Milvus e Vespa. Cada um possui recursos exclusivos, então escolha o que melhor se ajusta aos requisitos do seu projeto.

Este sistema é semelhante à geração aumentada de recuperação (RAG)?

Não. Enquanto ambos usam pesquisas vetoriais, o RAG integra a recuperação à geração de idiomas para tarefas como a resposta das perguntas. Aqui, o foco está puramente nas recomendações de similaridade visible.

Sou cientista de dados com experiência em processamento de linguagem pure (PNL), modelos de idiomas grandes (LLMS), visão computacional (CV), modelagem preditiva, aprendizado de máquina, sistemas de recomendação e computação em nuvem.

Eu me especializo no treinamento de modelos ML/DL adaptados a casos de uso específicos.

Eu construo aplicativos de banco de dados vetoriais para permitir que o LLMS acesse dados externos para obter uma resposta mais precisa das perguntas.

Eu ajustei os LLMs nos dados específicos do domínio.

I Bairragem LLMS para gerar saídas estruturadas para automatizar a extração de dados a partir de texto não estruturado.

Projeto de arquiteturas de soluções de IA na AWS seguindo as melhores práticas.

Sou apaixonado por explorar novas tecnologias e resolver problemas complexos de IA, e estou ansioso para contribuir com informações valiosas para a comunidade Analytics Vidhya.

Faça login para continuar lendo e desfrutar de conteúdo com curado especialista.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *