Skip to content
Open
Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
df317c5
Created a model download + Openvino IR format conversion script, used…
Raghavyadav17 Jun 9, 2025
730d0d1
Add image embedding pipeline with model conversion, preprocessing, po…
Raghavyadav17 Jun 23, 2025
39e7126
Fix: Use numpy<2.0.0 in Dockerfile for compatibility
Raghavyadav17 Jun 23, 2025
9c3be96
Cleanup: Removed venvs and config/make.save files per mentor feedback
Raghavyadav17 Jun 24, 2025
ad2151f
Removed stray convert_clip.py from old PR (not needed)
Raghavyadav17 Jun 24, 2025
9c61416
Fix: updated MediaPipe graph based on mentor feedback
Raghavyadav17 Jun 24, 2025
df9413d
Updated files corrected under Damian's supervision in the meeting
Raghavyadav17 Jul 2, 2025
30bc6a9
Restore Dockerfile.ubuntu after accidental deletion
Raghavyadav17 Jul 2, 2025
38ad1f3
fully functional grpc client + requirements.txt
Raghavyadav17 Jul 22, 2025
f92dd9c
Conversion scripts for dino and laion models to openvino IR
Raghavyadav17 Jul 22, 2025
11c17b5
Updated pre.py
Raghavyadav17 Aug 2, 2025
d2519fa
Updated post.py
Raghavyadav17 Aug 2, 2025
012583a
updated .json file for all models and their respective mediapipe
Raghavyadav17 Aug 2, 2025
a2d7460
Final grpc script, updated clip conversion script, updated requiremen…
Raghavyadav17 Aug 27, 2025
b835e8a
Demo images folder which contains all the images required to build ve…
Raghavyadav17 Aug 27, 2025
709e1f7
mediapipe for clip model
Raghavyadav17 Aug 27, 2025
e119826
mediapipe for dino
Raghavyadav17 Aug 27, 2025
a2fd941
mediapipe for laion
Raghavyadav17 Aug 27, 2025
b0368b2
demo image
Raghavyadav17 Aug 28, 2025
629fa64
search logic
Raghavyadav17 Aug 28, 2025
12bb4a6
demo frontend
Raghavyadav17 Aug 28, 2025
57b2bc9
config json for the project
Raghavyadav17 Aug 30, 2025
8367268
readme for the project
Raghavyadav17 Aug 30, 2025
04f4a53
Final grpc script with cli argument + loading bar as discussed in the…
Raghavyadav17 Aug 30, 2025
259e4ac
demo img for testing
Raghavyadav17 Aug 30, 2025
24196cb
final dino conversion script based on copilot suggestions
Raghavyadav17 Aug 30, 2025
cfc063a
final pre.py based on copilt suggestion
Raghavyadav17 Aug 30, 2025
d1f24b4
fixed dockerfile
Raghavyadav17 Aug 30, 2025
1a5129b
Merge branch 'main' into raghav/image-embedding
Raghavyadav17 Aug 30, 2025
00c8fb2
Merge branch 'main' into raghav/image-embedding
Raghavyadav17 Sep 1, 2025
6e0f4d0
Update demos/python_demos/image_embeddings/Readme.md
Raghavyadav17 Sep 1, 2025
212485d
Update demos/python_demos/image_embeddings/Readme.md
Raghavyadav17 Sep 1, 2025
0aeb55e
Merge branch 'main' into raghav/image-embedding
Raghavyadav17 Sep 2, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions Dockerfile.ubuntu
Original file line number Diff line number Diff line change
Expand Up @@ -396,8 +396,8 @@ RUN apt-get update ; \
curl -L -O https://github.com/intel/linux-npu-driver/releases/download/v1.16.0/intel-driver-compiler-npu_1.16.0.20250328-14132024782_ubuntu24.04_amd64.deb ; \
curl -L -O https://github.com/intel/linux-npu-driver/releases/download/v1.16.0/intel-fw-npu_1.16.0.20250328-14132024782_ubuntu24.04_amd64.deb ; \
curl -L -O https://github.com/intel/linux-npu-driver/releases/download/v1.16.0/intel-level-zero-npu_1.16.0.20250328-14132024782_ubuntu24.04_amd64.deb ; \
curl -L -O https://github.com/oneapi-src/level-zero/releases/download/v1.20.2/level-zero_1.20.2+u24.04_amd64.deb ; \
fi ; \
curl -L -O https://github.com/oneapi-src/level-zero/releases/download/v1.20.2/level-zero_1.20.2+u24.04_amd64.deb ; \
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please don't edit Dockerfile.ubuntu in this pull request (this makes conflicts and is really not required)

