add centernet dla34 ctdet task. (#558)
* add centernet dla34 ctdet task. * update readme. * update readme and fix a bug in sample. Co-authored-by: chandler <chandler@invix.com>
This commit is contained in:
parent
1457e6fcb7
commit
d9e2cbc294
29
centernet/README.md
Normal file
29
centernet/README.md
Normal file
@ -0,0 +1,29 @@
|
||||
# CenterNet
|
||||
|
||||
This is the trt implementation of detection model [ctdet_coco_dla_2x](https://drive.google.com/open?id=1pl_-ael8wERdUREEnaIfqOV_VF2bEVRT) from [xingyizhou/CenterNet](https://github.com/xingyizhou/CenterNet) official work.
|
||||
|
||||
## How to Run
|
||||
|
||||
1. Follow [NVIDIA/TensorRT](https://github.com/NVIDIA/TensorRT) tutorial to build TensorRT7
|
||||
|
||||
2. Copy folder `dcnv2Plugin` to `TensorRT/plugin` and edit `InferPlugin.cpp` and `CMakeLists.txt`
|
||||
|
||||
3. Rebuild to install custom plugin
|
||||
|
||||
4. Use `tensorrt-7.2.3.4-cp36-none-linux_x86_64.whl` in TensorRT OSS to update your python-tensorrt
|
||||
|
||||
5. Run `python centernet.py -m ${PTH_PATH} -s` to create trt engine
|
||||
|
||||
## Sample
|
||||
|
||||
```
|
||||
// Download ctdet_coco_dla_2x.pth and transfer it into trt engine first
|
||||
// Download the test img from https://raw.githubusercontent.com/tensorflow/models/master/research/deeplab/g3doc/img/image2.jpg or choose your own one
|
||||
cd sample
|
||||
python test.py ${ENGINE_PATH} ${IMG_PATH}
|
||||
```
|
||||

|
||||
|
||||
## TODO
|
||||
|
||||
Integrate the post process with trt engine to make it more easier to use.
|
||||
333
centernet/centernet.py
Normal file
333
centernet/centernet.py
Normal file
@ -0,0 +1,333 @@
|
||||
import numpy as np
|
||||
|
||||
import tensorrt as trt
|
||||
import torch
|
||||
|
||||
from sample import common
|
||||
import argparse
|
||||
import time
|
||||
|
||||
# You can set the logger severity higher to suppress messages (or lower to display more messages).
|
||||
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
|
||||
|
||||
trt.init_libnvinfer_plugins(TRT_LOGGER, '')
|
||||
PLUGIN_CREATORS = trt.get_plugin_registry().plugin_creator_list
|
||||
|
||||
for plugin_creator in PLUGIN_CREATORS:
|
||||
if plugin_creator.name == 'DCNv2_TRT':
|
||||
dcnCreator = plugin_creator
|
||||
|
||||
|
||||
class ModelData(object):
|
||||
INPUT_NAME = "data"
|
||||
INPUT_SHAPE = (3, 512, 512)
|
||||
OUTPUT_NAME = "prob"
|
||||
DTYPE = trt.float16
|
||||
|
||||
|
||||
class Centernet_dla34(object):
|
||||
def __init__(self, weights) -> None:
|
||||
super().__init__()
|
||||
self.weights = weights
|
||||
self.levels = [1, 1, 1, 2, 2, 1]
|
||||
self.channels = [16, 32, 64, 128, 256, 512]
|
||||
self.down_ratio = 4
|
||||
self.last_level = 5
|
||||
self.engine = self.build_engine()
|
||||
|
||||
def add_batchnorm_2d(self, input_tensor, parent):
|
||||
gamma = self.weights[parent + '.weight'].numpy()
|
||||
beta = self.weights[parent + '.bias'].numpy()
|
||||
mean = self.weights[parent + '.running_mean'].numpy()
|
||||
var = self.weights[parent + '.running_var'].numpy()
|
||||
eps = 1e-5
|
||||
|
||||
scale = gamma / np.sqrt(var + eps)
|
||||
shift = beta - mean * gamma / np.sqrt(var + eps)
|
||||
power = np.ones_like(scale)
|
||||
|
||||
return self.network.add_scale(input=input_tensor.get_output(0), mode=trt.ScaleMode.CHANNEL, shift=shift, scale=scale, power=power)
|
||||
|
||||
def add_basic_block(self, input_tensor, out_channels, residual=None, stride=1, dilation=1, parent=''):
|
||||
conv1_w = self.weights[parent + '.conv1.weight'].numpy()
|
||||
conv1 = self.network.add_convolution(input=input_tensor.get_output(
|
||||
0), num_output_maps=out_channels, kernel_shape=(3, 3), kernel=conv1_w)
|
||||
conv1.stride = (stride, stride)
|
||||
conv1.padding = (dilation, dilation)
|
||||
conv1.dilation = (dilation, dilation)
|
||||
|
||||
bn1 = self.add_batchnorm_2d(conv1, parent + '.bn1')
|
||||
ac1 = self.network.add_activation(
|
||||
input=bn1.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
conv2_w = self.weights[parent + '.conv2.weight'].numpy()
|
||||
conv2 = self.network.add_convolution(input=ac1.get_output(
|
||||
0), num_output_maps=out_channels, kernel_shape=(3, 3), kernel=conv2_w)
|
||||
conv2.padding = (dilation, dilation)
|
||||
conv2.dilation = (dilation, dilation)
|
||||
|
||||
out = self.add_batchnorm_2d(conv2, parent + '.bn2')
|
||||
|
||||
if residual is None:
|
||||
out = self.network.add_elementwise(input_tensor.get_output(
|
||||
0), out.get_output(0), trt.ElementWiseOperation.SUM)
|
||||
else:
|
||||
out = self.network.add_elementwise(residual.get_output(
|
||||
0), out.get_output(0), trt.ElementWiseOperation.SUM)
|
||||
return self.network.add_activation(input=out.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
def add_level(self, input_tensor, out_channels, stride=1, dilation=1, parent=''):
|
||||
conv1_w = self.weights[parent + '.0.weight'].numpy()
|
||||
conv1 = self.network.add_convolution(input=input_tensor.get_output(
|
||||
0), num_output_maps=out_channels, kernel_shape=(3, 3), kernel=conv1_w)
|
||||
conv1.stride = (stride, stride)
|
||||
conv1.padding = (dilation, dilation)
|
||||
conv1.dilation = (dilation, dilation)
|
||||
|
||||
bn1 = self.add_batchnorm_2d(conv1, parent + '.1')
|
||||
ac1 = self.network.add_activation(
|
||||
input=bn1.get_output(0), type=trt.ActivationType.RELU)
|
||||
return ac1
|
||||
|
||||
def add_root(self, input_tensors: list, out_channels, kernel_size=1, residual=False, parent=''):
|
||||
ct = self.network.add_concatenation(
|
||||
[x.get_output(0) for x in input_tensors])
|
||||
|
||||
conv_w = self.weights[parent + '.conv.weight'].numpy()
|
||||
conv = self.network.add_convolution(input=ct.get_output(
|
||||
0), num_output_maps=out_channels, kernel_shape=(1, 1), kernel=conv_w)
|
||||
conv.padding = ((kernel_size - 1) // 2, (kernel_size - 1) // 2)
|
||||
|
||||
bn1 = self.add_batchnorm_2d(conv, parent + '.bn')
|
||||
out = self.network.add_activation(
|
||||
input=bn1.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
if residual:
|
||||
out = self.network.add_elementwise(input_tensors[0].get_output(
|
||||
0), out.get_output(0), trt.ElementWiseOperation.SUM)
|
||||
|
||||
return self.network.add_activation(input=out.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
def add_tree(self, input_tensor, level, out_channels, residual=None, children=None, stride=1, level_root=False, parent=''):
|
||||
children = [] if children is None else children
|
||||
if stride > 1:
|
||||
bottom = self.network.add_pooling(input_tensor.get_output(
|
||||
0), trt.PoolingType.MAX, (stride, stride))
|
||||
bottom.stride = (stride, stride)
|
||||
else:
|
||||
bottom = input_tensor
|
||||
|
||||
if input_tensor.get_output(0).shape[0] != out_channels:
|
||||
project_conv1_w = self.weights[parent +
|
||||
'.project.0.weight'].numpy()
|
||||
project_conv1 = self.network.add_convolution(input=bottom.get_output(
|
||||
0), num_output_maps=out_channels, kernel_shape=(1, 1), kernel=project_conv1_w)
|
||||
residual = self.add_batchnorm_2d(
|
||||
project_conv1, parent + '.project.1')
|
||||
else:
|
||||
residual = bottom
|
||||
|
||||
if level_root:
|
||||
children.append(bottom)
|
||||
|
||||
if level == 1:
|
||||
tree1 = self.add_basic_block(
|
||||
input_tensor, out_channels, residual, stride, parent=parent+'.tree1')
|
||||
tree2 = self.add_basic_block(
|
||||
tree1, out_channels, parent=parent+'.tree2')
|
||||
return self.add_root([tree2, tree1]+children, out_channels, parent=parent+'.root')
|
||||
else:
|
||||
tree1 = self.add_tree(input_tensor, level-1, out_channels,
|
||||
residual, stride=stride, parent=parent+'.tree1')
|
||||
children.append(tree1)
|
||||
return self.add_tree(tree1, level-1, out_channels, children=children, parent=parent+'.tree2')
|
||||
|
||||
def add_base(self, input_tensor, parent):
|
||||
base_conv1_w = self.weights[parent+'.base_layer.0.weight'].numpy()
|
||||
base_conv1 = self.network.add_convolution(
|
||||
input=input_tensor, num_output_maps=self.channels[0], kernel_shape=(7, 7), kernel=base_conv1_w)
|
||||
base_conv1.padding = (3, 3)
|
||||
|
||||
base_bn1 = self.add_batchnorm_2d(base_conv1, parent+'.base_layer.1')
|
||||
base_ac1 = self.network.add_activation(
|
||||
input=base_bn1.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
level0 = self.add_level(
|
||||
base_ac1, self.channels[0], parent=parent+'.level0')
|
||||
level1 = self.add_level(
|
||||
level0, self.channels[1], 2, parent=parent+'.level1')
|
||||
|
||||
level2 = self.add_tree(
|
||||
level1, self.levels[2], self.channels[2], stride=2, level_root=False, parent=parent+'.level2')
|
||||
level3 = self.add_tree(
|
||||
level2, self.levels[3], self.channels[3], stride=2, level_root=True, parent=parent+'.level3')
|
||||
level4 = self.add_tree(
|
||||
level3, self.levels[4], self.channels[4], stride=2, level_root=True, parent=parent+'.level4')
|
||||
level5 = self.add_tree(
|
||||
level4, self.levels[5], self.channels[5], stride=2, level_root=True, parent=parent+'.level5')
|
||||
|
||||
return [level0, level1, level2, level3, level4, level5]
|
||||
|
||||
def add_deform_conv(self, input_tensor, out_channels, kernel=3, stride=1, padding=1, dilation=1, deformable_group=1, parent=''):
|
||||
conv_offset_mask_w = self.weights[parent +
|
||||
'.conv.conv_offset_mask.weight'].numpy()
|
||||
conv_offset_mask_b = self.weights[parent +
|
||||
'.conv.conv_offset_mask.bias'].numpy()
|
||||
conv_offset_mask = self.network.add_convolution(input=input_tensor.get_output(0),
|
||||
num_output_maps=deformable_group*3*kernel*kernel,
|
||||
kernel_shape=(
|
||||
kernel, kernel),
|
||||
kernel=conv_offset_mask_w,
|
||||
bias=conv_offset_mask_b)
|
||||
conv_offset_mask.stride = (stride, stride)
|
||||
conv_offset_mask.padding = (padding, padding)
|
||||
|
||||
out_channels = trt.PluginField("out_channels", np.array(
|
||||
[out_channels], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
kernel = trt.PluginField("kernel", np.array(
|
||||
[kernel], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
deformable_group = trt.PluginField("deformable_group", np.array(
|
||||
[deformable_group], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
dilation = trt.PluginField("dilation", np.array(
|
||||
[dilation], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
padding = trt.PluginField("padding", np.array(
|
||||
[padding], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
stride = trt.PluginField("stride", np.array(
|
||||
[stride], dtype=np.int32), trt.PluginFieldType.INT32)
|
||||
weight = trt.PluginField(
|
||||
"weight", self.weights[parent + '.conv.weight'].numpy(), trt.PluginFieldType.FLOAT32)
|
||||
bias = trt.PluginField(
|
||||
"bias", self.weights[parent + '.conv.bias'].numpy(), trt.PluginFieldType.FLOAT32)
|
||||
field_collection = trt.PluginFieldCollection(
|
||||
[out_channels, kernel, deformable_group, dilation, padding, stride, weight, bias])
|
||||
DCN = dcnCreator.create_plugin(
|
||||
name='DCNv2_TRT', field_collection=field_collection)
|
||||
|
||||
sigmoid_conv_offset_mask = self.network.add_activation(
|
||||
input=conv_offset_mask.get_output(0), type=trt.ActivationType.SIGMOID)
|
||||
|
||||
dcn = self.network.add_plugin_v2(inputs=[input_tensor.get_output(
|
||||
0), conv_offset_mask.get_output(0), sigmoid_conv_offset_mask.get_output(0)], plugin=DCN)
|
||||
bn = self.add_batchnorm_2d(dcn, parent+'.actf.0')
|
||||
return self.network.add_activation(input=bn.get_output(0), type=trt.ActivationType.RELU)
|
||||
|
||||
def add_ida_up(self, input_tensors, out_channels, up_f, startp, parent):
|
||||
for i in range(startp + 1, len(input_tensors)):
|
||||
proj = self.add_deform_conv(
|
||||
input_tensors[i], out_channels, parent=parent+'.proj_%d' % (i-startp))
|
||||
f = up_f[i-startp]
|
||||
up_w = self.weights[parent + '.up_%d.weight' % (i-startp)].numpy()
|
||||
up = self.network.add_deconvolution(
|
||||
proj.get_output(0), out_channels, (f*2, f*2), up_w)
|
||||
up.stride = (f, f)
|
||||
up.padding = (f//2, f//2)
|
||||
up.num_groups = out_channels
|
||||
node = self.network.add_elementwise(
|
||||
input_tensors[i-1].get_output(0), up.get_output(0), trt.ElementWiseOperation.SUM)
|
||||
input_tensors[i] = self.add_deform_conv(
|
||||
node, out_channels, parent=parent+'.node_%d' % (i-startp))
|
||||
return input_tensors
|
||||
|
||||
def add_dla_up(self, input_tensors, first_level, parent):
|
||||
channels = self.channels[first_level:]
|
||||
scales = [2 ** i for i in range(len(self.channels[first_level:]))]
|
||||
scales = np.array(scales, dtype=int)
|
||||
out = [input_tensors[-1]]
|
||||
for i in range(len(channels) - 1):
|
||||
j = -i - 2
|
||||
input_tensors = self.add_ida_up(
|
||||
input_tensors, channels[j], scales[j:] // scales[j], len(input_tensors) - i - 2, parent+'.ida_%d' % i)
|
||||
out.insert(0, input_tensors[-1])
|
||||
scales[j + 1:] = scales[j]
|
||||
channels[j + 1:] = [channels[j] for _ in channels[j + 1:]]
|
||||
return out
|
||||
|
||||
def add_head(self, input_tensor, out_channels, head, head_conv=256, final_kernal=1):
|
||||
conv1_w = self.weights[head+'.0.weight'].numpy()
|
||||
conv1_b = self.weights[head+'.0.bias'].numpy()
|
||||
conv1 = self.network.add_convolution(
|
||||
input_tensor.get_output(0), head_conv, (3, 3), conv1_w, conv1_b)
|
||||
conv1.padding = (1, 1)
|
||||
ac1 = self.network.add_activation(
|
||||
input=conv1.get_output(0), type=trt.ActivationType.RELU)
|
||||
conv2_w = self.weights[head + '.2.weight'].numpy()
|
||||
conv2_b = self.weights[head+'.2.bias'].numpy()
|
||||
conv2 = self.network.add_convolution(ac1.get_output(
|
||||
0), out_channels, (final_kernal, final_kernal), conv2_w, conv2_b)
|
||||
return conv2
|
||||
|
||||
def populate_network(self):
|
||||
# Configure the network layers based on the self.weights provided.
|
||||
input_tensor = self.network.add_input(
|
||||
name=ModelData.INPUT_NAME, dtype=ModelData.DTYPE, shape=ModelData.INPUT_SHAPE)
|
||||
|
||||
y = self.add_base(input_tensor, 'module.base')
|
||||
|
||||
first_level = int(np.log2(self.down_ratio))
|
||||
last_level = self.last_level
|
||||
dla_up = self.add_dla_up(y, first_level, 'module.dla_up')
|
||||
ida_up = self.add_ida_up(dla_up[:last_level-first_level], self.channels[first_level], [
|
||||
2 ** i for i in range(last_level - first_level)], 0, 'module.ida_up')
|
||||
|
||||
hm = self.add_head(ida_up[-1], 80, 'module.hm')
|
||||
wh = self.add_head(ida_up[-1], 2, 'module.wh')
|
||||
reg = self.add_head(ida_up[-1], 2, 'module.reg')
|
||||
|
||||
hm.get_output(0).name = 'hm'
|
||||
wh.get_output(0).name = 'wh'
|
||||
reg.get_output(0).name = 'reg'
|
||||
self.network.mark_output(tensor=hm.get_output(0))
|
||||
self.network.mark_output(tensor=wh.get_output(0))
|
||||
self.network.mark_output(tensor=reg.get_output(0))
|
||||
|
||||
def build_engine(self):
|
||||
# For more information on TRT basics, refer to the introductory samples.
|
||||
with trt.Builder(TRT_LOGGER) as builder, builder.create_network() as network:
|
||||
self.network = network
|
||||
builder.max_workspace_size = common.GiB(1)
|
||||
builder.max_batch_size = 1
|
||||
# Populate the network using self.weights from the PyTorch model.
|
||||
self.populate_network()
|
||||
# Build and return an engine.
|
||||
return builder.build_cuda_engine(self.network)
|
||||
|
||||
|
||||
def load_random_test_case(pagelocked_buffer):
|
||||
# Select an image at random to be the test case.
|
||||
img = np.random.randn(1, 3, 512, 512).astype(np.float32)
|
||||
# Copy to the pagelocked input buffer
|
||||
np.copyto(pagelocked_buffer, img.ravel())
|
||||
return img
|
||||
|
||||
|
||||
def main(args):
|
||||
# Get the PyTorch weights
|
||||
weights = torch.load(args.model, map_location={
|
||||
'cuda:0': 'cpu'})['state_dict']
|
||||
# Do inference with TensorRT.
|
||||
with Centernet_dla34(weights).engine as engine:
|
||||
if args.save_engine:
|
||||
with open('centernet.engine', "wb") as f:
|
||||
f.write(engine.serialize())
|
||||
inputs, outputs, bindings, stream = common.allocate_buffers(engine)
|
||||
with engine.create_execution_context() as context:
|
||||
img = load_random_test_case(pagelocked_buffer=inputs[0].host)
|
||||
# For more information on performing inference, refer to the introductory samples.
|
||||
# The common.do_inference function will return a list of outputs - we only have one in this case.
|
||||
t = time.time()
|
||||
[hm, wh, reg] = common.do_inference(
|
||||
context, bindings=bindings, inputs=inputs, outputs=outputs, stream=stream, batch_size=1)
|
||||
t = time.time() - t
|
||||
print('output: hm:%f, wh:%f, reg:%f' %
|
||||
(hm.mean(), wh.mean(), reg.mean()))
|
||||
print(t)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='CenterNet dla34 ctdet')
|
||||
parser.add_argument('--model', '-m', type=str,
|
||||
default='./ctdet_coco_dla_2x.pth', help='path of pytorch .pth')
|
||||
parser.add_argument('--save_engine', '-s',
|
||||
action='store_true', help='if save trt engine')
|
||||
args = parser.parse_args()
|
||||
main(args)
|
||||
21
centernet/dcnv2Plugin/CMakeLists.txt
Normal file
21
centernet/dcnv2Plugin/CMakeLists.txt
Normal file
@ -0,0 +1,21 @@
|
||||
#
|
||||
# Copyright (c) 2020, NVIDIA CORPORATION. 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.
|
||||
#
|
||||
file(GLOB SRCS *.cpp)
|
||||
set(PLUGIN_SOURCES ${PLUGIN_SOURCES} ${SRCS})
|
||||
set(PLUGIN_SOURCES ${PLUGIN_SOURCES} PARENT_SCOPE)
|
||||
file(GLOB CU_SRCS *.cu)
|
||||
set(PLUGIN_CU_SOURCES ${PLUGIN_CU_SOURCES} ${CU_SRCS})
|
||||
set(PLUGIN_CU_SOURCES ${PLUGIN_CU_SOURCES} PARENT_SCOPE)
|
||||
399
centernet/dcnv2Plugin/dcn_v2_im2col_cuda.cu
Normal file
399
centernet/dcnv2Plugin/dcn_v2_im2col_cuda.cu
Normal file
@ -0,0 +1,399 @@
|
||||
#include "dcn_v2_im2col_cuda.h"
|
||||
#include <cstdio>
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
|
||||
#define CUDA_KERNEL_LOOP(i, n) \
|
||||
for (int i = blockIdx.x * blockDim.x + threadIdx.x; \
|
||||
i < (n); \
|
||||
i += blockDim.x * gridDim.x)
|
||||
|
||||
const int CUDA_NUM_THREADS = 512;
|
||||
//inline int GET_BLOCKS(const int N)
|
||||
//{
|
||||
// return (N + CUDA_NUM_THREADS - 1) / CUDA_NUM_THREADS;
|
||||
//}
|
||||
dim3 GET_BLOCKS(uint n)
|
||||
{
|
||||
uint k = (n - 1) /CUDA_NUM_THREADS + 1;
|
||||
uint x = k ;
|
||||
uint y = 1 ;
|
||||
if (x > 65535 )
|
||||
{
|
||||
x = ceil(sqrt(x));
|
||||
y = (n - 1 )/(x*CUDA_NUM_THREADS) + 1;
|
||||
}
|
||||
dim3 d = {x,y,1} ;
|
||||
return d;
|
||||
}
|
||||
|
||||
__device__ float dmcn_im2col_bilinear(const float *bottom_data, const int data_width,
|
||||
const int height, const int width, float h, float w)
|
||||
{
|
||||
int h_low = floor(h);
|
||||
int w_low = floor(w);
|
||||
int h_high = h_low + 1;
|
||||
int w_high = w_low + 1;
|
||||
|
||||
float lh = h - h_low;
|
||||
float lw = w - w_low;
|
||||
float hh = 1 - lh, hw = 1 - lw;
|
||||
|
||||
float v1 = 0;
|
||||
if (h_low >= 0 && w_low >= 0)
|
||||
v1 = bottom_data[h_low * data_width + w_low];
|
||||
float v2 = 0;
|
||||
if (h_low >= 0 && w_high <= width - 1)
|
||||
v2 = bottom_data[h_low * data_width + w_high];
|
||||
float v3 = 0;
|
||||
if (h_high <= height - 1 && w_low >= 0)
|
||||
v3 = bottom_data[h_high * data_width + w_low];
|
||||
float v4 = 0;
|
||||
if (h_high <= height - 1 && w_high <= width - 1)
|
||||
v4 = bottom_data[h_high * data_width + w_high];
|
||||
|
||||
float w1 = hh * hw, w2 = hh * lw, w3 = lh * hw, w4 = lh * lw;
|
||||
|
||||
float val = (w1 * v1 + w2 * v2 + w3 * v3 + w4 * v4);
|
||||
return val;
|
||||
}
|
||||
|
||||
__device__ float dmcn_get_gradient_weight(float argmax_h, float argmax_w,
|
||||
const int h, const int w, const int height, const int width)
|
||||
{
|
||||
if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
|
||||
{
|
||||
//empty
|
||||
return 0;
|
||||
}
|
||||
|
||||
int argmax_h_low = floor(argmax_h);
|
||||
int argmax_w_low = floor(argmax_w);
|
||||
int argmax_h_high = argmax_h_low + 1;
|
||||
int argmax_w_high = argmax_w_low + 1;
|
||||
|
||||
float weight = 0;
|
||||
if (h == argmax_h_low && w == argmax_w_low)
|
||||
weight = (h + 1 - argmax_h) * (w + 1 - argmax_w);
|
||||
if (h == argmax_h_low && w == argmax_w_high)
|
||||
weight = (h + 1 - argmax_h) * (argmax_w + 1 - w);
|
||||
if (h == argmax_h_high && w == argmax_w_low)
|
||||
weight = (argmax_h + 1 - h) * (w + 1 - argmax_w);
|
||||
if (h == argmax_h_high && w == argmax_w_high)
|
||||
weight = (argmax_h + 1 - h) * (argmax_w + 1 - w);
|
||||
return weight;
|
||||
}
|
||||
|
||||
__device__ float dmcn_get_coordinate_weight(float argmax_h, float argmax_w,
|
||||
const int height, const int width, const float *im_data,
|
||||
const int data_width, const int bp_dir)
|
||||
{
|
||||
if (argmax_h <= -1 || argmax_h >= height || argmax_w <= -1 || argmax_w >= width)
|
||||
{
|
||||
//empty
|
||||
return 0;
|
||||
}
|
||||
|
||||
int argmax_h_low = floor(argmax_h);
|
||||
int argmax_w_low = floor(argmax_w);
|
||||
int argmax_h_high = argmax_h_low + 1;
|
||||
int argmax_w_high = argmax_w_low + 1;
|
||||
|
||||
float weight = 0;
|
||||
|
||||
if (bp_dir == 0)
|
||||
{
|
||||
if (argmax_h_low >= 0 && argmax_w_low >= 0)
|
||||
weight += -1 * (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_low * data_width + argmax_w_low];
|
||||
if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
|
||||
weight += -1 * (argmax_w - argmax_w_low) * im_data[argmax_h_low * data_width + argmax_w_high];
|
||||
if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
|
||||
weight += (argmax_w_low + 1 - argmax_w) * im_data[argmax_h_high * data_width + argmax_w_low];
|
||||
if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
|
||||
weight += (argmax_w - argmax_w_low) * im_data[argmax_h_high * data_width + argmax_w_high];
|
||||
}
|
||||
else if (bp_dir == 1)
|
||||
{
|
||||
if (argmax_h_low >= 0 && argmax_w_low >= 0)
|
||||
weight += -1 * (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_low];
|
||||
if (argmax_h_low >= 0 && argmax_w_high <= width - 1)
|
||||
weight += (argmax_h_low + 1 - argmax_h) * im_data[argmax_h_low * data_width + argmax_w_high];
|
||||
if (argmax_h_high <= height - 1 && argmax_w_low >= 0)
|
||||
weight += -1 * (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_low];
|
||||
if (argmax_h_high <= height - 1 && argmax_w_high <= width - 1)
|
||||
weight += (argmax_h - argmax_h_low) * im_data[argmax_h_high * data_width + argmax_w_high];
|
||||
}
|
||||
|
||||
return weight;
|
||||
}
|
||||
|
||||
__global__ void modulated_deformable_im2col_gpu_kernel(const int n,
|
||||
const float *data_im, const float *data_offset, const float *data_mask,
|
||||
const int height, const int width, const int kernel_h, const int kernel_w,
|
||||
const int pad_h, const int pad_w,
|
||||
const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int channel_per_deformable_group,
|
||||
const int batch_size, const int num_channels, const int deformable_group,
|
||||
const int height_col, const int width_col,
|
||||
float *data_col)
|
||||
{
|
||||
CUDA_KERNEL_LOOP(index, n)
|
||||
{
|
||||
// index index of output matrix
|
||||
const int w_col = index % width_col;
|
||||
const int h_col = (index / width_col) % height_col;
|
||||
const int b_col = (index / width_col / height_col) % batch_size;
|
||||
const int c_im = (index / width_col / height_col) / batch_size;
|
||||
const int c_col = c_im * kernel_h * kernel_w;
|
||||
|
||||
// compute deformable group index
|
||||
const int deformable_group_index = c_im / channel_per_deformable_group;
|
||||
|
||||
const int h_in = h_col * stride_h - pad_h;
|
||||
const int w_in = w_col * stride_w - pad_w;
|
||||
|
||||
float *data_col_ptr = data_col + ((c_col * batch_size + b_col) * height_col + h_col) * width_col + w_col;
|
||||
//const float* data_im_ptr = data_im + ((b_col * num_channels + c_im) * height + h_in) * width + w_in;
|
||||
const float *data_im_ptr = data_im + (b_col * num_channels + c_im) * height * width;
|
||||
const float *data_offset_ptr = data_offset + (b_col * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
|
||||
|
||||
const float *data_mask_ptr = data_mask + (b_col * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
|
||||
|
||||
for (int i = 0; i < kernel_h; ++i)
|
||||
{
|
||||
for (int j = 0; j < kernel_w; ++j)
|
||||
{
|
||||
const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_col) * width_col + w_col;
|
||||
const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_col) * width_col + w_col;
|
||||
const int data_mask_hw_ptr = ((i * kernel_w + j) * height_col + h_col) * width_col + w_col;
|
||||
const float offset_h = data_offset_ptr[data_offset_h_ptr];
|
||||
const float offset_w = data_offset_ptr[data_offset_w_ptr];
|
||||
const float mask = data_mask_ptr[data_mask_hw_ptr];
|
||||
float val = static_cast<float>(0);
|
||||
const float h_im = h_in + i * dilation_h + offset_h;
|
||||
const float w_im = w_in + j * dilation_w + offset_w;
|
||||
//if (h_im >= 0 && w_im >= 0 && h_im < height && w_im < width) {
|
||||
if (h_im > -1 && w_im > -1 && h_im < height && w_im < width)
|
||||
{
|
||||
//const float map_h = i * dilation_h + offset_h;
|
||||
//const float map_w = j * dilation_w + offset_w;
|
||||
//const int cur_height = height - h_in;
|
||||
//const int cur_width = width - w_in;
|
||||
//val = dmcn_im2col_bilinear(data_im_ptr, width, cur_height, cur_width, map_h, map_w);
|
||||
val = dmcn_im2col_bilinear(data_im_ptr, width, height, width, h_im, w_im);
|
||||
}
|
||||
*data_col_ptr = val * mask;
|
||||
data_col_ptr += batch_size * height_col * width_col;
|
||||
//data_col_ptr += height_col * width_col;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void modulated_deformable_col2im_gpu_kernel(const int n,
|
||||
const float *data_col, const float *data_offset, const float *data_mask,
|
||||
const int channels, const int height, const int width,
|
||||
const int kernel_h, const int kernel_w,
|
||||
const int pad_h, const int pad_w,
|
||||
const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int channel_per_deformable_group,
|
||||
const int batch_size, const int deformable_group,
|
||||
const int height_col, const int width_col,
|
||||
float *grad_im)
|
||||
{
|
||||
CUDA_KERNEL_LOOP(index, n)
|
||||
{
|
||||
const int j = (index / width_col / height_col / batch_size) % kernel_w;
|
||||
const int i = (index / width_col / height_col / batch_size / kernel_w) % kernel_h;
|
||||
const int c = index / width_col / height_col / batch_size / kernel_w / kernel_h;
|
||||
// compute the start and end of the output
|
||||
|
||||
const int deformable_group_index = c / channel_per_deformable_group;
|
||||
|
||||
int w_out = index % width_col;
|
||||
int h_out = (index / width_col) % height_col;
|
||||
int b = (index / width_col / height_col) % batch_size;
|
||||
int w_in = w_out * stride_w - pad_w;
|
||||
int h_in = h_out * stride_h - pad_h;
|
||||
|
||||
const float *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
|
||||
const float *data_mask_ptr = data_mask + (b * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
|
||||
const int data_offset_h_ptr = ((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out;
|
||||
const int data_offset_w_ptr = ((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out;
|
||||
const int data_mask_hw_ptr = ((i * kernel_w + j) * height_col + h_out) * width_col + w_out;
|
||||
const float offset_h = data_offset_ptr[data_offset_h_ptr];
|
||||
const float offset_w = data_offset_ptr[data_offset_w_ptr];
|
||||
const float mask = data_mask_ptr[data_mask_hw_ptr];
|
||||
const float cur_inv_h_data = h_in + i * dilation_h + offset_h;
|
||||
const float cur_inv_w_data = w_in + j * dilation_w + offset_w;
|
||||
|
||||
const float cur_top_grad = data_col[index] * mask;
|
||||
const int cur_h = (int)cur_inv_h_data;
|
||||
const int cur_w = (int)cur_inv_w_data;
|
||||
for (int dy = -2; dy <= 2; dy++)
|
||||
{
|
||||
for (int dx = -2; dx <= 2; dx++)
|
||||
{
|
||||
if (cur_h + dy >= 0 && cur_h + dy < height &&
|
||||
cur_w + dx >= 0 && cur_w + dx < width &&
|
||||
abs(cur_inv_h_data - (cur_h + dy)) < 1 &&
|
||||
abs(cur_inv_w_data - (cur_w + dx)) < 1)
|
||||
{
|
||||
int cur_bottom_grad_pos = ((b * channels + c) * height + cur_h + dy) * width + cur_w + dx;
|
||||
float weight = dmcn_get_gradient_weight(cur_inv_h_data, cur_inv_w_data, cur_h + dy, cur_w + dx, height, width);
|
||||
atomicAdd(grad_im + cur_bottom_grad_pos, weight * cur_top_grad);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__global__ void modulated_deformable_col2im_coord_gpu_kernel(const int n,
|
||||
const float *data_col, const float *data_im,
|
||||
const float *data_offset, const float *data_mask,
|
||||
const int channels, const int height, const int width,
|
||||
const int kernel_h, const int kernel_w,
|
||||
const int pad_h, const int pad_w,
|
||||
const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int channel_per_deformable_group,
|
||||
const int batch_size, const int offset_channels, const int deformable_group,
|
||||
const int height_col, const int width_col,
|
||||
float *grad_offset, float *grad_mask)
|
||||
{
|
||||
CUDA_KERNEL_LOOP(index, n)
|
||||
{
|
||||
float val = 0, mval = 0;
|
||||
int w = index % width_col;
|
||||
int h = (index / width_col) % height_col;
|
||||
int c = (index / width_col / height_col) % offset_channels;
|
||||
int b = (index / width_col / height_col) / offset_channels;
|
||||
// compute the start and end of the output
|
||||
|
||||
const int deformable_group_index = c / (2 * kernel_h * kernel_w);
|
||||
const int col_step = kernel_h * kernel_w;
|
||||
int cnt = 0;
|
||||
const float *data_col_ptr = data_col + deformable_group_index * channel_per_deformable_group * batch_size * width_col * height_col;
|
||||
const float *data_im_ptr = data_im + (b * deformable_group + deformable_group_index) * channel_per_deformable_group / kernel_h / kernel_w * height * width;
|
||||
const float *data_offset_ptr = data_offset + (b * deformable_group + deformable_group_index) * 2 * kernel_h * kernel_w * height_col * width_col;
|
||||
const float *data_mask_ptr = data_mask + (b * deformable_group + deformable_group_index) * kernel_h * kernel_w * height_col * width_col;
|
||||
|
||||
const int offset_c = c - deformable_group_index * 2 * kernel_h * kernel_w;
|
||||
|
||||
for (int col_c = (offset_c / 2); col_c < channel_per_deformable_group; col_c += col_step)
|
||||
{
|
||||
const int col_pos = (((col_c * batch_size + b) * height_col) + h) * width_col + w;
|
||||
const int bp_dir = offset_c % 2;
|
||||
|
||||
int j = (col_pos / width_col / height_col / batch_size) % kernel_w;
|
||||
int i = (col_pos / width_col / height_col / batch_size / kernel_w) % kernel_h;
|
||||
int w_out = col_pos % width_col;
|
||||
int h_out = (col_pos / width_col) % height_col;
|
||||
int w_in = w_out * stride_w - pad_w;
|
||||
int h_in = h_out * stride_h - pad_h;
|
||||
const int data_offset_h_ptr = (((2 * (i * kernel_w + j)) * height_col + h_out) * width_col + w_out);
|
||||
const int data_offset_w_ptr = (((2 * (i * kernel_w + j) + 1) * height_col + h_out) * width_col + w_out);
|
||||
const int data_mask_hw_ptr = (((i * kernel_w + j) * height_col + h_out) * width_col + w_out);
|
||||
const float offset_h = data_offset_ptr[data_offset_h_ptr];
|
||||
const float offset_w = data_offset_ptr[data_offset_w_ptr];
|
||||
const float mask = data_mask_ptr[data_mask_hw_ptr];
|
||||
float inv_h = h_in + i * dilation_h + offset_h;
|
||||
float inv_w = w_in + j * dilation_w + offset_w;
|
||||
if (inv_h <= -1 || inv_w <= -1 || inv_h >= height || inv_w >= width)
|
||||
{
|
||||
inv_h = inv_w = -2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mval += data_col_ptr[col_pos] * dmcn_im2col_bilinear(data_im_ptr + cnt * height * width, width, height, width, inv_h, inv_w);
|
||||
}
|
||||
const float weight = dmcn_get_coordinate_weight(
|
||||
inv_h, inv_w,
|
||||
height, width, data_im_ptr + cnt * height * width, width, bp_dir);
|
||||
val += weight * data_col_ptr[col_pos] * mask;
|
||||
cnt += 1;
|
||||
}
|
||||
// KERNEL_ASSIGN(grad_offset[index], offset_req, val);
|
||||
grad_offset[index] = val;
|
||||
if (offset_c % 2 == 0)
|
||||
// KERNEL_ASSIGN(grad_mask[(((b * deformable_group + deformable_group_index) * kernel_h * kernel_w + offset_c / 2) * height_col + h) * width_col + w], mask_req, mval);
|
||||
grad_mask[(((b * deformable_group + deformable_group_index) * kernel_h * kernel_w + offset_c / 2) * height_col + h) * width_col + w] = mval;
|
||||
}
|
||||
}
|
||||
|
||||
void modulated_deformable_im2col_cuda(cudaStream_t stream,
|
||||
const float* data_im, const float* data_offset, const float* data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kenerl_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group, float* data_col) {
|
||||
// num_axes should be smaller than block size
|
||||
const int channel_per_deformable_group = channels / deformable_group;
|
||||
const int num_kernels = channels * batch_size * height_col * width_col;
|
||||
modulated_deformable_im2col_gpu_kernel
|
||||
<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS,
|
||||
0, stream>>>(
|
||||
num_kernels, data_im, data_offset, data_mask, height_im, width_im, kernel_h, kenerl_w,
|
||||
pad_h, pad_w, stride_h, stride_w, dilation_h, dilation_w, channel_per_deformable_group,
|
||||
batch_size, channels, deformable_group, height_col, width_col, data_col);
|
||||
|
||||
cudaError_t err = cudaGetLastError();
|
||||
if (err != cudaSuccess)
|
||||
{
|
||||
printf("error in modulated_deformable_im2col_cuda: %s\n", cudaGetErrorString(err));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void modulated_deformable_col2im_cuda(cudaStream_t stream,
|
||||
const float* data_col, const float* data_offset, const float* data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kernel_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group, float* grad_im){
|
||||
|
||||
const int channel_per_deformable_group = channels / deformable_group;
|
||||
const int num_kernels = channels * kernel_h * kernel_w * batch_size * height_col * width_col;
|
||||
modulated_deformable_col2im_gpu_kernel
|
||||
<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS,
|
||||
0, stream>>>(
|
||||
num_kernels, data_col, data_offset, data_mask, channels, height_im, width_im,
|
||||
kernel_h, kernel_w, pad_h, pad_h, stride_h, stride_w,
|
||||
dilation_h, dilation_w, channel_per_deformable_group,
|
||||
batch_size, deformable_group, height_col, width_col, grad_im);
|
||||
cudaError_t err = cudaGetLastError();
|
||||
if (err != cudaSuccess)
|
||||
{
|
||||
printf("error in modulated_deformable_col2im_cuda: %s\n", cudaGetErrorString(err));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void modulated_deformable_col2im_coord_cuda(cudaStream_t stream,
|
||||
const float* data_col, const float* data_im, const float* data_offset, const float* data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kernel_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group,
|
||||
float* grad_offset, float* grad_mask) {
|
||||
const int num_kernels = batch_size * height_col * width_col * 2 * kernel_h * kernel_w * deformable_group;
|
||||
const int channel_per_deformable_group = channels * kernel_h * kernel_w / deformable_group;
|
||||
modulated_deformable_col2im_coord_gpu_kernel
|
||||
<<<GET_BLOCKS(num_kernels), CUDA_NUM_THREADS,
|
||||
0, stream>>>(
|
||||
num_kernels, data_col, data_im, data_offset, data_mask, channels, height_im, width_im,
|
||||
kernel_h, kernel_w, pad_h, pad_w, stride_h, stride_w,
|
||||
dilation_h, dilation_w, channel_per_deformable_group,
|
||||
batch_size, 2 * kernel_h * kernel_w * deformable_group, deformable_group, height_col, width_col,
|
||||
grad_offset, grad_mask);
|
||||
cudaError_t err = cudaGetLastError();
|
||||
if (err != cudaSuccess)
|
||||
{
|
||||
printf("error in modulated_deformable_col2im_coord_cuda: %s\n", cudaGetErrorString(err));
|
||||
}
|
||||
}
|
||||
100
centernet/dcnv2Plugin/dcn_v2_im2col_cuda.h
Normal file
100
centernet/dcnv2Plugin/dcn_v2_im2col_cuda.h
Normal file
@ -0,0 +1,100 @@
|
||||
/*!
|
||||
******************* BEGIN Caffe Copyright Notice and Disclaimer ****************
|
||||
*
|
||||
* COPYRIGHT
|
||||
*
|
||||
* All contributions by the University of California:
|
||||
* Copyright (c) 2014-2017 The Regents of the University of California (Regents)
|
||||
* All rights reserved.
|
||||
*
|
||||
* All other contributions:
|
||||
* Copyright (c) 2014-2017, the respective contributors
|
||||
* All rights reserved.
|
||||
*
|
||||
* Caffe uses a shared copyright model: each contributor holds copyright over
|
||||
* their contributions to Caffe. The project versioning records all such
|
||||
* contribution and copyright details. If a contributor wants to further mark
|
||||
* their specific copyright on a particular contribution, they should indicate
|
||||
* their copyright solely in the commit message of the change when it is
|
||||
* committed.
|
||||
*
|
||||
* LICENSE
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||
* list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* CONTRIBUTION AGREEMENT
|
||||
*
|
||||
* By contributing to the BVLC/caffe repository through pull-request, comment,
|
||||
* or otherwise, the contributor releases their content to the
|
||||
* license and copyright terms herein.
|
||||
*
|
||||
***************** END Caffe Copyright Notice and Disclaimer ********************
|
||||
*
|
||||
* Copyright (c) 2018 Microsoft
|
||||
* Licensed under The MIT License [see LICENSE for details]
|
||||
* \file modulated_deformable_im2col.h
|
||||
* \brief Function definitions of converting an image to
|
||||
* column matrix based on kernel, padding, dilation, and offset.
|
||||
* These functions are mainly used in deformable convolution operators.
|
||||
* \ref: https://arxiv.org/abs/1811.11168
|
||||
* \author Yuwen Xiong, Haozhi Qi, Jifeng Dai, Xizhou Zhu, Han Hu
|
||||
*/
|
||||
|
||||
/***************** Adapted by Charles Shang *********************/
|
||||
|
||||
#ifndef DCN_V2_IM2COL_CUDA
|
||||
#define DCN_V2_IM2COL_CUDA
|
||||
|
||||
// #ifdef __cplusplus
|
||||
// extern "C"
|
||||
// {
|
||||
// #endif
|
||||
|
||||
void modulated_deformable_im2col_cuda(cudaStream_t stream,
|
||||
const float *data_im, const float *data_offset, const float *data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kenerl_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group, float *data_col);
|
||||
|
||||
void modulated_deformable_col2im_cuda(cudaStream_t stream,
|
||||
const float *data_col, const float *data_offset, const float *data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kenerl_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group, float *grad_im);
|
||||
|
||||
void modulated_deformable_col2im_coord_cuda(cudaStream_t stream,
|
||||
const float *data_col, const float *data_im, const float *data_offset, const float *data_mask,
|
||||
const int batch_size, const int channels, const int height_im, const int width_im,
|
||||
const int height_col, const int width_col, const int kernel_h, const int kenerl_w,
|
||||
const int pad_h, const int pad_w, const int stride_h, const int stride_w,
|
||||
const int dilation_h, const int dilation_w,
|
||||
const int deformable_group,
|
||||
float *grad_offset, float *grad_mask);
|
||||
|
||||
// #ifdef __cplusplus
|
||||
// }
|
||||
// #endif
|
||||
|
||||
#endif
|
||||
402
centernet/dcnv2Plugin/dcnv2Plugin.cpp
Normal file
402
centernet/dcnv2Plugin/dcnv2Plugin.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
#include "dcnv2Plugin.h"
|
||||
#include <iostream>
|
||||
|
||||
using namespace nvinfer1;
|
||||
using nvinfer1::plugin::DeformableConvolutionalLayer;
|
||||
using nvinfer1::plugin::DCNv2PluginCreator;
|
||||
|
||||
namespace
|
||||
{
|
||||
const char* DCNv2_PLUGIN_VERSION{"1"};
|
||||
const char* DCNv2_PLUGIN_NAME{"DCNv2_TRT"};
|
||||
} // namespace
|
||||
|
||||
#define CHECK_CUDA(call) \
|
||||
do \
|
||||
{ \
|
||||
cudaError_t status = call; \
|
||||
if (status != cudaSuccess) \
|
||||
{ \
|
||||
return status; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
PluginFieldCollection DCNv2PluginCreator::mFC{};
|
||||
std::vector<PluginField> DCNv2PluginCreator::mPluginAttributes;
|
||||
|
||||
// Parameterized constructor
|
||||
DeformableConvolutionalLayer::DeformableConvolutionalLayer(
|
||||
int out_channels,
|
||||
int kernel,
|
||||
int deformable_group,
|
||||
int dilation,
|
||||
int padding,
|
||||
int stride,
|
||||
const Weights* weight, const Weights* bias):
|
||||
out_channels(out_channels),kernel_size(kernel),deformable_group(deformable_group),
|
||||
dilation(dilation),padding(padding),stride(stride){
|
||||
mWeight = copyToDevice(weight[0].values, weight[0].count);
|
||||
mBias = copyToDevice(bias[0].values, bias[0].count);
|
||||
}
|
||||
|
||||
DeformableConvolutionalLayer::DeformableConvolutionalLayer(const void* buffer, size_t length)
|
||||
{
|
||||
const char* d = static_cast<const char*>(buffer);
|
||||
const char* a = d;
|
||||
in_channels = read<int>(d);
|
||||
height = read<int>(d);
|
||||
width = read<int>(d);
|
||||
height_out = read<int>(d);
|
||||
width_out = read<int>(d);
|
||||
|
||||
out_channels = read<int>(d);
|
||||
kernel_size = read<int>(d);
|
||||
deformable_group = read<int>(d);
|
||||
dilation = read<int>(d);
|
||||
padding = read<int>(d);
|
||||
stride = read<int>(d);
|
||||
|
||||
int count = read<int>(d);
|
||||
mWeight = deserializeToDevice(d, count);
|
||||
count = read<int>(d);
|
||||
mBias = deserializeToDevice(d, count);
|
||||
|
||||
ASSERT(d == a + length);
|
||||
}
|
||||
|
||||
int DeformableConvolutionalLayer::getNbOutputs() const
|
||||
{
|
||||
// Plugin layer has 2 outputs
|
||||
return 1;
|
||||
}
|
||||
|
||||
int DeformableConvolutionalLayer::initialize()
|
||||
{
|
||||
size_t oneSize = height_out * width_out * sizeof(float);
|
||||
std::vector<float> one_((int)oneSize, 1.0f);
|
||||
CHECK_CUDA(cudaMalloc((void**)&mOne, oneSize));
|
||||
CHECK_CUDA(cudaMalloc((void**)&mColumn, in_channels * kernel_size * kernel_size * oneSize));
|
||||
CHECK_CUDA(cudaMemcpy(mOne, one_.data(), oneSize, cudaMemcpyHostToDevice));
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
Dims DeformableConvolutionalLayer::getOutputDimensions(int index, const Dims* inputs, int nbInputs)
|
||||
{
|
||||
ASSERT(index == 0);
|
||||
ASSERT(nbInputs == 3);
|
||||
|
||||
in_channels = inputs[0].d[0];
|
||||
height = inputs[0].d[1];
|
||||
width = inputs[0].d[2];
|
||||
height_out = (inputs[0].d[1] + 2 * padding - (dilation * (kernel_size - 1) + 1)) / stride + 1;
|
||||
width_out = (inputs[0].d[2] + 2 * padding - (dilation * (kernel_size - 1) + 1)) / stride + 1;
|
||||
|
||||
return Dims3(out_channels, height_out, width_out);
|
||||
}
|
||||
|
||||
size_t DeformableConvolutionalLayer::getWorkspaceSize(int maxBatchSize) const
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int DeformableConvolutionalLayer::enqueue(int batchSize, const void* const* inputs, void** outputs, void* workspace, cudaStream_t stream)
|
||||
{
|
||||
const float* input = static_cast<const float *>(inputs[0]);
|
||||
const float* offset = static_cast<const float *>(inputs[1]);
|
||||
const float* offset_mask = static_cast<const float *>(inputs[2]);
|
||||
const float* mask = offset_mask + deformable_group * 2 * kernel_size * kernel_size * height * width;
|
||||
float * output = static_cast<float *>(outputs[0]);
|
||||
|
||||
float alpha{1}, beta{0};
|
||||
|
||||
// Do Bias first:
|
||||
// M,N,K are dims of matrix A and B
|
||||
// (see http://docs.nvidia.com/cuda/cublas/#cublas-lt-t-gt-gemm)
|
||||
// (N x 1) (1 x M)
|
||||
int m_ = out_channels;
|
||||
int n_ = height_out * width_out;
|
||||
int k_ = 1;
|
||||
cublasSgemm(mCublas, CUBLAS_OP_T, CUBLAS_OP_N, n_, m_, k_, &alpha,
|
||||
mOne, k_,
|
||||
static_cast<const float *>(mBias.values), k_, &beta,
|
||||
output, n_);
|
||||
|
||||
modulated_deformable_im2col_cuda(stream, input, offset, mask,
|
||||
1, in_channels, height, width,
|
||||
height_out, width_out, kernel_size, kernel_size,
|
||||
padding, padding, stride, stride, dilation, dilation,
|
||||
deformable_group, mColumn);
|
||||
|
||||
//(k * m) x (m * n)
|
||||
// Y = WC
|
||||
int m = out_channels;
|
||||
int n = height_out * width_out;
|
||||
int k = in_channels * kernel_size * kernel_size;
|
||||
cublasSgemm(mCublas, CUBLAS_OP_N, CUBLAS_OP_N, n, m, k, &alpha,
|
||||
mColumn, n,
|
||||
static_cast<const float *>(mWeight.values), k, &alpha,
|
||||
output, n);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t DeformableConvolutionalLayer::getSerializationSize() const
|
||||
{
|
||||
return sizeof(int) * 13 + (mWeight.count + mBias.count) * sizeof(float);
|
||||
}
|
||||
|
||||
void DeformableConvolutionalLayer::serialize(void* buffer) const
|
||||
{
|
||||
char *d = reinterpret_cast<char*>(buffer), *a = d;
|
||||
write(d, in_channels);
|
||||
write(d, height);
|
||||
write(d, width);
|
||||
write(d, height_out);
|
||||
write(d, width_out);
|
||||
|
||||
write(d, out_channels);
|
||||
write(d, kernel_size);
|
||||
write(d, deformable_group);
|
||||
write(d, dilation);
|
||||
write(d, padding);
|
||||
write(d, stride);
|
||||
|
||||
write(d, (int) mWeight.count);
|
||||
serializeFromDevice(d, mWeight);
|
||||
write(d, (int) mBias.count);
|
||||
serializeFromDevice(d, mBias);
|
||||
|
||||
ASSERT(d == a + getSerializationSize());
|
||||
}
|
||||
|
||||
bool DeformableConvolutionalLayer::supportsFormat(DataType type, PluginFormat format) const
|
||||
{
|
||||
return (type == DataType::kFLOAT && format == PluginFormat::kNCHW);
|
||||
}
|
||||
|
||||
Weights DeformableConvolutionalLayer::copyToDevice(const void* hostData, size_t count)
|
||||
{
|
||||
void* deviceData;
|
||||
CUASSERT(cudaMalloc(&deviceData, count * sizeof(float)));
|
||||
CUASSERT(cudaMemcpy(deviceData, hostData, count * sizeof(float), cudaMemcpyHostToDevice));
|
||||
return Weights{DataType::kFLOAT, deviceData, int64_t(count)};
|
||||
}
|
||||
|
||||
void DeformableConvolutionalLayer::serializeFromDevice(char*& hostBuffer, Weights deviceWeights) const
|
||||
{
|
||||
CUASSERT(cudaMemcpy(hostBuffer, deviceWeights.values, deviceWeights.count * sizeof(float), cudaMemcpyDeviceToHost));
|
||||
hostBuffer += deviceWeights.count * sizeof(float);
|
||||
}
|
||||
|
||||
Weights DeformableConvolutionalLayer::deserializeToDevice(const char*& hostBuffer, size_t count)
|
||||
{
|
||||
Weights w = copyToDevice(hostBuffer, count);
|
||||
hostBuffer += count * sizeof(float);
|
||||
return w;
|
||||
}
|
||||
|
||||
const char* DeformableConvolutionalLayer::getPluginType() const
|
||||
{
|
||||
return DCNv2_PLUGIN_NAME;
|
||||
}
|
||||
|
||||
const char* DeformableConvolutionalLayer::getPluginVersion() const
|
||||
{
|
||||
return DCNv2_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
void DeformableConvolutionalLayer::terminate() {
|
||||
if (mOne)
|
||||
{
|
||||
cudaFree(mOne);
|
||||
mOne = nullptr;
|
||||
}
|
||||
if (mColumn)
|
||||
{
|
||||
cudaFree(mColumn);
|
||||
mColumn = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void DeformableConvolutionalLayer::destroy()
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
IPluginV2Ext* DeformableConvolutionalLayer::clone() const
|
||||
{
|
||||
IPluginV2Ext* plugin = new DeformableConvolutionalLayer(*this);
|
||||
plugin->setPluginNamespace(mPluginNamespace.c_str());
|
||||
return plugin;
|
||||
}
|
||||
|
||||
// Set plugin namespace
|
||||
void DeformableConvolutionalLayer::setPluginNamespace(const char* pluginNamespace)
|
||||
{
|
||||
mPluginNamespace = pluginNamespace;
|
||||
}
|
||||
|
||||
const char* DeformableConvolutionalLayer::getPluginNamespace() const
|
||||
{
|
||||
return mPluginNamespace.c_str();
|
||||
}
|
||||
|
||||
// Return the DataType of the plugin output at the requested index.
|
||||
DataType DeformableConvolutionalLayer::getOutputDataType(int index, const nvinfer1::DataType* inputTypes, int nbInputs) const
|
||||
{
|
||||
// Only DataType::kFLOAT is acceptable by the plugin layer
|
||||
return DataType::kFLOAT;
|
||||
}
|
||||
// Return true if output tensor is broadcast across a batch.
|
||||
bool DeformableConvolutionalLayer::isOutputBroadcastAcrossBatch(int outputIndex, const bool* inputIsBroadcasted, int nbInputs) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Return true if plugin can use input that is broadcast across batch without replication.
|
||||
bool DeformableConvolutionalLayer::canBroadcastInputAcrossBatch(int inputIndex) const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Configure the layer with input and output data types.
|
||||
// inutDims: input Dimensions for the plugin layer
|
||||
// nInputs : Number of inputs to the plugin layer
|
||||
// outputDims: output Dimensions from the plugin layer
|
||||
// nOutputs: number of outputs from the plugin layer
|
||||
// type: DataType configuration for the plugin layer
|
||||
// format: format NCHW, NHWC etc
|
||||
// maxbatchSize: maximum batch size for the plugin layer
|
||||
void DeformableConvolutionalLayer::configurePlugin(const Dims* inputDims, int nbInputs, const Dims* outputDims, int nbOutputs,
|
||||
const DataType* inputTypes, const DataType* outputTypes, const bool* inputIsBroadcast,
|
||||
const bool* outputIsBroadcast, PluginFormat floatFormat, int maxBatchSize)
|
||||
{
|
||||
ASSERT(*inputTypes == DataType::kFLOAT && floatFormat == PluginFormat::kNCHW);
|
||||
}
|
||||
|
||||
// Attach the plugin object to an execution context and grant the plugin the access to some context resource.
|
||||
void DeformableConvolutionalLayer::attachToContext(cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator)
|
||||
{
|
||||
mCublas = cublasContext;
|
||||
}
|
||||
|
||||
// Detach the plugin object from its execution context.
|
||||
void DeformableConvolutionalLayer::detachFromContext() {}
|
||||
|
||||
DCNv2PluginCreator::DCNv2PluginCreator()
|
||||
{
|
||||
mPluginAttributes.emplace_back(PluginField("out_channels", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("kernel", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("deformable_group", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("dilation", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("padding", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("stride", nullptr, PluginFieldType::kINT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("weight", nullptr, PluginFieldType::kFLOAT32, 1));
|
||||
mPluginAttributes.emplace_back(PluginField("bias", nullptr, PluginFieldType::kFLOAT32, 1));
|
||||
|
||||
mFC.nbFields = mPluginAttributes.size();
|
||||
mFC.fields = mPluginAttributes.data();
|
||||
}
|
||||
|
||||
const char* DCNv2PluginCreator::getPluginName() const
|
||||
{
|
||||
return DCNv2_PLUGIN_NAME;
|
||||
}
|
||||
|
||||
const char* DCNv2PluginCreator::getPluginVersion() const
|
||||
{
|
||||
return DCNv2_PLUGIN_VERSION;
|
||||
}
|
||||
|
||||
const PluginFieldCollection* DCNv2PluginCreator::getFieldNames()
|
||||
{
|
||||
return &mFC;
|
||||
}
|
||||
|
||||
IPluginV2Ext* DCNv2PluginCreator::createPlugin(const char* name, const PluginFieldCollection* fc)
|
||||
{
|
||||
std::vector<float> weight;
|
||||
std::vector<float> bias;
|
||||
int out_channels, kernel, deformable_group, padding, stride, dilation;
|
||||
const PluginField* fields = fc->fields;
|
||||
for (int i = 0; i < fc->nbFields; ++i)
|
||||
{
|
||||
const char* attrName = fields[i].name;
|
||||
if (!strcmp(attrName, "out_channels"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
out_channels = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "kernel"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
kernel = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "deformable_group"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
deformable_group = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "dilation"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
dilation = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "stride"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
stride = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "padding"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kINT32);
|
||||
padding = *(static_cast<const int*>(fields[i].data));
|
||||
}
|
||||
else if (!strcmp(attrName, "weight"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
|
||||
int size = fields[i].length;
|
||||
weight.reserve(size);
|
||||
const auto* w = static_cast<const float*>(fields[i].data);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
weight.push_back(*w);
|
||||
w++;
|
||||
}
|
||||
}
|
||||
else if (!strcmp(attrName, "bias"))
|
||||
{
|
||||
ASSERT(fields[i].type == PluginFieldType::kFLOAT32);
|
||||
int size = fields[i].length;
|
||||
bias.reserve(size);
|
||||
const auto* w = static_cast<const float*>(fields[i].data);
|
||||
for (int j = 0; j < size; j++)
|
||||
{
|
||||
bias.push_back(*w);
|
||||
w++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Weights mWeight{DataType::kFLOAT, weight.data(), (int64_t) weight.size()};
|
||||
Weights mBias{DataType::kFLOAT, bias.data(), (int64_t) bias.size()};
|
||||
|
||||
DeformableConvolutionalLayer* obj = new DeformableConvolutionalLayer(out_channels,
|
||||
kernel,
|
||||
deformable_group,
|
||||
dilation,
|
||||
padding,
|
||||
stride,
|
||||
&mWeight, &mBias);
|
||||
obj->setPluginNamespace(mNamespace.c_str());
|
||||
return obj;
|
||||
}
|
||||
|
||||
IPluginV2Ext* DCNv2PluginCreator::deserializePlugin(const char* name, const void* serialData, size_t serialLength)
|
||||
{
|
||||
// This object will be deleted when the network is destroyed, which will
|
||||
// call Normalize::destroy()
|
||||
DeformableConvolutionalLayer* obj = new DeformableConvolutionalLayer(serialData, serialLength);
|
||||
obj->setPluginNamespace(mNamespace.c_str());
|
||||
return obj;
|
||||
}
|
||||
152
centernet/dcnv2Plugin/dcnv2Plugin.h
Normal file
152
centernet/dcnv2Plugin/dcnv2Plugin.h
Normal file
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* Copyright (c) 2020, NVIDIA CORPORATION. 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.
|
||||
*/
|
||||
#ifndef TRT_DCNV2_PLUGIN_H
|
||||
#define TRT_DCNV2_PLUGIN_H
|
||||
#include "kernel.h"
|
||||
#include "plugin.h"
|
||||
#include "dcn_v2_im2col_cuda.h"
|
||||
|
||||
#include "serialize.hpp"
|
||||
#include <cudnn.h>
|
||||
#include <vector>
|
||||
#include <cublas_v2.h>
|
||||
#include <cuda.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
using namespace nvinfer1::plugin;
|
||||
namespace nvinfer1
|
||||
{
|
||||
namespace plugin
|
||||
{
|
||||
|
||||
class DeformableConvolutionalLayer : public IPluginV2Ext
|
||||
{
|
||||
public:
|
||||
DeformableConvolutionalLayer(int out_channels,
|
||||
int kernel,
|
||||
int deformable_group,
|
||||
int dilation,
|
||||
int padding,
|
||||
int stride,
|
||||
const Weights* weight, const Weights* bias);
|
||||
|
||||
DeformableConvolutionalLayer(const void* buffer, size_t length);
|
||||
|
||||
~DeformableConvolutionalLayer() override = default;
|
||||
|
||||
int getNbOutputs() const override;
|
||||
|
||||
Dims getOutputDimensions(int index, const Dims* inputs, int nbInputs) override;
|
||||
|
||||
int initialize() override;
|
||||
|
||||
void terminate() override;
|
||||
|
||||
size_t getWorkspaceSize(int maxBatchSize) const override;
|
||||
|
||||
int enqueue(
|
||||
int batchSize, const void* const* inputs, void** outputs, void* workspace, cudaStream_t stream) override;
|
||||
|
||||
size_t getSerializationSize() const override;
|
||||
|
||||
void serialize(void* buffer) const override;
|
||||
|
||||
bool supportsFormat(DataType type, PluginFormat format) const override;
|
||||
|
||||
const char* getPluginType() const override;
|
||||
|
||||
const char* getPluginVersion() const override;
|
||||
|
||||
void destroy() override;
|
||||
|
||||
IPluginV2Ext* clone() const override;
|
||||
|
||||
void setPluginNamespace(const char* pluginNamespace) override;
|
||||
|
||||
const char* getPluginNamespace() const override;
|
||||
|
||||
DataType getOutputDataType(int index, const nvinfer1::DataType* inputTypes, int nbInputs) const override;
|
||||
|
||||
bool isOutputBroadcastAcrossBatch(int outputIndex, const bool* inputIsBroadcasted, int nbInputs) const override;
|
||||
|
||||
bool canBroadcastInputAcrossBatch(int inputIndex) const override;
|
||||
|
||||
void attachToContext(
|
||||
cudnnContext* cudnnContext, cublasContext* cublasContext, IGpuAllocator* gpuAllocator) override;
|
||||
|
||||
void configurePlugin(const Dims* inputDims, int nbInputs, const Dims* outputDims, int nbOutputs,
|
||||
const DataType* inputTypes, const DataType* outputTypes, const bool* inputIsBroadcast,
|
||||
const bool* outputIsBroadcast, PluginFormat floatFormat, int maxBatchSize) override;
|
||||
|
||||
void detachFromContext() override;
|
||||
|
||||
private:
|
||||
Weights copyToDevice(const void* hostData, size_t count);
|
||||
void serializeFromDevice(char*& hostBuffer, Weights deviceWeights) const;
|
||||
Weights deserializeToDevice(const char*& hostBuffer, size_t count);
|
||||
|
||||
std::string mPluginNamespace;
|
||||
|
||||
int in_channels{};
|
||||
int height_out{};
|
||||
int width_out{};
|
||||
int height{};
|
||||
int width{};
|
||||
|
||||
int out_channels{};
|
||||
int kernel_size{};
|
||||
int deformable_group{};
|
||||
int dilation{};
|
||||
int padding{};
|
||||
int stride{};
|
||||
|
||||
Weights mWeight{};
|
||||
Weights mBias{};
|
||||
|
||||
float* mOne;
|
||||
float* mColumn;
|
||||
|
||||
cublasHandle_t mCublas;
|
||||
};
|
||||
|
||||
class DCNv2PluginCreator : public BaseCreator
|
||||
{
|
||||
public:
|
||||
DCNv2PluginCreator();
|
||||
|
||||
~DCNv2PluginCreator() override = default;
|
||||
|
||||
const char* getPluginName() const override;
|
||||
|
||||
const char* getPluginVersion() const override;
|
||||
|
||||
const PluginFieldCollection* getFieldNames() override;
|
||||
|
||||
IPluginV2Ext* createPlugin(const char* name, const PluginFieldCollection* fc) override;
|
||||
|
||||
IPluginV2Ext* deserializePlugin(const char* name, const void* serialData, size_t serialLength) override;
|
||||
|
||||
private:
|
||||
static PluginFieldCollection mFC;
|
||||
|
||||
// Parameters for DeformableConvolutionalLayer
|
||||
static std::vector<PluginField> mPluginAttributes;
|
||||
};
|
||||
} // namespace plugin
|
||||
} // namespace nvinfer1
|
||||
|
||||
#endif // TRT_DCNv2_PLUGIN_H
|
||||
238
centernet/sample/common.py
Normal file
238
centernet/sample/common.py
Normal file
@ -0,0 +1,238 @@
|
||||
#
|
||||
# Copyright 1993-2020 NVIDIA Corporation. All rights reserved.
|
||||
#
|
||||
# NOTICE TO LICENSEE:
|
||||
#
|
||||
# This source code and/or documentation ("Licensed Deliverables") are
|
||||
# subject to NVIDIA intellectual property rights under U.S. and
|
||||
# international Copyright laws.
|
||||
#
|
||||
# These Licensed Deliverables contained herein is PROPRIETARY and
|
||||
# CONFIDENTIAL to NVIDIA and is being provided under the terms and
|
||||
# conditions of a form of NVIDIA software license agreement by and
|
||||
# between NVIDIA and Licensee ("License Agreement") or electronically
|
||||
# accepted by Licensee. Notwithstanding any terms or conditions to
|
||||
# the contrary in the License Agreement, reproduction or disclosure
|
||||
# of the Licensed Deliverables to any third party without the express
|
||||
# written consent of NVIDIA is prohibited.
|
||||
#
|
||||
# NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE
|
||||
# LICENSE AGREEMENT, NVIDIA MAKES NO REPRESENTATION ABOUT THE
|
||||
# SUITABILITY OF THESE LICENSED DELIVERABLES FOR ANY PURPOSE. IT IS
|
||||
# PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY OF ANY KIND.
|
||||
# NVIDIA DISCLAIMS ALL WARRANTIES WITH REGARD TO THESE LICENSED
|
||||
# DELIVERABLES, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||
# NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE.
|
||||
# NOTWITHSTANDING ANY TERMS OR CONDITIONS TO THE CONTRARY IN THE
|
||||
# LICENSE AGREEMENT, IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY
|
||||
# SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, OR ANY
|
||||
# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
|
||||
# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
|
||||
# OF THESE LICENSED DELIVERABLES.
|
||||
#
|
||||
# U.S. Government End Users. These Licensed Deliverables are a
|
||||
# "commercial item" as that term is defined at 48 C.F.R. 2.101 (OCT
|
||||
# 1995), consisting of "commercial computer software" and "commercial
|
||||
# computer software documentation" as such terms are used in 48
|
||||
# C.F.R. 12.212 (SEPT 1995) and is provided to the U.S. Government
|
||||
# only as a commercial end item. Consistent with 48 C.F.R.12.212 and
|
||||
# 48 C.F.R. 227.7202-1 through 227.7202-4 (JUNE 1995), all
|
||||
# U.S. Government End Users acquire the Licensed Deliverables with
|
||||
# only those rights set forth herein.
|
||||
#
|
||||
# Any use of the Licensed Deliverables in individual and commercial
|
||||
# software must include, in the user documentation and internal
|
||||
# comments to the code, the above Disclaimer and U.S. Government End
|
||||
# Users Notice.
|
||||
#
|
||||
|
||||
from itertools import chain
|
||||
import argparse
|
||||
import os
|
||||
|
||||
import pycuda.driver as cuda
|
||||
import pycuda.autoinit
|
||||
import numpy as np
|
||||
|
||||
import tensorrt as trt
|
||||
|
||||
try:
|
||||
# Sometimes python2 does not understand FileNotFoundError
|
||||
FileNotFoundError
|
||||
except NameError:
|
||||
FileNotFoundError = IOError
|
||||
|
||||
EXPLICIT_BATCH = 1 << (int)(trt.NetworkDefinitionCreationFlag.EXPLICIT_BATCH)
|
||||
|
||||
def GiB(val):
|
||||
return val * 1 << 30
|
||||
|
||||
|
||||
def add_help(description):
|
||||
parser = argparse.ArgumentParser(description=description, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
|
||||
def find_sample_data(description="Runs a TensorRT Python sample", subfolder="", find_files=[], err_msg=""):
|
||||
'''
|
||||
Parses sample arguments.
|
||||
|
||||
Args:
|
||||
description (str): Description of the sample.
|
||||
subfolder (str): The subfolder containing data relevant to this sample
|
||||
find_files (str): A list of filenames to find. Each filename will be replaced with an absolute path.
|
||||
|
||||
Returns:
|
||||
str: Path of data directory.
|
||||
'''
|
||||
|
||||
# Standard command-line arguments for all samples.
|
||||
kDEFAULT_DATA_ROOT = os.path.join(os.sep, "usr", "src", "tensorrt", "data")
|
||||
parser = argparse.ArgumentParser(description=description, formatter_class=argparse.ArgumentDefaultsHelpFormatter)
|
||||
parser.add_argument("-d", "--datadir", help="Location of the TensorRT sample data directory, and any additional data directories.", action="append", default=[kDEFAULT_DATA_ROOT])
|
||||
args, _ = parser.parse_known_args()
|
||||
|
||||
def get_data_path(data_dir):
|
||||
# If the subfolder exists, append it to the path, otherwise use the provided path as-is.
|
||||
data_path = os.path.join(data_dir, subfolder)
|
||||
if not os.path.exists(data_path):
|
||||
if data_dir != kDEFAULT_DATA_ROOT:
|
||||
print("WARNING: " + data_path + " does not exist. Trying " + data_dir + " instead.")
|
||||
data_path = data_dir
|
||||
# Make sure data directory exists.
|
||||
if not (os.path.exists(data_path)) and data_dir != kDEFAULT_DATA_ROOT:
|
||||
print("WARNING: {:} does not exist. Please provide the correct data path with the -d option.".format(data_path))
|
||||
return data_path
|
||||
|
||||
data_paths = [get_data_path(data_dir) for data_dir in args.datadir]
|
||||
return data_paths, locate_files(data_paths, find_files, err_msg)
|
||||
|
||||
def locate_files(data_paths, filenames, err_msg=""):
|
||||
"""
|
||||
Locates the specified files in the specified data directories.
|
||||
If a file exists in multiple data directories, the first directory is used.
|
||||
|
||||
Args:
|
||||
data_paths (List[str]): The data directories.
|
||||
filename (List[str]): The names of the files to find.
|
||||
|
||||
Returns:
|
||||
List[str]: The absolute paths of the files.
|
||||
|
||||
Raises:
|
||||
FileNotFoundError if a file could not be located.
|
||||
"""
|
||||
found_files = [None] * len(filenames)
|
||||
for data_path in data_paths:
|
||||
# Find all requested files.
|
||||
for index, (found, filename) in enumerate(zip(found_files, filenames)):
|
||||
if not found:
|
||||
file_path = os.path.abspath(os.path.join(data_path, filename))
|
||||
if os.path.exists(file_path):
|
||||
found_files[index] = file_path
|
||||
|
||||
# Check that all files were found
|
||||
for f, filename in zip(found_files, filenames):
|
||||
if not f or not os.path.exists(f):
|
||||
raise FileNotFoundError("Could not find {:}. Searched in data paths: {:}\n{:}".format(filename, data_paths, err_msg))
|
||||
return found_files
|
||||
|
||||
# Simple helper data class that's a little nicer to use than a 2-tuple.
|
||||
class HostDeviceMem(object):
|
||||
def __init__(self, host_mem, device_mem):
|
||||
self.host = host_mem
|
||||
self.device = device_mem
|
||||
|
||||
def __str__(self):
|
||||
return "Host:\n" + str(self.host) + "\nDevice:\n" + str(self.device)
|
||||
|
||||
def __repr__(self):
|
||||
return self.__str__()
|
||||
|
||||
# Allocates all buffers required for an engine, i.e. host/device inputs/outputs.
|
||||
def allocate_buffers(engine):
|
||||
inputs = []
|
||||
outputs = []
|
||||
bindings = []
|
||||
stream = cuda.Stream()
|
||||
for binding in engine:
|
||||
size = trt.volume(engine.get_binding_shape(binding)) * engine.max_batch_size
|
||||
dtype = trt.nptype(engine.get_binding_dtype(binding))
|
||||
# Allocate host and device buffers
|
||||
host_mem = cuda.pagelocked_empty(size, dtype)
|
||||
device_mem = cuda.mem_alloc(host_mem.nbytes)
|
||||
# Append the device buffer to device bindings.
|
||||
bindings.append(int(device_mem))
|
||||
# Append to the appropriate list.
|
||||
if engine.binding_is_input(binding):
|
||||
inputs.append(HostDeviceMem(host_mem, device_mem))
|
||||
else:
|
||||
outputs.append(HostDeviceMem(host_mem, device_mem))
|
||||
return inputs, outputs, bindings, stream
|
||||
|
||||
# This function is generalized for multiple inputs/outputs.
|
||||
# inputs and outputs are expected to be lists of HostDeviceMem objects.
|
||||
def do_inference(context, bindings, inputs, outputs, stream, batch_size=1):
|
||||
# Transfer input data to the GPU.
|
||||
[cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
|
||||
# Run inference.
|
||||
context.execute_async(batch_size=batch_size, bindings=bindings, stream_handle=stream.handle)
|
||||
# Transfer predictions back from the GPU.
|
||||
[cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
|
||||
# Synchronize the stream
|
||||
stream.synchronize()
|
||||
# Return only the host outputs.
|
||||
return [out.host for out in outputs]
|
||||
|
||||
# This function is generalized for multiple inputs/outputs for full dimension networks.
|
||||
# inputs and outputs are expected to be lists of HostDeviceMem objects.
|
||||
def do_inference_v2(context, bindings, inputs, outputs, stream):
|
||||
# Transfer input data to the GPU.
|
||||
[cuda.memcpy_htod_async(inp.device, inp.host, stream) for inp in inputs]
|
||||
# Run inference.
|
||||
context.execute_async_v2(bindings=bindings, stream_handle=stream.handle)
|
||||
# Transfer predictions back from the GPU.
|
||||
[cuda.memcpy_dtoh_async(out.host, out.device, stream) for out in outputs]
|
||||
# Synchronize the stream
|
||||
stream.synchronize()
|
||||
# Return only the host outputs.
|
||||
return [out.host for out in outputs]
|
||||
|
||||
|
||||
# `retry_call` and `retry` are used to wrap the function we want to try multiple times
|
||||
def retry_call(func, args=[], kwargs={}, n_retries=3):
|
||||
"""Wrap a function to retry it several times.
|
||||
|
||||
Args:
|
||||
func: function to call
|
||||
args (List): args parsed to func
|
||||
kwargs (Dict): kwargs parsed to func
|
||||
n_retries (int): maximum times of tries
|
||||
"""
|
||||
for i_try in range(n_retries):
|
||||
try:
|
||||
func(*args, **kwargs)
|
||||
break
|
||||
except:
|
||||
if i_try == n_retries - 1:
|
||||
raise
|
||||
print("retry...")
|
||||
|
||||
# Usage: @retry(n_retries)
|
||||
def retry(n_retries=3):
|
||||
"""Wrap a function to retry it several times. Decorator version of `retry_call`.
|
||||
|
||||
Args:
|
||||
n_retries (int): maximum times of tries
|
||||
|
||||
Usage:
|
||||
@retry(n_retries)
|
||||
def func(...):
|
||||
pass
|
||||
"""
|
||||
def wrapper(func):
|
||||
def _wrapper(*args, **kwargs):
|
||||
retry_call(func, args, kwargs, n_retries)
|
||||
return _wrapper
|
||||
return wrapper
|
||||
134
centernet/sample/test.py
Normal file
134
centernet/sample/test.py
Normal file
@ -0,0 +1,134 @@
|
||||
import cv2 as cv
|
||||
import numpy as np
|
||||
|
||||
import tensorrt as trt
|
||||
import common
|
||||
|
||||
import torch
|
||||
import time
|
||||
from sys import argv
|
||||
|
||||
# You can set the logger severity higher to suppress messages (or lower to display more messages).
|
||||
TRT_LOGGER = trt.Logger(trt.Logger.WARNING)
|
||||
trt.init_libnvinfer_plugins(TRT_LOGGER, '')
|
||||
|
||||
|
||||
def _gather_feat(feat, ind, mask=None):
|
||||
dim = feat.size(2)
|
||||
ind = ind.unsqueeze(2).expand(ind.size(0), ind.size(1), dim)
|
||||
feat = feat.gather(1, ind)
|
||||
if mask is not None:
|
||||
mask = mask.unsqueeze(2).expand_as(feat)
|
||||
feat = feat[mask]
|
||||
feat = feat.view(-1, dim)
|
||||
return feat
|
||||
|
||||
|
||||
def _transpose_and_gather_feat(feat, ind):
|
||||
feat = feat.permute(0, 2, 3, 1).contiguous()
|
||||
feat = feat.view(feat.size(0), -1, feat.size(3))
|
||||
feat = _gather_feat(feat, ind)
|
||||
return feat
|
||||
|
||||
|
||||
def pre_process(image):
|
||||
long_size = max(image.shape)
|
||||
img = np.zeros((long_size, long_size, 3))
|
||||
img[:image.shape[0], :img.shape[1], :] = image[:]
|
||||
img = cv.resize(img, (512,512))
|
||||
inp_image = ((img / 255. - 0.5) / 0.5).astype(np.float32)
|
||||
images = inp_image.transpose(2, 0, 1)
|
||||
return images, long_size/512
|
||||
|
||||
|
||||
def _nms(heat, kernel=3):
|
||||
pad = (kernel - 1) // 2
|
||||
|
||||
hmax = torch.nn.functional.max_pool2d(
|
||||
heat, (kernel, kernel), stride=1, padding=pad)
|
||||
keep = (hmax == heat).float()
|
||||
return heat * keep
|
||||
|
||||
|
||||
def _topk(scores, K=40):
|
||||
batch, cat, height, width = scores.size()
|
||||
|
||||
topk_scores, topk_inds = torch.topk(scores.view(batch, cat, -1), K)
|
||||
|
||||
topk_inds = topk_inds % (height * width)
|
||||
topk_ys = (topk_inds.true_divide(width)).int().float()
|
||||
topk_xs = (topk_inds % width).int().float()
|
||||
|
||||
topk_score, topk_ind = torch.topk(topk_scores.view(batch, -1), K)
|
||||
topk_clses = (topk_ind.true_divide(K)).int()
|
||||
topk_inds = _gather_feat(
|
||||
topk_inds.view(batch, -1, 1), topk_ind).view(batch, K)
|
||||
topk_ys = _gather_feat(topk_ys.view(batch, -1, 1), topk_ind).view(batch, K)
|
||||
topk_xs = _gather_feat(topk_xs.view(batch, -1, 1), topk_ind).view(batch, K)
|
||||
|
||||
return topk_score, topk_inds, topk_clses, topk_ys, topk_xs
|
||||
|
||||
|
||||
def ctdet_decode(heat, wh, reg=None, cat_spec_wh=False, K=100):
|
||||
batch, cat, height, width = heat.size()
|
||||
|
||||
heat = torch.sigmoid(heat)
|
||||
# perform nms on heatmaps
|
||||
heat = _nms(heat)
|
||||
|
||||
scores, inds, clses, ys, xs = _topk(heat, K=K)
|
||||
if reg is not None:
|
||||
reg = _transpose_and_gather_feat(reg, inds)
|
||||
reg = reg.view(batch, K, 2)
|
||||
xs = xs.view(batch, K, 1) + reg[:, :, 0:1]
|
||||
ys = ys.view(batch, K, 1) + reg[:, :, 1:2]
|
||||
else:
|
||||
xs = xs.view(batch, K, 1) + 0.5
|
||||
ys = ys.view(batch, K, 1) + 0.5
|
||||
wh = _transpose_and_gather_feat(wh, inds)
|
||||
if cat_spec_wh:
|
||||
wh = wh.view(batch, K, cat, 2)
|
||||
clses_ind = clses.view(batch, K, 1, 1).expand(batch, K, 1, 2).long()
|
||||
wh = wh.gather(2, clses_ind).view(batch, K, 2)
|
||||
else:
|
||||
wh = wh.view(batch, K, 2)
|
||||
clses = clses.view(batch, K, 1).float()
|
||||
scores = scores.view(batch, K, 1)
|
||||
bboxes = torch.cat([xs - wh[..., 0:1] / 2,
|
||||
ys - wh[..., 1:2] / 2,
|
||||
xs + wh[..., 0:1] / 2,
|
||||
ys + wh[..., 1:2] / 2], dim=2)
|
||||
detections = torch.cat([bboxes, scores, clses], dim=2)
|
||||
return detections
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
engine_path = argv[1]
|
||||
img_path = argv[2]
|
||||
except:
|
||||
print('engine path and image path are needed!')
|
||||
exit()
|
||||
with open(engine_path, "rb") as f, trt.Runtime(TRT_LOGGER) as runtime, runtime.deserialize_cuda_engine(f.read()) as engine:
|
||||
inputs, outputs, bindings, stream = common.allocate_buffers(engine)
|
||||
with engine.create_execution_context() as context:
|
||||
img = cv.imread('test.jpg')
|
||||
dis = img.copy()
|
||||
img, s = pre_process(img)
|
||||
# Copy to the pagelocked input buffer
|
||||
np.copyto(inputs[0].host, img.ravel())
|
||||
[hm, wh, reg] = common.do_inference(
|
||||
context, bindings=bindings, inputs=inputs, outputs=outputs, stream=stream, batch_size=1)
|
||||
|
||||
[dets] = ctdet_decode(torch.from_numpy(hm.reshape(1, 80, 128, 128)), torch.from_numpy(
|
||||
wh.reshape(1, 2, 128, 128)), torch.from_numpy(reg.reshape(1, 2, 128, 128)))
|
||||
|
||||
for i in dets:
|
||||
if i[-2] > 0.5:
|
||||
i[:4] *= 4*s
|
||||
cv.rectangle(dis, (int(i[0]), int(
|
||||
i[1])), (int(i[2]), int(i[3])), 255, 1)
|
||||
cv.putText(dis, '%d' %
|
||||
int(i[-1]), (int(i[0]), int(i[1])), 1, 1, 255)
|
||||
|
||||
cv.imwrite('trt_out.jpg', dis)
|
||||
Loading…
Reference in New Issue
Block a user