sdk/python/foundation-models/system/inference/image-embeddings/image-embeddings-online-endpoint.ipynb (330 lines of code) (raw):
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Image Embeddings Inference using Online Endpoints\n",
"\n",
"This sample notebook shows how to deploy `embeddings` type models to an online endpoint for image embeddings inference.\n",
"\n",
"### Task\n",
"The input to the `embeddings` task is images, text or image-text pairs, and the output is feature embeddings produced by the model. In this notebook, we are only concerned with image inputs.\n",
" \n",
"### Model\n",
"Models that can perform the `embeddings` task are tagged with `embeddings` in the catalog. We will use the `Facebook-DinoV2-Image-Embeddings-ViT-Base` model in this notebook. If you opened this notebook from a specific model card, remember to replace the specific model name. If you don't find a model that suits your scenario or domain, you can discover and [import models from HuggingFace hub](../../import/import_model_into_registry.ipynb) and then use them for inference. \n",
"\n",
"### Inference data\n",
"We will use the [fridgeObjects](https://automlsamplenotebookdata-adcuc7f7bqhhh8a4.b02.azurefd.net/image-classification/fridgeObjects.zip) dataset.\n",
"\n",
"\n",
"### Outline\n",
"1. Setup pre-requisites\n",
"2. Pick a model to deploy\n",
"3. Prepare data for inference\n",
"4. Deploy the model to an online endpoint\n",
"5. Test the endpoint\n",
"6. Clean up resources - delete the endpoint"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 1. Setup pre-requisites\n",
"* Install dependencies\n",
"* Connect to AzureML Workspace. Learn more at [set up SDK authentication](https://learn.microsoft.com/en-us/azure/machine-learning/how-to-setup-authentication?tabs=sdk). Replace `<WORKSPACE_NAME>`, `<RESOURCE_GROUP>` and `<SUBSCRIPTION_ID>` below.\n",
"* Connect to `azureml` system registry"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azure.ai.ml import MLClient\n",
"from azure.identity import (\n",
" DefaultAzureCredential,\n",
" InteractiveBrowserCredential,\n",
" ClientSecretCredential,\n",
")\n",
"from azure.ai.ml.entities import AmlCompute\n",
"import time\n",
"\n",
"try:\n",
" credential = DefaultAzureCredential()\n",
" credential.get_token(\"https://management.azure.com/.default\")\n",
"except Exception as ex:\n",
" credential = InteractiveBrowserCredential()\n",
"\n",
"try:\n",
" workspace_ml_client = MLClient.from_config(credential)\n",
" subscription_id = workspace_ml_client.subscription_id\n",
" resource_group = workspace_ml_client.resource_group_name\n",
" workspace_name = workspace_ml_client.workspace_name\n",
"except Exception as ex:\n",
" print(ex)\n",
" # Enter details of your AML workspace\n",
" subscription_id = \"<SUBSCRIPTION_ID>\"\n",
" resource_group = \"<RESOURCE_GROUP>\"\n",
" workspace_name = \"<AML_WORKSPACE_NAME>\"\n",
"\n",
"workspace_ml_client = MLClient(\n",
" credential, subscription_id, resource_group, workspace_name\n",
")\n",
"\n",
"# The models are available in the AzureML system registry, \"azureml\"\n",
"registry_ml_client = MLClient(\n",
" credential,\n",
" subscription_id,\n",
" resource_group,\n",
" registry_name=\"azureml\",\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 2. Pick a model to deploy\n",
"\n",
"Browse models in the Model Catalog in the AzureML Studio, filtering by the `embeddings` task. In this example, we use the `Facebook-DinoV2-Image-Embeddings-ViT-Base` model. If you have opened this notebook for a different model, replace the model name accordingly."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"model_name = \"Facebook-DinoV2-Image-Embeddings-ViT-Base\"\n",
"foundation_model = registry_ml_client.models.get(name=model_name, label=\"latest\")\n",
"print(\n",
" f\"\\n\\nUsing model name: {foundation_model.name}, version: {foundation_model.version}, id: {foundation_model.id} for inferencing\"\n",
")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 3. Prepare data for inference\n",
"\n",
"We will use the [fridgeObjects](https://automlsamplenotebookdata-adcuc7f7bqhhh8a4.b02.azurefd.net/image-classification/fridgeObjects.zip) dataset for multi-class classification task. The fridge object dataset is stored in a directory. There are four different folders inside:\n",
"- /water_bottle\n",
"- /milk_bottle\n",
"- /carton\n",
"- /can\n",
"\n",
"This is the most common data format for multiclass image classification. Each folder title corresponds to the image label for the images contained inside. "
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import os\n",
"import urllib\n",
"from zipfile import ZipFile\n",
"\n",
"# Change to a different location if you prefer\n",
"dataset_parent_dir = \"./data\"\n",
"\n",
"# Create data folder if it doesnt exist.\n",
"os.makedirs(dataset_parent_dir, exist_ok=True)\n",
"\n",
"# Download data\n",
"download_url = \"https://automlsamplenotebookdata-adcuc7f7bqhhh8a4.b02.azurefd.net/image-classification/fridgeObjects.zip\"\n",
"\n",
"# Extract current dataset name from dataset url\n",
"dataset_name = os.path.split(download_url)[-1].split(\".\")[0]\n",
"# Get dataset path for later use\n",
"dataset_dir = os.path.join(dataset_parent_dir, dataset_name)\n",
"\n",
"# Get the data zip file path\n",
"data_file = os.path.join(dataset_parent_dir, f\"{dataset_name}.zip\")\n",
"\n",
"# Download the dataset\n",
"urllib.request.urlretrieve(download_url, filename=data_file)\n",
"\n",
"# Extract files\n",
"with ZipFile(data_file, \"r\") as zip:\n",
" print(\"extracting files...\")\n",
" zip.extractall(path=dataset_parent_dir)\n",
" print(\"done\")\n",
"# Delete zip file\n",
"os.remove(data_file)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from IPython.display import Image\n",
"\n",
"sample_image = os.path.join(dataset_dir, \"milk_bottle\", \"99.jpg\")\n",
"Image(filename=sample_image)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 4. Deploy the model to an online endpoint for real time inference\n",
"Online endpoints give a durable REST API that can be used to integrate with applications that need to use the model."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import time, sys\n",
"from azure.ai.ml.entities import (\n",
" ManagedOnlineEndpoint,\n",
" ManagedOnlineDeployment,\n",
")\n",
"\n",
"# Endpoint names need to be unique in a region, hence using timestamp to create unique endpoint name\n",
"timestamp = int(time.time())\n",
"online_endpoint_name = \"dinov2-embeddings-\" + str(timestamp)\n",
"# Create an online endpoint\n",
"endpoint = ManagedOnlineEndpoint(\n",
" name=online_endpoint_name,\n",
" description=\"Online endpoint for \"\n",
" + foundation_model.name\n",
" + \", for image-embeddings task\",\n",
" auth_mode=\"key\",\n",
")\n",
"workspace_ml_client.begin_create_or_update(endpoint).wait()"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from azure.ai.ml.entities import OnlineRequestSettings, ProbeSettings\n",
"\n",
"deployment_name = \"embeddings-mlflow-deploy\"\n",
"\n",
"# Create a deployment\n",
"demo_deployment = ManagedOnlineDeployment(\n",
" name=deployment_name,\n",
" endpoint_name=online_endpoint_name,\n",
" model=foundation_model.id,\n",
" instance_type=\"Standard_DS3_V2\", # Use GPU instance type like Standard_NC6s_v3 for faster inference\n",
" instance_count=1,\n",
" request_settings=OnlineRequestSettings(\n",
" max_concurrent_requests_per_instance=1,\n",
" request_timeout_ms=90000,\n",
" max_queue_wait_ms=500,\n",
" ),\n",
" liveness_probe=ProbeSettings(\n",
" failure_threshold=49,\n",
" success_threshold=1,\n",
" timeout=299,\n",
" period=180,\n",
" initial_delay=180,\n",
" ),\n",
" readiness_probe=ProbeSettings(\n",
" failure_threshold=10,\n",
" success_threshold=1,\n",
" timeout=10,\n",
" period=10,\n",
" initial_delay=10,\n",
" ),\n",
")\n",
"workspace_ml_client.online_deployments.begin_create_or_update(demo_deployment).wait()\n",
"endpoint.traffic = {deployment_name: 100}\n",
"workspace_ml_client.begin_create_or_update(endpoint).result()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 5. Test the endpoint\n",
"\n",
"We will submit some images from the dataset to the online endpoint for inference."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"import base64\n",
"import json\n",
"\n",
"sample_image_1 = os.path.join(dataset_dir, \"milk_bottle\", \"99.jpg\")\n",
"sample_image_2 = os.path.join(dataset_dir, \"can\", \"1.jpg\")\n",
"\n",
"\n",
"def read_image(image_path):\n",
" with open(image_path, \"rb\") as f:\n",
" return f.read()\n",
"\n",
"\n",
"request_json = {\n",
" \"input_data\": {\n",
" \"columns\": [\"image\"],\n",
" \"index\": [0, 1],\n",
" \"data\": [\n",
" [base64.encodebytes(read_image(sample_image_1)).decode(\"utf-8\")],\n",
" [base64.encodebytes(read_image(sample_image_2)).decode(\"utf-8\")],\n",
" ],\n",
" }\n",
"}\n",
"\n",
"# Create request json\n",
"request_file_name = \"sample_request_data.json\"\n",
"with open(request_file_name, \"w\") as request_file:\n",
" json.dump(request_json, request_file)"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Score the sample_score.json file using the online endpoint with the azureml endpoint invoke method\n",
"response = workspace_ml_client.online_endpoints.invoke(\n",
" endpoint_name=online_endpoint_name,\n",
" deployment_name=demo_deployment.name,\n",
" request_file=request_file_name,\n",
")\n",
"print(f\"raw response: {response}\\n\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### 6. Clean up resources - delete the online endpoint\n",
"Do not forget to delete the online endpoint. You will be billed for the compute used by the endpoint if it is not deleted."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"workspace_ml_client.online_endpoints.begin_delete(name=online_endpoint_name).wait()"
]
}
],
"metadata": {},
"nbformat": 4,
"nbformat_minor": 2
}