mirror of
https://github.com/alibaba/EasyCV.git
synced 2025-06-03 14:49:00 +08:00
Compare commits
10 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
901ff18693 | ||
|
31897984d8 | ||
|
8c90ceaf84 | ||
|
1d1ac8aa5e | ||
|
5ba3057ff8 | ||
|
09232dac33 | ||
|
af4e9d5d19 | ||
|
cecb36a9ce | ||
|
447a1665c6 | ||
|
0b3045ff87 |
@ -248,7 +248,7 @@ Please refer to the following model zoo for more details.
|
|||||||
|
|
||||||
## Data Hub
|
## 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).
|
Please refer to [data_hub.md](docs/source/data_hub.md).
|
||||||
|
|
||||||
|
@ -4,16 +4,31 @@ num_classes = 1000
|
|||||||
# model settings
|
# model settings
|
||||||
model = dict(
|
model = dict(
|
||||||
type='Classification',
|
type='Classification',
|
||||||
backbone=dict(type='Inception3'),
|
backbone=dict(type='Inception3', num_classes=1000),
|
||||||
head=dict(
|
head=[
|
||||||
type='ClsHead',
|
dict(
|
||||||
with_avg_pool=True,
|
type='ClsHead',
|
||||||
in_channels=2048,
|
with_fc=False,
|
||||||
loss_config=dict(
|
in_channels=2048,
|
||||||
type='CrossEntropyLossWithLabelSmooth',
|
loss_config=dict(
|
||||||
label_smooth=0,
|
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 = [
|
class_list = [
|
||||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13',
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13',
|
||||||
@ -196,3 +211,5 @@ log_config = dict(
|
|||||||
interval=10,
|
interval=10,
|
||||||
hooks=[dict(type='TextLoggerHook'),
|
hooks=[dict(type='TextLoggerHook'),
|
||||||
dict(type='TensorboardLoggerHook')])
|
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',
|
type='CrossEntropyLossWithLabelSmooth',
|
||||||
label_smooth=0,
|
label_smooth=0,
|
||||||
),
|
),
|
||||||
num_classes=num_classes))
|
num_classes=num_classes),
|
||||||
|
pretrained=True)
|
||||||
|
|
||||||
# optimizer
|
# optimizer
|
||||||
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
|
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
|
# runtime settings
|
||||||
total_epochs = 100
|
total_epochs = 100
|
||||||
checkpoint_sync_export = True
|
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,
|
depth=50,
|
||||||
out_indices=[4], # 0: conv-1, x: stage-x
|
out_indices=[4], # 0: conv-1, x: stage-x
|
||||||
norm_cfg=dict(type='BN')))
|
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',
|
type='CrossEntropyLossWithLabelSmooth',
|
||||||
label_smooth=0,
|
label_smooth=0,
|
||||||
),
|
),
|
||||||
num_classes=num_classes))
|
num_classes=num_classes),
|
||||||
|
pretrained=True)
|
||||||
|
|
||||||
# optimizer
|
# optimizer
|
||||||
optimizer = dict(type='SGD', lr=0.1, momentum=0.9, weight_decay=0.0001)
|
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
|
# runtime settings
|
||||||
total_epochs = 100
|
total_epochs = 100
|
||||||
|
export = dict(export_type='raw', export_neck=True)
|
||||||
|
@ -92,13 +92,13 @@
|
|||||||
|
|
||||||
### Verification
|
### Verification
|
||||||
|
|
||||||
Simple verification
|
Simple verification
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from easycv.apis import *
|
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
|
## Examples
|
||||||
|
@ -157,6 +157,52 @@ def _export_jit_and_blade(model, cfg, filename, dummy_inputs, fp16=False):
|
|||||||
torch.jit.save(blade_model, ofile)
|
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):
|
def _export_cls(model, cfg, filename):
|
||||||
""" export cls (cls & metric learning)model and preprocess config
|
""" export cls (cls & metric learning)model and preprocess config
|
||||||
|
|
||||||
@ -170,6 +216,7 @@ def _export_cls(model, cfg, filename):
|
|||||||
else:
|
else:
|
||||||
export_cfg = dict(export_neck=False)
|
export_cfg = dict(export_neck=False)
|
||||||
|
|
||||||
|
export_type = export_cfg.get('export_type', 'raw')
|
||||||
export_neck = export_cfg.get('export_neck', True)
|
export_neck = export_cfg.get('export_neck', True)
|
||||||
label_map_path = cfg.get('label_map_path', None)
|
label_map_path = cfg.get('label_map_path', None)
|
||||||
class_list = 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')):
|
if export_neck and (k.startswith('neck') or k.startswith('head')):
|
||||||
state_dict[k] = v
|
state_dict[k] = v
|
||||||
|
|
||||||
checkpoint = dict(state_dict=state_dict, meta=meta, author='EasyCV')
|
if export_type == 'raw':
|
||||||
with io.open(filename, 'wb') as ofile:
|
checkpoint = dict(state_dict=state_dict, meta=meta, author='EasyCV')
|
||||||
torch.save(checkpoint, ofile)
|
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):
|
def _export_yolox(model, cfg, filename):
|
||||||
@ -675,6 +727,12 @@ def _export_pose_topdown(model, cfg, filename, fp16=False, dummy_inputs=None):
|
|||||||
model.to(device)
|
model.to(device)
|
||||||
|
|
||||||
if hasattr(cfg, 'export') and getattr(cfg.export, 'type', 'raw') == 'raw':
|
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)
|
return _export_common(model, cfg, filename)
|
||||||
|
|
||||||
def _dummy_inputs(cfg):
|
def _dummy_inputs(cfg):
|
||||||
|
@ -110,16 +110,16 @@ class SegSourceCityscapes(SegSourceRaw):
|
|||||||
'')[:-len(self.img_suffix[0])]
|
'')[:-len(self.img_suffix[0])]
|
||||||
find_label_path = False
|
find_label_path = False
|
||||||
for label_format in self.label_suffix:
|
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)
|
img_name + label_format)
|
||||||
if io.exists(lable_path):
|
if io.exists(label_path):
|
||||||
find_label_path = True
|
find_label_path = True
|
||||||
self.label_files.append(lable_path)
|
self.label_files.append(label_path)
|
||||||
break
|
break
|
||||||
if not find_label_path:
|
if not find_label_path:
|
||||||
logging.warning(
|
logging.warning(
|
||||||
'Not find label file %s for img: %s, skip the sample!' %
|
'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)
|
self.img_files.remove(img_path)
|
||||||
|
|
||||||
assert len(self.img_files) == len(self.label_files)
|
assert len(self.img_files) == len(self.label_files)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
# Copyright (c) OpenMMLab and Alibaba. All rights reserved.
|
# Copyright (c) OpenMMLab and Alibaba. All rights reserved.
|
||||||
from collections import Sequence
|
from collections.abc import Sequence
|
||||||
|
|
||||||
import mmcv
|
import mmcv
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
@ -10,6 +10,7 @@ from .face_keypoint_backbone import FaceKeypointBackbone
|
|||||||
from .genet import PlainNet
|
from .genet import PlainNet
|
||||||
from .hrnet import HRNet
|
from .hrnet import HRNet
|
||||||
from .inceptionv3 import Inception3
|
from .inceptionv3 import Inception3
|
||||||
|
from .inceptionv4 import Inception4
|
||||||
from .lighthrnet import LiteHRNet
|
from .lighthrnet import LiteHRNet
|
||||||
from .mae_vit_transformer import *
|
from .mae_vit_transformer import *
|
||||||
from .mit import MixVisionTransformer
|
from .mit import MixVisionTransformer
|
||||||
|
@ -2,9 +2,6 @@
|
|||||||
r""" This model is taken from the official PyTorch model zoo.
|
r""" This model is taken from the official PyTorch model zoo.
|
||||||
- torchvision.models.inception.py on 31th Aug, 2019
|
- torchvision.models.inception.py on 31th Aug, 2019
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from collections import namedtuple
|
|
||||||
|
|
||||||
import torch
|
import torch
|
||||||
import torch.nn as nn
|
import torch.nn as nn
|
||||||
import torch.nn.functional as F
|
import torch.nn.functional as F
|
||||||
@ -16,8 +13,6 @@ from ..registry import BACKBONES
|
|||||||
|
|
||||||
__all__ = ['Inception3']
|
__all__ = ['Inception3']
|
||||||
|
|
||||||
_InceptionOutputs = namedtuple('InceptionOutputs', ['logits', 'aux_logits'])
|
|
||||||
|
|
||||||
|
|
||||||
@BACKBONES.register_module
|
@BACKBONES.register_module
|
||||||
class Inception3(nn.Module):
|
class Inception3(nn.Module):
|
||||||
@ -113,6 +108,7 @@ class Inception3(nn.Module):
|
|||||||
# N x 768 x 17 x 17
|
# N x 768 x 17 x 17
|
||||||
x = self.Mixed_6e(x)
|
x = self.Mixed_6e(x)
|
||||||
# N x 768 x 17 x 17
|
# N x 768 x 17 x 17
|
||||||
|
aux = None
|
||||||
if self.training and self.aux_logits:
|
if self.training and self.aux_logits:
|
||||||
aux = self.AuxLogits(x)
|
aux = self.AuxLogits(x)
|
||||||
# N x 768 x 17 x 17
|
# N x 768 x 17 x 17
|
||||||
@ -132,10 +128,7 @@ class Inception3(nn.Module):
|
|||||||
if hasattr(self, 'fc'):
|
if hasattr(self, 'fc'):
|
||||||
x = self.fc(x)
|
x = self.fc(x)
|
||||||
|
|
||||||
# N x 1000 (num_classes)
|
return [aux, x]
|
||||||
if self.training and self.aux_logits and hasattr(self, 'fc'):
|
|
||||||
return [_InceptionOutputs(x, aux)]
|
|
||||||
return [x]
|
|
||||||
|
|
||||||
|
|
||||||
class InceptionA(nn.Module):
|
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)
|
x = self.backbone(img)
|
||||||
return x
|
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
|
@torch.jit.unused
|
||||||
def forward_train(self, img, gt_labels) -> Dict[str, torch.Tensor]:
|
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)
|
return self.forward_test_label(img, gt_labels)
|
||||||
else:
|
else:
|
||||||
return self.forward_test(img)
|
return self.forward_test(img)
|
||||||
|
elif mode == 'onnx':
|
||||||
|
return self.forward_onnx(img)
|
||||||
|
|
||||||
elif mode == 'extract':
|
elif mode == 'extract':
|
||||||
rd = self.forward_feature(img)
|
rd = self.forward_feature(img)
|
||||||
rv = {}
|
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())}'
|
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
|
self.pretrained = pretrained
|
||||||
|
|
||||||
in_channels = [256, 512, 1024]
|
in_channels = [256, 512, 1024]
|
||||||
@ -68,19 +84,14 @@ class YOLOX(BaseModel):
|
|||||||
asff_channel=asff_channel,
|
asff_channel=asff_channel,
|
||||||
use_att=use_att)
|
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:
|
if head is not None:
|
||||||
# head is None for YOLOX-edge to define a special head
|
# 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.head = build_head(head)
|
||||||
self.num_classes = self.head.num_classes
|
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',
|
'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 = {
|
genet = {
|
||||||
'PlainNetnormal':
|
'PlainNetnormal':
|
||||||
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/genet/GENet_normal.pth',
|
'http://pai-vision-data-hz.oss-cn-zhangjiakou.aliyuncs.com/pretrained_models/easycv/genet/GENet_normal.pth',
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
# Copyright (c) Alibaba, Inc. and its affiliates.
|
# Copyright (c) Alibaba, Inc. and its affiliates.
|
||||||
|
import glob
|
||||||
import math
|
import math
|
||||||
|
import os
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import torch
|
import torch
|
||||||
@ -7,11 +9,18 @@ from PIL import Image
|
|||||||
|
|
||||||
from easycv.file import io
|
from easycv.file import io
|
||||||
from easycv.framework.errors import ValueError
|
from easycv.framework.errors import ValueError
|
||||||
|
from easycv.utils.checkpoint import load_checkpoint
|
||||||
from easycv.utils.misc import deprecated
|
from easycv.utils.misc import deprecated
|
||||||
from .base import InputProcessor, OutputProcessor, Predictor, PredictorV2
|
from .base import InputProcessor, OutputProcessor, Predictor, PredictorV2
|
||||||
from .builder import PREDICTORS
|
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):
|
class ClsInputProcessor(InputProcessor):
|
||||||
"""Process inputs for classification models.
|
"""Process inputs for classification models.
|
||||||
|
|
||||||
@ -146,6 +155,20 @@ class ClassificationPredictor(PredictorV2):
|
|||||||
self.pil_input = pil_input
|
self.pil_input = pil_input
|
||||||
self.label_map_path = label_map_path
|
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:
|
if self.pil_input:
|
||||||
mode = 'RGB'
|
mode = 'RGB'
|
||||||
super(ClassificationPredictor, self).__init__(
|
super(ClassificationPredictor, self).__init__(
|
||||||
@ -186,6 +209,41 @@ class ClassificationPredictor(PredictorV2):
|
|||||||
|
|
||||||
return ClsOutputProcessor(topk=self.topk, label_map=self.label_map)
|
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:
|
try:
|
||||||
from easy_vision.python.inference.predictor import PredictorInterface
|
from easy_vision.python.inference.predictor import PredictorInterface
|
||||||
|
@ -19,6 +19,8 @@ from easycv.utils.config_tools import mmcv_config_fromfile
|
|||||||
from easycv.utils.misc import deprecated
|
from easycv.utils.misc import deprecated
|
||||||
from .base import InputProcessor, OutputProcessor, PredictorV2
|
from .base import InputProcessor, OutputProcessor, PredictorV2
|
||||||
|
|
||||||
|
np.set_printoptions(suppress=True)
|
||||||
|
|
||||||
|
|
||||||
def _box2cs(image_size, box):
|
def _box2cs(image_size, box):
|
||||||
"""This encodes bbox(x,y,w,h) into (center, scale)
|
"""This encodes bbox(x,y,w,h) into (center, scale)
|
||||||
@ -222,11 +224,12 @@ class PoseTopDownInputProcessor(InputProcessor):
|
|||||||
bboxes = bboxes[valid_idx]
|
bboxes = bboxes[valid_idx]
|
||||||
person_results = [person_results[i] for i in valid_idx]
|
person_results = [person_results[i] for i in valid_idx]
|
||||||
|
|
||||||
output_person_info = []
|
results = []
|
||||||
for person_result in person_results:
|
for person_result in person_results:
|
||||||
box = person_result['bbox'] # x,y,x,y
|
box = person_result['bbox'] # x,y,x,y,s
|
||||||
box = [box[0], box[1], box[2] - box[0], box[3] - box[1]] # x,y,w,h
|
boxc = [box[0], box[1], box[2] - box[0],
|
||||||
center, scale = _box2cs(self.cfg.data_cfg['image_size'], box)
|
box[3] - box[1]] # x,y,w,h
|
||||||
|
center, scale = _box2cs(self.cfg.data_cfg['image_size'], boxc)
|
||||||
data = {
|
data = {
|
||||||
'image_id':
|
'image_id':
|
||||||
0,
|
0,
|
||||||
@ -264,11 +267,10 @@ class PoseTopDownInputProcessor(InputProcessor):
|
|||||||
output['img_fields'],
|
output['img_fields'],
|
||||||
}
|
}
|
||||||
box_id += 1
|
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
|
return results
|
||||||
|
|
||||||
def __call__(self, inputs):
|
def __call__(self, inputs):
|
||||||
@ -296,12 +298,7 @@ class PoseTopDownOutputProcessor(OutputProcessor):
|
|||||||
def __call__(self, inputs):
|
def __call__(self, inputs):
|
||||||
output = {}
|
output = {}
|
||||||
output['keypoints'] = inputs['preds']
|
output['keypoints'] = inputs['preds']
|
||||||
output['bbox'] = inputs['boxes'] # c1, c2, s1, s2, area, core
|
output['bbox'] = np.array(inputs['boxes']) # x1, y1, x2, y2 score
|
||||||
|
|
||||||
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]]
|
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
@ -403,6 +400,7 @@ class PoseTopDownPredictor(PredictorV2):
|
|||||||
return model
|
return model
|
||||||
|
|
||||||
def model_forward(self, inputs, return_heatmap=False):
|
def model_forward(self, inputs, return_heatmap=False):
|
||||||
|
boxes = inputs['bbox'].cpu().numpy()
|
||||||
if self.model_type == 'raw':
|
if self.model_type == 'raw':
|
||||||
with torch.no_grad():
|
with torch.no_grad():
|
||||||
result = self.model(
|
result = self.model(
|
||||||
@ -423,6 +421,7 @@ class PoseTopDownPredictor(PredictorV2):
|
|||||||
result = decode_heatmap(output_heatmap, img_metas,
|
result = decode_heatmap(output_heatmap, img_metas,
|
||||||
self.cfg.model.test_cfg)
|
self.cfg.model.test_cfg)
|
||||||
|
|
||||||
|
result['boxes'] = np.array(boxes)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def get_input_processor(self):
|
def get_input_processor(self):
|
||||||
|
@ -48,9 +48,15 @@ class EasyCVDetectionPipeline(EasyCVPipeline):
|
|||||||
labels = []
|
labels = []
|
||||||
boxes = []
|
boxes = []
|
||||||
for output in outputs:
|
for output in outputs:
|
||||||
for score, label, box in zip(output['detection_scores'],
|
scores_list = output['detection_scores'] if output[
|
||||||
output['detection_classes'],
|
'detection_scores'] is not None else []
|
||||||
output['detection_boxes']):
|
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)
|
scores.append(score)
|
||||||
labels.append(self.cfg.CLASSES[label])
|
labels.append(self.cfg.CLASSES[label])
|
||||||
boxes.append([b for b in box])
|
boxes.append([b for b in box])
|
||||||
|
@ -515,6 +515,10 @@ CONFIG_TEMPLATE_ZOO = {
|
|||||||
'configs/classification/imagenet/swint/imagenet_swin_tiny_patch4_window7_224_jpg.py',
|
'configs/classification/imagenet/swint/imagenet_swin_tiny_patch4_window7_224_jpg.py',
|
||||||
'CLASSIFICATION_M0BILENET':
|
'CLASSIFICATION_M0BILENET':
|
||||||
'configs/classification/imagenet/mobilenet/mobilenetv2.py',
|
'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
|
# metric learning
|
||||||
'METRICLEARNING':
|
'METRICLEARNING':
|
||||||
|
@ -2,5 +2,5 @@
|
|||||||
# GENERATED VERSION FILE
|
# GENERATED VERSION FILE
|
||||||
# TIME: Thu Nov 5 14:17:50 2020
|
# TIME: Thu Nov 5 14:17:50 2020
|
||||||
|
|
||||||
__version__ = '0.11.5'
|
__version__ = '0.11.7'
|
||||||
short_version = '0.11.5'
|
short_version = '0.11.7'
|
||||||
|
@ -116,6 +116,7 @@ class ModelExportTest(unittest.TestCase):
|
|||||||
cfg = mmcv_config_fromfile(config_file)
|
cfg = mmcv_config_fromfile(config_file)
|
||||||
cfg_options = {
|
cfg_options = {
|
||||||
'model.backbone.norm_cfg.type': 'SyncBN',
|
'model.backbone.norm_cfg.type': 'SyncBN',
|
||||||
|
'export.export_type': 'raw'
|
||||||
}
|
}
|
||||||
if cfg_options is not None:
|
if cfg_options is not None:
|
||||||
cfg.merge_from_dict(cfg_options)
|
cfg.merge_from_dict(cfg_options)
|
||||||
@ -210,6 +211,27 @@ class ModelExportTest(unittest.TestCase):
|
|||||||
|
|
||||||
self.assertTrue(os.path.exists(filename + '.jit'))
|
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__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
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()
|
@ -11,7 +11,8 @@ import torch
|
|||||||
from easycv.predictors.classifier import ClassificationPredictor
|
from easycv.predictors.classifier import ClassificationPredictor
|
||||||
from easycv.utils.test_util import clean_up, get_tmp_dir
|
from easycv.utils.test_util import clean_up, get_tmp_dir
|
||||||
from tests.ut_config import (PRETRAINED_MODEL_RESNET50_WITHOUTHEAD,
|
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):
|
class ClassificationPredictorTest(unittest.TestCase):
|
||||||
@ -33,6 +34,17 @@ class ClassificationPredictorTest(unittest.TestCase):
|
|||||||
self.assertListEqual(results['class_name'], ['"Persian cat",'])
|
self.assertListEqual(results['class_name'], ['"Persian cat",'])
|
||||||
self.assertEqual(len(results['class_probs']), 1000)
|
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):
|
def test_batch(self):
|
||||||
checkpoint = PRETRAINED_MODEL_RESNET50_WITHOUTHEAD
|
checkpoint = PRETRAINED_MODEL_RESNET50_WITHOUTHEAD
|
||||||
config_file = 'configs/classification/imagenet/resnet/imagenet_resnet50_jpg.py'
|
config_file = 'configs/classification/imagenet/resnet/imagenet_resnet50_jpg.py'
|
||||||
|
@ -54,10 +54,10 @@ class PoseTopDownPredictorTest(unittest.TestCase):
|
|||||||
|
|
||||||
assert_array_almost_equal(
|
assert_array_almost_equal(
|
||||||
result0['bbox'],
|
result0['bbox'],
|
||||||
np.array([[352.3085, 59.00325, 691.4247, 511.15814, 1.],
|
np.array([[438.9, 59., 604.8, 511.2, 0.9],
|
||||||
[10.511196, 177.74883, 101.824326, 299.49966, 1.],
|
[10.5, 179.6, 101.8, 297.7, 0.9],
|
||||||
[224.82036, 114.439865, 312.51306, 231.36348, 1.],
|
[229.6, 114.4, 307.8, 231.4, 0.6],
|
||||||
[200.71407, 114.716736, 337.17535, 296.6651, 1.]],
|
[229.4, 114.7, 308.5, 296.7, 0.6]],
|
||||||
dtype=np.float32),
|
dtype=np.float32),
|
||||||
decimal=1)
|
decimal=1)
|
||||||
vis_result = predictor.show_result(img1, result0)
|
vis_result = predictor.show_result(img1, result0)
|
||||||
@ -92,10 +92,10 @@ class PoseTopDownPredictorTest(unittest.TestCase):
|
|||||||
|
|
||||||
assert_array_almost_equal(
|
assert_array_almost_equal(
|
||||||
result1['bbox'][:4],
|
result1['bbox'][:4],
|
||||||
np.array([[436.23096, 214.72766, 584.26013, 412.09985, 1.],
|
np.array([[470.6, 214.7, 549.9, 412.1, 0.9],
|
||||||
[43.990044, 91.04126, 164.28406, 251.43329, 1.],
|
[71.6, 91., 136.7, 251.4, 0.9],
|
||||||
[127.44148, 100.38604, 254.219, 269.42273, 1.],
|
[159.7, 100.4, 221.9, 269.4, 0.9],
|
||||||
[190.08075, 117.31801, 311.22394, 278.8423, 1.]],
|
[219.4, 117.3, 281.9, 278.8, 0.9]],
|
||||||
dtype=np.float32),
|
dtype=np.float32),
|
||||||
decimal=1)
|
decimal=1)
|
||||||
vis_result = predictor.show_result(img2, result1)
|
vis_result = predictor.show_result(img2, result1)
|
||||||
|
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()
|
@ -179,6 +179,9 @@ PRETRAINED_MODEL_RESNET50 = os.path.join(
|
|||||||
PRETRAINED_MODEL_RESNET50_WITHOUTHEAD = os.path.join(
|
PRETRAINED_MODEL_RESNET50_WITHOUTHEAD = os.path.join(
|
||||||
BASE_LOCAL_PATH,
|
BASE_LOCAL_PATH,
|
||||||
'pretrained_models/classification/resnet/resnet50_withhead.pth')
|
'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_MODEL_FACEID = os.path.join(BASE_LOCAL_PATH,
|
||||||
'pretrained_models/faceid')
|
'pretrained_models/faceid')
|
||||||
PRETRAINED_MODEL_YOLOXS_EXPORT = os.path.join(
|
PRETRAINED_MODEL_YOLOXS_EXPORT = os.path.join(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user