Step 03: mobilenet and resnet50 Shadow Deploy
This tutorial and the assets can be downloaded as part of the Wallaroo Tutorials repository.
Step 03: Detecting Objects Using Shadow Deploy
The following tutorial demonstrates how to use two trained models, one based on the resnet50, the other on mobilenet, deployed in Wallaroo to detect objects. This builds on the previous tutorials in this series, Step 01: Detecting Objects Using mobilenet" and “Step 02: Detecting Objects Using resnet50”.
For this tutorial, the Wallaroo feature Shadow Deploy will be used to submit inference requests to both models at once. The mobilnet object detector is the control and the faster-rcnn object detector is the challenger. The results between the two will be compared for their confidence, and that confidence will be used to draw bounding boxes around identified objects.
This process will use the following steps:
- Create a Wallaroo workspace and pipeline.
- Upload a trained resnet50 ML model and trained mobilenet model and add them as a shadow deployed step with the mobilenet as the control model.
- Deploy the pipeline.
- Perform an inference on a sample image.
- Based on the
- Draw the detected objects, their bounding boxes, their classifications, and the confidence of the classifications on the provided image.
- Review our results.
Steps
Import Libraries
The first step will be to import our libraries. Please check with Step 00: Introduction and Setup and verify that the necessary libraries and applications are added to your environment.
# preload needed libraries
import wallaroo
from wallaroo.object import EntityNotFoundError
from wallaroo.framework import Framework
from IPython.display import display
from IPython.display import Image
import pandas as pd
import json
import datetime
import time
import cv2
import matplotlib.pyplot as plt
import string
import random
import pyarrow as pa
import sys
import asyncio
pd.set_option('display.max_colwidth', None)
import sys
import utils
Connect to the Wallaroo Instance
The first step is to connect to Wallaroo through the Wallaroo client. The Python library is included in the Wallaroo install and available through the Jupyter Hub interface provided with your Wallaroo environment.
This is accomplished using the wallaroo.Client()
command, which provides a URL to grant the SDK permission to your specific Wallaroo environment. When displayed, enter the URL into a browser and confirm permissions. Store the connection into a variable that can be referenced later.
If logging into the Wallaroo instance through the internal JupyterHub service, use wl = wallaroo.Client()
. For more information on Wallaroo Client settings, see the Client Connection guide.
# Login through local service
wl = wallaroo.Client()
Set Variables
The following variables and methods are used later to create or connect to an existing workspace, pipeline, and model. This example has both the resnet model, and a post process script.
workspace_name = f'shadowimageworkspacetest'
pipeline_name = f'shadowimagepipelinetest'
control_model_name = f'mobilenet'
control_model_file_name = 'models/mobilenet.pt.onnx'
challenger_model_name = f'resnet50'
challenger_model_file_name = 'models/frcnn-resnet.pt.onnx'
Create Workspace
The workspace will be created or connected to, and set as the default workspace for this session. Once that is done, then all models and pipelines will be set in that workspace.
workspace = wl.get_workspace(name=workspace_name, create_if_not_exist=True)
wl.set_current_workspace(workspace)
wl.get_current_workspace()
{'name': 'shadowimageworkspacetest', 'id': 18, 'archived': False, 'created_by': '36e83b1d-b405-4d30-abc5-e7000163d930', 'created_at': '2024-04-09T21:56:49.731511+00:00', 'models': [{'name': 'mobilenet', 'versions': 4, 'owner_id': '""', 'last_update_time': datetime.datetime(2024, 4, 9, 22, 20, 30, 439305, tzinfo=tzutc()), 'created_at': datetime.datetime(2024, 4, 9, 21, 56, 58, 195369, tzinfo=tzutc())}, {'name': 'resnet50', 'versions': 4, 'owner_id': '""', 'last_update_time': datetime.datetime(2024, 4, 9, 22, 20, 53, 229478, tzinfo=tzutc()), 'created_at': datetime.datetime(2024, 4, 9, 21, 57, 24, 417535, tzinfo=tzutc())}, {'name': 'cv-post-process-drift-detection', 'versions': 4, 'owner_id': '""', 'last_update_time': datetime.datetime(2024, 4, 9, 22, 20, 54, 311560, tzinfo=tzutc()), 'created_at': datetime.datetime(2024, 4, 9, 21, 57, 25, 531197, tzinfo=tzutc())}], 'pipelines': [{'name': 'shadowimagepipelinetest', 'create_time': datetime.datetime(2024, 4, 9, 21, 56, 51, 111211, tzinfo=tzutc()), 'definition': '[]'}]}
Create Pipeline and Upload Model
We will now create or connect to an existing pipeline as named in the variables above, then upload each of the models.
pipeline = wl.build_pipeline(pipeline_name)
control = wl.upload_model(control_model_name, control_model_file_name,
framework=Framework.ONNX).configure(batch_config="single",
tensor_fields=["tensor"])
challenger = wl.upload_model(challenger_model_name, challenger_model_file_name,
framework=Framework.ONNX).configure(batch_config="single",
tensor_fields=["tensor"])
input_schema = pa.schema([
pa.field('boxes', pa.list_(pa.list_(pa.float32(), list_size=4))),
pa.field('classes', pa.list_(pa.int64())),
pa.field('confidences', pa.list_(pa.float32()))
]
)
output_schema = pa.schema([
pa.field('boxes', pa.list_(pa.list_(pa.float32(), list_size=4))),
pa.field('classes', pa.list_(pa.int64())),
pa.field('confidences', pa.list_(pa.float32())),
pa.field('avg_confidence', pa.list_(pa.float32())),
])
module_post_process_model = wl.upload_model("cv-post-process-drift-detection",
"./models/post-process-drift-detection.zip",
framework=Framework.PYTHON,
input_schema=input_schema,
output_schema=output_schema
)
Login successful!
successful
Ready
Shadow Deploy Pipeline
For this step, rather than deploying each model into a separate step, both will be deployed into a single step as a Shadow Deploy step. This will take the inference input data and process it through both pipelines at the same time. The inference results for the control will be stored in it’s ['outputs']
array, while the results for the challenger are stored the ['shadow_data']
array.
pipeline.clear()
pipeline.add_shadow_deploy(control, [challenger])
pipeline.add_model_step(module_post_process_model)
name | shadowimagepipelinetest |
---|---|
created | 2024-04-09 21:56:51.111211+00:00 |
last_updated | 2024-04-11 18:53:06.019919+00:00 |
deployed | False |
arch | x86 |
accel | none |
tags | |
versions | d9dfeded-9ed9-4230-b361-5b313179e659, 4e400bd1-99f6-43de-9395-58d8d4a43e16, 5438b690-fc57-4d21-bb43-edb77ab8d7a5, 449e9181-1cb2-4110-8a84-fa28c2210892, 70219393-5263-47d1-9593-706d7fa116cb, 8f22d6ad-8376-4849-9594-12c6a9b4d485, 03203e94-a9c8-437c-8fad-018fda8b31b2, dbe8a951-387c-43c0-88c9-63614186f530, 13604852-7fb6-4bda-9b0f-59b03464999f, e2e50bd4-ac47-4f7e-bc76-7cec9e3daa19, d848f83f-7aad-4e40-8b0d-6ae3ef7ac188, bda86e5c-89fd-4589-a6ea-0202d8a76052, 52709f9e-60a5-4661-900a-853e53c2989d, 8f643926-bed6-41b0-9d7b-6478295a8904, 85f24de8-f920-405d-835d-11eab3e38f92, 62c8264a-5f45-469a-9988-d50eededbbd8, 44cdbd86-c23d-4711-a509-56685e19dd19 |
steps | mobilenet |
published | False |
pipeline.undeploy()
deploy_config = wallaroo.DeploymentConfigBuilder().replica_count(1).cpus(2).memory("2Gi").build()
pipeline.deploy(deployment_config=deploy_config)
name | shadowimagepipelinetest |
---|---|
created | 2024-04-09 21:56:51.111211+00:00 |
last_updated | 2024-04-11 18:54:50.427295+00:00 |
deployed | True |
arch | x86 |
accel | none |
tags | |
versions | fa3fef3c-535a-4b8f-aaf5-6b96177b5a00, d9dfeded-9ed9-4230-b361-5b313179e659, 4e400bd1-99f6-43de-9395-58d8d4a43e16, 5438b690-fc57-4d21-bb43-edb77ab8d7a5, 449e9181-1cb2-4110-8a84-fa28c2210892, 70219393-5263-47d1-9593-706d7fa116cb, 8f22d6ad-8376-4849-9594-12c6a9b4d485, 03203e94-a9c8-437c-8fad-018fda8b31b2, dbe8a951-387c-43c0-88c9-63614186f530, 13604852-7fb6-4bda-9b0f-59b03464999f, e2e50bd4-ac47-4f7e-bc76-7cec9e3daa19, d848f83f-7aad-4e40-8b0d-6ae3ef7ac188, bda86e5c-89fd-4589-a6ea-0202d8a76052, 52709f9e-60a5-4661-900a-853e53c2989d, 8f643926-bed6-41b0-9d7b-6478295a8904, 85f24de8-f920-405d-835d-11eab3e38f92, 62c8264a-5f45-469a-9988-d50eededbbd8, 44cdbd86-c23d-4711-a509-56685e19dd19 |
steps | cv-post-process-drift-detection |
published | False |
Prepare input image
Next we will load a sample image and resize it to the width and height required for the object detector.
We will convert the image to a numpy ndim array and add it do a dictionary
image = cv2.imread('./data/images/input/example/dairy_bottles.png')
image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
plt.figure(figsize=(12,8))
plt.grid(False)
plt.imshow(image)
plt.show()
width, height = 640, 480
dfImage, resizedImage = utils.loadImageAndConvertToDataframe('./data/images/input/example/dairy_bottles.png', width, height)
Run Inference using Shadow Deployment
Now lets have the model detect the objects on the image by running inference and extracting the results
startTime = time.time()
infResults = pipeline.infer(dfImage, timeout=300)
endTime = time.time()
Extract Control Inference Results
First we’ll extract the inference result data for the control model and map it onto the image.
elapsed = 1.0
results = {
'model_name' : control_model_name,
'pipeline_name' : pipeline_name,
'width': width,
'height': height,
'image' : resizedImage,
'inf-results' : infResults,
'confidence-target' : 0.50,
'inference-time': (endTime-startTime),
'onnx-time' : int(elapsed) / 1e+9,
'classes_file': "./models/coco_classes.pickle",
'color': 'BLUE'
}
image = utils.drawDetectedObjectsFromInference(results)
Display the Challenger Results
Here we will use the Wallaroo CVDemo helper class to draw the challenger model results on the input image.
# get the average confidence values from the shadow deployed model
resnet50_avg_conf = sum(infResults["out_resnet50.confidences"][0]) / len(infResults["out_resnet50.confidences"][0])
resnet50_avg_conf
0.3588038691699998
# compare the models
display(f'Mobilenet Average Confidence: {infResults["out.avg_confidence"][0]}')
display(f'Resnet Average Confidence: {sum(infResults["out_resnet50.confidences"][0]) / len(infResults["out_resnet50.confidences"][0])}')
'Mobilenet Average Confidence: 0.2895055'
‘Resnet Average Confidence: 0.3588038691699998’
pipeline.undeploy()
name | shadowimagepipelinetest |
---|---|
created | 2024-04-09 21:56:51.111211+00:00 |
last_updated | 2024-04-11 18:54:50.427295+00:00 |
deployed | False |
arch | x86 |
accel | none |
tags | |
versions | fa3fef3c-535a-4b8f-aaf5-6b96177b5a00, d9dfeded-9ed9-4230-b361-5b313179e659, 4e400bd1-99f6-43de-9395-58d8d4a43e16, 5438b690-fc57-4d21-bb43-edb77ab8d7a5, 449e9181-1cb2-4110-8a84-fa28c2210892, 70219393-5263-47d1-9593-706d7fa116cb, 8f22d6ad-8376-4849-9594-12c6a9b4d485, 03203e94-a9c8-437c-8fad-018fda8b31b2, dbe8a951-387c-43c0-88c9-63614186f530, 13604852-7fb6-4bda-9b0f-59b03464999f, e2e50bd4-ac47-4f7e-bc76-7cec9e3daa19, d848f83f-7aad-4e40-8b0d-6ae3ef7ac188, bda86e5c-89fd-4589-a6ea-0202d8a76052, 52709f9e-60a5-4661-900a-853e53c2989d, 8f643926-bed6-41b0-9d7b-6478295a8904, 85f24de8-f920-405d-835d-11eab3e38f92, 62c8264a-5f45-469a-9988-d50eededbbd8, 44cdbd86-c23d-4711-a509-56685e19dd19 |
steps | cv-post-process-drift-detection |
published | False |
Conclusion
Notice the difference in the control confidence and the challenger confidence. Clearly we can see in this example the challenger resnet50 model is performing better than the control mobilenet model. This is likely due to the fact that frcnn resnet50 model is a 2 stage object detector vs the frcnn mobilenet is a single stage detector.
This completes using Wallaroo’s shadow deployment feature to compare different computer vision models.