first commit
This commit is contained in:
16
rtdetr_paddle/ppdet/modeling/architectures/__init__.py
Normal file
16
rtdetr_paddle/ppdet/modeling/architectures/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from .meta_arch import *
|
||||
from .detr import *
|
||||
116
rtdetr_paddle/ppdet/modeling/architectures/detr.py
Normal file
116
rtdetr_paddle/ppdet/modeling/architectures/detr.py
Normal file
@@ -0,0 +1,116 @@
|
||||
# Copyright (c) 2021 PaddlePaddle Authors. All Rights Reserved.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import paddle
|
||||
from .meta_arch import BaseArch
|
||||
from ppdet.core.workspace import register, create
|
||||
|
||||
__all__ = ['DETR']
|
||||
# Deformable DETR, DINO use the same architecture as DETR
|
||||
|
||||
|
||||
@register
|
||||
class DETR(BaseArch):
|
||||
__category__ = 'architecture'
|
||||
__inject__ = ['post_process']
|
||||
__shared__ = ['with_mask', 'exclude_post_process']
|
||||
|
||||
def __init__(self,
|
||||
backbone,
|
||||
transformer='DETRTransformer',
|
||||
detr_head='DETRHead',
|
||||
neck=None,
|
||||
post_process='DETRPostProcess',
|
||||
with_mask=False,
|
||||
exclude_post_process=False):
|
||||
super(DETR, self).__init__()
|
||||
self.backbone = backbone
|
||||
self.transformer = transformer
|
||||
self.detr_head = detr_head
|
||||
self.neck = neck
|
||||
self.post_process = post_process
|
||||
self.with_mask = with_mask
|
||||
self.exclude_post_process = exclude_post_process
|
||||
|
||||
@classmethod
|
||||
def from_config(cls, cfg, *args, **kwargs):
|
||||
# backbone
|
||||
backbone = create(cfg['backbone'])
|
||||
# neck
|
||||
kwargs = {'input_shape': backbone.out_shape}
|
||||
neck = create(cfg['neck'], **kwargs) if cfg['neck'] else None
|
||||
|
||||
# transformer
|
||||
if neck is not None:
|
||||
kwargs = {'input_shape': neck.out_shape}
|
||||
transformer = create(cfg['transformer'], **kwargs)
|
||||
# head
|
||||
kwargs = {
|
||||
'hidden_dim': transformer.hidden_dim,
|
||||
'nhead': transformer.nhead,
|
||||
'input_shape': backbone.out_shape
|
||||
}
|
||||
detr_head = create(cfg['detr_head'], **kwargs)
|
||||
|
||||
return {
|
||||
'backbone': backbone,
|
||||
'transformer': transformer,
|
||||
"detr_head": detr_head,
|
||||
"neck": neck
|
||||
}
|
||||
|
||||
def _forward(self):
|
||||
# Backbone
|
||||
body_feats = self.backbone(self.inputs)
|
||||
|
||||
# Neck
|
||||
if self.neck is not None:
|
||||
body_feats = self.neck(body_feats)
|
||||
|
||||
# Transformer
|
||||
pad_mask = self.inputs.get('pad_mask', None)
|
||||
out_transformer = self.transformer(body_feats, pad_mask, self.inputs)
|
||||
|
||||
# DETR Head
|
||||
if self.training:
|
||||
detr_losses = self.detr_head(out_transformer, body_feats,
|
||||
self.inputs)
|
||||
detr_losses.update({
|
||||
'loss': paddle.add_n(
|
||||
[v for k, v in detr_losses.items() if 'log' not in k])
|
||||
})
|
||||
return detr_losses
|
||||
else:
|
||||
preds = self.detr_head(out_transformer, body_feats)
|
||||
if self.exclude_post_process:
|
||||
bbox, bbox_num, mask = preds
|
||||
else:
|
||||
bbox, bbox_num, mask = self.post_process(
|
||||
preds, self.inputs['im_shape'], self.inputs['scale_factor'],
|
||||
paddle.shape(self.inputs['image'])[2:])
|
||||
|
||||
output = {'bbox': bbox, 'bbox_num': bbox_num}
|
||||
if self.with_mask:
|
||||
output['mask'] = mask
|
||||
return output
|
||||
|
||||
def get_loss(self):
|
||||
return self._forward()
|
||||
|
||||
def get_pred(self):
|
||||
return self._forward()
|
||||
132
rtdetr_paddle/ppdet/modeling/architectures/meta_arch.py
Normal file
132
rtdetr_paddle/ppdet/modeling/architectures/meta_arch.py
Normal file
@@ -0,0 +1,132 @@
|
||||
from __future__ import absolute_import
|
||||
from __future__ import division
|
||||
from __future__ import print_function
|
||||
|
||||
import numpy as np
|
||||
import paddle
|
||||
import paddle.nn as nn
|
||||
import typing
|
||||
|
||||
from ppdet.core.workspace import register
|
||||
from ppdet.modeling.post_process import nms
|
||||
|
||||
__all__ = ['BaseArch']
|
||||
|
||||
|
||||
@register
|
||||
class BaseArch(nn.Layer):
|
||||
def __init__(self, data_format='NCHW', use_extra_data=False):
|
||||
super(BaseArch, self).__init__()
|
||||
self.data_format = data_format
|
||||
self.inputs = {}
|
||||
self.fuse_norm = False
|
||||
self.use_extra_data = use_extra_data
|
||||
|
||||
def load_meanstd(self, cfg_transform):
|
||||
scale = 1.
|
||||
mean = np.array([0.485, 0.456, 0.406], dtype=np.float32)
|
||||
std = np.array([0.229, 0.224, 0.225], dtype=np.float32)
|
||||
for item in cfg_transform:
|
||||
if 'NormalizeImage' in item:
|
||||
mean = np.array(
|
||||
item['NormalizeImage']['mean'], dtype=np.float32)
|
||||
std = np.array(item['NormalizeImage']['std'], dtype=np.float32)
|
||||
if item['NormalizeImage'].get('is_scale', True):
|
||||
scale = 1. / 255.
|
||||
break
|
||||
if self.data_format == 'NHWC':
|
||||
self.scale = paddle.to_tensor(scale / std).reshape((1, 1, 1, 3))
|
||||
self.bias = paddle.to_tensor(-mean / std).reshape((1, 1, 1, 3))
|
||||
else:
|
||||
self.scale = paddle.to_tensor(scale / std).reshape((1, 3, 1, 1))
|
||||
self.bias = paddle.to_tensor(-mean / std).reshape((1, 3, 1, 1))
|
||||
|
||||
def forward(self, inputs):
|
||||
if self.data_format == 'NHWC':
|
||||
image = inputs['image']
|
||||
inputs['image'] = paddle.transpose(image, [0, 2, 3, 1])
|
||||
|
||||
if self.fuse_norm:
|
||||
image = inputs['image']
|
||||
self.inputs['image'] = image * self.scale + self.bias
|
||||
self.inputs['im_shape'] = inputs['im_shape']
|
||||
self.inputs['scale_factor'] = inputs['scale_factor']
|
||||
else:
|
||||
self.inputs = inputs
|
||||
|
||||
self.model_arch()
|
||||
|
||||
if self.training:
|
||||
out = self.get_loss()
|
||||
else:
|
||||
inputs_list = []
|
||||
# multi-scale input
|
||||
if not isinstance(inputs, typing.Sequence):
|
||||
inputs_list.append(inputs)
|
||||
else:
|
||||
inputs_list.extend(inputs)
|
||||
outs = []
|
||||
for inp in inputs_list:
|
||||
if self.fuse_norm:
|
||||
self.inputs['image'] = inp['image'] * self.scale + self.bias
|
||||
self.inputs['im_shape'] = inp['im_shape']
|
||||
self.inputs['scale_factor'] = inp['scale_factor']
|
||||
else:
|
||||
self.inputs = inp
|
||||
outs.append(self.get_pred())
|
||||
|
||||
# multi-scale test
|
||||
if len(outs) > 1:
|
||||
out = self.merge_multi_scale_predictions(outs)
|
||||
else:
|
||||
out = outs[0]
|
||||
return out
|
||||
|
||||
def merge_multi_scale_predictions(self, outs):
|
||||
# default values for architectures not included in following list
|
||||
num_classes = 80
|
||||
nms_threshold = 0.5
|
||||
keep_top_k = 100
|
||||
|
||||
if self.__class__.__name__ in ('CascadeRCNN', 'FasterRCNN', 'MaskRCNN'):
|
||||
num_classes = self.bbox_head.num_classes
|
||||
keep_top_k = self.bbox_post_process.nms.keep_top_k
|
||||
nms_threshold = self.bbox_post_process.nms.nms_threshold
|
||||
else:
|
||||
raise Exception(
|
||||
"Multi scale test only supports CascadeRCNN, FasterRCNN and MaskRCNN for now"
|
||||
)
|
||||
|
||||
final_boxes = []
|
||||
all_scale_outs = paddle.concat([o['bbox'] for o in outs]).numpy()
|
||||
for c in range(num_classes):
|
||||
idxs = all_scale_outs[:, 0] == c
|
||||
if np.count_nonzero(idxs) == 0:
|
||||
continue
|
||||
r = nms(all_scale_outs[idxs, 1:], nms_threshold)
|
||||
final_boxes.append(
|
||||
np.concatenate([np.full((r.shape[0], 1), c), r], 1))
|
||||
out = np.concatenate(final_boxes)
|
||||
out = np.concatenate(sorted(
|
||||
out, key=lambda e: e[1])[-keep_top_k:]).reshape((-1, 6))
|
||||
out = {
|
||||
'bbox': paddle.to_tensor(out),
|
||||
'bbox_num': paddle.to_tensor(np.array([out.shape[0], ]))
|
||||
}
|
||||
|
||||
return out
|
||||
|
||||
def build_inputs(self, data, input_def):
|
||||
inputs = {}
|
||||
for i, k in enumerate(input_def):
|
||||
inputs[k] = data[i]
|
||||
return inputs
|
||||
|
||||
def model_arch(self, ):
|
||||
pass
|
||||
|
||||
def get_loss(self, ):
|
||||
raise NotImplementedError("Should implement get_loss method!")
|
||||
|
||||
def get_pred(self, ):
|
||||
raise NotImplementedError("Should implement get_pred method!")
|
||||
Reference in New Issue
Block a user