mirror of
https://github.com/alibaba/EasyCV.git
synced 2025-06-03 14:49:00 +08:00
Compare commits
24 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
901ff18693 | ||
|
31897984d8 | ||
|
8c90ceaf84 | ||
|
1d1ac8aa5e | ||
|
5ba3057ff8 | ||
|
09232dac33 | ||
|
af4e9d5d19 | ||
|
cecb36a9ce | ||
|
447a1665c6 | ||
|
0b3045ff87 | ||
|
d2b95eac13 | ||
|
fc16bc1b10 | ||
|
8c3ba59aaf | ||
|
db33ced143 | ||
|
915bb73f5d | ||
|
a9ee453d04 | ||
|
e967ef3585 | ||
|
be657338f1 | ||
|
4a9c2fd392 | ||
|
269aa6d01c | ||
|
ebef5f5800 | ||
|
c6382bec97 | ||
|
f8644f2f93 | ||
|
9f29a489b0 |
15
.github/workflows/citest.yaml
vendored
15
.github/workflows/citest.yaml
vendored
@ -39,7 +39,7 @@ concurrency:
|
||||
jobs:
|
||||
ut-torch180:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: [unittest-t4]
|
||||
runs-on: [self-hosted]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@ -64,8 +64,8 @@ jobs:
|
||||
# pip install -r requirements.txt
|
||||
#run test
|
||||
export CUDA_VISIBLE_DEVICES=7
|
||||
source ~/workspace/anaconda2/etc/profile.d/conda.sh
|
||||
conda activate easycv_torch1.8.0_py37
|
||||
source ~/anaconda3/etc/profile.d/conda.sh
|
||||
conda activate easycv_torch1.8.0
|
||||
|
||||
# pip install pai-easycv
|
||||
pip uninstall -y pai-easycv
|
||||
@ -75,13 +75,16 @@ jobs:
|
||||
# move source code, ensure import easycv from site-package
|
||||
mv ./easycv ./easycv_src
|
||||
|
||||
PYTHONPATH=. python tests/run.py
|
||||
PYTHONPATH=. python tests/run.py --skip_dir tests/test_toolkit/modelscope
|
||||
|
||||
conda activate easycv_torch1.8.0_py37
|
||||
PYTHONPATH=. python tests/run.py --test_dir tests/test_toolkit/modelscope
|
||||
|
||||
|
||||
# blade test env will be updated! we do not support test with trt_efficient_nms
|
||||
ut-torch181-blade:
|
||||
# The type of runner that the job will run on
|
||||
runs-on: [unittest-t4]
|
||||
runs-on: [self-hosted]
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
@ -107,7 +110,7 @@ jobs:
|
||||
# pip install -r requirements.txt
|
||||
#run test
|
||||
export CUDA_VISIBLE_DEVICES=6
|
||||
source ~/workspace/anaconda2/etc/profile.d/conda.sh
|
||||
source ~/anaconda3/etc/profile.d/conda.sh
|
||||
conda activate torch1.8.1_blade
|
||||
PYTHONPATH=. python tests/test_predictors/test_detector_blade.py
|
||||
PYTHONPATH=. python tests/test_apis/test_export_blade.py
|
||||
|
@ -248,7 +248,7 @@ Please refer to the following model zoo for more details.
|
||||
|
||||
## Data Hub
|
||||
|
||||
EasyCV have collected dataset info for different senarios, making it easy for users to finetune or evaluate models in EasyCV model zoo.
|
||||
EasyCV have collected dataset info for different scenarios, making it easy for users to finetune or evaluate models in EasyCV model zoo.
|
||||
|
||||
Please refer to [data_hub.md](docs/source/data_hub.md).
|
||||
|
||||
|
@ -153,7 +153,7 @@ eval_pipelines = [
|
||||
data=data['val'],
|
||||
dist_eval=True,
|
||||
evaluators=[
|
||||
dict(type='ClsEvaluator', topk=(1, 5), class_list=class_list)
|
||||
dict(type='ClsEvaluator', topk=(1, ), class_list=class_list)
|
||||
],
|
||||
)
|
||||
]
|
||||
|
@ -4,16 +4,31 @@ num_classes = 1000
|
||||
# model settings
|
||||
model = dict(
|
||||
type='Classification',
|
||||
backbone=dict(type='Inception3'),
|
||||
head=dict(
|
||||
type='ClsHead',
|
||||
with_avg_pool=True,
|
||||
in_channels=2048,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
backbone=dict(type='Inception3', num_classes=1000),
|
||||
head=[
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=2048,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[1],
|
||||
),
|
||||
num_classes=num_classes))
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=768,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[0],
|
||||
)
|
||||
])
|
||||
|
||||
class_list = [
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13',
|
||||
@ -196,3 +211,5 @@ log_config = dict(
|
||||
interval=10,
|
||||
hooks=[dict(type='TextLoggerHook'),
|
||||
dict(type='TensorboardLoggerHook')])
|
||||
|
||||
export = dict(export_type='raw', export_neck=True)
|
||||
|
@ -0,0 +1,33 @@
|
||||
_base_ = 'configs/classification/imagenet/inception/inceptionv3_b32x8_100e.py'
|
||||
|
||||
num_classes = 1000
|
||||
# model settings
|
||||
model = dict(
|
||||
type='Classification',
|
||||
backbone=dict(type='Inception4', num_classes=num_classes),
|
||||
head=[
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=1536,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[1],
|
||||
),
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=768,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[0],
|
||||
)
|
||||
])
|
||||
|
||||
img_norm_cfg = dict(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
|
@ -0,0 +1,46 @@
|
||||
# A config with the optimization settings from https://arxiv.org/pdf/1602.07261
|
||||
# May run with 20 GPUs
|
||||
_base_ = 'configs/classification/imagenet/inception/inceptionv3_b32x8_100e.py'
|
||||
|
||||
num_classes = 1000
|
||||
# model settings
|
||||
model = dict(
|
||||
type='Classification',
|
||||
backbone=dict(type='Inception4', num_classes=num_classes),
|
||||
head=[
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=1536,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[1],
|
||||
),
|
||||
dict(
|
||||
type='ClsHead',
|
||||
with_fc=False,
|
||||
in_channels=768,
|
||||
loss_config=dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes,
|
||||
input_feature_index=[0],
|
||||
)
|
||||
])
|
||||
|
||||
img_norm_cfg = dict(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])
|
||||
|
||||
# optimizer
|
||||
optimizer = dict(
|
||||
type='RMSprop', lr=0.045, momentum=0.9, weight_decay=0.9, eps=1.0)
|
||||
|
||||
# learning policy
|
||||
lr_config = dict(policy='exp', gamma=0.96954) # gamma**2 ~ 0.94
|
||||
checkpoint_config = dict(interval=10)
|
||||
|
||||
# runtime settings
|
||||
total_epochs = 200
|
@ -13,7 +13,8 @@ model = dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes))
|
||||
num_classes=num_classes),
|
||||
pretrained=True)
|
||||
|
||||
# optimizer
|
||||
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
|
||||
@ -25,4 +26,4 @@ checkpoint_config = dict(interval=5)
|
||||
# runtime settings
|
||||
total_epochs = 100
|
||||
checkpoint_sync_export = True
|
||||
export = dict(export_neck=True)
|
||||
export = dict(export_type='raw', export_neck=True)
|
||||
|
@ -6,3 +6,6 @@ model = dict(
|
||||
depth=50,
|
||||
out_indices=[4], # 0: conv-1, x: stage-x
|
||||
norm_cfg=dict(type='BN')))
|
||||
|
||||
checkpoint_sync_export = True
|
||||
export = dict(export_type='raw', export_neck=True)
|
||||
|
@ -19,7 +19,8 @@ model = dict(
|
||||
type='CrossEntropyLossWithLabelSmooth',
|
||||
label_smooth=0,
|
||||
),
|
||||
num_classes=num_classes))
|
||||
num_classes=num_classes),
|
||||
pretrained=True)
|
||||
|
||||
# optimizer
|
||||
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
|
||||
@ -30,3 +31,4 @@ checkpoint_config = dict(interval=10)
|
||||
|
||||
# runtime settings
|
||||
total_epochs = 100
|
||||
export = dict(export_type='raw', export_neck=True)
|
||||
|
@ -49,14 +49,14 @@ img_norm_cfg = dict(
|
||||
mean=[123.675, 116.28, 103.53], std=[58.395, 57.12, 57.375], to_rgb=True)
|
||||
|
||||
train_pipeline = [
|
||||
dict(type='MMMosaic', img_scale='${img_scale}', pad_val=114.0),
|
||||
dict(type='MMMosaic', img_scale=tuple(img_scale), pad_val=114.0),
|
||||
dict(
|
||||
type='MMRandomAffine',
|
||||
scaling_ratio_range='${scale_ratio}',
|
||||
border=['-${img_scale}[0] // 2', '-${img_scale}[1] // 2']),
|
||||
scaling_ratio_range=scale_ratio,
|
||||
border=[img_scale[0] // 2, img_scale[1] // 2]),
|
||||
dict(
|
||||
type='MMMixUp', # s m x l; tiny nano will detele
|
||||
img_scale='${img_scale}',
|
||||
img_scale=tuple(img_scale),
|
||||
ratio_range=(0.8, 1.6),
|
||||
pad_val=114.0),
|
||||
dict(
|
||||
@ -70,45 +70,43 @@ train_pipeline = [
|
||||
dict(type='MMPad', pad_to_square=True, pad_val=(114.0, 114.0, 114.0)),
|
||||
dict(
|
||||
type='MMNormalize',
|
||||
mean='${img_norm_cfg.mean}',
|
||||
std='${img_norm_cfg.std}',
|
||||
to_rgb='${img_norm_cfg.to_rgb}'),
|
||||
mean=img_norm_cfg['mean'],
|
||||
std=img_norm_cfg['std'],
|
||||
to_rgb=img_norm_cfg['to_rgb']),
|
||||
dict(type='DefaultFormatBundle'),
|
||||
dict(type='Collect', keys=['img', 'gt_bboxes', 'gt_labels'])
|
||||
]
|
||||
test_pipeline = [
|
||||
dict(type='MMResize', img_scale='${img_scale}', keep_ratio=True),
|
||||
dict(type='MMResize', img_scale=img_scale, keep_ratio=True),
|
||||
dict(type='MMPad', pad_to_square=True, pad_val=(114.0, 114.0, 114.0)),
|
||||
dict(
|
||||
type='MMNormalize',
|
||||
mean='${img_norm_cfg.mean}',
|
||||
std='${img_norm_cfg.std}',
|
||||
to_rgb='${img_norm_cfg.to_rgb}'),
|
||||
mean=img_norm_cfg['mean'],
|
||||
std=img_norm_cfg['std'],
|
||||
to_rgb=img_norm_cfg['to_rgb']),
|
||||
dict(type='DefaultFormatBundle'),
|
||||
dict(type='Collect', keys=['img'])
|
||||
]
|
||||
|
||||
train_path = 'data/coco/train2017.manifest'
|
||||
val_path = 'data/coco/val2017.manifest'
|
||||
|
||||
train_dataset = dict(
|
||||
type='DetImagesMixDataset',
|
||||
data_source=dict(type='DetSourcePAI', path=train_path, classes=CLASSES),
|
||||
pipeline=train_pipeline,
|
||||
dynamic_scale=tuple(img_scale))
|
||||
|
||||
val_dataset = dict(
|
||||
type='DetImagesMixDataset',
|
||||
imgs_per_gpu=2,
|
||||
data_source=dict(type='DetSourcePAI', path=val_path, classes=CLASSES),
|
||||
pipeline=test_pipeline,
|
||||
dynamic_scale=None,
|
||||
label_padding=False)
|
||||
|
||||
data = dict(
|
||||
imgs_per_gpu=16,
|
||||
workers_per_gpu=4,
|
||||
train=dict(
|
||||
type='DetImagesMixDataset',
|
||||
data_source=dict(
|
||||
type='DetSourcePAI',
|
||||
path='data/coco/train2017.manifest',
|
||||
classes='${CLASSES}'),
|
||||
pipeline='${train_pipeline}',
|
||||
dynamic_scale='${img_scale}'),
|
||||
val=dict(
|
||||
type='DetImagesMixDataset',
|
||||
imgs_per_gpu=2,
|
||||
data_source=dict(
|
||||
type='DetSourcePAI',
|
||||
path='data/coco/val2017.manifest',
|
||||
classes='${CLASSES}'),
|
||||
pipeline='${test_pipeline}',
|
||||
dynamic_scale=None,
|
||||
label_padding=False))
|
||||
imgs_per_gpu=16, workers_per_gpu=4, train=train_dataset, val=val_dataset)
|
||||
|
||||
# additional hooks
|
||||
interval = 10
|
||||
@ -120,14 +118,14 @@ custom_hooks = [
|
||||
priority=48),
|
||||
dict(
|
||||
type='SyncRandomSizeHook',
|
||||
ratio_range='${random_size}',
|
||||
img_scale='${img_scale}',
|
||||
interval='${interval}',
|
||||
ratio_range=random_size,
|
||||
img_scale=img_scale,
|
||||
interval=interval,
|
||||
priority=48),
|
||||
dict(
|
||||
type='SyncNormHook',
|
||||
num_last_epochs=15,
|
||||
interval='${interval}',
|
||||
interval=interval,
|
||||
priority=48)
|
||||
]
|
||||
|
||||
@ -135,23 +133,23 @@ custom_hooks = [
|
||||
vis_num = 20
|
||||
score_thr = 0.5
|
||||
eval_config = dict(
|
||||
interval='${interval}',
|
||||
interval=interval,
|
||||
gpu_collect=False,
|
||||
visualization_config=dict(
|
||||
vis_num='${vis_num}',
|
||||
score_thr='${score_thr}',
|
||||
vis_num=vis_num,
|
||||
score_thr=score_thr,
|
||||
) # show by TensorboardLoggerHookV2
|
||||
)
|
||||
|
||||
eval_pipelines = [
|
||||
dict(
|
||||
mode='test',
|
||||
data='${data.val}',
|
||||
data=val_dataset,
|
||||
evaluators=[dict(type='CocoDetectionEvaluator', classes=CLASSES)],
|
||||
)
|
||||
]
|
||||
|
||||
checkpoint_config = dict(interval='${interval}')
|
||||
checkpoint_config = dict(interval=interval)
|
||||
# optimizer
|
||||
# basic_lr_per_img = 0.01 / 64.0
|
||||
optimizer = dict(
|
||||
|
@ -102,6 +102,7 @@ eval_config = dict(interval=1, gpu_collect=False)
|
||||
eval_pipelines = [
|
||||
dict(
|
||||
mode='test',
|
||||
data=data['val'],
|
||||
evaluators=[
|
||||
dict(type='CocoDetectionEvaluator', classes=CLASSES),
|
||||
],
|
||||
|
@ -92,13 +92,13 @@
|
||||
|
||||
### Verification
|
||||
|
||||
Simple verification
|
||||
Simple verification
|
||||
|
||||
```python
|
||||
from easycv.apis import *
|
||||
```
|
||||
```python
|
||||
from easycv.apis import *
|
||||
```
|
||||
|
||||
You can also verify your installation using following quick-start examples
|
||||
You can also verify your installation using following quick-start examples
|
||||
|
||||
|
||||
## Examples
|
||||
|
@ -1,4 +1,9 @@
|
||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||
# flake8: noqa
|
||||
# isort:skip_file
|
||||
import os
|
||||
os.environ['SETUPTOOLS_USE_DISTUTILS'] = 'stdlib'
|
||||
|
||||
from .version import __version__, short_version
|
||||
|
||||
__all__ = ['__version__', 'short_version']
|
||||
|
@ -157,6 +157,52 @@ def _export_jit_and_blade(model, cfg, filename, dummy_inputs, fp16=False):
|
||||
torch.jit.save(blade_model, ofile)
|
||||
|
||||
|
||||
def _export_onnx_cls(model, model_config, cfg, filename, meta):
|
||||
support_backbones = {
|
||||
'ResNet': {
|
||||
'depth': [50]
|
||||
},
|
||||
'MobileNetV2': {},
|
||||
'Inception3': {},
|
||||
'Inception4': {},
|
||||
'ResNeXt': {
|
||||
'depth': [50]
|
||||
}
|
||||
}
|
||||
if model_config['backbone'].get('type', None) not in support_backbones:
|
||||
tmp = ' '.join(support_backbones.keys())
|
||||
info_str = f'Only support export onnx model for {tmp} now!'
|
||||
raise ValueError(info_str)
|
||||
configs = support_backbones[model_config['backbone'].get('type')]
|
||||
for k, v in configs.items():
|
||||
if v[0].__class__(model_config['backbone'].get(k, None)) not in v:
|
||||
raise ValueError(
|
||||
f"Unsupport config for {model_config['backbone'].get('type')}")
|
||||
|
||||
# save json config for test_pipline and class
|
||||
with io.open(
|
||||
filename +
|
||||
'.config.json' if filename.endswith('onnx') else filename +
|
||||
'.onnx.config.json', 'w') as ofile:
|
||||
json.dump(meta, ofile)
|
||||
|
||||
device = 'cuda' if torch.cuda.is_available() else 'cpu'
|
||||
model.eval()
|
||||
model.to(device)
|
||||
img_size = int(cfg.image_size2)
|
||||
x_input = torch.randn((1, 3, img_size, img_size)).to(device)
|
||||
torch.onnx.export(
|
||||
model,
|
||||
(x_input, 'onnx'),
|
||||
filename if filename.endswith('onnx') else filename + '.onnx',
|
||||
export_params=True,
|
||||
opset_version=12,
|
||||
do_constant_folding=True,
|
||||
input_names=['input'],
|
||||
output_names=['output'],
|
||||
)
|
||||
|
||||
|
||||
def _export_cls(model, cfg, filename):
|
||||
""" export cls (cls & metric learning)model and preprocess config
|
||||
|
||||
@ -170,6 +216,7 @@ def _export_cls(model, cfg, filename):
|
||||
else:
|
||||
export_cfg = dict(export_neck=False)
|
||||
|
||||
export_type = export_cfg.get('export_type', 'raw')
|
||||
export_neck = export_cfg.get('export_neck', True)
|
||||
label_map_path = cfg.get('label_map_path', None)
|
||||
class_list = None
|
||||
@ -232,9 +279,14 @@ def _export_cls(model, cfg, filename):
|
||||
if export_neck and (k.startswith('neck') or k.startswith('head')):
|
||||
state_dict[k] = v
|
||||
|
||||
checkpoint = dict(state_dict=state_dict, meta=meta, author='EasyCV')
|
||||
with io.open(filename, 'wb') as ofile:
|
||||
torch.save(checkpoint, ofile)
|
||||
if export_type == 'raw':
|
||||
checkpoint = dict(state_dict=state_dict, meta=meta, author='EasyCV')
|
||||
with io.open(filename, 'wb') as ofile:
|
||||
torch.save(checkpoint, ofile)
|
||||
elif export_type == 'onnx':
|
||||
_export_onnx_cls(model, model_config, cfg, filename, config)
|
||||
else:
|
||||
raise ValueError('Only support export onnx/raw model!')
|
||||
|
||||
|
||||
def _export_yolox(model, cfg, filename):
|
||||
@ -247,10 +299,10 @@ def _export_yolox(model, cfg, filename):
|
||||
|
||||
if hasattr(cfg, 'export'):
|
||||
export_type = getattr(cfg.export, 'export_type', 'raw')
|
||||
default_export_type_list = ['raw', 'jit', 'blade']
|
||||
default_export_type_list = ['raw', 'jit', 'blade', 'onnx']
|
||||
if export_type not in default_export_type_list:
|
||||
logging.warning(
|
||||
'YOLOX-PAI only supports the export type as [raw,jit,blade], otherwise we use raw as default'
|
||||
'YOLOX-PAI only supports the export type as [raw,jit,blade,onnx], otherwise we use raw as default'
|
||||
)
|
||||
export_type = 'raw'
|
||||
|
||||
@ -276,7 +328,7 @@ def _export_yolox(model, cfg, filename):
|
||||
len(img_scale) == 2
|
||||
), 'Export YoloX predictor config contains img_scale must be (int, int) tuple!'
|
||||
|
||||
input = 255 * torch.rand((batch_size, 3) + img_scale)
|
||||
input = 255 * torch.rand((batch_size, 3) + tuple(img_scale))
|
||||
|
||||
# assert use_trt_efficientnms only happens when static_opt=True
|
||||
if static_opt is not True:
|
||||
@ -355,6 +407,31 @@ def _export_yolox(model, cfg, filename):
|
||||
|
||||
json.dump(config, ofile)
|
||||
|
||||
if export_type == 'onnx':
|
||||
|
||||
with io.open(
|
||||
filename + '.config.json' if filename.endswith('onnx')
|
||||
else filename + '.onnx.config.json', 'w') as ofile:
|
||||
config = dict(
|
||||
model=cfg.model,
|
||||
export=cfg.export,
|
||||
test_pipeline=cfg.test_pipeline,
|
||||
classes=cfg.CLASSES)
|
||||
|
||||
json.dump(config, ofile)
|
||||
|
||||
torch.onnx.export(
|
||||
model,
|
||||
input.to(device),
|
||||
filename if filename.endswith('onnx') else filename +
|
||||
'.onnx',
|
||||
export_params=True,
|
||||
opset_version=12,
|
||||
do_constant_folding=True,
|
||||
input_names=['input'],
|
||||
output_names=['output'],
|
||||
)
|
||||
|
||||
if export_type == 'jit':
|
||||
with io.open(filename + '.jit', 'wb') as ofile:
|
||||
torch.jit.save(yolox_trace, ofile)
|
||||
@ -650,6 +727,12 @@ def _export_pose_topdown(model, cfg, filename, fp16=False, dummy_inputs=None):
|
||||
model.to(device)
|
||||
|
||||
if hasattr(cfg, 'export') and getattr(cfg.export, 'type', 'raw') == 'raw':
|
||||
from mmcv.utils.path import is_filepath
|
||||
|
||||
if hasattr(cfg, 'dataset_info') and is_filepath(cfg.dataset_info):
|
||||
dataset_info_cfg = Config.fromfile(cfg.dataset_info)
|
||||
cfg.dataset_info = dataset_info_cfg._cfg_dict['dataset_info']
|
||||
|
||||
return _export_common(model, cfg, filename)
|
||||
|
||||
def _dummy_inputs(cfg):
|
||||
|
@ -146,10 +146,14 @@ class ClsEvaluator(Evaluator):
|
||||
matrix = confusion_matrix(
|
||||
valid_true, valid_pred, labels=self.class_list)
|
||||
|
||||
print_log(
|
||||
'recall:{}\nprecision:{}\nattend:{}\nTP:{}\nFN:{}\nFP:{}\nTN:{}\nrecall/mean:{}\nprecision/mean:{}\nF1/mean:{}\nconfusion_matrix:{}\n'
|
||||
.format(recall, precision, attend, tp, fn, fp, tn,
|
||||
recall_mean, precision_mean, f1_mean, matrix))
|
||||
# print_log(
|
||||
# 'recall:{}\nprecision:{}\nattend:{}\nTP:{}\nFN:{}\nFP:{}\nTN:{}\nrecall/mean:{}\nprecision/mean:{}\nF1/mean:{}\nconfusion_matrix:{}\n'
|
||||
# .format(recall, precision, attend, tp, fn, fp, tn,
|
||||
# recall_mean, precision_mean, f1_mean, matrix))
|
||||
|
||||
eval_res[key] = \
|
||||
'recall:{}\nprecision:{}\nattend:{}\nTP:{}\nFN:{}\nFP:{}\nTN:{}\nrecall/mean:{}\nprecision/mean:{}\nF1/mean:{}\nconfusion_matrix:{}\n'\
|
||||
.format(recall, precision, attend, tp, fn, fp, tn, recall_mean, precision_mean, f1_mean, matrix.tolist())
|
||||
|
||||
return eval_res
|
||||
|
||||
|
@ -467,8 +467,8 @@ class COCOeval:
|
||||
fps = np.logical_and(
|
||||
np.logical_not(dtm), np.logical_not(dtIg))
|
||||
|
||||
tp_sum = np.cumsum(tps, axis=1).astype(dtype=np.float)
|
||||
fp_sum = np.cumsum(fps, axis=1).astype(dtype=np.float)
|
||||
tp_sum = np.cumsum(tps, axis=1).astype(dtype=np.float32)
|
||||
fp_sum = np.cumsum(fps, axis=1).astype(dtype=np.float32)
|
||||
for t, (tp, fp) in enumerate(zip(tp_sum, fp_sum)):
|
||||
tp = np.array(tp)
|
||||
fp = np.array(fp)
|
||||
|
@ -252,7 +252,7 @@ class FaceKeypointsDataAugumentation:
|
||||
skin_factor_list = [0.6, 0.8, 1.0, 1.2, 1.4]
|
||||
skin_factor = np.random.choice(skin_factor_list)
|
||||
img_ycrcb_raw[:, :, 0:1] = np.clip(
|
||||
img_ycrcb_raw[:, :, 0:1].astype(np.float) * skin_factor, 0,
|
||||
img_ycrcb_raw[:, :, 0:1].astype(np.float32) * skin_factor, 0,
|
||||
255).astype(np.uint8)
|
||||
img = cv2.cvtColor(img_ycrcb_raw, cv2.COLOR_YCR_CB2BGR)
|
||||
|
||||
|
@ -246,7 +246,7 @@ class DistributedSampler(_DistributedSampler):
|
||||
l, size_per_label, replace=(len(l) <= size_per_label)))
|
||||
indices = np.array(indices)
|
||||
np.random.shuffle(indices)
|
||||
indices = indices[:N].astype(np.int).tolist()
|
||||
indices = indices[:N].astype(np.int64).tolist()
|
||||
|
||||
# add extra samples to make it evenly divisible
|
||||
assert len(indices) <= self.total_size, \
|
||||
@ -438,7 +438,7 @@ class DistributedGivenIterationSampler(Sampler):
|
||||
l, size_per_label, replace=(len(l) <= size_per_label)))
|
||||
indices = np.array(indices)
|
||||
np.random.shuffle(indices)
|
||||
indices = indices[:N].astype(np.int)
|
||||
indices = indices[:N].astype(np.int64)
|
||||
# repeat
|
||||
all_size = self.total_size * self.world_size
|
||||
indices = indices[:all_size]
|
||||
|
@ -110,16 +110,16 @@ class SegSourceCityscapes(SegSourceRaw):
|
||||
'')[:-len(self.img_suffix[0])]
|
||||
find_label_path = False
|
||||
for label_format in self.label_suffix:
|
||||
lable_path = os.path.join(self.label_root,
|
||||
label_path = os.path.join(self.label_root,
|
||||
img_name + label_format)
|
||||
if io.exists(lable_path):
|
||||
if io.exists(label_path):
|
||||
find_label_path = True
|
||||
self.label_files.append(lable_path)
|
||||
self.label_files.append(label_path)
|
||||
break
|
||||
if not find_label_path:
|
||||
logging.warning(
|
||||
'Not find label file %s for img: %s, skip the sample!' %
|
||||
(lable_path, img_path))
|
||||
(label_path, img_path))
|
||||
self.img_files.remove(img_path)
|
||||
|
||||
assert len(self.img_files) == len(self.label_files)
|
||||
|
@ -1,5 +1,5 @@
|
||||
# Copyright (c) OpenMMLab and Alibaba. All rights reserved.
|
||||
from collections import Sequence
|
||||
from collections.abc import Sequence
|
||||
|
||||
import mmcv
|
||||
import numpy as np
|
||||
|
@ -161,7 +161,7 @@ class SampleFrames:
|
||||
ratio = (num_frames - ori_clip_len + 1.0) / self.num_clips
|
||||
clip_offsets = np.around(np.arange(self.num_clips) * ratio)
|
||||
else:
|
||||
clip_offsets = np.zeros((self.num_clips, ), dtype=np.int)
|
||||
clip_offsets = np.zeros((self.num_clips, ), dtype=np.int64)
|
||||
|
||||
return clip_offsets
|
||||
|
||||
@ -180,11 +180,11 @@ class SampleFrames:
|
||||
avg_interval = (num_frames - ori_clip_len + 1) / float(self.num_clips)
|
||||
if num_frames > ori_clip_len - 1:
|
||||
base_offsets = np.arange(self.num_clips) * avg_interval
|
||||
clip_offsets = (base_offsets + avg_interval / 2.0).astype(np.int)
|
||||
clip_offsets = (base_offsets + avg_interval / 2.0).astype(np.int64)
|
||||
if self.twice_sample:
|
||||
clip_offsets = np.concatenate([clip_offsets, base_offsets])
|
||||
else:
|
||||
clip_offsets = np.zeros((self.num_clips, ), dtype=np.int)
|
||||
clip_offsets = np.zeros((self.num_clips, ), dtype=np.int64)
|
||||
return clip_offsets
|
||||
|
||||
def _sample_clips(self, num_frames):
|
||||
@ -259,7 +259,7 @@ class SampleFrames:
|
||||
start_index = results['start_index']
|
||||
frame_inds = np.concatenate(frame_inds) + start_index
|
||||
|
||||
results['frame_inds'] = frame_inds.astype(np.int)
|
||||
results['frame_inds'] = frame_inds.astype(np.int64)
|
||||
results['clip_len'] = self.clip_len
|
||||
results['frame_interval'] = self.frame_interval
|
||||
results['num_clips'] = self.num_clips
|
||||
|
@ -34,7 +34,7 @@ class PaddingWithLoop:
|
||||
inds = np.arange(start, start + self.clip_len)
|
||||
inds = np.mod(inds, num_frames)
|
||||
|
||||
results['frame_inds'] = inds.astype(np.int)
|
||||
results['frame_inds'] = inds.astype(np.int64)
|
||||
results['clip_len'] = self.clip_len
|
||||
results['frame_interval'] = None
|
||||
results['num_clips'] = self.num_clips
|
||||
|
@ -1,4 +1,4 @@
|
||||
from .file_io import IO
|
||||
from .utils import is_oss_path
|
||||
from .utils import get_oss_config, is_oss_path
|
||||
|
||||
io = IO()
|
||||
|
@ -10,6 +10,7 @@ from .face_keypoint_backbone import FaceKeypointBackbone
|
||||
from .genet import PlainNet
|
||||
from .hrnet import HRNet
|
||||
from .inceptionv3 import Inception3
|
||||
from .inceptionv4 import Inception4
|
||||
from .lighthrnet import LiteHRNet
|
||||
from .mae_vit_transformer import *
|
||||
from .mit import MixVisionTransformer
|
||||
|
@ -1,15 +1,21 @@
|
||||
# Copyright (c) 2022 Snap Inc. All rights reserved.
|
||||
import itertools
|
||||
import os
|
||||
from distutils.version import LooseVersion
|
||||
|
||||
import timm
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
from timm.models.layers import DropPath, trunc_normal_
|
||||
from timm.models.layers.helpers import to_2tuple
|
||||
|
||||
from ..modelzoo import efficientformer as model_urls
|
||||
from ..registry import BACKBONES
|
||||
|
||||
if LooseVersion(timm.__version__) <= LooseVersion('0.8.2'):
|
||||
from timm.models.layers.helpers import to_2tuple
|
||||
else:
|
||||
from timm.layers.helpers import to_2tuple
|
||||
|
||||
|
||||
class Attention(torch.nn.Module):
|
||||
|
||||
|
@ -2,9 +2,6 @@
|
||||
r""" This model is taken from the official PyTorch model zoo.
|
||||
- torchvision.models.inception.py on 31th Aug, 2019
|
||||
"""
|
||||
|
||||
from collections import namedtuple
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
@ -16,8 +13,6 @@ from ..registry import BACKBONES
|
||||
|
||||
__all__ = ['Inception3']
|
||||
|
||||
_InceptionOutputs = namedtuple('InceptionOutputs', ['logits', 'aux_logits'])
|
||||
|
||||
|
||||
@BACKBONES.register_module
|
||||
class Inception3(nn.Module):
|
||||
@ -113,6 +108,7 @@ class Inception3(nn.Module):
|
||||
# N x 768 x 17 x 17
|
||||
x = self.Mixed_6e(x)
|
||||
# N x 768 x 17 x 17
|
||||
aux = None
|
||||
if self.training and self.aux_logits:
|
||||
aux = self.AuxLogits(x)
|
||||
# N x 768 x 17 x 17
|
||||
@ -132,10 +128,7 @@ class Inception3(nn.Module):
|
||||
if hasattr(self, 'fc'):
|
||||
x = self.fc(x)
|
||||
|
||||
# N x 1000 (num_classes)
|
||||
if self.training and self.aux_logits and hasattr(self, 'fc'):
|
||||
return [_InceptionOutputs(x, aux)]
|
||||
return [x]
|
||||
return [aux, x]
|
||||
|
||||
|
||||
class InceptionA(nn.Module):
|
||||
|
393
easycv/models/backbones/inceptionv4.py
Normal file
393
easycv/models/backbones/inceptionv4.py
Normal file
@ -0,0 +1,393 @@
|
||||
from __future__ import absolute_import, division, print_function
|
||||
from collections import namedtuple
|
||||
|
||||
import torch
|
||||
import torch.nn as nn
|
||||
import torch.nn.functional as F
|
||||
from mmcv.cnn import constant_init, kaiming_init
|
||||
from torch.nn.modules.batchnorm import _BatchNorm
|
||||
|
||||
from ..modelzoo import inceptionv4 as model_urls
|
||||
from ..registry import BACKBONES
|
||||
|
||||
__all__ = ['Inception4']
|
||||
|
||||
|
||||
class BasicConv2d(nn.Module):
|
||||
|
||||
def __init__(self,
|
||||
in_planes,
|
||||
out_planes,
|
||||
kernel_size,
|
||||
stride=1,
|
||||
padding=0):
|
||||
super(BasicConv2d, self).__init__()
|
||||
self.conv = nn.Conv2d(
|
||||
in_planes,
|
||||
out_planes,
|
||||
kernel_size=kernel_size,
|
||||
stride=stride,
|
||||
padding=padding,
|
||||
bias=False) # verify bias false
|
||||
self.bn = nn.BatchNorm2d(
|
||||
out_planes,
|
||||
eps=0.001, # value found in tensorflow
|
||||
momentum=0.1, # default pytorch value
|
||||
affine=True)
|
||||
self.relu = nn.ReLU(inplace=True)
|
||||
|
||||
def forward(self, x):
|
||||
x = self.conv(x)
|
||||
x = self.bn(x)
|
||||
x = self.relu(x)
|
||||
return x
|
||||
|
||||
|
||||
class Mixed_3a(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Mixed_3a, self).__init__()
|
||||
self.maxpool = nn.MaxPool2d(3, stride=2)
|
||||
self.conv = BasicConv2d(64, 96, kernel_size=3, stride=2)
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.maxpool(x)
|
||||
x1 = self.conv(x)
|
||||
out = torch.cat((x0, x1), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Mixed_4a(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Mixed_4a, self).__init__()
|
||||
|
||||
self.branch0 = nn.Sequential(
|
||||
BasicConv2d(160, 64, kernel_size=1, stride=1),
|
||||
BasicConv2d(64, 96, kernel_size=3, stride=1))
|
||||
|
||||
self.branch1 = nn.Sequential(
|
||||
BasicConv2d(160, 64, kernel_size=1, stride=1),
|
||||
BasicConv2d(64, 64, kernel_size=(1, 7), stride=1, padding=(0, 3)),
|
||||
BasicConv2d(64, 64, kernel_size=(7, 1), stride=1, padding=(3, 0)),
|
||||
BasicConv2d(64, 96, kernel_size=(3, 3), stride=1))
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
x1 = self.branch1(x)
|
||||
out = torch.cat((x0, x1), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Mixed_5a(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Mixed_5a, self).__init__()
|
||||
self.conv = BasicConv2d(192, 192, kernel_size=3, stride=2)
|
||||
self.maxpool = nn.MaxPool2d(3, stride=2)
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.conv(x)
|
||||
x1 = self.maxpool(x)
|
||||
out = torch.cat((x0, x1), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Inception_A(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Inception_A, self).__init__()
|
||||
self.branch0 = BasicConv2d(384, 96, kernel_size=1, stride=1)
|
||||
|
||||
self.branch1 = nn.Sequential(
|
||||
BasicConv2d(384, 64, kernel_size=1, stride=1),
|
||||
BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1))
|
||||
|
||||
self.branch2 = nn.Sequential(
|
||||
BasicConv2d(384, 64, kernel_size=1, stride=1),
|
||||
BasicConv2d(64, 96, kernel_size=3, stride=1, padding=1),
|
||||
BasicConv2d(96, 96, kernel_size=3, stride=1, padding=1))
|
||||
|
||||
self.branch3 = nn.Sequential(
|
||||
nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
|
||||
BasicConv2d(384, 96, kernel_size=1, stride=1))
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
x1 = self.branch1(x)
|
||||
x2 = self.branch2(x)
|
||||
x3 = self.branch3(x)
|
||||
out = torch.cat((x0, x1, x2, x3), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Reduction_A(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Reduction_A, self).__init__()
|
||||
self.branch0 = BasicConv2d(384, 384, kernel_size=3, stride=2)
|
||||
|
||||
self.branch1 = nn.Sequential(
|
||||
BasicConv2d(384, 192, kernel_size=1, stride=1),
|
||||
BasicConv2d(192, 224, kernel_size=3, stride=1, padding=1),
|
||||
BasicConv2d(224, 256, kernel_size=3, stride=2))
|
||||
|
||||
self.branch2 = nn.MaxPool2d(3, stride=2)
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
x1 = self.branch1(x)
|
||||
x2 = self.branch2(x)
|
||||
out = torch.cat((x0, x1, x2), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Inception_B(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Inception_B, self).__init__()
|
||||
self.branch0 = BasicConv2d(1024, 384, kernel_size=1, stride=1)
|
||||
|
||||
self.branch1 = nn.Sequential(
|
||||
BasicConv2d(1024, 192, kernel_size=1, stride=1),
|
||||
BasicConv2d(
|
||||
192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)),
|
||||
BasicConv2d(
|
||||
224, 256, kernel_size=(7, 1), stride=1, padding=(3, 0)))
|
||||
|
||||
self.branch2 = nn.Sequential(
|
||||
BasicConv2d(1024, 192, kernel_size=1, stride=1),
|
||||
BasicConv2d(
|
||||
192, 192, kernel_size=(7, 1), stride=1, padding=(3, 0)),
|
||||
BasicConv2d(
|
||||
192, 224, kernel_size=(1, 7), stride=1, padding=(0, 3)),
|
||||
BasicConv2d(
|
||||
224, 224, kernel_size=(7, 1), stride=1, padding=(3, 0)),
|
||||
BasicConv2d(
|
||||
224, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)))
|
||||
|
||||
self.branch3 = nn.Sequential(
|
||||
nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
|
||||
BasicConv2d(1024, 128, kernel_size=1, stride=1))
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
x1 = self.branch1(x)
|
||||
x2 = self.branch2(x)
|
||||
x3 = self.branch3(x)
|
||||
out = torch.cat((x0, x1, x2, x3), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Reduction_B(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Reduction_B, self).__init__()
|
||||
|
||||
self.branch0 = nn.Sequential(
|
||||
BasicConv2d(1024, 192, kernel_size=1, stride=1),
|
||||
BasicConv2d(192, 192, kernel_size=3, stride=2))
|
||||
|
||||
self.branch1 = nn.Sequential(
|
||||
BasicConv2d(1024, 256, kernel_size=1, stride=1),
|
||||
BasicConv2d(
|
||||
256, 256, kernel_size=(1, 7), stride=1, padding=(0, 3)),
|
||||
BasicConv2d(
|
||||
256, 320, kernel_size=(7, 1), stride=1, padding=(3, 0)),
|
||||
BasicConv2d(320, 320, kernel_size=3, stride=2))
|
||||
|
||||
self.branch2 = nn.MaxPool2d(3, stride=2)
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
x1 = self.branch1(x)
|
||||
x2 = self.branch2(x)
|
||||
out = torch.cat((x0, x1, x2), 1)
|
||||
return out
|
||||
|
||||
|
||||
class Inception_C(nn.Module):
|
||||
|
||||
def __init__(self):
|
||||
super(Inception_C, self).__init__()
|
||||
|
||||
self.branch0 = BasicConv2d(1536, 256, kernel_size=1, stride=1)
|
||||
|
||||
self.branch1_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1)
|
||||
self.branch1_1a = BasicConv2d(
|
||||
384, 256, kernel_size=(1, 3), stride=1, padding=(0, 1))
|
||||
self.branch1_1b = BasicConv2d(
|
||||
384, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))
|
||||
|
||||
self.branch2_0 = BasicConv2d(1536, 384, kernel_size=1, stride=1)
|
||||
self.branch2_1 = BasicConv2d(
|
||||
384, 448, kernel_size=(3, 1), stride=1, padding=(1, 0))
|
||||
self.branch2_2 = BasicConv2d(
|
||||
448, 512, kernel_size=(1, 3), stride=1, padding=(0, 1))
|
||||
self.branch2_3a = BasicConv2d(
|
||||
512, 256, kernel_size=(1, 3), stride=1, padding=(0, 1))
|
||||
self.branch2_3b = BasicConv2d(
|
||||
512, 256, kernel_size=(3, 1), stride=1, padding=(1, 0))
|
||||
|
||||
self.branch3 = nn.Sequential(
|
||||
nn.AvgPool2d(3, stride=1, padding=1, count_include_pad=False),
|
||||
BasicConv2d(1536, 256, kernel_size=1, stride=1))
|
||||
|
||||
def forward(self, x):
|
||||
x0 = self.branch0(x)
|
||||
|
||||
x1_0 = self.branch1_0(x)
|
||||
x1_1a = self.branch1_1a(x1_0)
|
||||
x1_1b = self.branch1_1b(x1_0)
|
||||
x1 = torch.cat((x1_1a, x1_1b), 1)
|
||||
|
||||
x2_0 = self.branch2_0(x)
|
||||
x2_1 = self.branch2_1(x2_0)
|
||||
x2_2 = self.branch2_2(x2_1)
|
||||
x2_3a = self.branch2_3a(x2_2)
|
||||
x2_3b = self.branch2_3b(x2_2)
|
||||
x2 = torch.cat((x2_3a, x2_3b), 1)
|
||||
|
||||
x3 = self.branch3(x)
|
||||
|
||||
out = torch.cat((x0, x1, x2, x3), 1)
|
||||
return out
|
||||
|
||||
|
||||
class InceptionAux(nn.Module):
|
||||
|
||||
def __init__(self, in_channels, num_classes):
|
||||
super(InceptionAux, self).__init__()
|
||||
self.conv0 = BasicConv2d(in_channels, 128, kernel_size=1)
|
||||
self.conv1 = BasicConv2d(128, 768, kernel_size=5)
|
||||
self.conv1.stddev = 0.01
|
||||
self.fc = nn.Linear(768, num_classes)
|
||||
self.fc.stddev = 0.001
|
||||
|
||||
def forward(self, x):
|
||||
# N x 768 x 17 x 17
|
||||
x = F.avg_pool2d(x, kernel_size=5, stride=3)
|
||||
# N x 768 x 5 x 5
|
||||
x = self.conv0(x)
|
||||
# N x 128 x 5 x 5
|
||||
x = self.conv1(x)
|
||||
# N x 768 x 1 x 1
|
||||
# Adaptive average pooling
|
||||
x = F.adaptive_avg_pool2d(x, (1, 1))
|
||||
# N x 768 x 1 x 1
|
||||
x = torch.flatten(x, 1)
|
||||
# N x 768
|
||||
x = self.fc(x)
|
||||
# N x 1000
|
||||
return x
|
||||
|
||||
|
||||
# class BasicConv2d(nn.Module):
|
||||
|
||||
# def __init__(self, in_channels, out_channels, **kwargs):
|
||||
# super(BasicConv2d, self).__init__()
|
||||
# self.conv = nn.Conv2d(in_channels, out_channels, bias=False, **kwargs)
|
||||
# self.bn = nn.BatchNorm2d(out_channels, eps=0.001)
|
||||
|
||||
# def forward(self, x):
|
||||
# x = self.conv(x)
|
||||
# x = self.bn(x)
|
||||
# return F.relu(x, inplace=True)
|
||||
|
||||
|
||||
@BACKBONES.register_module
|
||||
class Inception4(nn.Module):
|
||||
"""InceptionV4 backbone.
|
||||
|
||||
Args:
|
||||
num_classes (int): The num_classes of InceptionV4. An extra fc will be used if
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
num_classes: int = 0,
|
||||
p_dropout=0.2,
|
||||
aux_logits: bool = True):
|
||||
super(Inception4, self).__init__()
|
||||
self.aux_logits = aux_logits
|
||||
# Modules
|
||||
self.features = nn.Sequential(
|
||||
BasicConv2d(3, 32, kernel_size=3, stride=2),
|
||||
BasicConv2d(32, 32, kernel_size=3, stride=1),
|
||||
BasicConv2d(32, 64, kernel_size=3, stride=1, padding=1),
|
||||
Mixed_3a(),
|
||||
Mixed_4a(),
|
||||
Mixed_5a(),
|
||||
Inception_A(),
|
||||
Inception_A(),
|
||||
Inception_A(),
|
||||
Inception_A(),
|
||||
Reduction_A(), # Mixed_6a
|
||||
Inception_B(),
|
||||
Inception_B(),
|
||||
Inception_B(),
|
||||
Inception_B(),
|
||||
Inception_B(),
|
||||
Inception_B(),
|
||||
Inception_B(), # Mixed_6h 1024 x 17 x 17
|
||||
Reduction_B(), # Mixed_7a
|
||||
Inception_C(),
|
||||
Inception_C(),
|
||||
Inception_C())
|
||||
|
||||
if aux_logits:
|
||||
self.AuxLogits = InceptionAux(1024, num_classes)
|
||||
|
||||
self.dropout = nn.Dropout(p_dropout)
|
||||
self.last_linear = None
|
||||
if num_classes > 0:
|
||||
self.last_linear = nn.Linear(1536, num_classes)
|
||||
|
||||
self.default_pretrained_model_path = model_urls[
|
||||
self.__class__.__name__]
|
||||
|
||||
@property
|
||||
def fc(self):
|
||||
return self.last_linear
|
||||
|
||||
def init_weights(self):
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d) or isinstance(m, nn.Linear):
|
||||
for m in self.modules():
|
||||
if isinstance(m, nn.Conv2d):
|
||||
kaiming_init(m, mode='fan_in', nonlinearity='relu')
|
||||
elif isinstance(m, (_BatchNorm, nn.GroupNorm)):
|
||||
constant_init(m, 1)
|
||||
elif isinstance(m, nn.BatchNorm2d):
|
||||
nn.init.constant_(m.weight, 1)
|
||||
nn.init.constant_(m.bias, 0)
|
||||
|
||||
def logits(self, features):
|
||||
x = F.adaptive_avg_pool2d(features, output_size=(1, 1))
|
||||
# x = F.avg_pool2d(features, kernel_size=adaptiveAvgPoolWidth)
|
||||
x = x.view(x.size(0), -1) # B x 1536
|
||||
x = self.fc(x)
|
||||
# B x num_classes
|
||||
return x
|
||||
|
||||
def forward(self, input: torch.Tensor):
|
||||
"""_summary_
|
||||
|
||||
Args:
|
||||
input (torch.Tensor): A RGB image tensor with shape B x C x H x W
|
||||
|
||||
Returns:
|
||||
torch.Tensor: A feature tensor or a logit tensor when num_classes is 0 (default)
|
||||
"""
|
||||
|
||||
if self.training and self.aux_logits:
|
||||
x = self.features[:-4](input)
|
||||
aux = self.AuxLogits(x)
|
||||
x = self.features[-4:](x)
|
||||
else:
|
||||
x = self.features(input)
|
||||
aux = None
|
||||
|
||||
if self.fc is not None:
|
||||
x = self.logits(x)
|
||||
|
||||
return [aux, x]
|
@ -151,6 +151,21 @@ class Classification(BaseModel):
|
||||
x = self.backbone(img)
|
||||
return x
|
||||
|
||||
@torch.jit.unused
|
||||
def forward_onnx(self, img: torch.Tensor) -> Dict[str, torch.Tensor]:
|
||||
"""
|
||||
forward_onnx means generate prob from image only support one neck + one head
|
||||
"""
|
||||
x = self.forward_backbone(img) # tuple
|
||||
|
||||
# if self.neck_num > 0:
|
||||
if hasattr(self, 'neck_0'):
|
||||
x = self.neck_0([i for i in x])
|
||||
|
||||
out = self.head_0(x)[0].cpu()
|
||||
out = self.activate_fn(out)
|
||||
return out
|
||||
|
||||
@torch.jit.unused
|
||||
def forward_train(self, img, gt_labels) -> Dict[str, torch.Tensor]:
|
||||
"""
|
||||
@ -290,6 +305,9 @@ class Classification(BaseModel):
|
||||
return self.forward_test_label(img, gt_labels)
|
||||
else:
|
||||
return self.forward_test(img)
|
||||
elif mode == 'onnx':
|
||||
return self.forward_onnx(img)
|
||||
|
||||
elif mode == 'extract':
|
||||
rd = self.forward_feature(img)
|
||||
rv = {}
|
||||
|
@ -52,6 +52,22 @@ class YOLOX(BaseModel):
|
||||
|
||||
assert model_type in self.param_map, f'invalid model_type for yolox {model_type}, valid ones are {list(self.param_map.keys())}'
|
||||
|
||||
if num_classes is not None:
|
||||
# adapt to previous export model (before easycv0.6.0)
|
||||
logging.warning(
|
||||
'Warning: You are now attend to use an old YOLOX model before easycv0.6.0 with key num_classes'
|
||||
)
|
||||
head = dict(
|
||||
type='YOLOXHead',
|
||||
model_type=model_type,
|
||||
num_classes=num_classes,
|
||||
)
|
||||
|
||||
# the change of backbone/neck/head only support model_type as 's'
|
||||
if model_type != 's':
|
||||
head_type = head.get('type', None)
|
||||
assert backbone == 'CSPDarknet' and neck_type == 'yolo' and neck_mode == 'all' and head_type == 'YOLOXHead', 'We only support the architecture modification for YOLOX-S.'
|
||||
|
||||
self.pretrained = pretrained
|
||||
|
||||
in_channels = [256, 512, 1024]
|
||||
@ -68,19 +84,14 @@ class YOLOX(BaseModel):
|
||||
asff_channel=asff_channel,
|
||||
use_att=use_att)
|
||||
|
||||
if num_classes is not None:
|
||||
# adapt to previous export model (before easycv0.6.0)
|
||||
logging.warning(
|
||||
'Warning: You are now attend to use an old YOLOX model before easycv0.6.0 with key num_classes'
|
||||
)
|
||||
head = dict(
|
||||
type='YOLOXHead',
|
||||
model_type=model_type,
|
||||
num_classes=num_classes,
|
||||
)
|
||||
|
||||
if head is not None:
|
||||
# head is None for YOLOX-edge to define a special head
|
||||
# set and check model type in head as the same of yolox
|
||||
head_model_type = head.get('model_type', None)
|
||||
if head_model_type is None:
|
||||
head['model_type'] = model_type
|
||||
else:
|
||||
assert model_type == head_model_type, 'Please provide the same model_type of YOLOX in config.'
|
||||
self.head = build_head(head)
|
||||
self.num_classes = self.head.num_classes
|
||||
|
||||
|
@ -79,6 +79,12 @@ inceptionv3 = {
|
||||
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/inceptionv3/inception_v3.pth',
|
||||
}
|
||||
|
||||
inceptionv4 = {
|
||||
# Inception v4 ported from http://data.lip6.fr/cadene/pretrainedmodels/inceptionv4-8e4777a0.pth
|
||||
'Inception4':
|
||||
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/inceptionv4/inception_v4.pth',
|
||||
}
|
||||
|
||||
genet = {
|
||||
'PlainNetnormal':
|
||||
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/genet/GENet_normal.pth',
|
||||
|
@ -135,10 +135,10 @@ class DBPostProcess(object):
|
||||
'''
|
||||
h, w = bitmap.shape[:2]
|
||||
box = _box.copy()
|
||||
xmin = np.clip(np.floor(box[:, 0].min()).astype(np.int), 0, w - 1)
|
||||
xmax = np.clip(np.ceil(box[:, 0].max()).astype(np.int), 0, w - 1)
|
||||
ymin = np.clip(np.floor(box[:, 1].min()).astype(np.int), 0, h - 1)
|
||||
ymax = np.clip(np.ceil(box[:, 1].max()).astype(np.int), 0, h - 1)
|
||||
xmin = np.clip(np.floor(box[:, 0].min()).astype(np.int32), 0, w - 1)
|
||||
xmax = np.clip(np.ceil(box[:, 0].max()).astype(np.int32), 0, w - 1)
|
||||
ymin = np.clip(np.floor(box[:, 1].min()).astype(np.int32), 0, h - 1)
|
||||
ymax = np.clip(np.ceil(box[:, 1].max()).astype(np.int32), 0, h - 1)
|
||||
|
||||
mask = np.zeros((ymax - ymin + 1, xmax - xmin + 1), dtype=np.uint8)
|
||||
box[:, 0] = box[:, 0] - xmin
|
||||
|
@ -47,7 +47,7 @@ def get_1d_sincos_pos_embed_from_grid(embed_dim, pos):
|
||||
out: (M, D)
|
||||
"""
|
||||
assert embed_dim % 2 == 0
|
||||
omega = np.arange(embed_dim // 2, dtype=np.float)
|
||||
omega = np.arange(embed_dim // 2, dtype=np.float32)
|
||||
omega /= embed_dim / 2.
|
||||
omega = 1. / 10000**omega # (D/2,)
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||
import glob
|
||||
import math
|
||||
import os
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
@ -7,11 +9,18 @@ from PIL import Image
|
||||
|
||||
from easycv.file import io
|
||||
from easycv.framework.errors import ValueError
|
||||
from easycv.utils.checkpoint import load_checkpoint
|
||||
from easycv.utils.misc import deprecated
|
||||
from .base import InputProcessor, OutputProcessor, Predictor, PredictorV2
|
||||
from .builder import PREDICTORS
|
||||
|
||||
|
||||
# onnx specific
|
||||
def onnx_to_numpy(tensor):
|
||||
return tensor.detach().cpu().numpy(
|
||||
) if tensor.requires_grad else tensor.cpu().numpy()
|
||||
|
||||
|
||||
class ClsInputProcessor(InputProcessor):
|
||||
"""Process inputs for classification models.
|
||||
|
||||
@ -146,6 +155,20 @@ class ClassificationPredictor(PredictorV2):
|
||||
self.pil_input = pil_input
|
||||
self.label_map_path = label_map_path
|
||||
|
||||
if model_path.endswith('onnx'):
|
||||
self.model_type = 'onnx'
|
||||
pwd_model = os.path.dirname(model_path)
|
||||
raw_model = glob.glob(
|
||||
os.path.join(pwd_model, '*.onnx.config.json'))
|
||||
if len(raw_model) != 0:
|
||||
config_file = raw_model[0]
|
||||
else:
|
||||
assert len(
|
||||
raw_model
|
||||
) == 0, 'Please have a file with the .onnx.config.json extension in your directory'
|
||||
else:
|
||||
self.model_type = 'raw'
|
||||
|
||||
if self.pil_input:
|
||||
mode = 'RGB'
|
||||
super(ClassificationPredictor, self).__init__(
|
||||
@ -186,6 +209,41 @@ class ClassificationPredictor(PredictorV2):
|
||||
|
||||
return ClsOutputProcessor(topk=self.topk, label_map=self.label_map)
|
||||
|
||||
def prepare_model(self):
|
||||
"""Build model from config file by default.
|
||||
If the model is not loaded from a configuration file, e.g. torch jit model, you need to reimplement it.
|
||||
"""
|
||||
if self.model_type == 'raw':
|
||||
model = self._build_model()
|
||||
model.to(self.device)
|
||||
model.eval()
|
||||
load_checkpoint(model, self.model_path, map_location='cpu')
|
||||
return model
|
||||
else:
|
||||
import onnxruntime
|
||||
if onnxruntime.get_device() == 'GPU':
|
||||
onnx_model = onnxruntime.InferenceSession(
|
||||
self.model_path, providers=['CUDAExecutionProvider'])
|
||||
else:
|
||||
onnx_model = onnxruntime.InferenceSession(self.model_path)
|
||||
|
||||
return onnx_model
|
||||
|
||||
def model_forward(self, inputs):
|
||||
"""Model forward.
|
||||
If you need refactor model forward, you need to reimplement it.
|
||||
"""
|
||||
with torch.no_grad():
|
||||
if self.model_type == 'raw':
|
||||
outputs = self.model(**inputs, mode='test')
|
||||
else:
|
||||
outputs = self.model.run(None, {
|
||||
self.model.get_inputs()[0].name:
|
||||
onnx_to_numpy(inputs['img'])
|
||||
})[0]
|
||||
outputs = dict(prob=torch.from_numpy(outputs))
|
||||
return outputs
|
||||
|
||||
|
||||
try:
|
||||
from easy_vision.python.inference.predictor import PredictorInterface
|
||||
|
@ -23,6 +23,12 @@ except Exception:
|
||||
from .interface import PredictorInterface
|
||||
|
||||
|
||||
# 将张量转化为ndarray格式
|
||||
def onnx_to_numpy(tensor):
|
||||
return tensor.detach().cpu().numpy(
|
||||
) if tensor.requires_grad else tensor.cpu().numpy()
|
||||
|
||||
|
||||
class DetInputProcessor(InputProcessor):
|
||||
|
||||
def build_processor(self):
|
||||
@ -349,9 +355,11 @@ class YoloXPredictor(DetectionPredictor):
|
||||
self.model_type = 'jit'
|
||||
elif model_path.endswith('blade'):
|
||||
self.model_type = 'blade'
|
||||
elif model_path.endswith('onnx'):
|
||||
self.model_type = 'onnx'
|
||||
else:
|
||||
self.model_type = 'raw'
|
||||
assert self.model_type in ['raw', 'jit', 'blade']
|
||||
assert self.model_type in ['raw', 'jit', 'blade', 'onnx']
|
||||
|
||||
if self.model_type == 'blade' or self.use_trt_efficientnms:
|
||||
import torch_blade
|
||||
@ -381,8 +389,16 @@ class YoloXPredictor(DetectionPredictor):
|
||||
|
||||
def _build_model(self):
|
||||
if self.model_type != 'raw':
|
||||
with io.open(self.model_path, 'rb') as infile:
|
||||
model = torch.jit.load(infile, self.device)
|
||||
if self.model_type != 'onnx':
|
||||
with io.open(self.model_path, 'rb') as infile:
|
||||
model = torch.jit.load(infile, self.device)
|
||||
else:
|
||||
import onnxruntime
|
||||
if onnxruntime.get_device() == 'GPU':
|
||||
model = onnxruntime.InferenceSession(
|
||||
self.model_path, providers=['CUDAExecutionProvider'])
|
||||
else:
|
||||
model = onnxruntime.InferenceSession(self.model_path)
|
||||
else:
|
||||
from easycv.utils.misc import reparameterize_models
|
||||
model = super()._build_model()
|
||||
@ -394,8 +410,9 @@ class YoloXPredictor(DetectionPredictor):
|
||||
If the model is not loaded from a configuration file, e.g. torch jit model, you need to reimplement it.
|
||||
"""
|
||||
model = self._build_model()
|
||||
model.to(self.device)
|
||||
model.eval()
|
||||
if self.model_type != 'onnx':
|
||||
model.to(self.device)
|
||||
model.eval()
|
||||
if self.model_type == 'raw':
|
||||
load_checkpoint(model, self.model_path, map_location='cpu')
|
||||
return model
|
||||
@ -406,7 +423,15 @@ class YoloXPredictor(DetectionPredictor):
|
||||
"""
|
||||
if self.model_type != 'raw':
|
||||
with torch.no_grad():
|
||||
outputs = self.model(inputs['img'])
|
||||
if self.model_type != 'onnx':
|
||||
outputs = self.model(inputs['img'])
|
||||
else:
|
||||
outputs = self.model.run(
|
||||
None, {
|
||||
self.model.get_inputs()[0].name:
|
||||
onnx_to_numpy(inputs['img'])
|
||||
})[0]
|
||||
outputs = torch.from_numpy(outputs)
|
||||
outputs = {'results': outputs} # convert to dict format
|
||||
else:
|
||||
outputs = super().model_forward(inputs)
|
||||
|
@ -19,6 +19,8 @@ from easycv.utils.config_tools import mmcv_config_fromfile
|
||||
from easycv.utils.misc import deprecated
|
||||
from .base import InputProcessor, OutputProcessor, PredictorV2
|
||||
|
||||
np.set_printoptions(suppress=True)
|
||||
|
||||
|
||||
def _box2cs(image_size, box):
|
||||
"""This encodes bbox(x,y,w,h) into (center, scale)
|
||||
@ -222,11 +224,12 @@ class PoseTopDownInputProcessor(InputProcessor):
|
||||
bboxes = bboxes[valid_idx]
|
||||
person_results = [person_results[i] for i in valid_idx]
|
||||
|
||||
output_person_info = []
|
||||
results = []
|
||||
for person_result in person_results:
|
||||
box = person_result['bbox'] # x,y,x,y
|
||||
box = [box[0], box[1], box[2] - box[0], box[3] - box[1]] # x,y,w,h
|
||||
center, scale = _box2cs(self.cfg.data_cfg['image_size'], box)
|
||||
box = person_result['bbox'] # x,y,x,y,s
|
||||
boxc = [box[0], box[1], box[2] - box[0],
|
||||
box[3] - box[1]] # x,y,w,h
|
||||
center, scale = _box2cs(self.cfg.data_cfg['image_size'], boxc)
|
||||
data = {
|
||||
'image_id':
|
||||
0,
|
||||
@ -264,11 +267,10 @@ class PoseTopDownInputProcessor(InputProcessor):
|
||||
output['img_fields'],
|
||||
}
|
||||
box_id += 1
|
||||
output_person_info.append(data)
|
||||
data_processor = self.processor(data)
|
||||
data_processor['bbox'] = box
|
||||
results.append(data_processor)
|
||||
|
||||
results = []
|
||||
for output in output_person_info:
|
||||
results.append(self.processor(output))
|
||||
return results
|
||||
|
||||
def __call__(self, inputs):
|
||||
@ -296,12 +298,7 @@ class PoseTopDownOutputProcessor(OutputProcessor):
|
||||
def __call__(self, inputs):
|
||||
output = {}
|
||||
output['keypoints'] = inputs['preds']
|
||||
output['bbox'] = inputs['boxes'] # c1, c2, s1, s2, area, core
|
||||
|
||||
for i, bbox in enumerate(output['bbox']):
|
||||
center, scale = bbox[:2], bbox[2:4]
|
||||
output['bbox'][i][:4] = bbox_cs2xyxy(center, scale)
|
||||
output['bbox'] = output['bbox'][:, [0, 1, 2, 3, 5]]
|
||||
output['bbox'] = np.array(inputs['boxes']) # x1, y1, x2, y2 score
|
||||
|
||||
return output
|
||||
|
||||
@ -403,6 +400,7 @@ class PoseTopDownPredictor(PredictorV2):
|
||||
return model
|
||||
|
||||
def model_forward(self, inputs, return_heatmap=False):
|
||||
boxes = inputs['bbox'].cpu().numpy()
|
||||
if self.model_type == 'raw':
|
||||
with torch.no_grad():
|
||||
result = self.model(
|
||||
@ -423,6 +421,7 @@ class PoseTopDownPredictor(PredictorV2):
|
||||
result = decode_heatmap(output_heatmap, img_metas,
|
||||
self.cfg.model.test_cfg)
|
||||
|
||||
result['boxes'] = np.array(boxes)
|
||||
return result
|
||||
|
||||
def get_input_processor(self):
|
||||
|
@ -156,7 +156,7 @@ class Mask2formerOutputProcessor(OutputProcessor):
|
||||
ids = ids[legal_indices]
|
||||
labels = np.array([id % 1000 for id in ids], dtype=np.int64)
|
||||
segms = (pan_results[None] == ids[:, None, None])
|
||||
masks = [it.astype(np.int) for it in segms]
|
||||
masks = [it.astype(np.int32) for it in segms]
|
||||
labels_txt = np.array(self.classes)[labels].tolist()
|
||||
|
||||
output['masks'] = masks
|
||||
|
@ -38,7 +38,7 @@ class STrack(BaseTrack):
|
||||
def __init__(self, tlwh, score):
|
||||
|
||||
# wait activate
|
||||
self._tlwh = np.asarray(tlwh, dtype=np.float)
|
||||
self._tlwh = np.asarray(tlwh, dtype=np.float32)
|
||||
self.kalman_filter = None
|
||||
self.mean, self.covariance = None, None
|
||||
self.is_activated = False
|
||||
|
12
easycv/thirdparty/mot/bytetrack/matching.py
vendored
12
easycv/thirdparty/mot/bytetrack/matching.py
vendored
@ -86,15 +86,15 @@ def ious(atlbrs, btlbrs):
|
||||
|
||||
:rtype ious np.ndarray
|
||||
"""
|
||||
ious = np.zeros((len(atlbrs), len(btlbrs)), dtype=np.float)
|
||||
ious = np.zeros((len(atlbrs), len(btlbrs)), dtype=np.float32)
|
||||
if ious.size == 0:
|
||||
return ious
|
||||
|
||||
from cython_bbox import bbox_overlaps as bbox_ious
|
||||
|
||||
ious = bbox_ious(
|
||||
np.ascontiguousarray(atlbrs, dtype=np.float),
|
||||
np.ascontiguousarray(btlbrs, dtype=np.float))
|
||||
np.ascontiguousarray(atlbrs, dtype=np.float32),
|
||||
np.ascontiguousarray(btlbrs, dtype=np.float32))
|
||||
|
||||
return ious
|
||||
|
||||
@ -151,15 +151,15 @@ def embedding_distance(tracks, detections, metric='cosine'):
|
||||
:return: cost_matrix np.ndarray
|
||||
"""
|
||||
|
||||
cost_matrix = np.zeros((len(tracks), len(detections)), dtype=np.float)
|
||||
cost_matrix = np.zeros((len(tracks), len(detections)), dtype=np.float32)
|
||||
if cost_matrix.size == 0:
|
||||
return cost_matrix
|
||||
det_features = np.asarray([track.curr_feat for track in detections],
|
||||
dtype=np.float)
|
||||
dtype=np.float32)
|
||||
#for i, track in enumerate(tracks):
|
||||
#cost_matrix[i, :] = np.maximum(0.0, cdist(track.smooth_feat.reshape(1,-1), det_features, metric))
|
||||
track_features = np.asarray([track.smooth_feat for track in tracks],
|
||||
dtype=np.float)
|
||||
dtype=np.float32)
|
||||
cost_matrix = np.maximum(0.0, cdist(track_features, det_features,
|
||||
metric)) # Nomalized features
|
||||
return cost_matrix
|
||||
|
@ -1,5 +1 @@
|
||||
import os
|
||||
|
||||
from . import models, msdatasets, pipelines, trainers
|
||||
|
||||
os.environ['SETUPTOOLS_USE_DISTUTILS'] = 'stdlib'
|
||||
|
@ -48,9 +48,15 @@ class EasyCVDetectionPipeline(EasyCVPipeline):
|
||||
labels = []
|
||||
boxes = []
|
||||
for output in outputs:
|
||||
for score, label, box in zip(output['detection_scores'],
|
||||
output['detection_classes'],
|
||||
output['detection_boxes']):
|
||||
scores_list = output['detection_scores'] if output[
|
||||
'detection_scores'] is not None else []
|
||||
classes_list = output['detection_classes'] if output[
|
||||
'detection_classes'] is not None else []
|
||||
boxes_list = output['detection_boxes'] if output[
|
||||
'detection_boxes'] is not None else []
|
||||
|
||||
for score, label, box in zip(scores_list, classes_list,
|
||||
boxes_list):
|
||||
scores.append(score)
|
||||
labels.append(self.cfg.CLASSES[label])
|
||||
boxes.append([b for b in box])
|
||||
|
@ -36,7 +36,7 @@ class EasyCVSegmentationPipeline(EasyCVPipeline):
|
||||
legal_indices = ids != len(self.predict_op.CLASSES) # for VOID label
|
||||
ids = ids[legal_indices]
|
||||
segms = (semantic_result[None] == ids[:, None, None])
|
||||
masks = [it.astype(np.int) for it in segms]
|
||||
masks = [it.astype(np.int32) for it in segms]
|
||||
labels_txt = np.array(self.predict_op.CLASSES)[ids].tolist()
|
||||
|
||||
results = {
|
||||
|
@ -515,6 +515,10 @@ CONFIG_TEMPLATE_ZOO = {
|
||||
'configs/classification/imagenet/swint/imagenet_swin_tiny_patch4_window7_224_jpg.py',
|
||||
'CLASSIFICATION_M0BILENET':
|
||||
'configs/classification/imagenet/mobilenet/mobilenetv2.py',
|
||||
'CLASSIFICATION_INCEPTIONV4':
|
||||
'configs/classification/imagenet/inception/inceptionv4_b32x8_100e.py',
|
||||
'CLASSIFICATION_INCEPTIONV3':
|
||||
'configs/classification/imagenet/inception/inceptionv3_b32x8_100e.py',
|
||||
|
||||
# metric learning
|
||||
'METRICLEARNING':
|
||||
|
@ -2,5 +2,5 @@
|
||||
# GENERATED VERSION FILE
|
||||
# TIME: Thu Nov 5 14:17:50 2020
|
||||
|
||||
__version__ = '0.11.0'
|
||||
short_version = '0.11.0'
|
||||
__version__ = '0.11.7'
|
||||
short_version = '0.11.7'
|
||||
|
@ -13,6 +13,7 @@ lmdb
|
||||
numba
|
||||
numpy
|
||||
nuscenes-devkit
|
||||
onnxruntime
|
||||
opencv-python
|
||||
oss2
|
||||
packaging
|
||||
@ -23,8 +24,9 @@ pycocotools
|
||||
pytorch_metric_learning>=0.9.89
|
||||
rapidfuzz
|
||||
scikit-image
|
||||
scikit-learn
|
||||
seaborn
|
||||
sklearn
|
||||
shapely==1.8.4
|
||||
tensorboard
|
||||
thop
|
||||
timm==0.5.4
|
||||
|
22
tests/run.py
22
tests/run.py
@ -8,15 +8,26 @@ import unittest
|
||||
from fnmatch import fnmatch
|
||||
|
||||
|
||||
def gather_test_cases(test_dir, pattern, list_tests):
|
||||
def get_skip_file(skip_dir, pattern=None):
|
||||
case_list = []
|
||||
if skip_dir:
|
||||
for path in skip_dir:
|
||||
for dirpath, dirnames, filenames in os.walk(path):
|
||||
for file in filenames:
|
||||
if fnmatch(file, pattern):
|
||||
case_list.append(file)
|
||||
return case_list
|
||||
|
||||
|
||||
def gather_test_cases(test_dir, pattern, list_tests, skip_dir):
|
||||
case_list = []
|
||||
skip_list = get_skip_file(skip_dir, pattern)
|
||||
for dirpath, dirnames, filenames in os.walk(test_dir):
|
||||
for file in filenames:
|
||||
if fnmatch(file, pattern):
|
||||
if fnmatch(file, pattern) and file not in skip_list:
|
||||
case_list.append(file)
|
||||
|
||||
test_suite = unittest.TestSuite()
|
||||
|
||||
for case in case_list:
|
||||
test_case = unittest.defaultTestLoader.discover(
|
||||
start_dir=test_dir, pattern=case)
|
||||
@ -34,7 +45,8 @@ def gather_test_cases(test_dir, pattern, list_tests):
|
||||
def main(args):
|
||||
runner = unittest.TextTestRunner()
|
||||
test_suite = gather_test_cases(
|
||||
os.path.abspath(args.test_dir), args.pattern, args.list_tests)
|
||||
os.path.abspath(args.test_dir), args.pattern, args.list_tests,
|
||||
args.skip_dir)
|
||||
if not args.list_tests:
|
||||
result = runner.run(test_suite)
|
||||
if len(result.failures) > 0 or len(result.errors) > 0:
|
||||
@ -49,5 +61,7 @@ if __name__ == '__main__':
|
||||
'--pattern', default='test_*.py', help='test file pattern')
|
||||
parser.add_argument(
|
||||
'--test_dir', default='tests', help='directory to be tested')
|
||||
parser.add_argument(
|
||||
'--skip_dir', nargs='+', required=False, help='it`s not run testcase')
|
||||
args = parser.parse_args()
|
||||
main(args)
|
||||
|
@ -116,6 +116,7 @@ class ModelExportTest(unittest.TestCase):
|
||||
cfg = mmcv_config_fromfile(config_file)
|
||||
cfg_options = {
|
||||
'model.backbone.norm_cfg.type': 'SyncBN',
|
||||
'export.export_type': 'raw'
|
||||
}
|
||||
if cfg_options is not None:
|
||||
cfg.merge_from_dict(cfg_options)
|
||||
@ -210,6 +211,27 @@ class ModelExportTest(unittest.TestCase):
|
||||
|
||||
self.assertTrue(os.path.exists(filename + '.jit'))
|
||||
|
||||
def test_export_resnet_onnx(self):
|
||||
|
||||
ckpt_path = PRETRAINED_MODEL_RESNET50
|
||||
|
||||
easycv_dir = os.path.dirname(easycv.__file__)
|
||||
|
||||
if os.path.exists(os.path.join(easycv_dir, 'configs')):
|
||||
config_dir = os.path.join(easycv_dir, 'configs')
|
||||
else:
|
||||
config_dir = os.path.join(os.path.dirname(easycv_dir), 'configs')
|
||||
config_file = os.path.join(
|
||||
config_dir,
|
||||
'classification/imagenet/resnet/imagenet_resnet50_jpg.py')
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
cfg = mmcv_config_fromfile(config_file)
|
||||
cfg.export.export_type = 'onnx'
|
||||
filename = os.path.join(tmpdir, 'imagenet_resnet50')
|
||||
export(cfg, ckpt_path, filename)
|
||||
self.assertTrue(os.path.exists(filename + '.onnx'))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -89,8 +89,8 @@ class CocoToolsTest(unittest.TestCase):
|
||||
def testExportGroundtruthToCOCO(self):
|
||||
image_ids = ['first', 'second']
|
||||
groundtruth_boxes = [
|
||||
np.array([[100, 100, 200, 200]], np.float),
|
||||
np.array([[50, 50, 100, 100]], np.float)
|
||||
np.array([[100, 100, 200, 200]], np.float32),
|
||||
np.array([[50, 50, 100, 100]], np.float32)
|
||||
]
|
||||
groundtruth_classes = [
|
||||
np.array([1], np.int32),
|
||||
@ -126,12 +126,12 @@ class CocoToolsTest(unittest.TestCase):
|
||||
def testExportDetectionsToCOCO(self):
|
||||
image_ids = ['first', 'second']
|
||||
detections_boxes = [
|
||||
np.array([[100, 100, 200, 200]], np.float),
|
||||
np.array([[50, 50, 100, 100]], np.float)
|
||||
np.array([[100, 100, 200, 200]], np.float32),
|
||||
np.array([[50, 50, 100, 100]], np.float32)
|
||||
]
|
||||
detections_scores = [
|
||||
np.array([.8], np.float),
|
||||
np.array([.7], np.float)
|
||||
np.array([.8], np.float32),
|
||||
np.array([.7], np.float32)
|
||||
]
|
||||
detections_classes = [np.array([1], np.int32), np.array([1], np.int32)]
|
||||
categories = [{
|
||||
@ -152,7 +152,17 @@ class CocoToolsTest(unittest.TestCase):
|
||||
detections_classes,
|
||||
categories,
|
||||
output_path=output_path)
|
||||
self.assertListEqual(result, self._detections_list)
|
||||
|
||||
self.assertEqual(len(result), len(detections_boxes))
|
||||
self.assertEqual(len(detections_boxes), len(detections_boxes))
|
||||
|
||||
score_list = []
|
||||
for i in range(len(detections_boxes)):
|
||||
score = self._detections_list[i].pop('score')
|
||||
score_list.append(score)
|
||||
self.assertAlmostEqual(result[i].pop('score'), score)
|
||||
self.assertDictEqual(result[i], self._detections_list[i])
|
||||
|
||||
with io.open(output_path, 'r') as f:
|
||||
written_result = f.read()
|
||||
# The json output should have floats written to 4 digits of precision.
|
||||
@ -160,7 +170,10 @@ class CocoToolsTest(unittest.TestCase):
|
||||
re.MULTILINE)
|
||||
self.assertTrue(matcher.findall(written_result))
|
||||
written_result = json.loads(written_result)
|
||||
self.assertAlmostEqual(result, written_result)
|
||||
for i in range(len(result)):
|
||||
self.assertAlmostEqual(written_result[i].pop('score'),
|
||||
score_list[i])
|
||||
self.assertDictEqual(result[i], written_result[i])
|
||||
|
||||
def testExportSegmentsToCOCO(self):
|
||||
image_ids = ['first', 'second']
|
||||
@ -176,7 +189,10 @@ class CocoToolsTest(unittest.TestCase):
|
||||
for i, detection_mask in enumerate(detection_masks):
|
||||
detection_masks[i] = detection_mask[:, :, :, None]
|
||||
|
||||
detection_scores = [np.array([.8], np.float), np.array([.7], np.float)]
|
||||
detection_scores = [
|
||||
np.array([.8], np.float32),
|
||||
np.array([.7], np.float32)
|
||||
]
|
||||
detection_classes = [np.array([1], np.int32), np.array([1], np.int32)]
|
||||
|
||||
categories = [{
|
||||
@ -202,7 +218,12 @@ class CocoToolsTest(unittest.TestCase):
|
||||
written_result = json.loads(written_result)
|
||||
mask_load = mask.decode([written_result[0]['segmentation']])
|
||||
self.assertTrue(np.allclose(mask_load, detection_masks[0]))
|
||||
self.assertAlmostEqual(result, written_result)
|
||||
self.assertEqual(len(result), len(detection_masks))
|
||||
self.assertEqual(len(written_result), len(detection_masks))
|
||||
for i in range(len(detection_masks)):
|
||||
self.assertAlmostEqual(result[i].pop('score'),
|
||||
written_result[i].pop('score'))
|
||||
self.assertDictEqual(result[i], written_result[i])
|
||||
|
||||
def testExportKeypointsToCOCO(self):
|
||||
image_ids = ['first', 'second']
|
||||
@ -216,8 +237,8 @@ class CocoToolsTest(unittest.TestCase):
|
||||
]
|
||||
|
||||
detection_scores = [
|
||||
np.array([.8, 0.2], np.float),
|
||||
np.array([.7, 0.3], np.float)
|
||||
np.array([.8, 0.2], np.float32),
|
||||
np.array([.7, 0.3], np.float32)
|
||||
]
|
||||
detection_classes = [
|
||||
np.array([1, 1], np.int32),
|
||||
@ -248,7 +269,12 @@ class CocoToolsTest(unittest.TestCase):
|
||||
with io.open(output_path, 'r') as f:
|
||||
written_result = f.read()
|
||||
written_result = json.loads(written_result)
|
||||
self.assertAlmostEqual(result, written_result)
|
||||
self.assertEqual(len(result), 4)
|
||||
self.assertEqual(len(written_result), 4)
|
||||
for i in range(4):
|
||||
self.assertAlmostEqual(result[i].pop('score'),
|
||||
written_result[i].pop('score'))
|
||||
self.assertDictEqual(result[i], written_result[i])
|
||||
|
||||
def testSingleImageDetectionBoxesExport(self):
|
||||
boxes = np.array([[0, 0, 1, 1], [0, 0, .5, .5], [.5, .5, 1, 1]],
|
||||
|
63
tests/test_models/backbones/test_inceptionv4.py
Normal file
63
tests/test_models/backbones/test_inceptionv4.py
Normal file
@ -0,0 +1,63 @@
|
||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||
import copy
|
||||
import random
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import torch
|
||||
|
||||
from easycv.models import modelzoo
|
||||
from easycv.models.backbones import Inception4
|
||||
|
||||
|
||||
class InceptionV3Test(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
print(('Testing %s.%s' % (type(self).__name__, self._testMethodName)))
|
||||
|
||||
def test_inceptionv3_withfc(self):
|
||||
with torch.no_grad():
|
||||
# input data
|
||||
batch_size = random.randint(10, 30)
|
||||
a = torch.rand(batch_size, 3, 299, 299).to('cuda')
|
||||
|
||||
num_classes = random.randint(10, 1000)
|
||||
net = Inception4(
|
||||
aux_logits=True, num_classes=num_classes).to('cuda')
|
||||
net.init_weights()
|
||||
net.train()
|
||||
|
||||
self.assertTrue(len(list(net(a)[-1].shape)) == 2)
|
||||
self.assertTrue(len(list(net(a)[0].shape)) == 2)
|
||||
self.assertTrue(net(a)[-1].size(1) == num_classes)
|
||||
self.assertTrue(net(a)[-1].size(0) == batch_size)
|
||||
self.assertTrue(net(a)[0].size(1) == num_classes)
|
||||
self.assertTrue(net(a)[0].size(0) == batch_size)
|
||||
|
||||
def test_inceptionv3_withoutfc(self):
|
||||
with torch.no_grad():
|
||||
# input data
|
||||
batch_size = random.randint(10, 30)
|
||||
a = torch.rand(batch_size, 3, 299, 299).to('cuda')
|
||||
|
||||
net = Inception4(aux_logits=True, num_classes=0).to('cuda')
|
||||
net.init_weights()
|
||||
net.eval()
|
||||
|
||||
self.assertTrue(net(a)[-1].size(1) == 1536)
|
||||
self.assertTrue(net(a)[-1].size(0) == batch_size)
|
||||
|
||||
def test_inceptionv3_load_modelzoo(self):
|
||||
with torch.no_grad():
|
||||
net = Inception4(aux_logits=True, num_classes=1000).to('cuda')
|
||||
original_weight = net.features[0].conv.weight
|
||||
original_weight = copy.deepcopy(original_weight.cpu().data.numpy())
|
||||
|
||||
net.init_weights()
|
||||
load_weight = net.features[0].conv.weight.cpu().data.numpy()
|
||||
|
||||
self.assertFalse(np.allclose(original_weight, load_weight))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -40,9 +40,9 @@ class YOLOXTest(unittest.TestCase):
|
||||
}
|
||||
output = model(imgs, mode='train', **kwargs)
|
||||
self.assertEqual(output['img_h'].cpu().numpy(),
|
||||
np.array(640, dtype=np.float))
|
||||
np.array(640, dtype=np.float32))
|
||||
self.assertEqual(output['img_w'].cpu().numpy(),
|
||||
np.array(640, dtype=np.float))
|
||||
np.array(640, dtype=np.float32))
|
||||
self.assertEqual(output['total_loss'].shape, torch.Size([]))
|
||||
self.assertEqual(output['iou_l'].shape, torch.Size([]))
|
||||
self.assertEqual(output['conf_l'].shape, torch.Size([]))
|
||||
|
@ -45,9 +45,9 @@ class YOLOXEDGETest(unittest.TestCase):
|
||||
}
|
||||
output = model(imgs, mode='train', **kwargs)
|
||||
self.assertEqual(output['img_h'].cpu().numpy(),
|
||||
np.array(640, dtype=np.float))
|
||||
np.array(640, dtype=np.float32))
|
||||
self.assertEqual(output['img_w'].cpu().numpy(),
|
||||
np.array(640, dtype=np.float))
|
||||
np.array(640, dtype=np.float32))
|
||||
self.assertEqual(output['total_loss'].shape, torch.Size([]))
|
||||
self.assertEqual(output['iou_l'].shape, torch.Size([]))
|
||||
self.assertEqual(output['conf_l'].shape, torch.Size([]))
|
||||
|
@ -11,7 +11,8 @@ import torch
|
||||
from easycv.predictors.classifier import ClassificationPredictor
|
||||
from easycv.utils.test_util import clean_up, get_tmp_dir
|
||||
from tests.ut_config import (PRETRAINED_MODEL_RESNET50_WITHOUTHEAD,
|
||||
IMAGENET_LABEL_TXT, TEST_IMAGES_DIR)
|
||||
IMAGENET_LABEL_TXT, TEST_IMAGES_DIR,
|
||||
PRETRAINED_MODEL_RESNET50_ONNX_WITHOUTHEAD)
|
||||
|
||||
|
||||
class ClassificationPredictorTest(unittest.TestCase):
|
||||
@ -33,6 +34,17 @@ class ClassificationPredictorTest(unittest.TestCase):
|
||||
self.assertListEqual(results['class_name'], ['"Persian cat",'])
|
||||
self.assertEqual(len(results['class_probs']), 1000)
|
||||
|
||||
def test_onnx_single(self):
|
||||
checkpoint = PRETRAINED_MODEL_RESNET50_ONNX_WITHOUTHEAD
|
||||
predict_op = ClassificationPredictor(model_path=checkpoint)
|
||||
|
||||
img_path = os.path.join(TEST_IMAGES_DIR, 'catb.jpg')
|
||||
|
||||
results = predict_op([img_path])[0]
|
||||
self.assertListEqual(results['class'], [578])
|
||||
self.assertListEqual(results['class_name'], ['gown'])
|
||||
self.assertEqual(len(results['class_probs']), 1000)
|
||||
|
||||
def test_batch(self):
|
||||
checkpoint = PRETRAINED_MODEL_RESNET50_WITHOUTHEAD
|
||||
config_file = 'configs/classification/imagenet/resnet/imagenet_resnet50_jpg.py'
|
||||
|
@ -54,10 +54,10 @@ class PoseTopDownPredictorTest(unittest.TestCase):
|
||||
|
||||
assert_array_almost_equal(
|
||||
result0['bbox'],
|
||||
np.array([[352.3085, 59.00325, 691.4247, 511.15814, 1.],
|
||||
[10.511196, 177.74883, 101.824326, 299.49966, 1.],
|
||||
[224.82036, 114.439865, 312.51306, 231.36348, 1.],
|
||||
[200.71407, 114.716736, 337.17535, 296.6651, 1.]],
|
||||
np.array([[438.9, 59., 604.8, 511.2, 0.9],
|
||||
[10.5, 179.6, 101.8, 297.7, 0.9],
|
||||
[229.6, 114.4, 307.8, 231.4, 0.6],
|
||||
[229.4, 114.7, 308.5, 296.7, 0.6]],
|
||||
dtype=np.float32),
|
||||
decimal=1)
|
||||
vis_result = predictor.show_result(img1, result0)
|
||||
@ -92,10 +92,10 @@ class PoseTopDownPredictorTest(unittest.TestCase):
|
||||
|
||||
assert_array_almost_equal(
|
||||
result1['bbox'][:4],
|
||||
np.array([[436.23096, 214.72766, 584.26013, 412.09985, 1.],
|
||||
[43.990044, 91.04126, 164.28406, 251.43329, 1.],
|
||||
[127.44148, 100.38604, 254.219, 269.42273, 1.],
|
||||
[190.08075, 117.31801, 311.22394, 278.8423, 1.]],
|
||||
np.array([[470.6, 214.7, 549.9, 412.1, 0.9],
|
||||
[71.6, 91., 136.7, 251.4, 0.9],
|
||||
[159.7, 100.4, 221.9, 269.4, 0.9],
|
||||
[219.4, 117.3, 281.9, 278.8, 0.9]],
|
||||
dtype=np.float32),
|
||||
decimal=1)
|
||||
vis_result = predictor.show_result(img2, result1)
|
||||
|
@ -8,13 +8,11 @@ from modelscope.outputs import OutputKeys
|
||||
from modelscope.pipelines import pipeline
|
||||
from modelscope.utils.constant import Tasks
|
||||
from modelscope.utils.cv.image_utils import panoptic_seg_masks_to_image
|
||||
from modelscope.utils.demo_utils import DemoCompatibilityCheck
|
||||
from modelscope.utils.test_utils import test_level
|
||||
from tests.ut_config import BASE_LOCAL_PATH
|
||||
|
||||
|
||||
class EasyCVPanopticSegmentationPipelineTest(unittest.TestCase,
|
||||
DemoCompatibilityCheck):
|
||||
class EasyCVPanopticSegmentationPipelineTest(unittest.TestCase):
|
||||
img_path = os.path.join(
|
||||
BASE_LOCAL_PATH, 'data/test_images/image_semantic_segmentation.jpg')
|
||||
|
||||
@ -32,10 +30,6 @@ class EasyCVPanopticSegmentationPipelineTest(unittest.TestCase,
|
||||
cv2.imwrite(tmp_save_path, draw_img)
|
||||
print('print ' + self.model_id + ' success')
|
||||
|
||||
@unittest.skipUnless(test_level() >= 0, 'skip test in current test level')
|
||||
def test_demo_compatibility(self):
|
||||
self.compatibility_check()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -9,14 +9,12 @@ from modelscope.outputs import OutputKeys
|
||||
from modelscope.pipelines import pipeline
|
||||
from modelscope.utils.constant import Tasks
|
||||
from modelscope.utils.cv.image_utils import semantic_seg_masks_to_image
|
||||
from modelscope.utils.demo_utils import DemoCompatibilityCheck
|
||||
from modelscope.utils.test_utils import test_level
|
||||
from PIL import Image
|
||||
from tests.ut_config import BASE_LOCAL_PATH
|
||||
|
||||
|
||||
class EasyCVSegmentationPipelineTest(unittest.TestCase,
|
||||
DemoCompatibilityCheck):
|
||||
class EasyCVSegmentationPipelineTest(unittest.TestCase):
|
||||
img_path = os.path.join(BASE_LOCAL_PATH,
|
||||
'data/test_images/image_segmentation.jpg')
|
||||
|
||||
@ -82,10 +80,6 @@ class EasyCVSegmentationPipelineTest(unittest.TestCase,
|
||||
model_id = 'damo/cv_segformer-b5_image_semantic-segmentation_coco-stuff164k'
|
||||
self._internal_test_(model_id)
|
||||
|
||||
@unittest.skipUnless(test_level() >= 0, 'skip test in current test level')
|
||||
def test_demo_compatibility(self):
|
||||
self.compatibility_check()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -40,6 +40,7 @@ class EasyCVTrainerTestDetectionDino(unittest.TestCase):
|
||||
train_dataset=train_dataset,
|
||||
eval_dataset=eval_dataset,
|
||||
work_dir=tmp_dir,
|
||||
use_fp16=True,
|
||||
cfg_options=cfg_options)
|
||||
|
||||
trainer = build_trainer(trainer_name, kwargs)
|
||||
|
@ -98,7 +98,9 @@ class ClassificationTrainTest(unittest.TestCase):
|
||||
(tmp_cfg_file, work_dir, args_str)
|
||||
|
||||
logging.info('run command: %s' % cmd)
|
||||
run_in_subprocess(cmd)
|
||||
# run_in_subprocess(cmd) # 管道缓冲区被写满,后面的写入请求都hang住了
|
||||
import subprocess
|
||||
subprocess.call(cmd, shell=True)
|
||||
|
||||
output_files = io.listdir(work_dir)
|
||||
self.assertIn('epoch_1.pth', output_files)
|
||||
|
138
tests/test_tools/test_export.py
Normal file
138
tests/test_tools/test_export.py
Normal file
@ -0,0 +1,138 @@
|
||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||
import logging
|
||||
import os
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
import numpy as np
|
||||
import onnxruntime
|
||||
import torch
|
||||
|
||||
from easycv.models import build_model
|
||||
from easycv.utils.checkpoint import load_checkpoint
|
||||
from easycv.utils.config_tools import mmcv_config_fromfile, rebuild_config
|
||||
from easycv.utils.test_util import run_in_subprocess
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
logging.basicConfig(level=logging.INFO)
|
||||
|
||||
WORK_DIRECTORY = 'work_dir3'
|
||||
|
||||
BASIC_EXPORT_CONFIGS = {
|
||||
'config_file': None,
|
||||
'checkpoint': 'dummy',
|
||||
'output_filename': f'{WORK_DIRECTORY}/test_out.pth',
|
||||
'user_config_params': ['--export.export_type', 'onnx']
|
||||
}
|
||||
|
||||
|
||||
def build_cmd(export_configs, MODEL_TYPE) -> str:
|
||||
base_cmd = 'python tools/export.py'
|
||||
base_cmd += f" {export_configs['config_file']}"
|
||||
base_cmd += f" {export_configs['checkpoint']}"
|
||||
base_cmd += f" {export_configs['output_filename']}"
|
||||
base_cmd += f' --model_type {MODEL_TYPE}'
|
||||
user_params = ' '.join(export_configs['user_config_params'])
|
||||
base_cmd += f' --user_config_params {user_params}'
|
||||
return base_cmd
|
||||
|
||||
|
||||
class ExportTest(unittest.TestCase):
|
||||
"""In this unittest, we test the onnx export functionality of
|
||||
some classification/detection models.
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
print(('Testing %s.%s' % (type(self).__name__, self._testMethodName)))
|
||||
os.makedirs(WORK_DIRECTORY, exist_ok=True)
|
||||
|
||||
def tearDown(self):
|
||||
super().tearDown()
|
||||
|
||||
def run_test(self,
|
||||
CONFIG_FILE,
|
||||
MODEL_TYPE,
|
||||
img_size: int = 224,
|
||||
**override_configs):
|
||||
configs = BASIC_EXPORT_CONFIGS.copy()
|
||||
configs['config_file'] = CONFIG_FILE
|
||||
|
||||
configs.update(override_configs)
|
||||
|
||||
cmd = build_cmd(configs, MODEL_TYPE)
|
||||
logging.info(f'Export with commands: {cmd}')
|
||||
run_in_subprocess(cmd)
|
||||
|
||||
cfg = mmcv_config_fromfile(configs['config_file'])
|
||||
cfg = rebuild_config(cfg, configs['user_config_params'])
|
||||
|
||||
if hasattr(cfg.model, 'pretrained'):
|
||||
cfg.model.pretrained = False
|
||||
|
||||
torch_model = build_model(cfg.model).eval()
|
||||
if 'checkpoint' in override_configs:
|
||||
load_checkpoint(
|
||||
torch_model,
|
||||
override_configs['checkpoint'],
|
||||
strict=False,
|
||||
logger=logging.getLogger())
|
||||
session = onnxruntime.InferenceSession(configs['output_filename'] +
|
||||
'.onnx')
|
||||
input_tensor = torch.randn((1, 3, img_size, img_size))
|
||||
|
||||
torch_output = torch_model(input_tensor, mode='test')['prob']
|
||||
|
||||
onnx_output = session.run(
|
||||
[session.get_outputs()[0].name],
|
||||
{session.get_inputs()[0].name: np.array(input_tensor)})
|
||||
if isinstance(onnx_output, list):
|
||||
onnx_output = onnx_output[0]
|
||||
|
||||
onnx_output = torch.tensor(onnx_output)
|
||||
|
||||
is_same_shape = torch_output.shape == onnx_output.shape
|
||||
|
||||
self.assertTrue(
|
||||
is_same_shape,
|
||||
f'The shapes of the two outputs are mismatch, got {torch_output.shape} and {onnx_output.shape}'
|
||||
)
|
||||
is_allclose = torch.allclose(torch_output, onnx_output)
|
||||
|
||||
torch_out_minmax = f'{float(torch_output.min())}~{float(torch_output.max())}'
|
||||
onnx_out_minmax = f'{float(onnx_output.min())}~{float(onnx_output.max())}'
|
||||
|
||||
info_msg = f'got avg: {float(torch_output.mean())} and {float(onnx_output.mean())},'
|
||||
info_msg += f' and range: {torch_out_minmax} and {onnx_out_minmax}'
|
||||
self.assertTrue(
|
||||
is_allclose,
|
||||
f'The values between the two outputs are mismatch, {info_msg}')
|
||||
|
||||
def test_inceptionv3(self):
|
||||
CONFIG_FILE = 'configs/classification/imagenet/inception/inceptionv3_b32x8_100e.py'
|
||||
self.run_test(CONFIG_FILE, 'CLASSIFICATION_INCEPTIONV3', 299)
|
||||
|
||||
def test_inceptionv4(self):
|
||||
CONFIG_FILE = 'configs/classification/imagenet/inception/inceptionv4_b32x8_100e.py'
|
||||
self.run_test(CONFIG_FILE, 'CLASSIFICATION_INCEPTIONV4', 299)
|
||||
|
||||
def test_resnext50(self):
|
||||
CONFIG_FILE = 'configs/classification/imagenet/resnext/imagenet_resnext50-32x4d_jpg.py'
|
||||
self.run_test(
|
||||
CONFIG_FILE,
|
||||
'CLASSIFICATION_RESNEXT',
|
||||
checkpoint=
|
||||
'https://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/EasyCV/modelzoo/classification/resnext/resnext50-32x4d/epoch_100.pth'
|
||||
)
|
||||
|
||||
def test_mobilenetv2(self):
|
||||
CONFIG_FILE = 'configs/classification/imagenet/mobilenet/mobilenetv2.py'
|
||||
self.run_test(
|
||||
CONFIG_FILE,
|
||||
'CLASSIFICATION_M0BILENET',
|
||||
checkpoint=
|
||||
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/mobilenetv2/mobilenet_v2.pth'
|
||||
)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
@ -13,7 +13,7 @@ from mmcv import Config
|
||||
from tests.ut_config import (PRETRAINED_MODEL_SEGFORMER,
|
||||
PRETRAINED_MODEL_YOLOXS_EXPORT, TEST_IMAGES_DIR)
|
||||
|
||||
from easycv.file import io
|
||||
from easycv.file import get_oss_config, io
|
||||
from easycv.utils.test_util import run_in_subprocess
|
||||
|
||||
sys.path.append(os.path.dirname(os.path.realpath(__file__)))
|
||||
@ -75,6 +75,32 @@ class PredictTest(unittest.TestCase):
|
||||
model_path = PRETRAINED_MODEL_YOLOXS_EXPORT
|
||||
self._base_predict(model_type, model_path, dist=True)
|
||||
|
||||
def test_predict_oss_path(self):
|
||||
model_type = 'YoloXPredictor'
|
||||
model_path = PRETRAINED_MODEL_YOLOXS_EXPORT
|
||||
|
||||
os.environ['OSS_CONFIG_FILE'] = '~/.ossutilconfig.unittest'
|
||||
oss_config = get_oss_config()
|
||||
ak_id = oss_config['ak_id']
|
||||
ak_secret = oss_config['ak_secret']
|
||||
hosts = oss_config['hosts']
|
||||
hosts = ','.join(_ for _ in hosts)
|
||||
buckets = oss_config['buckets']
|
||||
buckets = ','.join(_ for _ in buckets)
|
||||
|
||||
input_file = 'oss://pai-vision-data-hz/unittest/local_backup/easycv_nfs/data/test_images/http_image_list.txt'
|
||||
output_file = tempfile.NamedTemporaryFile('w').name
|
||||
cmd = f'PYTHONPATH=. python tools/predict.py \
|
||||
--input_file {input_file} \
|
||||
--output_file {output_file} \
|
||||
--model_type {model_type} \
|
||||
--model_path {model_path} \
|
||||
--oss_io_config ak_id={ak_id} ak_secret={ak_secret} hosts={hosts} buckets={buckets}'
|
||||
|
||||
logging.info('run command: %s' % cmd)
|
||||
run_in_subprocess(cmd)
|
||||
io.remove(output_file)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
||||
|
@ -179,6 +179,9 @@ PRETRAINED_MODEL_RESNET50 = os.path.join(
|
||||
PRETRAINED_MODEL_RESNET50_WITHOUTHEAD = os.path.join(
|
||||
BASE_LOCAL_PATH,
|
||||
'pretrained_models/classification/resnet/resnet50_withhead.pth')
|
||||
PRETRAINED_MODEL_RESNET50_ONNX_WITHOUTHEAD = os.path.join(
|
||||
BASE_LOCAL_PATH,
|
||||
'pretrained_models/classification/resnet/imagenet_resnet50.onnx')
|
||||
PRETRAINED_MODEL_FACEID = os.path.join(BASE_LOCAL_PATH,
|
||||
'pretrained_models/faceid')
|
||||
PRETRAINED_MODEL_YOLOXS_EXPORT = os.path.join(
|
||||
|
@ -10,8 +10,9 @@ import logging
|
||||
import os
|
||||
import threading
|
||||
import traceback
|
||||
|
||||
import torch
|
||||
from mmcv import DictAction
|
||||
from easycv.file import io
|
||||
|
||||
try:
|
||||
import easy_predict
|
||||
@ -115,6 +116,12 @@ def define_args():
|
||||
type=str,
|
||||
choices=[None, 'pytorch'],
|
||||
help='if assigned pytorch, should be used in gpu environment')
|
||||
parser.add_argument(
|
||||
'--oss_io_config',
|
||||
nargs='+',
|
||||
action=DictAction,
|
||||
help='designer needs a oss of config to access the data')
|
||||
|
||||
args = parser.parse_args()
|
||||
if 'LOCAL_RANK' not in os.environ:
|
||||
os.environ['LOCAL_RANK'] = str(args.local_rank)
|
||||
@ -255,7 +262,7 @@ def create_default_predictor_kwargs(model_dir):
|
||||
if config_path:
|
||||
return {'model_path': model_path, 'config_file': config_path}
|
||||
else:
|
||||
return {'model_path': model_path}
|
||||
return {'model_path': model_path, 'config_file': None}
|
||||
|
||||
|
||||
def create_predictor_kwargs(model_type, model_dir):
|
||||
@ -288,7 +295,7 @@ def replace_oss_with_local_path(ori_file, dst_file, bucket_prefix,
|
||||
local_prefix):
|
||||
bucket_prefix = bucket_prefix.rstrip('/') + '/'
|
||||
local_prefix = local_prefix.rstrip('/') + '/'
|
||||
with open(ori_file, 'r') as infile:
|
||||
with io.open(ori_file, 'r') as infile:
|
||||
with open(dst_file, 'w') as ofile:
|
||||
for l in infile:
|
||||
if l.startswith('oss://'):
|
||||
@ -301,9 +308,26 @@ def build_and_run_file_io(args):
|
||||
rank, world_size = get_dist_info()
|
||||
worker_id = rank
|
||||
|
||||
input_oss_file_new_host = args.input_file + '.tmp%d' % worker_id
|
||||
replace_oss_with_local_path(args.input_file, input_oss_file_new_host,
|
||||
args.oss_prefix, args.local_prefix)
|
||||
# check oss_config and init oss io
|
||||
if args.oss_io_config is not None:
|
||||
io.access_oss(**args.oss_io_config)
|
||||
|
||||
# acquire the temporary save path
|
||||
if args.output_file:
|
||||
io.makedirs(os.path.dirname(args.output_file))
|
||||
input_oss_file_new_host = os.path.join(
|
||||
os.path.dirname(args.output_file),
|
||||
os.path.basename(args.input_file + '.tmp%d' % worker_id))
|
||||
replace_oss_with_local_path(args.input_file, input_oss_file_new_host,
|
||||
args.oss_prefix, args.local_prefix)
|
||||
else:
|
||||
io.makedirs(args.output_dir)
|
||||
input_oss_file_new_host = os.path.join(
|
||||
args.output_dir,
|
||||
os.path.basename(args.input_file + '.tmp%d' % worker_id))
|
||||
replace_oss_with_local_path(args.input_file, input_oss_file_new_host,
|
||||
args.oss_prefix, args.local_prefix)
|
||||
|
||||
args.input_file = input_oss_file_new_host
|
||||
num_worker = world_size
|
||||
print(f'worker num {num_worker}')
|
||||
|
Loading…
x
Reference in New Issue
Block a user