chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
// Copyright (c) 2022 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.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paddle/common/hostdevice.h"
|
||||
#include "paddle/phi/core/dense_tensor.h"
|
||||
#include "paddle/phi/kernels/empty_kernel.h"
|
||||
#include "paddle/phi/kernels/full_kernel.h"
|
||||
#include "paddle/phi/kernels/funcs/blas/blas.h"
|
||||
#include "paddle/phi/kernels/funcs/deformable_conv_functor.h"
|
||||
#include "paddle/phi/kernels/transpose_kernel.h"
|
||||
#include "paddle/utils/optional.h"
|
||||
|
||||
namespace phi {
|
||||
|
||||
template <typename T, typename Context>
|
||||
void DeformableConvKernel(const Context& dev_ctx,
|
||||
const DenseTensor& x,
|
||||
const DenseTensor& offset,
|
||||
const DenseTensor& filter,
|
||||
const optional<DenseTensor>& mask,
|
||||
const std::vector<int>& strides,
|
||||
const std::vector<int>& paddings,
|
||||
const std::vector<int>& dilations,
|
||||
int deformable_groups,
|
||||
int groups,
|
||||
int im2col_step,
|
||||
DenseTensor* out) {
|
||||
if (x.numel() == 0 || filter.numel() == 0) {
|
||||
Full<T, Context>(dev_ctx, out->dims(), 0, out);
|
||||
return;
|
||||
}
|
||||
|
||||
const int64_t batch_size = static_cast<int64_t>(x.dims()[0]);
|
||||
|
||||
int64_t temp_step = std::min<int64_t>(64, batch_size);
|
||||
if (batch_size % temp_step == 0) {
|
||||
im2col_step = temp_step;
|
||||
}
|
||||
|
||||
std::vector<int64_t> filter_shape_vec(vectorize(filter.dims()));
|
||||
std::vector<int64_t> output_shape_vec(vectorize(out->dims()));
|
||||
|
||||
// col_shape_vec: {c_i * k_h * k_w, im2col_step, o_h, o_w}
|
||||
std::vector<int64_t> col_buffer_shape_vec(filter_shape_vec.size());
|
||||
col_buffer_shape_vec[0] = x.dims()[1] * filter.dims()[2] * filter.dims()[3];
|
||||
col_buffer_shape_vec[1] = im2col_step;
|
||||
for (size_t j = 0; j < filter_shape_vec.size() - 2; ++j) {
|
||||
col_buffer_shape_vec[j + 2] = output_shape_vec[j + 2];
|
||||
}
|
||||
|
||||
std::vector<int64_t> output_buffer_shape_vec(1);
|
||||
output_buffer_shape_vec[0] = batch_size * output_shape_vec[1] *
|
||||
output_shape_vec[2] * output_shape_vec[3];
|
||||
|
||||
DenseTensor col_buffer = Empty<T>(dev_ctx, col_buffer_shape_vec);
|
||||
DenseTensor output_buffer = Empty<T>(dev_ctx, output_buffer_shape_vec);
|
||||
|
||||
int64_t M = output_shape_vec[1] / groups;
|
||||
int64_t N = im2col_step * output_shape_vec[2] * output_shape_vec[3];
|
||||
int64_t K = x.dims()[1] * filter_shape_vec[2] * filter_shape_vec[3] / groups;
|
||||
|
||||
DenseTensor weight_3d;
|
||||
weight_3d.ShareDataWith(filter).Resize({groups, M, K});
|
||||
|
||||
DenseTensor col_buffer_3d;
|
||||
col_buffer_3d.ShareDataWith(col_buffer).Resize({groups, K, N});
|
||||
|
||||
DenseTensor output_4d;
|
||||
output_4d.ShareDataWith(output_buffer)
|
||||
.Resize({batch_size / im2col_step, groups, M, N});
|
||||
|
||||
DDim input_shape = slice_ddim(x.dims(), 1, x.dims().size());
|
||||
std::vector<int64_t> input_shape_vec = vectorize(input_shape);
|
||||
|
||||
int64_t input_dim = x.numel() / x.dims()[0];
|
||||
int64_t input_offset_dim = offset.numel() / offset.dims()[0];
|
||||
int64_t input_mask_dim = mask ? mask->numel() / mask->dims()[0] : 0;
|
||||
|
||||
const T* input_ptr = x.data<T>();
|
||||
const T* offset_ptr = offset.data<T>();
|
||||
const T* mask_ptr = mask ? mask->data<T>() : nullptr;
|
||||
T* col_buffer_ptr = col_buffer.data<T>();
|
||||
|
||||
auto blas = funcs::GetBlas<Context, T>(dev_ctx);
|
||||
|
||||
bool using_int32_index =
|
||||
(x.numel() <= std::numeric_limits<int>::max()) &&
|
||||
(offset.numel() <= std::numeric_limits<int>::max()) &&
|
||||
(filter.numel() <= std::numeric_limits<int>::max()) &&
|
||||
(mask ? mask->numel() <= std::numeric_limits<int>::max() : true) &&
|
||||
(out->numel() <= std::numeric_limits<int>::max());
|
||||
|
||||
for (int64_t i = 0; i < batch_size / im2col_step; ++i) {
|
||||
const T* temp_mask_ptr =
|
||||
mask_ptr ? mask_ptr + i * im2col_step * input_mask_dim : nullptr;
|
||||
if (using_int32_index) {
|
||||
funcs::ModulatedDeformableIm2col<T, Context, int>(
|
||||
dev_ctx,
|
||||
input_ptr + i * im2col_step * input_dim,
|
||||
offset_ptr + i * im2col_step * input_offset_dim,
|
||||
temp_mask_ptr,
|
||||
input_shape_vec,
|
||||
col_buffer_shape_vec,
|
||||
filter_shape_vec,
|
||||
paddings,
|
||||
strides,
|
||||
dilations,
|
||||
deformable_groups,
|
||||
col_buffer_ptr);
|
||||
} else {
|
||||
funcs::ModulatedDeformableIm2col<T, Context, int64_t>(
|
||||
dev_ctx,
|
||||
input_ptr + i * im2col_step * input_dim,
|
||||
offset_ptr + i * im2col_step * input_offset_dim,
|
||||
temp_mask_ptr,
|
||||
input_shape_vec,
|
||||
col_buffer_shape_vec,
|
||||
filter_shape_vec,
|
||||
paddings,
|
||||
strides,
|
||||
dilations,
|
||||
deformable_groups,
|
||||
col_buffer_ptr);
|
||||
}
|
||||
|
||||
DenseTensor output_3d = output_4d.Slice(i, i + 1).Resize(slice_ddim(
|
||||
output_4d.dims(),
|
||||
1,
|
||||
output_4d.dims().size())); // group * C/group * (im2step * H * W)
|
||||
|
||||
// get the product of pixel and weight
|
||||
for (int g = 0; g < groups; ++g) {
|
||||
DenseTensor weight_3d_slice = weight_3d.Slice(g, g + 1).Resize(
|
||||
slice_ddim(weight_3d.dims(), 1, weight_3d.dims().size()));
|
||||
DenseTensor col_buffer_3d_slice = col_buffer_3d.Slice(g, g + 1).Resize(
|
||||
slice_ddim(col_buffer_3d.dims(), 1, col_buffer_3d.dims().size()));
|
||||
DenseTensor output_3d_slice = output_3d.Slice(g, g + 1).Resize(
|
||||
slice_ddim(output_3d.dims(),
|
||||
1,
|
||||
output_3d.dims().size())); // C * ((im2col_step)*H*W))
|
||||
blas.MatMul(weight_3d_slice,
|
||||
false,
|
||||
col_buffer_3d_slice,
|
||||
false,
|
||||
T(1.0),
|
||||
&output_3d_slice,
|
||||
T(0.0));
|
||||
}
|
||||
}
|
||||
|
||||
// swap axis to get the right result when im2col_step is greater than 1
|
||||
if (im2col_step > 1) {
|
||||
std::vector<int> axis(4);
|
||||
axis[0] = 0;
|
||||
axis[1] = 2;
|
||||
axis[2] = 1;
|
||||
axis[3] = 3;
|
||||
|
||||
DenseTensor real_output_buffer = Transpose<T, Context>(
|
||||
dev_ctx,
|
||||
output_4d.Resize(
|
||||
make_ddim({batch_size / im2col_step,
|
||||
output_shape_vec[1],
|
||||
im2col_step,
|
||||
output_shape_vec[2] * output_shape_vec[3]})),
|
||||
axis);
|
||||
|
||||
out->ShareDataWith(real_output_buffer).Resize(output_shape_vec);
|
||||
} else {
|
||||
out->ShareDataWith(output_buffer).Resize(output_shape_vec);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace phi
|
||||
Reference in New Issue
Block a user