fi ; \
dpkg -i ./*.deb && rm -Rf /tmp/npu_deps ; \
fi ; \
apt-get clean ; \
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added demos/python_demos/image_embeddings/demo_img.jpg
169 changes: 169 additions & 0 deletions demos/python_demos/image_embeddings/grpc_cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
import sys
sys.path.append("../../common/python")
import tritonclient.grpc as grpcclient
from tritonclient.grpc import service_pb2
from tritonclient.grpc import service_pb2_grpc

import numpy as np
import os
import grpc
import time
import json
from qdrant_client import QdrantClient
from qdrant_client.http import models as rest

# ------------------------ Settings ------------------------
IMAGE_FOLDER = "./demo_images"
QDRANT_COLLECTION = "image_embeddings"
MODEL_CONFIG_FILE = "./selected_model.json" # New: Save model choice


def setup_grpc_client():
"""Setup GRPC client and wait for server ready"""
url = "localhost:9000"
client = grpcclient.InferenceServerClient(url)
channel = grpc.insecure_channel(url)
grpc_stub = service_pb2_grpc.GRPCInferenceServiceStub(channel)

# Wait for server ready
timeout = 15
while timeout:
request = service_pb2.ServerReadyRequest()
response = grpc_stub.ServerReady(request)
print("Server Ready: {}".format(response.ready))
if response.ready:
break
time.sleep(1)
timeout -= 1

if not response.ready:
print("Models are not ready. Increase timeout or check server setup.")
exit(-1)

return client


def select_model():
"""Interactive model selection"""
available_models = ["clip_graph", "dino_graph", "laion_graph"]
print("\nSelect a model to use:")
for i, model in enumerate(available_models):
print(f"{i + 1}. {model}")

while True:
try:
choice = int(input("Enter the number corresponding to the model: "))
if 1 <= choice <= len(available_models):
selected_model = available_models[choice - 1]
break
else:
print("Invalid choice.")
except ValueError:
print("Invalid input.")

print(f"\nYou selected: {selected_model}")

# Save model selection
with open(MODEL_CONFIG_FILE, 'w') as f:
json.dump({"selected_model": selected_model}, f)
print(f"Saved model selection: {selected_model}")

return selected_model


def build_database(client, selected_model):
"""Build/Update the image database"""
qdrant = QdrantClient("localhost", port=6333)
vector_size = None
inference_times = [] # Track per-image inference times
total_start = time.perf_counter() # For total time

# Create collection if not exists
if not qdrant.collection_exists(QDRANT_COLLECTION):
print(f"Creating Qdrant collection: {QDRANT_COLLECTION}")

# Process all images in demo folder
image_files = [f for f in os.listdir(IMAGE_FOLDER) if f.lower().endswith((".jpg", ".jpeg", ".png"))]
print(f"\nFound {len(image_files)} images in '{IMAGE_FOLDER}'")

points = []

for idx, img_name in enumerate(image_files):
img_path = os.path.join(IMAGE_FOLDER, img_name)
with open(img_path, "rb") as f:
image_data = f.read()

image_np = np.array([image_data], dtype=np.object_)
image_input = grpcclient.InferInput("image", [1], "BYTES")
image_input.set_data_from_numpy(image_np)

# --- measure inference time ---
start_time = time.perf_counter()
results = client.infer(selected_model, [image_input])
end_time = time.perf_counter()
elapsed_ms = (end_time - start_time) * 1000
inference_times.append(elapsed_ms)
# --------------------------------

embedding = results.as_numpy('embedding')[0]

if vector_size is None:
vector_size = embedding.shape[0]
if not qdrant.collection_exists(QDRANT_COLLECTION):
qdrant.create_collection(
collection_name=QDRANT_COLLECTION,
vectors_config=rest.VectorParams(size=vector_size, distance=rest.Distance.COSINE)
)

points.append(
rest.PointStruct(
id=idx,
vector=embedding.tolist(),
payload={"filename": img_name}
)
)

# Upload to Qdrant
if points:
qdrant.upsert(
collection_name=QDRANT_COLLECTION,
points=points
)

total_end = time.perf_counter()
total_time = total_end - total_start
avg_time = sum(inference_times) / len(inference_times) if inference_times else 0
throughput = len(inference_times) / total_time if total_time > 0 else 0

print(f"\nInserted {len(points)} embeddings into Qdrant collection '{QDRANT_COLLECTION}'")
print(f"Avg Inference Time: {avg_time:.2f} ms")
print(f"Total Processing Time: {total_time:.2f} s")
print(f"Throughput: {throughput:.2f} images/sec")

return len(points)


def main():
print("Building Image Database")
print("=" * 50)

try:
# Setup
client = setup_grpc_client()
selected_model = select_model()

# Build database
count = build_database(client, selected_model)

print(f"\nDatabase built successfully!")
print(f"Total images processed: {count}")
print(f"Model saved for future searches: {selected_model}")

except Exception as e:
print(f"Error: {str(e)}")
import traceback
traceback.print_exc()


if __name__ == "__main__":
main()
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import openvino as ov
import os

model_id = "openai/clip-vit-base-patch32"
print(f"Downloading pretrained model {model_id}...")

full_model = CLIPModel.from_pretrained(model_id)
model = full_model.vision_model
processor = CLIPProcessor.from_pretrained(model_id)

image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]

print("Converting model...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "clip_image_encoder.xml")
print("Model saved!")

mod_path = "saved_mod/clip/1"
os.makedirs(mod_path, exist_ok=True)
os.replace("clip_image_encoder.xml", f"{mod_path}/clip_image_encoder.xml")
os.replace("clip_image_encoder.bin", f"{mod_path}/clip_image_encoder.bin")
print("Model ready for OVMS")
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
from transformers import AutoImageProcessor, AutoModel
from PIL import Image
import openvino as ov
import os

model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")

model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)

image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]

print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")

mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around assignment operators and after commas throughout the file. Should follow PEP 8 spacing conventions.

Suggested change
model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)
image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")
mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
model_id = "facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model = AutoModel.from_pretrained(model_id)
processor = AutoImageProcessor.from_pretrained(model_id)
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "dino_image_encoder.xml")
print("Model saved!")
mod_path = "saved_mod/dino/1"
os.makedirs(mod_path, exist_ok=True)

Copilot uses AI. Check for mistakes.

Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around assignment operators and after commas throughout the file. Should follow PEP 8 spacing conventions.

Suggested change
model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)
image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")
mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
model_id = "facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model = AutoModel.from_pretrained(model_id)
processor = AutoImageProcessor.from_pretrained(model_id)
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "dino_image_encoder.xml")
print("Model saved!")
mod_path = "saved_mod/dino/1"
os.makedirs(mod_path, exist_ok=True)

Copilot uses AI. Check for mistakes.

Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around assignment operators and after commas throughout the file. Should follow PEP 8 spacing conventions.

Suggested change
model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)
image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")
mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
model_id = "facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model = AutoModel.from_pretrained(model_id)
processor = AutoImageProcessor.from_pretrained(model_id)
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "dino_image_encoder.xml")
print("Model saved!")
mod_path = "saved_mod/dino/1"
os.makedirs(mod_path, exist_ok=True)

Copilot uses AI. Check for mistakes.

Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around assignment operators and after commas throughout the file. Should follow PEP 8 spacing conventions.

Suggested change
model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)
image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")
mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
model_id = "facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model = AutoModel.from_pretrained(model_id)
processor = AutoImageProcessor.from_pretrained(model_id)
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "dino_image_encoder.xml")
print("Model saved!")
mod_path = "saved_mod/dino/1"
os.makedirs(mod_path, exist_ok=True)

Copilot uses AI. Check for mistakes.

Copy link
Preview

Copilot AI Aug 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing spaces around assignment operators and after commas throughout the file. Should follow PEP 8 spacing conventions.

Suggested change
model_id="facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model=AutoModel.from_pretrained(model_id)
processor=AutoImageProcessor.from_pretrained(model_id)
image=Image.new("RGB",(224,224))
inputs=processor(images=image,return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model=ov.convert_model(model,example_input=inputs)
ov.save_model(ov_model,"dino_image_encoder.xml")
print("Model saved!")
mod_path="saved_mod/dino/1"
os.makedirs(mod_path,exist_ok=True)
model_id = "facebook/dinov2-base"
print(f"Downloading pretrained model {model_id}...")
model = AutoModel.from_pretrained(model_id)
processor = AutoImageProcessor.from_pretrained(model_id)
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]
print("Converting models...")
ov_model = ov.convert_model(model, example_input=inputs)
ov.save_model(ov_model, "dino_image_encoder.xml")
print("Model saved!")
mod_path = "saved_mod/dino/1"
os.makedirs(mod_path, exist_ok=True)

Copilot uses AI. Check for mistakes.

os.replace("dino_image_encoder.xml", f"{mod_path}/dino_image_encoder.xml")
os.replace("dino_image_encoder.bin", f"{mod_path}/dino_image_encoder.bin")
print("Model ready for OVMS")



Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
from transformers import CLIPProcessor, CLIPModel
from PIL import Image
import openvino as ov
import torch
import os

# Replace this with your LAION model
model_id = "laion/CLIP-ViT-B-32-laion2B-s34B-b79K"
print(f"Downloading pretrained model: {model_id}")

# Load processor and model
processor = CLIPProcessor.from_pretrained(model_id)
full_model = CLIPModel.from_pretrained(model_id)
image_encoder = full_model.vision_model
image_encoder.eval()

# Dummy image input for tracing
image = Image.new("RGB", (224, 224))
inputs = processor(images=image, return_tensors="pt")["pixel_values"]

# Convert to OpenVINO IR
print("Converting image encoder to OpenVINO IR...")
ov_model = ov.convert_model(image_encoder, example_input=inputs)
ov.save_model(ov_model, "clip_image_encoder.xml")
print("Model saved!")

# Move to proper OVMS path
mod_path = "saved_mod/laion/1"
os.makedirs(mod_path, exist_ok=True)
os.replace("clip_image_encoder.xml", f"{mod_path}/clip_image_encoder.xml")
os.replace("clip_image_encoder.bin", f"{mod_path}/clip_image_encoder.bin")
print(f"Model ready at {mod_path} for OpenVINO Model Server")
10 changes: 10 additions & 0 deletions demos/python_demos/image_embeddings/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tritonclient[all]==2.51.0
numpy<2.0.0
--extra-index-url "https://download.pytorch.org/whl/cpu"
--extra-index-url "https://storage.openvinotoolkit.org/simple/wheels/nightly"
--pre
openvino==2025.2.*
numpy<2.0
transformers<4.52
pillow==10.3.0
torch==2.7.0+cpu
Loading