NOTE: The Jupyter Notebook below is included in the Chimera SDK and can be run interactively by running the following CLI command:
$ quadric sdk notebook
From the Jupyter Notebook window in your browser, select the notebook named /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn.ipynb.
Keypoint R-CNN
Abstract
The Mask R-CNN framework can easily be extended to human pose estimation. A keypoint’s location is modeled as a one-hot mask, and Mask R-CNN is adopted to predict K masks, one for each of K keypoint types (e.g., left shoulder, right elbow). This task helps demonstrate the flexibility of Mask R-CNN.
Please refer papers for details.
- Kaiming He, Georgia Gkioxari, Piotr Dollár, Ross Girshick, Section 5 of "Mask R-CNN"
Human Pose Estimation as Bottom-Up Approach
There are two different approaches to address to multi-person pose estimation.
- Top-down approach: A human detector first detects the location of body parts, and then a pose estimator calculaties a pose for each person.
- Bottom-up approach: A pose estimator detects all parts of each human within an image, and then associates the parts that belong to each individual.
This model adopts the bottom-up approach.
Setup
import matplotlib.pyplot as plt
import numpy as np
import onnx
import os
from pathlib import Path
from PIL import Image
import torch, torchvision
from torch.utils.data import Subset
from torchvision.transforms import Compose, Normalize, ToTensor
import warnings
from examples.models.zoo.zoo_utils import onnx_check_and_simplify
from tvm.contrib.epu.chimera_job.chimera_job import ChimeraJob
import tvm.contrib.epu.chimera_job.constants as sdk_constants
from sdk_cli.lib.inference import InferenceEngine, batch_inference
from sdk_cli.lib.quantize import (
QuantizedONNXModel,
quantize_onnx_model,
)
from sdk_cli.utils.models.rcnn import RCNNModelVariant
from sdk_cli.node_builtins.classical.rcnn_postprocessing import (
get_rcnn_parameters,
get_rcnn_postprocessor,
rcnn_postprocessing,
)
from sdk_cli.node_builtins.outputs.bbox_label_visualizer import draw_bbox
from sdk_cli.node_builtins.outputs.keypoints_visualizer import draw_keypoints
from sdk_cli.utils.transforms import ResizePad
from sdk_cli.utils.datasets import QuadricCalibration
from sdk_cli.utils.datasets.COCO import COCO91CLASSES
import tvm.contrib.epu.graphutils as gutils
warnings.filterwarnings("ignore")
Model Selection
In this notebook, the following models can be experimented. We are going to use keypoint_rcnn_800x800 here.
- keypoint_rcnn_800x800
- keypoint_rcnn_800x1344
MODEL_NAME = RCNNModelVariant.keypoint_rcnn_800x800
rcnn_parameters = get_rcnn_parameters(MODEL_NAME)
model_input_size = rcnn_parameters.model_input_size
Load Model
## Export Model from torchvision
weights = torchvision.models.detection.KeypointRCNN_ResNet50_FPN_Weights.DEFAULT
transforms = weights.transforms()
model = torchvision.models.detection.keypointrcnn_resnet50_fpn(weights=weights, progress=False)
model.eval();
Export ONNX
onnx_file = Path(f"{MODEL_NAME}.onnx")
x = torch.rand(1, 3, *model_input_size[::-1])
output_edges = ["boxes", "labels", "scores", "keypoints", "keypoints_scores"]
torch.onnx.export(
model, # model being run
x, # model input (or a tuple for multiple inputs)
str(onnx_file), # where to save the model (can be a file or file-like object)
export_params=True, # store the trained parameter weights inside the model file
do_constant_folding=True, # whether to execute constant folding for optimization
opset_version=sdk_constants.DEFAULT_ONNX_OPSET,
input_names=["inputs0"], # the model's input names
output_names=output_edges,
)
model = onnx_check_and_simplify(onnx.load(onnx_file))
onnx.save(model, onnx_file)
print(f"ONNX is exported and simplified as {str(onnx_file)}")
ONNX is exported and simplified as keypoint_rcnn_800x800.onnx
Extract Backbone
model = onnx.load(onnx_file)
util = gutils.CustomOpReplacer(model)
sub_graph, _ = util.extract_subgraph_by_name_matching(["/backbone/.*"])
backbone_onnx_file = f"{onnx_file.stem}-backbone{onnx_file.suffix}"
onnx.save(sub_graph, backbone_onnx_file)
print(f"Backbone onnx is saved as {backbone_onnx_file}")
Backbone onnx is saved as keypoint_rcnn_800x800-backbone.onnx
Quantization
dataset_mean, dataset_std = [0.485, 0.456, 0.406], [0.229, 0.224, 0.225]
transforms = Compose(
[
ResizePad(model_input_size),
ToTensor(),
Normalize(dataset_mean, dataset_std),
]
)
## Path to directory containing data to use for for numerical range calibration during quantization
## Data is used also used to compare accuracy of fp32 and int8 models
dataset = QuadricCalibration.Dataset(transform=transforms)
## NOTE: `coco-like` is the 0th index target for `QuadricCalibration.Dataset`
coco_like_data_indices = [index for index, target in enumerate(dataset.targets) if target == 0]
coco_like_subset_of_dataset = Subset(dataset, coco_like_data_indices)
quantized_onnx_model: QuantizedONNXModel = quantize_onnx_model(
backbone_onnx_file,
coco_like_subset_of_dataset,
asymmetric_activation=True,
)
print(
f"quantized onnx: {quantized_onnx_model.model_path}, tranges file: {quantized_onnx_model.tensor_ranges_path}"
)
2026-06-19 04:07 - INFO - sdk - quantize - ONNX model shapes inferred.
2026-06-19 04:07 - DEBUG - sdk - quantize - Forcing node types: []
2026-06-19 04:07 - DEBUG - sdk - quantize - ONNX Node types excluded from quantization: ['Softmax', 'Sigmoid', 'QuadricCustomOp']
2026-06-19 04:07 - DEBUG - sdk - quantize - ONNX Node names excluded from quantization: []
2026-06-19 04:07 - INFO - sdk - quantize - Starting quantization...
WARNING:root:Please use QuantFormat.QDQ for activation type QInt8 and weight type QInt8. Or it will lead to bad performance on x64.
2026-06-19 04:07 - INFO - sdk - quantize - Quantization completed! Quantized model saved to /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q.onnx
2026-06-19 04:07 - INFO - sdk - quantize - ONNX full precision model size: 102.51MB
2026-06-19 04:07 - INFO - sdk - quantize - ONNX quantized model size: 25.79MB
2026-06-19 04:07 - INFO - sdk - quantize - ONNX model shapes inferred.
2026-06-19 04:07 - INFO - sdk - quantize - ONNX Model with well-defined shapes has been saved at `/quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.onnx`.
2026-06-19 04:07 - DEBUG - sdk - quantize - Checking for FLOAT/FLOAT16 types...
2026-06-19 04:07 - INFO - sdk - quantize - Checking for remaining FLOAT/FLOAT16 types.
2026-06-19 04:07 - INFO - sdk - quantize - Model still has FLOAT/FLOAT16 types after quantization. Creating ranges for floating point tensors using calibration data...
2026-06-19 04:07 - INFO - sdk - quantize - Saved computed tensor ranges to /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.tranges.
2026-06-19 04:07 - INFO - sdk - quantize -
╒════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╤═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Quantized ONNX Model │ Tensor Ranges File │
╞════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╪═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╡
│ /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.onnx │ /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.tranges │
╘════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╧═══════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
quantized onnx: /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.onnx, tranges file: /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.tranges
Compilation
cgc_job = ChimeraJob(
model_p=str(quantized_onnx_model.model_path),
trange_file=str(quantized_onnx_model.tensor_ranges_path),
)
cgc_job.compile(quiet=True)
print(cgc_job)
╒═════════════════════╤════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Module Name │ keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ONNX File │ /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.onnx │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Product Target │ QC-U │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Number of Cores │ 1 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ISS Clock Frequency │ 1.700 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ L2M Size │ 16MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ LRM Size │ 4kB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Read BW │ 128GBps │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Write BW │ 128GBps │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ MACS per PE │ 16 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max L2M │ 15.906MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max LRM │ 3.000kB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Temp Ext Bytes │ 36.621MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Network GMACs │ 88.381 │
╘═════════════════════╧════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
╒════╤════════╤═════════════════════════════════════════════════════════════╤════════════════════╤══════════════════════════╤═══════╕
│ │ Type │ Name │ shape │ type │ mse │
╞════╪════════╪═════════════════════════════════════════════════════════════╪════════════════════╪══════════════════════════╪═══════╡
│ 0 │ Input │ /transform/Unsqueeze_12_output_0 │ [1, 3, 800, 800] │ tensor[FixedPoint32<29>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 1 │ Output │ /backbone/fpn/layer_blocks.0/layer_blocks.0.0/Conv_output_0 │ [1, 256, 200, 200] │ tensor[FixedPoint32<27>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 2 │ Output │ /backbone/fpn/layer_blocks.1/layer_blocks.1.0/Conv_output_0 │ [1, 256, 100, 100] │ tensor[FixedPoint32<27>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 3 │ Output │ /backbone/fpn/layer_blocks.2/layer_blocks.2.0/Conv_output_0 │ [1, 256, 50, 50] │ tensor[FixedPoint32<27>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 4 │ Output │ /backbone/fpn/layer_blocks.3/layer_blocks.3.0/Conv_output_0 │ [1, 256, 25, 25] │ tensor[FixedPoint32<27>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 5 │ Output │ /backbone/fpn/extra_blocks/MaxPool_output_0 │ [1, 256, 13, 13] │ tensor[FixedPoint32<27>] │ n/a │
╘════╧════════╧═════════════════════════════════════════════════════════════╧════════════════════╧══════════════════════════╧═══════╛
Demo
Inference
all_image_paths = [
"../../../common/calibration/face/daniel_maverick.png",
"../../../common/calibration/coco-like/33823288584_1d21cf0a26_k.jpeg",
]
all_images = []
for image_path in all_image_paths:
all_images.append(np.expand_dims(transforms(Image.open(image_path)), axis=0))
NUM_IMAGES = len(all_images)
engines = {
InferenceEngine.CHIMERA_ORT_INT8: cgc_job,
InferenceEngine.CHIMERA_ISS_INT8: cgc_job,
}
outputs_per_inference_engine = {}
THREADS = min(NUM_IMAGES, 6)
for inference_engine, engine in engines.items():
all_outputs = batch_inference(
inference_engine,
engine,
all_images,
threads=THREADS,
)
outputs_per_inference_engine[inference_engine] = all_outputs
2026-06-19 04:09 - WARNING - epu - chimera_job - ORT is not threadsafe -- forcing single threaded batch execution
100%|████████████████████████████████████████████| 2/2 [00:01<00:00, 1.17it/s]
Processing: 100%|███████████████████████████████| 2/2 [05:35<00:00, 167.97s/it]
Run Statistics for Keypoint R-CNN Backbone
print(cgc_job)
cgc_job.plot_run_statistics()
╒═════════════════════╤════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╕
│ Module Name │ keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ONNX File │ /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/keypoint_rcnn_800x800-backbone_OpSet16_optimized_asym_int8_q_shaped.onnx │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Product Target │ QC-U │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Number of Cores │ 1 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ ISS Clock Frequency │ 1.700 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ L2M Size │ 16MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ LRM Size │ 4kB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Read BW │ 128GBps │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ External Write BW │ 128GBps │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ MACS per PE │ 16 │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max L2M │ 15.906MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max LRM │ 3.000kB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Max Temp Ext Bytes │ 36.621MB │
├─────────────────────┼────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────┤
│ Network GMACs │ 88.381 │
╘═════════════════════╧════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════════╛
╒════╤════════╤═════════════════════════════════════════════════════════════╤════════════════════╤══════════════════════════╤═══════╕
│ │ Type │ Name │ shape │ type │ mse │
╞════╪════════╪═════════════════════════════════════════════════════════════╪════════════════════╪══════════════════════════╪═══════╡
│ 0 │ Input │ /transform/Unsqueeze_12_output_0 │ [1, 3, 800, 800] │ tensor[FixedPoint32<29>] │ n/a │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 1 │ Output │ /backbone/fpn/layer_blocks.0/layer_blocks.0.0/Conv_output_0 │ [1, 256, 200, 200] │ tensor[FixedPoint32<27>] │ 0.002 │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 2 │ Output │ /backbone/fpn/layer_blocks.1/layer_blocks.1.0/Conv_output_0 │ [1, 256, 100, 100] │ tensor[FixedPoint32<27>] │ 0.002 │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 3 │ Output │ /backbone/fpn/layer_blocks.2/layer_blocks.2.0/Conv_output_0 │ [1, 256, 50, 50] │ tensor[FixedPoint32<27>] │ 0.001 │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 4 │ Output │ /backbone/fpn/layer_blocks.3/layer_blocks.3.0/Conv_output_0 │ [1, 256, 25, 25] │ tensor[FixedPoint32<27>] │ 0.001 │
├────┼────────┼─────────────────────────────────────────────────────────────┼────────────────────┼──────────────────────────┼───────┤
│ 5 │ Output │ /backbone/fpn/extra_blocks/MaxPool_output_0 │ [1, 256, 13, 13] │ tensor[FixedPoint32<27>] │ 0.001 │
╘════╧════════╧═════════════════════════════════════════════════════════════╧════════════════════╧══════════════════════════╧═══════╛
Post-ISS Report 1.7 GHz ***
Fully placed-and-routed gate simulation:
╒══════════════════════════════════╤═════════╕
│ Latency (ms) │ 11.76 │
├──────────────────────────────────┼─────────┤
│ FPS │ 85.03 │
├──────────────────────────────────┼─────────┤
│ Average Power @ 3nm SSGNP (mW) │ 2275.08 │
├──────────────────────────────────┼─────────┤
│ FPS per Watt @ 3nm SSGNP (FPS/W) │ 37.37 │
├──────────────────────────────────┼─────────┤
│ Ext Rd Bytes (MB) │ 130.50 │
├──────────────────────────────────┼─────────┤
│ Ext Wr Bytes (MB) │ 139.48 │
├──────────────────────────────────┼─────────┤
│ Avg Ext Rd BW (GBps) │ 10.84 │
├──────────────────────────────────┼─────────┤
│ Avg Ext Wr BW (GBps) │ 11.58 │
├──────────────────────────────────┼─────────┤
│ MAC Utilization │ 26.98% │
╘══════════════════════════════════╧═════════╛
*** Data generated using 7nm SSGNP gatesim and scaled to 3nm
[SDK-CLI] : TotalCycles: 19,993,023
[SDK-CLI] : Executions/second: 85.03
compute : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 5.772M
data_array : ▇▇▇▇▇▇▇▇▇▇ 1.868M
mac : ▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇▇ 8.579M
data_external: ▇▇▇▇▇▇▇▇▇▇▇ 1.942M
data_ocm : ▇▇▇▇▇▇▇▇▇ 1.587M
for more information check run directory: /quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/ccl_build/keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_040956_24c8de
2026-06-19 04:15 - INFO - epu - chimera_job - Combined plots generated and saved to:
/quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/ccl_build/keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_040956_24c8de/data/keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1.combined.png
'/quadric/sdk-cli/examples/models/mask_rcnn/pose_estimator/ccl_build/keypoint_rcnn_800x800_backbone_OpSet16_optimized_asym_int8_q_shaped_QC_U_1d7_16MB_4kB_128GBps_128GBps_16_OFF_x1_x1/run/20260619_040956_24c8de/data'

Post Processing
Keypoint_postprocessor = get_rcnn_postprocessor(rcnn_parameters.postprocess_model)
bboxes_per_inference_engine = {}
keypoints_per_inference_engine = {}
keypoints_scores_per_inference_engine = {}
## Postprocessing
for inference_engine, all_outputs in outputs_per_inference_engine.items():
bboxes_per_inference_engine[inference_engine] = []
keypoints_per_inference_engine[inference_engine] = []
keypoints_scores_per_inference_engine[inference_engine] = []
for image_path, outputs in zip(all_image_paths, all_outputs):
original_image_size = Image.open(image_path).size
detections, _, keypoints, keypoints_scores = rcnn_postprocessing(
outputs,
model_input_size,
original_image_size,
postprocessor=Keypoint_postprocessor,
score_threshold=rcnn_parameters.score_threshold,
)
bboxes_per_inference_engine[inference_engine].append(detections)
keypoints_per_inference_engine[inference_engine].append(keypoints)
keypoints_scores_per_inference_engine[inference_engine].append(keypoints_scores)
Display Bounding Boxes and Keypoints
%matplotlib inline
pic_len = len(engines) + 1
for i in range(len(all_image_paths)):
ax, idx = {}, 1
fig = plt.figure(figsize=(4 * pic_len, 4), tight_layout=True)
ax[idx] = fig.add_subplot(int("1%s%s" % (pic_len, idx)))
ax[idx].imshow(Image.open(all_image_paths[i]))
ax[idx].set_title("Original Image")
ax[idx].axis("off")
for (inference_engine, all_bboxes), all_keypoints, all_scores in zip(
bboxes_per_inference_engine.items(),
keypoints_per_inference_engine.values(),
keypoints_scores_per_inference_engine.values(),
):
frame = np.array(Image.open(all_image_paths[i]))
for keypoints, keypoints_scores in zip(all_keypoints[i], all_scores[i]):
frame = draw_keypoints(frame, keypoints, keypoints_scores)
frame = draw_bbox(frame, all_bboxes[i], classes=COCO91CLASSES)
idx += 1
ax[idx] = fig.add_subplot(int("1%s%s" % (pic_len, idx)))
ax[idx].imshow(frame)
ax[idx].set_title(f"{MODEL_NAME}: {str(inference_engine)}")
ax[idx].axis("off")
fig.show()

