Skip to content

Commit

Permalink
Add experimental CV-CUDA resize
Browse files Browse the repository at this point in the history
Signed-off-by: Rafal Banas <rbanas@nvidia.com>
  • Loading branch information
banasraf committed Sep 18, 2024
1 parent bdcf160 commit be71021
Show file tree
Hide file tree
Showing 14 changed files with 719 additions and 62 deletions.
2 changes: 1 addition & 1 deletion cmake/Dependencies.common.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@ if (BUILD_CVCUDA)
set(DALI_BUILD_PYTHON ${BUILD_PYTHON})
set(BUILD_PYTHON OFF)
# for now we use only median blur from CV-CUDA
set(CV_CUDA_SRC_PATERN medianblur median_blur morphology warp)
set(CV_CUDA_SRC_PATERN medianblur median_blur morphology warp HQResize)
check_and_add_cmake_submodule(${PROJECT_SOURCE_DIR}/third_party/cvcuda)
set(BUILD_PYTHON ${DALI_BUILD_PYTHON})
endif()
Expand Down
7 changes: 6 additions & 1 deletion dali/operators/image/resize/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright (c) 2017-2018, NVIDIA CORPORATION. All rights reserved.
# Copyright (c) 2017-2024, 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.
Expand All @@ -12,7 +12,12 @@
# See the License for the specific language governing permissions and
# limitations under the License.

if (BUILD_CVCUDA)
add_subdirectory(experimental)
endif()

# Get all the source files and dump test files
collect_headers(DALI_INST_HDRS PARENT_SCOPE)
collect_sources(DALI_OPERATOR_SRCS PARENT_SCOPE)
collect_test_sources(DALI_OPERATOR_TEST_SRCS PARENT_SCOPE)

18 changes: 18 additions & 0 deletions dali/operators/image/resize/experimental/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. 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.


collect_headers(DALI_INST_HDRS PARENT_SCOPE)
collect_sources(DALI_OPERATOR_SRCS PARENT_SCOPE)
collect_test_sources(DALI_OPERATOR_TEST_SRCS PARENT_SCOPE)
79 changes: 79 additions & 0 deletions dali/operators/image/resize/experimental/resize.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. 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.

#define DALI_RESIZE_BASE_CC

#include "dali/operators/image/resize/experimental/resize.h"
#include <cassert>
#include "dali/pipeline/data/views.h"

namespace dali {

DALI_SCHEMA(experimental__Resize)
.DocStr(R"code(Resize images.)code")
.NumInput(1)
.NumOutput(1)
.AdditionalOutputsFn([](const OpSpec& spec) {
return static_cast<int>(spec.GetArgument<bool>("save_attrs"));
})
.InputLayout(0, {"HWC", "FHWC", "CHW", "FCHW", "CFHW" ,
"DHWC", "FDHWC", "CDHW", "FCDHW", "CFDHW" })
.AddOptionalArg("save_attrs",
R"code(Save reshape attributes for testing.)code", false)
.AddOptionalArg<DALIImageType>("image_type", "Image type", nullptr)
.DeprecateArg("image_type") // deprecated since 0.25dev
.SupportVolumetric()
.AllowSequences()
.AddParent("ResizeAttr")
.AddParent("ResamplingFilterAttr");

CvCudaResize::CvCudaResize(const OpSpec &spec)
: StatelessOperator<GPUBackend>(spec)
, ResizeBase<GPUBackend>(spec) {
save_attrs_ = this->spec_.HasArgument("save_attrs");
InitializeBackend();
}

void CvCudaResize::InitializeBackend() {
InitializeGPU(spec_.GetArgument<int>("minibatch_size"),
spec_.GetArgument<int64_t>("temp_buffer_hint"));
}

void CvCudaResize::RunImpl(Workspace &ws) {
const auto &input = ws.Input<GPUBackend>(0);
auto &output = ws.Output<GPUBackend>(0);

RunResize(ws, output, input);
output.SetLayout(input.GetLayout());

if (save_attrs_) {
auto &attr_out = ws.Output<GPUBackend>(1);
const auto &attr_shape = attr_out.shape();
assert(attr_shape.num_samples() == input.shape().num_samples() &&
attr_shape.sample_dim() == 1 &&
is_uniform(attr_shape) &&
attr_shape[0][0] == NumSpatialDims());

if (!attr_staging_.has_data())
attr_staging_.set_pinned(true);
attr_staging_.Resize(attr_out.shape(), DALI_INT32);
auto attr_view = view<int, 1>(attr_staging_);
SaveAttrs(attr_view, input.shape());
attr_out.Copy(attr_staging_, ws.stream());
}
}

DALI_REGISTER_OPERATOR(experimental__Resize, CvCudaResize, GPU);

} // namespace dali
135 changes: 135 additions & 0 deletions dali/operators/image/resize/experimental/resize.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
// Copyright (c) 2024, NVIDIA CORPORATION & AFFILIATES. 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 DALI_OPERATORS_IMAGE_RESIZE_EXPERIMENTAL_RESIZE_H_
#define DALI_OPERATORS_IMAGE_RESIZE_EXPERIMENTAL_RESIZE_H_

