mirror of
https://github.com/open-mmlab/mmdeploy.git
synced 2025-01-14 08:09:43 +08:00
294 lines
9.4 KiB
Python
294 lines
9.4 KiB
Python
|
import copy
|
||
|
import importlib
|
||
|
import os
|
||
|
import random
|
||
|
import tempfile
|
||
|
|
||
|
import mmcv
|
||
|
import numpy as np
|
||
|
import pytest
|
||
|
import torch
|
||
|
|
||
|
from mmdeploy.utils.constants import Backend, Codebase
|
||
|
from mmdeploy.utils.test import (WrapModel, get_model_outputs,
|
||
|
get_rewrite_outputs)
|
||
|
|
||
|
|
||
|
def seed_everything(seed=1029):
|
||
|
random.seed(seed)
|
||
|
os.environ['PYTHONHASHSEED'] = str(seed)
|
||
|
np.random.seed(seed)
|
||
|
torch.manual_seed(seed)
|
||
|
if torch.cuda.is_available():
|
||
|
torch.cuda.manual_seed(seed)
|
||
|
torch.cuda.manual_seed_all(seed) # if you are using multi-GPU.
|
||
|
torch.backends.cudnn.benchmark = False
|
||
|
torch.backends.cudnn.deterministic = True
|
||
|
torch.backends.cudnn.enabled = False
|
||
|
|
||
|
|
||
|
def get_anchor_head_model():
|
||
|
"""AnchorHead Config."""
|
||
|
test_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
deploy_nms_pre=0,
|
||
|
min_bbox_size=0,
|
||
|
score_thr=0.05,
|
||
|
nms=dict(type='nms', iou_threshold=0.5),
|
||
|
max_per_img=100))
|
||
|
|
||
|
from mmdet.models import AnchorHead
|
||
|
model = AnchorHead(num_classes=4, in_channels=1, test_cfg=test_cfg)
|
||
|
model.requires_grad_(False)
|
||
|
|
||
|
return model
|
||
|
|
||
|
|
||
|
def get_fcos_head_model():
|
||
|
"""FCOS Head Config."""
|
||
|
test_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
deploy_nms_pre=0,
|
||
|
min_bbox_size=0,
|
||
|
score_thr=0.05,
|
||
|
nms=dict(type='nms', iou_threshold=0.5),
|
||
|
max_per_img=100))
|
||
|
|
||
|
from mmdet.models import FCOSHead
|
||
|
model = FCOSHead(num_classes=4, in_channels=1, test_cfg=test_cfg)
|
||
|
|
||
|
model.requires_grad_(False)
|
||
|
return model
|
||
|
|
||
|
|
||
|
def get_rpn_head_model():
|
||
|
"""RPN Head Config."""
|
||
|
test_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
deploy_nms_pre=0,
|
||
|
min_bbox_size=0,
|
||
|
score_thr=0.05,
|
||
|
nms=dict(type='nms', iou_threshold=0.5),
|
||
|
max_per_img=100))
|
||
|
from mmdet.models import RPNHead
|
||
|
model = RPNHead(in_channels=1, test_cfg=test_cfg)
|
||
|
|
||
|
model.requires_grad_(False)
|
||
|
return model
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize('backend_type', ['onnxruntime', 'ncnn'])
|
||
|
def test_anchor_head_get_bboxes(backend_type):
|
||
|
"""Test get_bboxes rewrite of anchor head."""
|
||
|
pytest.importorskip(backend_type, reason=f'requires {backend_type}')
|
||
|
anchor_head = get_anchor_head_model()
|
||
|
anchor_head.cpu().eval()
|
||
|
s = 128
|
||
|
img_metas = [{
|
||
|
'scale_factor': np.ones(4),
|
||
|
'pad_shape': (s, s, 3),
|
||
|
'img_shape': (s, s, 3)
|
||
|
}]
|
||
|
|
||
|
deploy_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
backend_config=dict(type=backend_type),
|
||
|
onnx_config=dict(
|
||
|
output_names=['dets', 'labels'], input_shape=None),
|
||
|
codebase_config=dict(
|
||
|
type='mmdet',
|
||
|
task='ObjectDetection',
|
||
|
post_processing=dict(
|
||
|
score_threshold=0.05,
|
||
|
iou_threshold=0.5,
|
||
|
max_output_boxes_per_class=200,
|
||
|
pre_top_k=-1,
|
||
|
keep_top_k=100,
|
||
|
background_label_id=-1,
|
||
|
))))
|
||
|
|
||
|
# the cls_score's size: (1, 36, 32, 32), (1, 36, 16, 16),
|
||
|
# (1, 36, 8, 8), (1, 36, 4, 4), (1, 36, 2, 2).
|
||
|
# the bboxes's size: (1, 36, 32, 32), (1, 36, 16, 16),
|
||
|
# (1, 36, 8, 8), (1, 36, 4, 4), (1, 36, 2, 2)
|
||
|
seed_everything(1234)
|
||
|
cls_score = [
|
||
|
torch.rand(1, 36, pow(2, i), pow(2, i)) for i in range(5, 0, -1)
|
||
|
]
|
||
|
seed_everything(5678)
|
||
|
bboxes = [torch.rand(1, 36, pow(2, i), pow(2, i)) for i in range(5, 0, -1)]
|
||
|
|
||
|
# to get outputs of pytorch model
|
||
|
model_inputs = {
|
||
|
'cls_scores': cls_score,
|
||
|
'bbox_preds': bboxes,
|
||
|
'img_metas': img_metas
|
||
|
}
|
||
|
model_outputs = get_model_outputs(anchor_head, 'get_bboxes', model_inputs)
|
||
|
|
||
|
# to get outputs of onnx model after rewrite
|
||
|
img_metas[0]['img_shape'] = torch.Tensor([s, s])
|
||
|
wrapped_model = WrapModel(
|
||
|
anchor_head, 'get_bboxes', img_metas=img_metas[0], with_nms=True)
|
||
|
rewrite_inputs = {
|
||
|
'cls_scores': cls_score,
|
||
|
'bbox_preds': bboxes,
|
||
|
}
|
||
|
rewrite_outputs = get_rewrite_outputs(
|
||
|
wrapped_model=wrapped_model,
|
||
|
model_inputs=rewrite_inputs,
|
||
|
deploy_cfg=deploy_cfg)
|
||
|
|
||
|
for model_output, rewrite_output in zip(model_outputs[0], rewrite_outputs):
|
||
|
model_output = model_output.squeeze().cpu().numpy()
|
||
|
rewrite_output = rewrite_output.squeeze()
|
||
|
# hard code to make two tensors with the same shape
|
||
|
# rewrite and original codes applied different nms strategy
|
||
|
assert np.allclose(
|
||
|
model_output[:rewrite_output.shape[0]],
|
||
|
rewrite_output,
|
||
|
rtol=1e-03,
|
||
|
atol=1e-05)
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize('backend_type', ['onnxruntime', 'ncnn'])
|
||
|
def test_get_bboxes_of_fcos_head(backend_type):
|
||
|
pytest.importorskip(backend_type, reason=f'requires {backend_type}')
|
||
|
fcos_head = get_fcos_head_model()
|
||
|
fcos_head.cpu().eval()
|
||
|
s = 128
|
||
|
img_metas = [{
|
||
|
'scale_factor': np.ones(4),
|
||
|
'pad_shape': (s, s, 3),
|
||
|
'img_shape': (s, s, 3)
|
||
|
}]
|
||
|
|
||
|
deploy_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
backend_config=dict(type=backend_type),
|
||
|
onnx_config=dict(
|
||
|
output_names=['dets', 'labels'], input_shape=None),
|
||
|
codebase_config=dict(
|
||
|
type='mmdet',
|
||
|
task='ObjectDetection',
|
||
|
post_processing=dict(
|
||
|
score_threshold=0.05,
|
||
|
iou_threshold=0.5,
|
||
|
max_output_boxes_per_class=200,
|
||
|
pre_top_k=-1,
|
||
|
keep_top_k=100,
|
||
|
background_label_id=-1,
|
||
|
))))
|
||
|
|
||
|
# the cls_score's size: (1, 36, 32, 32), (1, 36, 16, 16),
|
||
|
# (1, 36, 8, 8), (1, 36, 4, 4), (1, 36, 2, 2).
|
||
|
# the bboxes's size: (1, 36, 32, 32), (1, 36, 16, 16),
|
||
|
# (1, 36, 8, 8), (1, 36, 4, 4), (1, 36, 2, 2)
|
||
|
seed_everything(1234)
|
||
|
cls_score = [
|
||
|
torch.rand(1, fcos_head.num_classes, pow(2, i), pow(2, i))
|
||
|
for i in range(5, 0, -1)
|
||
|
]
|
||
|
seed_everything(5678)
|
||
|
bboxes = [torch.rand(1, 4, pow(2, i), pow(2, i)) for i in range(5, 0, -1)]
|
||
|
|
||
|
seed_everything(9101)
|
||
|
centernesses = [
|
||
|
torch.rand(1, 1, pow(2, i), pow(2, i)) for i in range(5, 0, -1)
|
||
|
]
|
||
|
|
||
|
# to get outputs of pytorch model
|
||
|
model_inputs = {
|
||
|
'cls_scores': cls_score,
|
||
|
'bbox_preds': bboxes,
|
||
|
'centernesses': centernesses,
|
||
|
'img_metas': img_metas
|
||
|
}
|
||
|
model_outputs = get_model_outputs(fcos_head, 'get_bboxes', model_inputs)
|
||
|
|
||
|
# to get outputs of onnx model after rewrite
|
||
|
img_metas[0]['img_shape'] = torch.Tensor([s, s])
|
||
|
wrapped_model = WrapModel(
|
||
|
fcos_head, 'get_bboxes', img_metas=img_metas[0], with_nms=True)
|
||
|
rewrite_inputs = {
|
||
|
'cls_scores': cls_score,
|
||
|
'bbox_preds': bboxes,
|
||
|
'centernesses': centernesses
|
||
|
}
|
||
|
rewrite_outputs = get_rewrite_outputs(
|
||
|
wrapped_model=wrapped_model,
|
||
|
model_inputs=rewrite_inputs,
|
||
|
deploy_cfg=deploy_cfg)
|
||
|
|
||
|
for model_output, rewrite_output in zip(model_outputs[0], rewrite_outputs):
|
||
|
model_output = model_output.squeeze().cpu().numpy()
|
||
|
rewrite_output = rewrite_output.squeeze()
|
||
|
# hard code to make two tensors with the same shape
|
||
|
# rewrite and original codes applied different nms strategy
|
||
|
assert np.allclose(
|
||
|
model_output[:rewrite_output.shape[0]],
|
||
|
rewrite_output,
|
||
|
rtol=1e-03,
|
||
|
atol=1e-05)
|
||
|
|
||
|
|
||
|
def _replace_r50_with_r18(model):
|
||
|
"""Replace ResNet50 with ResNet18 in config."""
|
||
|
model = copy.deepcopy(model)
|
||
|
if model.backbone.type == 'ResNet':
|
||
|
model.backbone.depth = 18
|
||
|
model.backbone.base_channels = 2
|
||
|
model.neck.in_channels = [2, 4, 8, 16]
|
||
|
return model
|
||
|
|
||
|
|
||
|
@pytest.mark.parametrize('model_cfg_path', [
|
||
|
'tests/test_mmdet/data/single_stage_model.json',
|
||
|
'tests/test_mmdet/data/mask_model.json'
|
||
|
])
|
||
|
@pytest.mark.skipif(
|
||
|
not importlib.util.find_spec('onnxruntime'), reason='requires onnxruntime')
|
||
|
def test_forward_of_base_detector_and_visualize(model_cfg_path):
|
||
|
deploy_cfg = mmcv.Config(
|
||
|
dict(
|
||
|
backend_config=dict(type='onnxruntime'),
|
||
|
onnx_config=dict(
|
||
|
output_names=['dets', 'labels'], input_shape=None),
|
||
|
codebase_config=dict(
|
||
|
type='mmdet',
|
||
|
task='ObjectDetection',
|
||
|
post_processing=dict(
|
||
|
score_threshold=0.05,
|
||
|
iou_threshold=0.5,
|
||
|
max_output_boxes_per_class=200,
|
||
|
pre_top_k=-1,
|
||
|
keep_top_k=100,
|
||
|
background_label_id=-1,
|
||
|
))))
|
||
|
|
||
|
model_cfg = mmcv.Config(dict(model=mmcv.load(model_cfg_path)))
|
||
|
model_cfg.model = _replace_r50_with_r18(model_cfg.model)
|
||
|
from mmdet.apis import init_detector
|
||
|
model = init_detector(model_cfg, None, 'cpu')
|
||
|
|
||
|
img = torch.randn(1, 3, 64, 64)
|
||
|
rewrite_inputs = {'img': img}
|
||
|
rewrite_outputs = get_rewrite_outputs(
|
||
|
wrapped_model=model,
|
||
|
model_inputs=rewrite_inputs,
|
||
|
deploy_cfg=deploy_cfg)
|
||
|
|
||
|
from mmdeploy.apis.utils import visualize
|
||
|
output_file = tempfile.NamedTemporaryFile(suffix='.jpg').name
|
||
|
model.CLASSES = [''] * 80
|
||
|
visualize(
|
||
|
Codebase.MMDET,
|
||
|
img.squeeze().permute(1, 2, 0).numpy(),
|
||
|
result=[torch.rand(0, 5).numpy()] * 80,
|
||
|
model=model,
|
||
|
output_file=output_file,
|
||
|
backend=Backend.ONNXRUNTIME,
|
||
|
show_result=False)
|
||
|
|
||
|
assert rewrite_outputs is not None
|