-
Notifications
You must be signed in to change notification settings - Fork 1.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'main' into add-appinsights-logging
- Loading branch information
Showing
10 changed files
with
2,881 additions
and
2 deletions.
There are no files selected for viewing
2 changes: 1 addition & 1 deletion
2
cli/foundation-models/system/inference/text-to-image/batch-deploy.yml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
113 changes: 113 additions & 0 deletions
113
cli/foundation-models/system/inference/text-to-image/image-text-to-image-batch-endpoint.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
set -x | ||
# the commands in this file map to steps in this notebook: https://aka.ms/azureml-infer-batch-sdk-text-classification | ||
|
||
# script inputs | ||
registry_name="azureml" | ||
|
||
subscription_id="<SUBSCRIPTION_ID>" | ||
resource_group_name="<RESOURCE_GROUP>" | ||
workspace_name="<WORKSPACE_NAME>" | ||
|
||
# This is the model from system registry that needs to be deployed | ||
model_name="stabilityai-stable-diffusion-xl-refiner-1-0" | ||
model_label="latest" | ||
|
||
version=$(date +%s) | ||
endpoint_name="image-text-to-image-$version" | ||
deployment_name="image-text-to-image-batch-deploy" | ||
|
||
deployment_compute="gpu-cluster" | ||
compute_sku="Standard_NC6s_v3" | ||
|
||
# 1. Setup pre-requisites | ||
if [ "$subscription_id" = "<SUBSCRIPTION_ID>" ] || \ | ||
["$resource_group_name" = "<RESOURCE_GROUP>" ] || \ | ||
[ "$workspace_name" = "<WORKSPACE_NAME>" ]; then | ||
echo "Please update the script with the subscription_id, resource_group_name and workspace_name" | ||
exit 1 | ||
fi | ||
|
||
az account set -s $subscription_id | ||
workspace_info="--resource-group $resource_group_name --workspace-name $workspace_name" | ||
|
||
# 2. Check if the model exists in the registry | ||
# Need to confirm model show command works for registries outside the tenant (aka system registry) | ||
if ! az ml model show --name $model_name --label $model_label --registry-name $registry_name | ||
then | ||
echo "Model $model_name:$model_label does not exist in registry $registry_name" | ||
exit 1 | ||
fi | ||
|
||
model_version=$(az ml model show --name $model_name --label $model_label --registry-name $registry_name --query version --output tsv) | ||
|
||
# 3. Check if compute $deployment_compute exists, else create it | ||
if az ml compute show --name $deployment_compute $workspace_info | ||
then | ||
echo "Compute cluster $deployment_compute already exists" | ||
else | ||
echo "Creating compute cluster $deployment_compute" | ||
az ml compute create --name $deployment_compute --type amlcompute --min-instances 0 --max-instances 2 --size $compute_sku $workspace_info || { | ||
echo "Failed to create compute cluster $deployment_compute" | ||
exit 1 | ||
} | ||
fi | ||
|
||
# 4. Deploy the model to an endpoint | ||
# create batch endpoint | ||
az ml batch-endpoint create --name $endpoint_name $workspace_info || { | ||
echo "endpoint create failed"; exit 1; | ||
} | ||
|
||
# deploy model from registry to endpoint in workspace | ||
az ml batch-deployment create --file batch-deploy.yml $workspace_info --set \ | ||
endpoint_name=$endpoint_name \ | ||
name=$deployment_name \ | ||
compute=$deployment_compute \ | ||
model=azureml://registries/$registry_name/models/$model_name/versions/$model_version || { | ||
echo "deployment create failed"; exit 1; | ||
} | ||
|
||
# 4. Submit a sample request to endpoint | ||
data_path="./inpainting_data/batch_data" | ||
python utils/prepare_data_image_text_to_image.py --payload-path $data_path --mode "batch" | ||
# Path where the processes csvs are dumped. This is the input to the endpoint | ||
processed_data_path="./inpainting_data/batch_data/processed_batch_data" | ||
|
||
# Check if scoring folder exists | ||
if [ -d $processed_data_path ]; then | ||
echo "Invoking endpoint $endpoint_name with following input:\n\n" | ||
ls $processed_data_path | ||
echo "\n\n" | ||
else | ||
echo "Scoring folder $processed_data_path does not exist" | ||
exit 1 | ||
fi | ||
|
||
# 5. Invoke a job on the batch endpoint | ||
job_name=$(az ml batch-endpoint invoke --name $endpoint_name \ | ||
--deployment-name $deployment_name \ | ||
--input $processed_data_path \ | ||
--input-type uri_folder --query name --output tsv $workspace_info) || { | ||
echo "endpoint invoke failed"; exit 1; | ||
} | ||
|
||
# 6. Stream the job logs | ||
az ml job stream --name $job_name $workspace_info || { | ||
echo "job stream-logs failed. If the job failed with Assertion Error stating actual size of csv exceeds 100 MB, then try splitting input csv file into multiple csv files."; exit 1; | ||
} | ||
|
||
# 7. Download the job output | ||
az ml job download --name $job_name --download-path "generated_images" $workspace_info || { | ||
echo "job output download failed"; exit 1; | ||
} | ||
|
||
# 8. Delete the endpoint | ||
az ml batch-endpoint delete --name $endpoint_name $workspace_info --yes || { | ||
echo "endpoint delete failed"; exit 1; | ||
} | ||
|
||
# 9. Delete the compute cluster (Uncomment the below lines to delete the created cluster) | ||
# az ml compute delete --name $deployment_compute $workspace_info --yes || { | ||
# echo "compute delete failed"; exit 1; | ||
# } | ||
|
83 changes: 83 additions & 0 deletions
83
cli/foundation-models/system/inference/text-to-image/image-text-to-image-online-endpoint.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,83 @@ | ||
set -x | ||
# the commands in this file map to steps in this notebook: https://aka.ms/azureml-infer-batch-sdk-text-classification | ||
|
||
# script inputs | ||
registry_name="azureml" | ||
|
||
subscription_id="<SUBSCRIPTION_ID>" | ||
resource_group_name="<RESOURCE_GROUP>" | ||
workspace_name="<WORKSPACE_NAME>" | ||
|
||
# This is the model from system registry that needs to be deployed | ||
model_name="stabilityai-stable-diffusion-xl-refiner-1-0" | ||
model_label="latest" | ||
response_file="generated_image.json" | ||
|
||
version=$(date +%s) | ||
endpoint_name="image-text-to-image-$version" | ||
deployment_name="image-text-to-image-deploy" | ||
|
||
deployment_sku="Standard_NC6s_v3" | ||
|
||
# sample_request_data | ||
sample_request_data="inpainting_data/sample_request_data.json" | ||
|
||
# 1. Setup pre-requisites | ||
if [ "$subscription_id" = "<SUBSCRIPTION_ID>" ] || \ | ||
["$resource_group_name" = "<RESOURCE_GROUP>" ] || \ | ||
[ "$workspace_name" = "<WORKSPACE_NAME>" ]; then | ||
echo "Please update the script with the subscription_id, resource_group_name and workspace_name" | ||
exit 1 | ||
fi | ||
|
||
az account set -s $subscription_id | ||
workspace_info="--resource-group $resource_group_name --workspace-name $workspace_name" | ||
|
||
# 2. Check if the model exists in the registry | ||
|
||
if ! az ml model show --name $model_name --label $model_label --registry-name $registry_name | ||
then | ||
echo "Model $model_name:$model_label does not exist in registry $registry_name" | ||
exit 1 | ||
fi | ||
|
||
# Get the latest model version | ||
model_version=$(az ml model show --name $model_name --label $model_label --registry-name $registry_name --query version --output tsv) | ||
|
||
# 3. Deploy the model to an endpoint | ||
# Create online endpoint | ||
az ml online-endpoint create --name $endpoint_name $workspace_info || { | ||
echo "endpoint create failed"; exit 1; | ||
} | ||
|
||
# Deploy model from registry to endpoint in workspace | ||
az ml online-deployment create --file deploy-online.yaml $workspace_info --all-traffic --set \ | ||
endpoint_name=$endpoint_name model=azureml://registries/$registry_name/models/$model_name/versions/$model_version \ | ||
name=$deployment_name \ | ||
instance_type=$deployment_sku || { | ||
echo "deployment create failed"; exit 1; | ||
} | ||
|
||
# 4. Submit a sample request to endpoint | ||
python utils/prepare_data_image_text_to_image.py --payload-path $sample_request_data --mode "online" | ||
|
||
# Check if scoring data file exists | ||
if [ -f $sample_request_data ]; then | ||
echo "Invoking endpoint $endpoint_name with $sample_request_data:\n\n" | ||
echo "\n\n" | ||
else | ||
echo "Request file $sample_request_data does not exist" | ||
exit 1 | ||
fi | ||
|
||
az ml online-endpoint invoke --name $endpoint_name --request-file $sample_request_data $workspace_info -o json > $response_file || { | ||
echo "endpoint invoke failed"; exit 1; | ||
} | ||
|
||
# 5. Convert bas64 form of image to jpeg | ||
python ./utils/base64_to_jpeg.py --response_file $response_file | ||
|
||
# 6. Delete the endpoint and sample_request_data.json | ||
az ml online-endpoint delete --name $endpoint_name $workspace_info --yes || { | ||
echo "endpoint delete failed"; exit 1; | ||
} |
151 changes: 151 additions & 0 deletions
151
...oundation-models/system/inference/text-to-image/utils/prepare_data_image_text_to_image.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,151 @@ | ||
# Copyright (c) Microsoft Corporation. | ||
# Licensed under the MIT License. | ||
|
||
# Prepare request payload for the image-text to image task | ||
|
||
import argparse | ||
import glob | ||
import json | ||
import io | ||
import base64 | ||
import os | ||
import pandas as pd | ||
from PIL import Image | ||
from pathlib import Path | ||
|
||
|
||
def read_image(image_path: str) -> bytes: | ||
"""Reads an image from a file path into a byte array. | ||
:param image_path: Path to image file. | ||
:type image_path: str | ||
:return: Byte array of image. | ||
:rtype: bytes | ||
""" | ||
with open(image_path, "rb") as f: | ||
return f.read() | ||
|
||
|
||
def prepare_batch_payload(payload_path: str) -> None: | ||
"""Prepare payload for online deployment. | ||
:param payload_path: Path to payload csv file. | ||
:type payload_path: str | ||
:return: None | ||
""" | ||
|
||
base_image1 = "inpainting_data/images/dog_on_bench.png" | ||
base_image2 = "inpainting_data/images/teapot.png" | ||
|
||
os.makedirs(payload_path, exist_ok=True) | ||
|
||
input_data = { | ||
"columns": ["image", "prompt"], | ||
"data": [ | ||
{ | ||
"image": base64.encodebytes(read_image(base_image1)).decode("utf-8"), | ||
"prompt": "A yellow cat, high resolution, sitting on a park bench", | ||
}, | ||
{ | ||
"image": base64.encodebytes(read_image(base_image2)).decode("utf-8"), | ||
"prompt": "A small flower featuring a blend of pink and purple colors.", | ||
}, | ||
], | ||
} | ||
pd.DataFrame(**input_data).to_csv( | ||
os.path.join(payload_path, "input1.csv"), index=False | ||
) | ||
|
||
input_data = { | ||
"columns": ["image", "prompt"], | ||
"data": [ | ||
{ | ||
"image": base64.encodebytes(read_image(base_image1)).decode("utf-8"), | ||
"prompt": "Pikachu, cinematic, digital art, sitting on bench", | ||
}, | ||
{ | ||
"image": base64.encodebytes(read_image(base_image2)).decode("utf-8"), | ||
"prompt": "A woman with red hair in the style of Tamara de Lempicka.", | ||
}, | ||
], | ||
} | ||
pd.DataFrame(**input_data).to_csv( | ||
os.path.join(payload_path, "input2.csv"), index=False | ||
) | ||
|
||
# Use glob to get a list of CSV files in the folder | ||
csv_files = glob.glob(os.path.join(payload_path, "*.csv")) | ||
|
||
# Read all CSV files into a single DataFrame using pd.concat | ||
batch_df = pd.concat((pd.read_csv(file) for file in csv_files), ignore_index=True) | ||
|
||
# Specify the folder where your CSV files should be saved | ||
processed_dataset_parent_dir = os.path.join(payload_path, "processed_batch_data") | ||
os.makedirs(processed_dataset_parent_dir, exist_ok=True) | ||
batch_input_file = "batch_input.csv" | ||
|
||
# Divide this into files of <x> rows each | ||
batch_size_per_predict = 2 | ||
for i in range(0, len(batch_df), batch_size_per_predict): | ||
j = i + batch_size_per_predict | ||
batch_df[i:j].to_csv( | ||
os.path.join(processed_dataset_parent_dir, str(i) + batch_input_file) | ||
) | ||
|
||
# Check out the first and last file name created | ||
input_paths = sorted( | ||
Path(processed_dataset_parent_dir).iterdir(), key=os.path.getmtime | ||
) | ||
input_files = [os.path.basename(path) for path in input_paths] | ||
print(f"{input_files[0]} to {str(i)}{batch_input_file}.") | ||
|
||
|
||
def prepare_online_payload(payload_path: str) -> None: | ||
"""Prepare payload for online deployment. | ||
:param payload_path: Path to payload json file. | ||
:type payload_path: str | ||
:return: None | ||
""" | ||
base_directory = os.path.dirname(os.path.dirname(__file__)) | ||
|
||
base_image = os.path.join( | ||
base_directory, "inpainting_data", "images", "dog_on_bench.png" | ||
) | ||
|
||
request_json = { | ||
"input_data": { | ||
"columns": ["image", "prompt"], | ||
"index": [0], | ||
"data": [ | ||
{ | ||
"image": base64.encodebytes(read_image(base_image)).decode("utf-8"), | ||
"prompt": "A yellow cat, high resolution, sitting on a park bench", | ||
} | ||
], | ||
} | ||
} | ||
print(base_directory) | ||
print(payload_path) | ||
payload_path = os.path.join(base_directory, payload_path) | ||
with open(payload_path, "w") as request_file: | ||
json.dump(request_json, request_file) | ||
|
||
|
||
if __name__ == "__main__": | ||
parser = argparse.ArgumentParser( | ||
description="Prepare sample data for image-text to image" | ||
) | ||
parser.add_argument("--payload-path", type=str, help="payload file/ folder path") | ||
parser.add_argument( | ||
"--mode", | ||
type=str, | ||
default="online", | ||
help="Generate payload for online or batch deployment.", | ||
) | ||
args, unknown = parser.parse_known_args() | ||
|
||
if args.mode == "online": | ||
prepare_online_payload(args.payload_path) | ||
else: | ||
prepare_batch_payload(args.payload_path) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.