#include <random>
#include <utility>
#include <vector>
#include <memory>

#include "dali/core/common.h"
#include "dali/core/error_handling.h"
#include "dali/kernels/context.h"
#include "dali/kernels/imgproc/resample/params.h"
#include "dali/kernels/scratch.h"
#include "dali/operators/image/resize/experimental/resize_op_impl_cvcuda.h"
#include "dali/operators/image/resize/resize_attr.h"
#include "dali/operators/image/resize/resize_base.h"
#include "dali/pipeline/operator/checkpointing/stateless_operator.h"
#include "dali/pipeline/operator/common.h"

namespace dali {

class CvCudaResize : public StatelessOperator<GPUBackend>, protected ResizeBase<GPUBackend> {
public:
explicit CvCudaResize(const OpSpec &spec);

protected:
void SetupResize(TensorListShape<> &out_shape, DALIDataType out_type,
const TensorListShape<> &in_shape, DALIDataType in_type,
span<const kernels::ResamplingParams> params, int spatial_ndim,
int first_spatial_dim) {
VALUE_SWITCH(spatial_ndim, static_spatial_ndim, (2, 3),
(
using ImplType = ResizeOpImplCvCuda<static_spatial_ndim>;
SetImpl<ImplType>([&]{ return std::make_unique<ImplType>(GetMinibatchSize()); });
impl_->Setup(out_shape, in_shape, first_spatial_dim, params);
), // NOLINT
(DALI_FAIL(make_string("Unsupported number of resized dimensions: ", spatial_ndim))));
}


int NumSpatialDims() const {
return resize_attr_.spatial_ndim_;
}
int FirstSpatialDim() const {
return resize_attr_.first_spatial_dim_;
}

bool CanInferOutputs() const override {
return true;
}

bool SetupImpl(std::vector<OutputDesc> &output_desc, const Workspace &ws) override;

void RunImpl(Workspace &ws) override;

void SaveAttrs(const TensorListView<StorageCPU, int, 1> &shape_data,
const TensorListShape<> &orig_shape) const {
int N = orig_shape.num_samples();
int D = NumSpatialDims();
assert(shape_data.sample_dim() == 1);
for (int i = 0; i < N; i++) {
auto sample_shape = orig_shape.tensor_shape_span(i);
assert(static_cast<int>(shape_data.shape[i][0]) == D);
int *out_shape = shape_data.data[i];
for (int d = 0; d < D; d++) {
out_shape[d] = sample_shape[FirstSpatialDim() + d];
}
}
}

void PrepareParams(const ArgumentWorkspace &ws, const TensorListShape<> &input_shape,
const TensorLayout &layout) {
resize_attr_.PrepareResizeParams(spec_, ws, input_shape, layout);
assert(NumSpatialDims() >= 1 && NumSpatialDims() <= 3);
assert(FirstSpatialDim() >= 0);
int N = input_shape.num_samples();
resample_params_.resize(N * NumSpatialDims());
resampling_attr_.PrepareFilterParams(spec_, ws, N);
resampling_attr_.GetResamplingParams(make_span(resample_params_),
make_cspan(resize_attr_.params_));
}

void InitializeBackend();

USE_OPERATOR_MEMBERS();
std::vector<kernels::ResamplingParams> resample_params_;
TensorList<CPUBackend> attr_staging_;
using Operator<GPUBackend>::RunImpl;
bool save_attrs_ = false;

ResizeAttr resize_attr_;
ResamplingFilterAttr resampling_attr_;
};

bool CvCudaResize::SetupImpl(std::vector<OutputDesc> &output_desc, const Workspace &ws) {
output_desc.resize(save_attrs_ ? 2 : 1);
auto &input = ws.Input<GPUBackend>(0);

const auto &in_shape = input.shape();
auto in_type = input.type();
auto in_layout = input.GetLayout();
int N = in_shape.num_samples();

PrepareParams(ws, in_shape, in_layout);

auto out_type = resampling_attr_.GetOutputType(in_type);

output_desc[0].type = out_type;
this->SetupResize(output_desc[0].shape, out_type, in_shape, in_type,
make_cspan(this->resample_params_), NumSpatialDims(), FirstSpatialDim());

if (save_attrs_) {
output_desc[1].shape = uniform_list_shape(N, TensorShape<1>({NumSpatialDims()}));
output_desc[1].type = DALI_INT32;
}
return true;
}

} // namespace dali

#endif // DALI_OPERATORS_IMAGE_RESIZE_EXPERIMENTAL_RESIZE_H_
Loading

0 comments on commit be71021

Please sign in to comment.