Spaces:
Sleeping
Sleeping
File size: 15,030 Bytes
792840c 1c4aa87 792840c 1c4aa87 792840c 1c4aa87 792840c 1c4aa87 792840c 1c4aa87 792840c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
import gradio as gr
import open_clip
import torch
import requests
import numpy as np
from PIL import Image
from io import BytesIO
# Sidebar content
sidebar_markdown = """
Note, this demo can classify 200 items. If you didn't find what you're looking for, reach out to us on our [Community](https://join.slack.com/t/marqo-community/shared_invite/zt-2iab0260n-QJrZLUSOJYUifVxf964Gdw) and request an item to be added.
## Documentation
📚 [Blog Post](https://www.marqo.ai/blog/search-model-for-fashion)
📝 [Use Case Blog Post](https://www.marqo.ai/blog/ecommerce-image-classification-with-marqo-fashionclip)
## Code
💻 [GitHub Repo](https://github.com/marqo-ai/marqo-FashionCLIP)
🤝 [Google Colab](https://colab.research.google.com/drive/1nq978xFJjJcnyrJ2aE5l82GHAXOvTmfd?usp=sharing)
🤗 [Hugging Face Collection](https://huggingface.co/collections/Marqo/marqo-fashionclip-and-marqo-fashionsiglip-66b43f2d09a06ad2368d4af6)
"""
# List of fashion items and their IDs
categories = [
{"name": "Nettoyants visage", "id": 101},
{"name": "Exfoliants visage", "id": 102},
{"name": "Hydratants visage", "id": 103},
{"name": "Masques visage", "id": 104},
{"name": "Soins ciblés visage", "id": 105},
{"name": "Protection solaire visage", "id": 106},
{"name": "Nettoyants visage homme", "id": 107},
{"name": "Crèmes hydratantes homme", "id": 108},
{"name": "Soins après-rasage", "id": 109},
{"name": "Hydratants corps", "id": 110},
{"name": "Exfoliants corps", "id": 111},
{"name": "Soins fermeté & minceur", "id": 112},
{"name": "Auto-bronzants", "id": 113},
{"name": "Soins des mains", "id": 114},
{"name": "Soins des pieds", "id": 115},
{"name": "Hydratants corps homme", "id": 116},
{"name": "Déodorants corps homme", "id": 117},
{"name": "Shampoings", "id": 118},
{"name": "Après-shampoings", "id": 119},
{"name": "Masques capillaires", "id": 120},
{"name": "Huiles capillaires", "id": 121},
{"name": "Coiffants", "id": 122},
{"name": "Accessoires cheveux", "id": 123},
{"name": "Soins cheveux homme", "id": 124},
{"name": "Produits coiffants homme", "id": 125},
{"name": "Fond de teint", "id": 126},
{"name": "BB/CC crèmes", "id": 127},
{"name": "Poudres", "id": 128},
{"name": "Fards à paupières", "id": 129},
{"name": "Mascaras", "id": 130},
{"name": "Eyeliners", "id": 131},
{"name": "Rouges à lèvres", "id": 132},
{"name": "Gloss", "id": 133},
{"name": "Crayons à sourcils", "id": 134},
{"name": "Accessoires maquillage", "id": 135},
{"name": "Correcteurs teint homme", "id": 136},
{"name": "Poudres matifiantes homme", "id": 137},
{"name": "Parfums", "id": 138},
{"name": "Brumes corporelles", "id": 139},
{"name": "Huiles essentielles", "id": 140},
{"name": "Diffuseurs d'huiles", "id": 141},
{"name": "Bougies parfumées", "id": 142},
{"name": "Déodorants solides", "id": 143},
{"name": "Déodorants sprays", "id": 144},
{"name": "Savons solides", "id": 145},
{"name": "Savons liquides", "id": 146},
{"name": "Produits bain", "id": 147},
{"name": "Hygiène intime", "id": 148},
{"name": "Cups menstruelles", "id": 149},
{"name": "Produits zéro déchet", "id": 150},
{"name": "Brosses nettoyantes visage", "id": 151},
{"name": "Pinces à épiler", "id": 152},
{"name": "Trousse de voyage", "id": 153},
{"name": "Huiles de CBD", "id": 154},
{"name": "Cosmétiques au CBD", "id": 155},
{"name": "Infusions au CBD", "id": 156},
{"name": "Bonbons au CBD", "id": 157},
{"name": "Accessoires CBD", "id": 158},
{"name": "Robes femme", "id": 201},
{"name": "Tops femme", "id": 202},
{"name": "Chemisiers femme", "id": 203},
{"name": "T-shirts femme", "id": 204},
{"name": "Pulls femme", "id": 205},
{"name": "Jeans femme", "id": 206},
{"name": "Pantalons femme", "id": 207},
{"name": "Jupes femme", "id": 208},
{"name": "Shorts femme", "id": 209},
{"name": "Vestes femme", "id": 210},
{"name": "Manteaux femme", "id": 211},
{"name": "Maillots de bain femme", "id": 212},
{"name": "Lingerie femme", "id": 213},
{"name": "Chaussures femme", "id": 214},
{"name": "Sacs femme", "id": 215},
{"name": "Bijoux femme", "id": 216},
{"name": "Chemises homme", "id": 301},
{"name": "T-shirts homme", "id": 302},
{"name": "Polos homme", "id": 303},
{"name": "Pulls homme", "id": 304},
{"name": "Jeans homme", "id": 305},
{"name": "Pantalons homme", "id": 306},
{"name": "Shorts homme", "id": 307},
{"name": "Vestes homme", "id": 308},
{"name": "Manteaux homme", "id": 309},
{"name": "Costumes homme", "id": 310},
{"name": "Maillots de bain homme", "id": 311},
{"name": "Sous-vêtements homme", "id": 312},
{"name": "Chaussures homme", "id": 313},
{"name": "Accessoires homme", "id": 314},
{"name": "Montres homme", "id": 315},
{"name": "Vêtements bébé (0-2 ans)", "id": 401},
{"name": "T-shirts enfant", "id": 402},
{"name": "Pulls enfant", "id": 403},
{"name": "Pantalons enfant", "id": 404},
{"name": "Robes enfant", "id": 405},
{"name": "Jeans enfant", "id": 406},
{"name": "Vestes enfant", "id": 407},
{"name": "Pyjamas enfant", "id": 408},
{"name": "Chaussures enfant", "id": 409},
{"name": "Accessoires enfant", "id": 410},
{"name": "Vêtements de sport enfant", "id": 411},
{"name": "Maillots de bain enfant", "id": 412},
{"name": "Sous-vêtements enfant", "id": 413},
{"name": "Déguisements enfant", "id": 414},
{"name": "Cartables et sacs enfant", "id": 415},
# Chaussures Femme détaillées
{"name": "Sneakers femme", "id": 217},
{"name": "Boots femme", "id": 218},
{"name": "Escarpins femme", "id": 219},
{"name": "Sandales femme", "id": 220},
{"name": "Ballerines femme", "id": 221},
{"name": "Mocassins femme", "id": 222},
{"name": "Bottines femme", "id": 223},
{"name": "Espadrilles femme", "id": 224},
{"name": "Mules femme", "id": 225},
{"name": "Chaussures de sport femme", "id": 226},
{"name": "Bottes hautes femme", "id": 227},
{"name": "Chaussures compensées femme", "id": 228},
# Chaussures Homme détaillées
{"name": "Sneakers homme", "id": 316},
{"name": "Boots homme", "id": 317},
{"name": "Chaussures de ville homme", "id": 318},
{"name": "Mocassins homme", "id": 319},
{"name": "Sandales homme", "id": 320},
{"name": "Chaussures bateau homme", "id": 321},
{"name": "Bottines homme", "id": 322},
{"name": "Chaussures de sport homme", "id": 323},
{"name": "Espadrilles homme", "id": 324},
{"name": "Derbies homme", "id": 325},
{"name": "Richelieus homme", "id": 326},
{"name": "Chaussures de randonnée homme", "id": 327},
# Chaussures Enfant détaillées
{"name": "Sneakers enfant", "id": 416},
{"name": "Bottes enfant", "id": 417},
{"name": "Sandales enfant", "id": 418},
{"name": "Chaussures de sport enfant", "id": 419},
{"name": "Chaussures premiers pas", "id": 420},
{"name": "Chaussures à scratch enfant", "id": 421},
{"name": "Chaussures d'école enfant", "id": 422},
{"name": "Pantoufles enfant", "id": 423},
{"name": "Chaussures de cérémonie enfant", "id": 424},
{"name": "Bottes de pluie enfant", "id": 425}
];
# Extract category names
items = [category["name"] for category in categories]
# Initialize the model and tokenizer
model_name = 'hf-hub:Marqo/marqo-fashionSigLIP'
model, preprocess_train, preprocess_val = open_clip.create_model_and_transforms(model_name)
tokenizer = open_clip.get_tokenizer(model_name)
# Generate descriptions
def generate_description(item):
return f"A fashion item called {item}"
items_desc = [generate_description(item) for item in items]
text = tokenizer(items_desc)
# Encode text features
device = 'cuda' if torch.cuda.is_available() else 'cpu'
model.to(device)
torch.cuda.empty_cache() # Avant de charger le modèle
with torch.no_grad(), torch.amp.autocast(device_type=device):
text_features = model.encode_text(text.to(device))
text_features /= text_features.norm(dim=-1, keepdim=True)
# Prediction function
def predict(image, url):
if url:
response = requests.get(url)
image = Image.open(BytesIO(response.content))
processed_image = preprocess_val(image).unsqueeze(0).to(device)
with torch.no_grad(), torch.amp.autocast(device_type=device):
image_features = model.encode_image(processed_image)
image_features /= image_features.norm(dim=-1, keepdim=True)
text_probs = (100 * image_features @ text_features.T).softmax(dim=-1)
sorted_confidences = sorted(
{items[i]: float(text_probs[0, i]) for i in range(len(items))}.items(),
key=lambda x: x[1],
reverse=True
)
# Include category IDs in the response
top_10_categories = [
{
"category_name": category["name"],
"id": category["id"],
"confidence": confidence
}
for category_name, confidence in sorted_confidences[:10]
for category in categories if category["name"] == category_name
]
return image, top_10_categories
# Ajout de la fonction de prédiction par lots
def predict_batch(images, urls):
# Combiner les images provenant des URLs et des téléchargements directs
combined_images = []
for image, url in zip(images, urls):
if url:
response = requests.get(url)
image = Image.open(BytesIO(response.content))
combined_images.append(preprocess_val(image).unsqueeze(0).to(device))
# Empiler toutes les images traitées en un seul lot
batch_images = torch.cat(combined_images, dim=0)
with torch.no_grad(), torch.amp.autocast(device_type=device):
image_features = model.encode_image(batch_images)
image_features /= image_features.norm(dim=-1, keepdim=True)
text_probs = (100 * image_features @ text_features.T).softmax(dim=-1)
# Traiter chaque image dans le lot
batch_results = []
for i in range(len(images)):
sorted_confidences = sorted(
{items[j]: float(text_probs[i, j]) for j in range(len(items))}.items(),
key=lambda x: x[1],
reverse=True
)
# Inclure les IDs de catégorie dans la réponse
top_10_categories = [
{
"category_name": category["name"],
"id": category["id"],
"confidence": confidence
}
for category_name, confidence in sorted_confidences[:10]
for category in categories if category["name"] == category_name
]
batch_results.append(top_10_categories)
return batch_results
# Fonction de prédiction avec texte
def predict_with_text(image, url, text_prompt):
if url:
response = requests.get(url)
image = Image.open(BytesIO(response.content))
processed_image = preprocess_val(image).unsqueeze(0).to(device)
# Encoder l'image
with torch.no_grad(), torch.amp.autocast(device_type=device):
image_features = model.encode_image(processed_image)
image_features /= image_features.norm(dim=-1, keepdim=True)
# Encoder le texte fourni par l'utilisateur
user_text = tokenizer([text_prompt]).to(device)
user_text_features = model.encode_text(user_text)
user_text_features /= user_text_features.norm(dim=-1, keepdim=True)
# Combiner les caractéristiques de l'image et du texte (moyenne pondérée)
combined_features = 0.7 * image_features + 0.3 * user_text_features
combined_features /= combined_features.norm(dim=-1, keepdim=True)
# Calculer les probabilités avec les caractéristiques combinées
text_probs = (100 * combined_features @ text_features.T).softmax(dim=-1)
sorted_confidences = sorted(
{items[i]: float(text_probs[0, i]) for i in range(len(items))}.items(),
key=lambda x: x[1],
reverse=True
)
# Inclure les IDs de catégorie dans la réponse
top_10_categories = [
{
"category_name": category["name"],
"id": category["id"],
"confidence": confidence
}
for category_name, confidence in sorted_confidences[:10]
for category in categories if category["name"] == category_name
]
return image, top_10_categories
# Fonction de prédiction combinée qui choisit la méthode appropriée
def predict_combined(image, url, text_prompt=""):
if text_prompt and text_prompt.strip():
return predict_with_text(image, url, text_prompt)
else:
return predict(image, url)
# Clear function
def clear_fields():
return None, "", "", None, ""
# Gradio interface
title = "Fashion Item Classifier with Marqo-FashionSigLIP"
description = "Upload an image or provide a URL of a fashion item to classify it using [Marqo-FashionSigLIP](https://huggingface.co/Marqo/marqo-fashionSigLIP)!"
examples = [
["images/dress.jpg", "Dress"],
["images/sweatpants.jpg", "Sweatpants"],
["images/t-shirt.jpg", "T-Shirt"],
]
with gr.Blocks() as demo:
with gr.Row():
with gr.Column(scale=1):
gr.Markdown(f"# {title}")
gr.Markdown(description)
gr.Markdown(sidebar_markdown)
with gr.Column(scale=2):
input_image = gr.Image(type="pil", label="Upload Fashion Item Image", height=312)
input_url = gr.Textbox(label="Or provide an image URL")
input_text = gr.Textbox(label="Ajouter une description textuelle (optionnel)", placeholder="Ex: Robe d'été fleurie pour femme")
input_images = gr.Image(type="pil", label="Upload Fashion Item Images", height=312)
input_urls = gr.Textbox(label="Or provide image URLs (comma-separated)", lines=2)
with gr.Row():
predict_button = gr.Button("Classifier")
clear_button = gr.Button("Effacer")
gr.Markdown("Ou cliquez sur l'une des images ci-dessous pour la classifier:")
gr.Examples(examples=examples, inputs=input_image)
output_label = gr.JSON(label="Top Categories")
output_batch_label = gr.JSON(label="Top Categories for Each Image")
predict_button.click(predict_combined, inputs=[input_image, input_url, input_text], outputs=[input_image, output_label])
clear_button.click(clear_fields, outputs=[input_image, input_url, input_text, input_images, input_urls])
# Launch the interface
demo.launch()
|