| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| import mxnet as mx |
| import numpy as np |
| import gluoncv |
| import onnxruntime |
| |
| from mxnet.test_utils import assert_almost_equal |
| from common import with_seed |
| |
| import json |
| import os |
| import pytest |
| import shutil |
| |
| |
| class GluonModel(): |
| def __init__(self, model_name, input_shape, input_dtype, tmpdir): |
| self.model_name = model_name |
| self.input_shape = input_shape |
| self.input_dtype = input_dtype |
| self.modelpath = os.path.join(tmpdir, model_name) |
| self.ctx = mx.cpu(0) |
| self.get_model() |
| self.export() |
| |
| def get_model(self): |
| self.model = gluoncv.model_zoo.get_model(self.model_name, pretrained=True, ctx=self.ctx) |
| self.model.hybridize() |
| |
| def export(self): |
| data = mx.nd.zeros(self.input_shape, dtype=self.input_dtype, ctx=self.ctx) |
| self.model.forward(data) |
| self.model.export(self.modelpath, 0) |
| |
| def export_onnx(self): |
| onnx_file = self.modelpath + ".onnx" |
| mx.onnx.export_model(self.modelpath + "-symbol.json", self.modelpath + "-0000.params", |
| [self.input_shape], self.input_dtype, onnx_file) |
| return onnx_file |
| |
| def export_onnx_dynamic(self, dynamic_input_shapes): |
| onnx_file = self.modelpath + ".onnx" |
| mx.onnx.export_model(self.modelpath + "-symbol.json", self.modelpath + "-0000.params", |
| [self.input_shape], self.input_dtype, onnx_file, dynamic=True, |
| dynamic_input_shapes=dynamic_input_shapes) |
| return onnx_file |
| |
| def export_onnx_argaux(self): |
| onnx_file = self.modelpath + ".onnx" |
| sym_file = self.modelpath + "-symbol.json" |
| params_file = self.modelpath + "-0000.params" |
| if not (os.path.isfile(sym_file) and os.path.isfile(params_file)): |
| raise ValueError("Symbol and params files provided are invalid") |
| |
| try: |
| # reads symbol.json file from given path and |
| # retrieves model prefix and number of epochs |
| model_name = sym_file.rsplit('.', 1)[0].rsplit('-', 1)[0] |
| params_file_list = params_file.rsplit('.', 1)[0].rsplit('-', 1) |
| # Setting num_epochs to 0 if not present in filename |
| num_epochs = 0 if len(params_file_list) == 1 else int(params_file_list[1]) |
| except IndexError: |
| logging.info("Model and params name should be in format: " |
| "prefix-symbol.json, prefix-epoch.params") |
| raise |
| |
| sym, arg_params, aux_params = mx.model.load_checkpoint(model_name, num_epochs) |
| params = [arg_params, aux_params] |
| mx.onnx.export_model(sym, params, [self.input_shape], self.input_dtype, onnx_file) |
| return onnx_file |
| |
| def predict(self, data): |
| return self.model(data) |
| |
| |
| @pytest.fixture(scope="session") |
| def obj_class_test_images(tmpdir_factory): |
| tmpdir = tmpdir_factory.mktemp("obj_class_data") |
| from urllib.parse import urlparse |
| test_image_urls = [ |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/bikers.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/car.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/dancer.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/duck.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/fieldhockey.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/flower.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/runners.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/shark.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/soccer2.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/tree.jpg', |
| ] |
| paths = [] |
| for url in test_image_urls: |
| fn = os.path.join(tmpdir, os.path.basename(urlparse(url).path)) |
| mx.test_utils.download(url, fname=fn) |
| paths.append(fn) |
| return paths |
| |
| @pytest.mark.onnx_cv_batch1 |
| @pytest.mark.parametrize('model', [ |
| 'alexnet', |
| 'cifar_resnet20_v1', |
| 'cifar_resnet56_v1', |
| 'cifar_resnet110_v1', |
| 'cifar_resnet20_v2', |
| 'cifar_resnet56_v2', |
| 'cifar_resnet110_v2', |
| 'cifar_wideresnet16_10', |
| 'cifar_wideresnet28_10', |
| 'cifar_wideresnet40_8', |
| 'cifar_resnext29_16x64d', |
| 'darknet53', |
| 'densenet121', |
| 'densenet161', |
| 'densenet169', |
| 'densenet201', |
| 'googlenet', |
| 'mobilenet1.0', |
| 'mobilenet0.75', |
| 'mobilenet0.5', |
| 'mobilenet0.25', |
| 'mobilenetv2_1.0', |
| 'mobilenetv2_0.75', |
| 'mobilenetv2_0.5', |
| 'mobilenetv2_0.25', |
| pytest.param('mobilenetv3_large', marks=pytest.mark.integration), |
| 'mobilenetv3_small', |
| 'resnest14', |
| 'resnest26', |
| 'resnest50', |
| 'resnest101', |
| pytest.param('resnest200', marks=pytest.mark.integration), |
| 'resnest269', |
| 'resnet18_v1', |
| 'resnet18_v1b_0.89', |
| 'resnet18_v2', |
| 'resnet34_v1', |
| 'resnet34_v2', |
| 'resnet50_v1', |
| 'resnet50_v1d_0.86', |
| 'resnet50_v1d_0.48', |
| 'resnet50_v1d_0.37', |
| 'resnet50_v1d_0.11', |
| pytest.param('resnet50_v2', marks=pytest.mark.integration), |
| 'resnet101_v1', |
| 'resnet101_v1d_0.76', |
| 'resnet101_v1d_0.73', |
| 'resnet101_v2', |
| 'resnet152_v1', |
| 'resnet152_v2', |
| 'resnext50_32x4d', |
| 'resnext101_32x4d', |
| 'resnext101_64x4d', |
| 'senet_154', |
| 'se_resnext101_32x4d', |
| 'se_resnext101_64x4d', |
| 'se_resnext50_32x4d', |
| 'squeezenet1.0', |
| 'squeezenet1.1', |
| 'vgg11', |
| 'vgg11_bn', |
| 'vgg13', |
| 'vgg13_bn', |
| 'vgg16', |
| 'vgg16_bn', |
| 'vgg19', |
| pytest.param('vgg19_bn', marks=pytest.mark.integration), |
| 'xception', |
| 'inceptionv3' |
| ]) |
| def test_obj_class_model_inference_onnxruntime(tmp_path, model, obj_class_test_images): |
| inlen = 299 if 'inceptionv3' == model else 224 |
| def normalize_image(imgfile): |
| img_data = mx.image.imread(imgfile) |
| img_data = mx.image.imresize(img_data, inlen, inlen) |
| img_data = img_data.transpose([2, 0, 1]).astype('float32') |
| mean_vec = mx.nd.array([0.485, 0.456, 0.406]) |
| stddev_vec = mx.nd.array([0.229, 0.224, 0.225]) |
| norm_img_data = mx.nd.zeros(img_data.shape).astype('float32') |
| for i in range(img_data.shape[0]): |
| norm_img_data[i,:,:] = (img_data[i,:,:]/255 - mean_vec[i]) / stddev_vec[i] |
| return norm_img_data.reshape(1, 3, inlen, inlen).astype('float32') |
| |
| try: |
| tmp_path = str(tmp_path) |
| M = GluonModel(model, (1,3,inlen,inlen), 'float32', tmp_path) |
| if model == 'resnet50_v2': |
| # testing export for arg/aux |
| onnx_file = M.export_onnx_argaux() |
| else: |
| onnx_file = M.export_onnx() |
| |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| session = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| input_name = session.get_inputs()[0].name |
| |
| for img in obj_class_test_images: |
| img_data = normalize_image(img) |
| mx_result = M.predict(img_data) |
| onnx_result = session.run([], {input_name: img_data.asnumpy()})[0] |
| assert_almost_equal(mx_result, onnx_result) |
| |
| finally: |
| shutil.rmtree(tmp_path) |
| |
| |
| @pytest.fixture(scope="session") |
| def obj_detection_test_images(tmpdir_factory): |
| tmpdir = tmpdir_factory.mktemp("obj_det_data") |
| from urllib.parse import urlparse |
| test_image_urls = [ |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/fieldhockey.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/flower.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/runners.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/shark.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/soccer2.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/tree.jpg', |
| ] |
| paths = [] |
| for url in test_image_urls: |
| fn = os.path.join(tmpdir, os.path.basename(urlparse(url).path)) |
| mx.test_utils.download(url, fname=fn) |
| paths.append(fn) |
| return paths |
| |
| |
| @pytest.mark.onnx_cv_batch2 |
| @pytest.mark.parametrize('model', [ |
| 'center_net_resnet18_v1b_voc', |
| 'center_net_resnet50_v1b_voc', |
| pytest.param('center_net_resnet101_v1b_voc', marks=pytest.mark.integration), |
| 'center_net_resnet18_v1b_coco', |
| 'center_net_resnet50_v1b_coco', |
| 'center_net_resnet101_v1b_coco', |
| 'ssd_300_vgg16_atrous_voc', |
| 'ssd_512_vgg16_atrous_voc', |
| 'ssd_512_resnet50_v1_voc', |
| 'ssd_512_mobilenet1.0_voc', |
| 'faster_rcnn_resnet50_v1b_voc', |
| 'yolo3_darknet53_voc', |
| 'yolo3_mobilenet1.0_voc', |
| 'ssd_300_vgg16_atrous_coco', |
| 'ssd_512_vgg16_atrous_coco', |
| 'ssd_300_resnet34_v1b_coco', |
| 'ssd_512_resnet50_v1_coco', |
| 'ssd_512_mobilenet1.0_coco', |
| 'faster_rcnn_resnet50_v1b_coco', |
| 'faster_rcnn_resnet101_v1d_coco', |
| 'yolo3_darknet53_coco', |
| 'yolo3_mobilenet1.0_coco', |
| 'faster_rcnn_fpn_resnet50_v1b_coco', |
| # Those two models were failing in nightly ci due to anticipated mxnet onnx nms numerical differences. |
| # Model ouputs look good to human eyes. We will need to rewrite the bbox check |
| #'faster_rcnn_fpn_resnet101_v1d_coco', |
| #'mask_rcnn_fpn_resnet18_v1b_coco', |
| 'mask_rcnn_resnet18_v1b_coco', |
| 'mask_rcnn_resnet50_v1b_coco', |
| 'mask_rcnn_resnet101_v1d_coco', |
| 'mask_rcnn_fpn_resnet50_v1b_coco', |
| 'mask_rcnn_fpn_resnet101_v1d_coco', |
| ]) |
| def test_obj_detection_model_inference_onnxruntime(tmp_path, model, obj_detection_test_images): |
| def assert_obj_detetion_result(mx_ids, mx_scores, mx_boxes, |
| onnx_ids, onnx_scores, onnx_boxes, |
| score_thresh=0.6, score_tol=0.0001, box_tol=0.01): |
| def assert_bbox(mx_boxe, onnx_boxe): |
| def assert_scalar(a, b): |
| return np.abs(a-b) <= box_tol |
| return assert_scalar(mx_boxe[0], onnx_boxe[0]) and assert_scalar(mx_boxe[1], onnx_boxe[1]) \ |
| and assert_scalar(mx_boxe[2], onnx_boxe[2]) and assert_scalar(mx_boxe[3], onnx_boxe[3]) |
| |
| found_match = False |
| for i in range(len(onnx_ids)): |
| onnx_id = onnx_ids[i][0] |
| onnx_score = onnx_scores[i][0] |
| onnx_boxe = onnx_boxes[i] |
| if onnx_score < score_thresh: |
| break |
| for j in range(len(mx_ids)): |
| mx_id = mx_ids[j].asnumpy()[0] |
| mx_score = mx_scores[j].asnumpy()[0] |
| mx_boxe = mx_boxes[j].asnumpy() |
| # check socre |
| if onnx_score < mx_score - score_tol: |
| continue |
| if onnx_score > mx_score + score_tol: |
| assert found_match, 'match not found' |
| # check id |
| if onnx_id != mx_id: |
| continue |
| # check bounding box |
| if assert_bbox(mx_boxe, onnx_boxe): |
| found_match = True |
| break |
| assert found_match, 'match not found' |
| found_match = False |
| |
| def normalize_image(imgfile): |
| img = mx.image.imread(imgfile) |
| img, _ = mx.image.center_crop(img, size=(512, 512)) |
| img, _ = gluoncv.data.transforms.presets.center_net.transform_test(img, short=512) |
| return img |
| |
| try: |
| tmp_path = str(tmp_path) |
| M = GluonModel(model, (1,3,512,512), 'float32', tmp_path) |
| onnx_file = M.export_onnx() |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| session = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| input_name = session.get_inputs()[0].name |
| |
| for img in obj_detection_test_images: |
| img_data = normalize_image(img) |
| if model.startswith('mask_rcnn'): |
| mx_class_ids, mx_scores, mx_boxes, _ = M.predict(img_data) |
| else: |
| mx_class_ids, mx_scores, mx_boxes = M.predict(img_data) |
| # center_net_resnet models have different output format |
| if 'center_net_resnet' in model: |
| onnx_scores, onnx_class_ids, onnx_boxes = session.run([], {input_name: img_data.asnumpy()}) |
| assert_almost_equal(mx_class_ids, onnx_class_ids) |
| assert_almost_equal(mx_scores, onnx_scores) |
| assert_almost_equal(mx_boxes, onnx_boxes) |
| else: |
| if model.startswith('mask_rcnn'): |
| onnx_class_ids, onnx_scores, onnx_boxes, _ = session.run([], {input_name: img_data.asnumpy()}) |
| assert_obj_detetion_result(mx_class_ids[0], mx_scores[0], mx_boxes[0], |
| onnx_class_ids[0], onnx_scores[0], onnx_boxes[0], |
| score_thresh=0.8, score_tol=0.05, box_tol=15) |
| elif model.startswith('faster_rcnn_fpn'): |
| onnx_class_ids, onnx_scores, onnx_boxes = session.run([], {input_name: img_data.asnumpy()}) |
| assert_obj_detetion_result(mx_class_ids[0], mx_scores[0], mx_boxes[0], |
| onnx_class_ids[0], onnx_scores[0], onnx_boxes[0], |
| score_thresh=0.8, score_tol=0.05, box_tol=30) |
| else: |
| onnx_class_ids, onnx_scores, onnx_boxes = session.run([], {input_name: img_data.asnumpy()}) |
| assert_obj_detetion_result(mx_class_ids[0], mx_scores[0], mx_boxes[0], |
| onnx_class_ids[0], onnx_scores[0], onnx_boxes[0]) |
| |
| finally: |
| shutil.rmtree(tmp_path) |
| |
| @pytest.fixture(scope="session") |
| def img_segmentation_test_images(tmpdir_factory): |
| tmpdir = tmpdir_factory.mktemp("img_seg_data") |
| from urllib.parse import urlparse |
| test_image_urls = [ |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/bikers.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/car.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/dancer.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/duck.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/fieldhockey.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/flower.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/runners.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/shark.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/soccer2.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/tree.jpg', |
| ] |
| paths = [] |
| for url in test_image_urls: |
| fn = os.path.join(tmpdir, os.path.basename(urlparse(url).path)) |
| mx.test_utils.download(url, fname=fn) |
| paths.append(fn) |
| return paths |
| |
| @pytest.mark.onnx_cv_batch2 |
| @pytest.mark.parametrize('model', [ |
| 'fcn_resnet50_ade', |
| 'fcn_resnet101_ade', |
| 'deeplab_resnet50_ade', |
| 'deeplab_resnet101_ade', |
| 'deeplab_resnest50_ade', |
| 'deeplab_resnest101_ade', |
| # cannot download this model, skipping for now |
| # 'deeplab_resnest200_ade', |
| 'deeplab_resnest269_ade', |
| 'fcn_resnet101_coco', |
| 'deeplab_resnet101_coco', |
| 'fcn_resnet101_voc', |
| 'deeplab_resnet101_voc', |
| 'deeplab_resnet152_voc', |
| pytest.param('deeplab_resnet50_citys', marks=pytest.mark.integration), |
| 'deeplab_resnet101_citys', |
| 'deeplab_v3b_plus_wideresnet_citys', |
| 'danet_resnet50_citys', |
| 'danet_resnet101_citys' |
| ]) |
| def test_img_segmentation_model_inference_onnxruntime(tmp_path, model, img_segmentation_test_images): |
| def normalize_image(imgfile): |
| img = mx.image.imread(imgfile).astype('float32') |
| img, _ = mx.image.center_crop(img, size=(480, 480)) |
| img = gluoncv.data.transforms.presets.segmentation.test_transform(img, mx.cpu(0)) |
| return img |
| |
| |
| try: |
| tmp_path = str(tmp_path) |
| M = GluonModel(model, (1,3,480,480), 'float32', tmp_path) |
| onnx_file = M.export_onnx() |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| session = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| input_name = session.get_inputs()[0].name |
| |
| for img in img_segmentation_test_images: |
| img_data = normalize_image(img) |
| mx_result = M.predict(img_data) |
| onnx_result = session.run([], {input_name: img_data.asnumpy()}) |
| assert(len(mx_result) == len(onnx_result)) |
| for i in range(len(mx_result)): |
| assert_almost_equal(mx_result[i], onnx_result[i]) |
| |
| finally: |
| shutil.rmtree(tmp_path) |
| |
| |
| @pytest.fixture(scope="session") |
| def pose_estimation_test_images(tmpdir_factory): |
| tmpdir = tmpdir_factory.mktemp("pose_est_data") |
| from urllib.parse import urlparse |
| test_image_urls = [ |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/bikers.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/dancer.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/fieldhockey.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/runners.jpg', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/images/soccer2.jpg', |
| ] |
| paths = [] |
| for url in test_image_urls: |
| fn = os.path.join(tmpdir, os.path.basename(urlparse(url).path)) |
| mx.test_utils.download(url, fname=fn) |
| paths.append(fn) |
| return paths |
| |
| @pytest.mark.onnx_cv_batch1 |
| @pytest.mark.parametrize('model', [ |
| 'simple_pose_resnet18_v1b', |
| 'simple_pose_resnet50_v1b', |
| 'simple_pose_resnet50_v1d', |
| 'simple_pose_resnet101_v1b', |
| 'simple_pose_resnet101_v1d', |
| 'simple_pose_resnet152_v1b', |
| 'simple_pose_resnet152_v1d', |
| 'alpha_pose_resnet101_v1b_coco', |
| 'mobile_pose_resnet18_v1b', |
| 'mobile_pose_resnet50_v1b', |
| pytest.param('mobile_pose_mobilenet1.0', marks=pytest.mark.integration), |
| 'mobile_pose_mobilenetv2_1.0', |
| 'mobile_pose_mobilenetv3_large', |
| 'mobile_pose_mobilenetv3_small', |
| ]) |
| def test_pose_estimation_model_inference_onnxruntime(tmp_path, model, pose_estimation_test_images): |
| def normalize_image(imgfile): |
| img = mx.image.imread(imgfile).astype('float32') |
| img, _ = mx.image.center_crop(img, size=(512, 512)) |
| img = gluoncv.data.transforms.presets.segmentation.test_transform(img, mx.cpu(0)) |
| return img |
| |
| try: |
| tmp_path = str(tmp_path) |
| M = GluonModel(model, (1,3,512,512), 'float32', tmp_path) |
| onnx_file = M.export_onnx() |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| session = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| input_name = session.get_inputs()[0].name |
| |
| for img in pose_estimation_test_images: |
| img_data = normalize_image(img) |
| mx_result = M.predict(img_data) |
| onnx_result = session.run([], {input_name: img_data.asnumpy()}) |
| assert(len(mx_result) == len(onnx_result)) |
| for i in range(len(mx_result)): |
| assert_almost_equal(mx_result[i], onnx_result[i]) |
| |
| finally: |
| shutil.rmtree(tmp_path) |
| |
| @pytest.fixture(scope="session") |
| def act_recognition_test_data(tmpdir_factory): |
| tmpdir = tmpdir_factory.mktemp("act_rec_data") |
| from urllib.parse import urlparse |
| test_image_urls = [ |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/actions/biking.rec', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/actions/diving.rec', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/actions/golfing.rec', |
| 'https://github.com/apache/mxnet-ci/raw/master/test-data/actions/sledding.rec', |
| ] |
| paths = [] |
| for url in test_image_urls: |
| fn = os.path.join(tmpdir, os.path.basename(urlparse(url).path)) |
| mx.test_utils.download(url, fname=fn) |
| paths.append(fn) |
| return paths |
| |
| @pytest.mark.onnx_cv_batch2 |
| @pytest.mark.parametrize('model', [ |
| 'inceptionv1_kinetics400', |
| 'resnet18_v1b_kinetics400', |
| 'resnet34_v1b_kinetics400', |
| 'resnet50_v1b_kinetics400', |
| 'resnet101_v1b_kinetics400', |
| 'resnet152_v1b_kinetics400', |
| 'resnet50_v1b_hmdb51', |
| 'resnet50_v1b_sthsthv2', |
| 'vgg16_ucf101', |
| pytest.param('inceptionv3_kinetics400', marks=pytest.mark.integration), |
| 'inceptionv3_ucf101', |
| ]) |
| def test_action_recognition_model_inference_onnxruntime(tmp_path, model, act_recognition_test_data): |
| batch_size = 64 |
| input_len = 224 |
| if 'inceptionv3' in model: |
| input_len = 340 |
| |
| def load_video(filepath): |
| iterator = mx.image.ImageIter(batch_size=batch_size, data_shape=(3,input_len,input_len), path_imgrec=filepath) |
| for batch in iterator: |
| return batch.data[0] |
| |
| try: |
| tmp_path = str(tmp_path) |
| M = GluonModel(model, (batch_size,3,input_len,input_len), 'float32', tmp_path) |
| onnx_file = M.export_onnx() |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| session = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| input_name = session.get_inputs()[0].name |
| |
| for video in act_recognition_test_data: |
| data = load_video(video) |
| mx_result = M.predict(data) |
| onnx_result = session.run([], {input_name: data.asnumpy()})[0] |
| assert_almost_equal(mx_result, onnx_result, rtol=0.001, atol=0.01) |
| |
| finally: |
| shutil.rmtree(tmp_path) |
| |
| |
| @with_seed() |
| @pytest.mark.onnx_cv_batch1 |
| @pytest.mark.integration |
| @pytest.mark.parametrize('model_name', ['mobilenet1.0', 'inceptionv3', 'darknet53', 'resnest14']) |
| def test_dynamic_shape_cv_inference_onnxruntime(tmp_path, model_name): |
| tmp_path = str(tmp_path) |
| try: |
| M = GluonModel(model_name, (1, 3, 512, 512), 'float32', tmp_path) |
| dynamic_input_shapes = [(None, 3, 512, 512)] |
| onnx_file = M.export_onnx_dynamic(dynamic_input_shapes) |
| |
| # create onnxruntime session using the generated onnx file |
| ses_opt = onnxruntime.SessionOptions() |
| ses_opt.log_severity_level = 3 |
| sess = onnxruntime.InferenceSession(onnx_file, ses_opt) |
| |
| # test on a different batch size |
| x = mx.random.uniform(0, 10, (5, 3, 512, 512)) |
| in_tensors = [x] |
| input_dict = dict((sess.get_inputs()[i].name, in_tensors[i].asnumpy()) for i in range(len(in_tensors))) |
| pred_on = sess.run(None, input_dict) |
| |
| pred_mx = M.predict(x) |
| |
| assert_almost_equal(pred_mx, pred_on[0]) |
| |
| finally: |
| shutil.rmtree(tmp_path) |