| import os |
|
|
| |
| os.environ["HF_HOME"] = "/tmp/hf" |
| os.environ["TRANSFORMERS_CACHE"] = "/tmp/hf" |
| os.environ["TORCH_HOME"] = "/tmp/torch" |
| os.environ["XDG_CACHE_HOME"] = "/tmp" |
|
|
| import gradio as gr |
| import torch |
| import open_clip |
| import faiss |
| import numpy as np |
| import json |
| from PIL import Image |
| from transformers import BlipProcessor, BlipForConditionalGeneration |
|
|
| with open("image_paths.json", "r") as f: |
| image_paths = json.load(f) |
|
|
| image_embeddings = np.load("image_embeddings.npy") |
|
|
| model, _, preprocess = open_clip.create_model_and_transforms('ViT-B-32', pretrained='laion2b_s34b_b79k') |
| tokenizer = open_clip.get_tokenizer('ViT-B-32') |
|
|
| d = image_embeddings.shape[1] |
| index = faiss.IndexFlatIP(d) |
| index.add(image_embeddings) |
|
|
| processor_cap = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base") |
| model_cap = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base") |
|
|
| def search_text(query, top_k=3): |
| with torch.no_grad(): |
| tokenized = tokenizer([query]) |
| text_embed = model.encode_text(tokenized) |
| text_embed = text_embed / text_embed.norm(dim=-1, keepdim=True) |
| text_np = text_embed.cpu().numpy() |
| _, I = index.search(text_np, top_k) |
| return [image_paths[i] for i in I[0]] |
|
|
| def search_image(image, top_k=3): |
| image_tensor = preprocess(image).unsqueeze(0) |
| with torch.no_grad(): |
| image_embed = model.encode_image(image_tensor) |
| image_embed = image_embed / image_embed.norm(dim=-1, keepdim=True) |
| image_np = image_embed.cpu().numpy() |
| _, I = index.search(image_np, top_k) |
| return [image_paths[i] for i in I[0]] |
|
|
| def generate_captions(paths): |
| imgs = [Image.open(p).convert("RGB") for p in paths] |
| inputs = processor_cap(images=imgs, return_tensors="pt") |
| out = model_cap.generate(**inputs) |
| captions = [processor_cap.decode(out[i], skip_special_tokens=True) for i in range(len(imgs))] |
| return captions |
|
|
| def predict(input_text, input_image): |
| if input_text: |
| paths = search_text(input_text) |
| elif input_image: |
| paths = search_image(input_image) |
| else: |
| return None, None |
|
|
| captions = generate_captions(paths) |
| return [(Image.open(p), c) for p, c in zip(paths, captions)] |
|
|
| with gr.Blocks() as demo: |
| gr.Markdown("## Animal Image Search π ποΈ π ") |
| gr.Markdown("Search database of 5400 animal images using text or image queries.") |
| gr.Markdown("Results come with automatic captions.") |
| gr.Markdown("For list of animal categories (90 animals x 60 images = 5400 images) visit [GitHub](https://github.com/TensorCruncher/animal-image-search/blob/main/animals.txt).") |
| gr.Markdown("Note: Make sure only one input field (text or image) is populated before searching") |
|
|
| with gr.Row(): |
| text_input = gr.Textbox(label="Type your query") |
| image_input = gr.Image(type="pil", label="Or upload an image") |
| |
| gr.Examples( |
| examples=[ |
| "examples/sample1.jpg", |
| "examples/sample2.jpg", |
| "examples/sample3.jpg" |
| ], |
| inputs=[image_input], |
| label="Choose a sample image" |
| ) |
|
|
| output = gr.Gallery(label="Top Matches with Captions") |
|
|
| submit = gr.Button("Search", variant="primary") |
| submit.click(predict, inputs=[text_input, image_input], outputs=output) |
|
|
| demo.launch() |
|
|