Browse Source

Add GridSampler3D and GridSampler3DGrad

feature/build-system-rewrite
bubtltk 4 years ago
parent
commit
f5ffb282ee
17 changed files with 1212 additions and 1 deletions
  1. +217
    -0
      mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_cpu_kernel.cc
  2. +76
    -0
      mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_cpu_kernel.h
  3. +326
    -0
      mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_grad_cpu_kernel.cc
  4. +99
    -0
      mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_grad_cpu_kernel.h
  5. +4
    -0
      mindspore/core/base/core_ops.h
  6. +102
    -0
      mindspore/core/ops/grad/grid_sampler_3d_grad.cc
  7. +44
    -0
      mindspore/core/ops/grad/grid_sampler_3d_grad.h
  8. +79
    -0
      mindspore/core/ops/grid_sampler_3d.cc
  9. +44
    -0
      mindspore/core/ops/grid_sampler_3d.h
  10. +12
    -0
      mindspore/python/mindspore/ops/_grad_experimental/grad_nn_ops.py
  11. +2
    -0
      mindspore/python/mindspore/ops/_op_impl/aicpu/__init__.py
  12. +34
    -0
      mindspore/python/mindspore/ops/_op_impl/aicpu/grid_sampler_3d.py
  13. +38
    -0
      mindspore/python/mindspore/ops/_op_impl/aicpu/grid_sampler_3d_grad.py
  14. +2
    -1
      mindspore/python/mindspore/ops/operations/__init__.py
  15. +49
    -0
      mindspore/python/mindspore/ops/operations/_grad_ops.py
  16. +79
    -0
      mindspore/python/mindspore/ops/operations/nn_ops.py
  17. +5
    -0
      tests/ut/python/ops/test_ops.py

+ 217
- 0
mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_cpu_kernel.cc View File

@@ -0,0 +1,217 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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.
*/
#include "backend/kernel_compiler/cpu/grid_sampler_3d_cpu_kernel.h"
#include "runtime/device/cpu/cpu_device_address.h"

namespace {
const size_t kDataSizeThreshold = 64 * 1024;
const size_t kZero = 0;
const size_t kOne = 1;
const size_t kTwo = 2;
const size_t kThree = 3;
const size_t kFour = 4;
const size_t kFive = 5;
} // namespace

namespace mindspore {
namespace kernel {
void GridSampler3DCPUKernel::InitKernel(const CNodePtr &kernel_node) {
x_shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, kZero);
grid_shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, kOne);
output_shape_ = AnfAlgo::GetOutputDeviceShape(kernel_node, kZero);
output_number_ =
output_shape_[kZero] * output_shape_[kOne] * output_shape_[kTwo] * output_shape_[kThree] * output_shape_[kFour];
dtype_ = AnfAlgo::GetInputDeviceDataType(kernel_node, kZero);
size_t stride_tmp = kOne;
auto stride_compute = [&](std::vector<size_t> &stride, std::vector<size_t> shape) {
for (size_t i = kFour; i > -kOne; i--) {
stride.insert(stride.begin(), stride_tmp);
stride_tmp *= shape[i];
}
stride_tmp = kOne;
};
stride_compute(x_stride_, x_shape_);
stride_compute(grid_stride_, grid_shape_);
stride_compute(output_stride_, output_shape_);
interpolation_mode = AnfAlgo::GetNodeAttr<std::string>(kernel_node, "interpolation_mode");
padding_mode = AnfAlgo::GetNodeAttr<std::string>(kernel_node, "padding_mode");
align_corners = AnfAlgo::GetNodeAttr<bool>(kernel_node, "align_corners");
}

bool GridSampler3DCPUKernel::Launch(const std::vector<kernel::AddressPtr> &inputs,
const std::vector<kernel::AddressPtr> &,
const std::vector<kernel::AddressPtr> &outputs) {
if (dtype_ == kNumberTypeFloat32) {
LaunchKernel<float>(inputs, outputs);
} else if (dtype_ == kNumberTypeFloat64) {
LaunchKernel<double>(inputs, outputs);
} else {
MS_EXCEPTION(TypeError) << "Input dtype only support float32 and float64!";
}
return true;
}

template <typename T>
void GridSampler3DCPUKernel::ComputeTask(T *x_addr, T *grid_addr, T *output_addr, const size_t &seq) {
size_t out_iter[kFive] = {kZero, seq, kZero, kZero, kZero};
size_t count = kFour;
while (out_iter[kOne] > kZero) {
if (count == kOne) {
count--;
}
out_iter[count] = out_iter[kOne] % output_shape_[count];
out_iter[kOne] /= output_shape_[count--];
}
const size_t out_c = output_shape_[kOne];
int64_t grid_offset = out_iter[kZero] * grid_stride_[kZero] + out_iter[kTwo] * grid_stride_[kOne] +
out_iter[kThree] * grid_stride_[kTwo] + out_iter[kFour] * grid_stride_[kThree];
T x = grid_addr[grid_offset];
T y = grid_addr[grid_offset + grid_stride_[kFour]];
T z = grid_addr[grid_offset + kTwo * grid_stride_[kFour]];
x = grid_sampler_compute_source_index(x, x_shape_[kFour], padding_mode, align_corners);
y = grid_sampler_compute_source_index(y, x_shape_[kThree], padding_mode, align_corners);
z = grid_sampler_compute_source_index(z, x_shape_[kTwo], padding_mode, align_corners);
auto x_ptr_NC = out_iter[kZero] * x_stride_[kZero];
auto output_ptr_NCDHW = out_iter[kZero] * output_stride_[kZero] + out_iter[kTwo] * output_stride_[kTwo] +
out_iter[kThree] * output_stride_[kThree] + out_iter[kFour] * output_stride_[kFour];
if (interpolation_mode == "bilinear") {
int64_t x_tnw = static_cast<int64_t>(std::floor(x));
int64_t y_tnw = static_cast<int64_t>(std::floor(y));
int64_t z_tnw = static_cast<int64_t>(std::floor(z));
int64_t x_tne = x_tnw + kOne, y_tne = y_tnw, z_tne = z_tnw;
int64_t x_tsw = x_tnw, y_tsw = y_tnw + kOne, z_tsw = z_tnw;
int64_t x_tse = x_tnw + kOne, y_tse = y_tnw + kOne, z_tse = z_tnw;
int64_t x_bnw = x_tnw, y_bnw = y_tnw, z_bnw = z_tnw + kOne;
int64_t x_bne = x_tnw + kOne, y_bne = y_tnw, z_bne = z_tnw + kOne;
int64_t x_bsw = x_tnw, y_bsw = y_tnw + kOne, z_bsw = z_tnw + kOne;
int64_t x_bse = x_tnw + kOne, y_bse = y_tnw + kOne, z_bse = z_tnw + kOne;
T tnw = (x_bse - x) * (y_bse - y) * (z_bse - z), tne = (x - x_bsw) * (y_bsw - y) * (z_bsw - z);
T tsw = (x_bne - x) * (y - y_bne) * (z_bne - z), tse = (x - x_bnw) * (y - y_bnw) * (z_bnw - z);
T bnw = (x_tse - x) * (y_tse - y) * (z - z_tse), bne = (x - x_tsw) * (y_tsw - y) * (z - z_tsw);
T bsw = (x_tne - x) * (y - y_tne) * (z - z_tne), bse = (x - x_tnw) * (y - y_tnw) * (z - z_tnw);
for (size_t c = kZero; c < out_c; c++, x_ptr_NC += x_stride_[kOne], output_ptr_NCDHW += output_stride_[kOne]) {
output_addr[output_ptr_NCDHW] = static_cast<T>(kZero);
if (within_bounds_3d(z_tnw, y_tnw, x_tnw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_tnw * x_stride_[kTwo] + y_tnw * x_stride_[kThree] + x_tnw * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * tnw;
}
if (within_bounds_3d(z_tne, y_tne, x_tne, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_tne * x_stride_[kTwo] + y_tne * x_stride_[kThree] + x_tne * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * tne;
}
if (within_bounds_3d(z_tsw, y_tsw, x_tsw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_tsw * x_stride_[kTwo] + y_tsw * x_stride_[kThree] + x_tsw * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * tsw;
}
if (within_bounds_3d(z_tse, y_tse, x_tse, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_tse * x_stride_[kTwo] + y_tse * x_stride_[kThree] + x_tse * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * tse;
}
if (within_bounds_3d(z_bnw, y_bnw, x_bnw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_bnw * x_stride_[kTwo] + y_bnw * x_stride_[kThree] + x_bnw * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * bnw;
}
if (within_bounds_3d(z_bne, y_bne, x_bne, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_bne * x_stride_[kTwo] + y_bne * x_stride_[kThree] + x_bne * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * bne;
}
if (within_bounds_3d(z_bsw, y_bsw, x_bsw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_bsw * x_stride_[kTwo] + y_bsw * x_stride_[kThree] + x_bsw * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * bsw;
}
if (within_bounds_3d(z_bse, y_bse, x_bse, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index = x_ptr_NC + z_bse * x_stride_[kTwo] + y_bse * x_stride_[kThree] + x_bse * x_stride_[kFour];
output_addr[output_ptr_NCDHW] += x_addr[x_index] * bse;
}
}
} else if (interpolation_mode == "nearest") {
int64_t x_nearest = static_cast<int64_t>(std::round(x));
int64_t y_nearest = static_cast<int64_t>(std::round(y));
int64_t z_nearest = static_cast<int64_t>(std::round(z));
for (size_t c = kZero; c < out_c; c++, x_ptr_NC += x_stride_[kOne], output_ptr_NCDHW += output_stride_[kOne]) {
if (within_bounds_3d(z_nearest, y_nearest, x_nearest, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
auto x_index =
x_ptr_NC + z_nearest * x_stride_[kTwo] + y_nearest * x_stride_[kThree] + x_nearest * x_stride_[kFour];
output_addr[output_ptr_NCDHW] = x_addr[x_index];
} else {
output_addr[output_ptr_NCDHW] = static_cast<T>(kZero);
}
}
}
}

template <typename T>
void GridSampler3DCPUKernel::LaunchKernel(const std::vector<AddressPtr> &inputs,
const std::vector<AddressPtr> &outputs) {
auto x_data_addr = reinterpret_cast<T *>(inputs[kZero]->addr);
auto grid_data_addr = reinterpret_cast<T *>(inputs[kOne]->addr);
auto output_data_addr = reinterpret_cast<T *>(outputs[kZero]->addr);
size_t loop_count = output_shape_[kZero] * output_shape_[kTwo] * output_shape_[kThree] * output_shape_[kFour];
auto task = [&](size_t start, size_t end) {
for (size_t i = start; i < end; i++) {
ComputeTask<T>(x_data_addr, grid_data_addr, output_data_addr, i);
}
};
if (output_number_ < kDataSizeThreshold) {
task(kZero, loop_count);
} else {
CPUKernelUtils::ParallelFor(task, loop_count);
}
}

template <typename T>
T GridSampler3DCPUKernel::grid_sampler_compute_source_index(T coord, int64_t size, std::string padding_mode,
bool align_corners) {
if (align_corners) {
coord = ((coord + 1.f) / kTwo) * (size - kOne);
} else {
coord = ((coord + 1.f) * size - kOne) / kTwo;
}
if (padding_mode == "border") {
coord = std::min(static_cast<T>(size - kOne), std::max(coord, static_cast<T>(kZero)));
} else if (padding_mode == "reflection") {
if (align_corners) {
coord = reflect_coordinates(coord, kZero, kTwo * (size - kOne));
} else {
coord = reflect_coordinates(coord, -kOne, kTwo * size - kOne);
}
coord = std::min(static_cast<T>(size - kOne), std::max(coord, static_cast<T>(kZero)));
}
return coord;
}

template <typename T>
T GridSampler3DCPUKernel::reflect_coordinates(T coord, int64_t twice_low, int64_t twice_high) {
if (twice_low == twice_high) {
return static_cast<T>(kZero);
}
T min = static_cast<T>(twice_low) / kTwo;
T span = static_cast<T>(twice_high - twice_low) / kTwo;
coord = std::fabs(coord - min);
T extra = std::fmod(coord, span);
int64_t flips = static_cast<int64_t>(std::floor(coord / span));
if (flips % kTwo == kZero) {
return extra + min;
} else {
return span - extra + min;
}
}

bool GridSampler3DCPUKernel::within_bounds_3d(int64_t d, int64_t h, int64_t w, int64_t D, int64_t H, int64_t W) {
return d >= 0 && d < D && h >= 0 && h < H && w >= 0 && w < W;
}
} // namespace kernel
} // namespace mindspore

+ 76
- 0
mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_cpu_kernel.h View File

@@ -0,0 +1,76 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_CPU_KERNEL_H_
#define MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_CPU_KERNEL_H_
#include <algorithm>
#include <vector>
#include <memory>
#include <string>
#include "backend/kernel_compiler/cpu/cpu_kernel.h"
#include "backend/kernel_compiler/cpu/cpu_kernel_factory.h"

namespace mindspore {
namespace kernel {
class GridSampler3DCPUKernel : public CPUKernel {
public:
GridSampler3DCPUKernel() = default;
~GridSampler3DCPUKernel() override = default;

void InitKernel(const CNodePtr &kernel_node) override;

bool Launch(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &workspace,
const std::vector<AddressPtr> &outputs) override;

template <typename T>
void LaunchKernel(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &outputs);

private:
std::vector<size_t> x_shape_;
std::vector<size_t> grid_shape_;
std::vector<size_t> output_shape_;
std::vector<size_t> x_stride_;
std::vector<size_t> grid_stride_;
std::vector<size_t> output_stride_;
std::string interpolation_mode;
std::string padding_mode;
bool align_corners;
size_t output_number_;
TypeId dtype_{kTypeUnknown};
template <typename T>
void ComputeTask(T *x_data_addr, T *grid_data_addr, T *output_data_addr, const size_t &seq);

template <typename T>
T grid_sampler_compute_source_index(T coord, int64_t size, std::string padding_mode, bool align_corners);

template <typename T>
T reflect_coordinates(T coord, int64_t twice_low, int64_t twice_high);

bool within_bounds_3d(int64_t d, int64_t h, int64_t w, int64_t D, int64_t H, int64_t W);
};

MS_REG_CPU_KERNEL(
GridSampler3D,
KernelAttr().AddInputAttr(kNumberTypeFloat32).AddInputAttr(kNumberTypeFloat32).AddOutputAttr(kNumberTypeFloat32),
GridSampler3DCPUKernel);

MS_REG_CPU_KERNEL(
GridSampler3D,
KernelAttr().AddInputAttr(kNumberTypeFloat64).AddInputAttr(kNumberTypeFloat64).AddOutputAttr(kNumberTypeFloat64),
GridSampler3DCPUKernel);
} // namespace kernel
} // namespace mindspore

#endif // MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_CPU_KERNEL_H_

+ 326
- 0
mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_grad_cpu_kernel.cc View File

@@ -0,0 +1,326 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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.
*/
#include "backend/kernel_compiler/cpu/grid_sampler_3d_grad_cpu_kernel.h"
#include "runtime/device/cpu/cpu_device_address.h"

namespace {
const size_t kDataSizeThreshold = 64 * 1024;
const size_t kZero = 0;
const size_t kOne = 1;
const size_t kTwo = 2;
const size_t kThree = 3;
const size_t kFour = 4;
} // namespace

namespace mindspore {
namespace kernel {
void GridSampler3DGradCPUKernel::InitKernel(const CNodePtr &kernel_node) {
grad_shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, kZero);
x_shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, kOne);
grid_shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, kTwo);
dx_shape_ = AnfAlgo::GetOutputDeviceShape(kernel_node, kZero);
dgrid_shape_ = AnfAlgo::GetOutputDeviceShape(kernel_node, kOne);
dx_size_ = dx_shape_[kZero] * dx_shape_[kOne] * dx_shape_[kTwo] * dx_shape_[kThree] * dx_shape_[kFour];
grid_size_ = grid_shape_[kZero] * grid_shape_[kOne] * grid_shape_[kTwo] * grid_shape_[kThree];
dtype_ = AnfAlgo::GetInputDeviceDataType(kernel_node, kZero);
size_t stride_tmp = kOne;
auto stride_compute = [&](std::vector<size_t> &stride, std::vector<size_t> shape) {
for (size_t i = kFour; i > -kOne; i--) {
stride.insert(stride.begin(), stride_tmp);
stride_tmp *= shape[i];
}
stride_tmp = kOne;
};
stride_compute(grad_stride_, grad_shape_);
stride_compute(x_stride_, x_shape_);
stride_compute(grid_stride_, grid_shape_);
stride_compute(dx_stride_, dx_shape_);
stride_compute(dgrid_stride_, dgrid_shape_);
interpolation_mode = AnfAlgo::GetNodeAttr<std::string>(kernel_node, "interpolation_mode");
padding_mode = AnfAlgo::GetNodeAttr<std::string>(kernel_node, "padding_mode");
align_corners = AnfAlgo::GetNodeAttr<bool>(kernel_node, "align_corners");
}

bool GridSampler3DGradCPUKernel::Launch(const std::vector<kernel::AddressPtr> &inputs,
const std::vector<kernel::AddressPtr> &,
const std::vector<kernel::AddressPtr> &outputs) {
if (dtype_ == kNumberTypeFloat32) {
LaunchKernel<float>(inputs, outputs);
} else if (dtype_ == kNumberTypeFloat64) {
LaunchKernel<double>(inputs, outputs);
} else {
MS_EXCEPTION(TypeError) << "Input dtype only support float32 and float64!";
}
return true;
}

template <typename T>
void GridSampler3DGradCPUKernel::BilinearKernel(std::vector<T *> addr, std::vector<T> location, std::vector<T> mult,
std::vector<size_t> ptr) {
T x = location[kZero], y = location[kOne], z = location[kTwo];
int64_t x_tnw = static_cast<int64_t>(std::floor(x));
int64_t y_tnw = static_cast<int64_t>(std::floor(y));
int64_t z_tnw = static_cast<int64_t>(std::floor(z));
int64_t x_tne = x_tnw + kOne, y_tne = y_tnw, z_tne = z_tnw;
int64_t x_tsw = x_tnw, y_tsw = y_tnw + kOne, z_tsw = z_tnw;
int64_t x_tse = x_tnw + kOne, y_tse = y_tnw + kOne, z_tse = z_tnw;
int64_t x_bnw = x_tnw, y_bnw = y_tnw, z_bnw = z_tnw + kOne;
int64_t x_bne = x_tnw + kOne, y_bne = y_tnw, z_bne = z_tnw + kOne;
int64_t x_bsw = x_tnw, y_bsw = y_tnw + kOne, z_bsw = z_tnw + kOne;
int64_t x_bse = x_tnw + kOne, y_bse = y_tnw + kOne, z_bse = z_tnw + kOne;
T tnw = (x_bse - x) * (y_bse - y) * (z_bse - z), tne = (x - x_bsw) * (y_bsw - y) * (z_bsw - z);
T tsw = (x_bne - x) * (y - y_bne) * (z_bne - z), tse = (x - x_bnw) * (y - y_bnw) * (z_bnw - z);
T bnw = (x_tse - x) * (y_tse - y) * (z - z_tse), bne = (x - x_tsw) * (y_tsw - y) * (z - z_tsw);
T bsw = (x_tne - x) * (y - y_tne) * (z - z_tne), bse = (x - x_tnw) * (y - y_tnw) * (z - z_tnw);
T gx = static_cast<T>(kZero), gy = static_cast<T>(kZero), gz = static_cast<T>(kZero);
for (size_t c = kZero; c < x_shape_[kOne];
c++, ptr[kZero] += grad_stride_[kOne], ptr[kOne] += x_stride_[kOne], ptr[kTwo] += dx_stride_[kOne]) {
T grad_out = addr[kZero][ptr[kZero]];
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_tnw, y_tnw, x_tnw, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], tnw * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_tne, y_tne, x_tne, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], tne * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_tsw, y_tsw, x_tsw, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], tsw * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_tse, y_tse, x_tse, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], tse * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_bnw, y_bnw, x_bnw, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], bnw * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_bne, y_bne, x_bne, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], bne * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_bsw, y_bsw, x_bsw, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], bsw * grad_out);
safe_add_3d(&addr[kTwo][ptr[kTwo]], z_bse, y_bse, x_bse, dx_stride_[kTwo], dx_stride_[kThree], dx_stride_[kFour],
x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour], bse * grad_out);
if (within_bounds_3d(z_tnw, y_tnw, x_tnw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_tnw * x_stride_[kTwo] + y_tnw * x_stride_[kThree] + x_tnw * x_stride_[kFour];
T tnw_val = addr[kOne][offset];
gx -= tnw_val * (y_bse - y) * (z_bse - z) * grad_out;
gy -= tnw_val * (x_bse - x) * (z_bse - z) * grad_out;
gz -= tnw_val * (x_bse - x) * (y_bse - y) * grad_out;
}
if (within_bounds_3d(z_tne, y_tne, x_tne, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_tne * x_stride_[kTwo] + y_tne * x_stride_[kThree] + x_tne * x_stride_[kFour];
T tne_val = addr[kOne][offset];
gx += tne_val * (y_bsw - y) * (z_bsw - z) * grad_out;
gy -= tne_val * (x - x_bsw) * (z_bsw - z) * grad_out;
gz -= tne_val * (x - x_bsw) * (y_bsw - y) * grad_out;
}
if (within_bounds_3d(z_tsw, y_tsw, x_tsw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_tsw * x_stride_[kTwo] + y_tsw * x_stride_[kThree] + x_tsw * x_stride_[kFour];
T tsw_val = addr[kOne][offset];
gx -= tsw_val * (y - y_bne) * (z_bne - z) * grad_out;
gy += tsw_val * (x_bne - x) * (z_bne - z) * grad_out;
gz -= tsw_val * (x_bne - x) * (y - y_bne) * grad_out;
}
if (within_bounds_3d(z_tse, y_tse, x_tse, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_tse * x_stride_[kTwo] + y_tse * x_stride_[kThree] + x_tse * x_stride_[kFour];
T tse_val = addr[kOne][offset];
gx += tse_val * (y - y_bnw) * (z_bnw - z) * grad_out;
gy += tse_val * (x - x_bnw) * (z_bnw - z) * grad_out;
gz -= tse_val * (x - x_bnw) * (y - y_bnw) * grad_out;
}
if (within_bounds_3d(z_bnw, y_bnw, x_bnw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_bnw * x_stride_[kTwo] + y_bnw * x_stride_[kThree] + x_bnw * x_stride_[kFour];
T bnw_val = addr[kOne][offset];
gx -= bnw_val * (y_tse - y) * (z - z_tse) * grad_out;
gy -= bnw_val * (x_tse - x) * (z - z_tse) * grad_out;
gz += bnw_val * (x_tse - x) * (y_tse - y) * grad_out;
}
if (within_bounds_3d(z_bne, y_bne, x_bne, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_bne * x_stride_[kTwo] + y_bne * x_stride_[kThree] + x_bne * x_stride_[kFour];
T bne_val = addr[kOne][offset];
gx += bne_val * (y_tsw - y) * (z - z_tsw) * grad_out;
gy -= bne_val * (x - x_tsw) * (z - z_tsw) * grad_out;
gz += bne_val * (x - x_tsw) * (y_tsw - y) * grad_out;
}
if (within_bounds_3d(z_bsw, y_bsw, x_bsw, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_bsw * x_stride_[kTwo] + y_bsw * x_stride_[kThree] + x_bsw * x_stride_[kFour];
T bsw_val = addr[kOne][offset];
gx -= bsw_val * (y - y_tne) * (z - z_tne) * grad_out;
gy += bsw_val * (x_tne - x) * (z - z_tne) * grad_out;
gz += bsw_val * (x_tne - x) * (y - y_tne) * grad_out;
}
if (within_bounds_3d(z_bse, y_bse, x_bse, x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour])) {
size_t offset = ptr[kOne] + z_bse * x_stride_[kTwo] + y_bse * x_stride_[kThree] + x_bse * x_stride_[kFour];
T bse_val = addr[kOne][offset];
gx += bse_val * (y - y_tnw) * (z - z_tnw) * grad_out;
gy += bse_val * (x - x_tnw) * (z - z_tnw) * grad_out;
gz += bse_val * (x - x_tnw) * (y - y_tnw) * grad_out;
}
}
addr[kThree][ptr[kThree]] = mult[kZero] * gx;
addr[kThree][ptr[kThree] + kOne] = mult[kOne] * gy;
addr[kThree][ptr[kThree] + kTwo] = mult[kTwo] * gz;
}

template <typename T>
void GridSampler3DGradCPUKernel::ComputeTask(T *grad_addr, T *x_addr, T *grid_addr, T *dx_addr, T *dgrid_addr,
const size_t &n) {
size_t grid_ptr_N = n * grid_stride_[kZero];
size_t dgrid_ptr_NDHW = n * dgrid_stride_[kZero];
for (size_t d = kZero; d < grid_shape_[kOne]; d++) {
for (size_t h = kZero; h < grid_shape_[kTwo]; h++) {
for (size_t w = kZero; w < grid_shape_[kThree]; w++, dgrid_ptr_NDHW += dgrid_stride_[kThree]) {
size_t grid_ptr_NDHW = grid_ptr_N + d * grid_stride_[kOne] + h * grid_stride_[kTwo] + w * grid_stride_[kThree];
T x = grid_addr[grid_ptr_NDHW];
T y = grid_addr[grid_ptr_NDHW + grid_stride_[kFour]];
T z = grid_addr[grid_ptr_NDHW + kTwo * grid_stride_[kFour]];
T gx_mult, gy_mult, gz_mult;
x = grid_sampler_compute_source_index_set_grad(x, x_shape_[kFour], padding_mode, align_corners, &gx_mult);
y = grid_sampler_compute_source_index_set_grad(y, x_shape_[kThree], padding_mode, align_corners, &gy_mult);
z = grid_sampler_compute_source_index_set_grad(z, x_shape_[kTwo], padding_mode, align_corners, &gz_mult);
if (interpolation_mode == "bilinear") {
size_t grad_ptr_NCDHW =
n * grad_stride_[kZero] + d * grad_stride_[kTwo] + h * grad_stride_[kThree] + w * grad_stride_[kFour];
size_t dx_ptr_NC = n * dx_stride_[kZero], x_ptr_NC = n * x_stride_[kZero];
std::vector<T *> addr = {grad_addr, x_addr, dx_addr, dgrid_addr};
std::vector<T> location = {x, y, z};
std::vector<T> mult = {gx_mult, gy_mult, gz_mult};
std::vector<size_t> ptr = {grad_ptr_NCDHW, x_ptr_NC, dx_ptr_NC, dgrid_ptr_NDHW};
BilinearKernel<T>(addr, location, mult, ptr);
} else if (interpolation_mode == "nearest") {
int64_t x_nearest = static_cast<int64_t>(std::round(x));
int64_t y_nearest = static_cast<int64_t>(std::round(y));
int64_t z_nearest = static_cast<int64_t>(std::round(z));
size_t grad_ptr_NCDHW =
n * grad_stride_[kZero] + d * grad_stride_[kTwo] + h * grad_stride_[kThree] + w * grad_stride_[kFour];
size_t dx_ptr_NC = n * dx_stride_[kZero];
for (size_t c = kZero; c < x_shape_[kOne];
c++, grad_ptr_NCDHW += grad_stride_[kOne], dx_ptr_NC += dx_stride_[kOne]) {
safe_add_3d(&dx_addr[dx_ptr_NC], z_nearest, y_nearest, x_nearest, dx_stride_[kTwo], dx_stride_[kThree],
dx_stride_[kFour], x_shape_[kTwo], x_shape_[kThree], x_shape_[kFour],
grad_addr[grad_ptr_NCDHW]);
}
dgrid_addr[dgrid_ptr_NDHW] = static_cast<T>(kZero);
dgrid_addr[dgrid_ptr_NDHW + kOne] = static_cast<T>(kZero);
dgrid_addr[dgrid_ptr_NDHW + kTwo] = static_cast<T>(kZero);
}
}
}
}
}

template <typename T>
void GridSampler3DGradCPUKernel::LaunchKernel(const std::vector<AddressPtr> &inputs,
const std::vector<AddressPtr> &outputs) {
auto grad_data_addr = reinterpret_cast<T *>(inputs[kZero]->addr);
auto x_data_addr = reinterpret_cast<T *>(inputs[kOne]->addr);
auto grid_data_addr = reinterpret_cast<T *>(inputs[kTwo]->addr);
auto dx_data_addr = reinterpret_cast<T *>(outputs[kZero]->addr);
auto dgrid_data_addr = reinterpret_cast<T *>(outputs[kOne]->addr);
size_t loop_count = x_shape_[kZero];
for (size_t i = kZero; i < dx_size_; i++) {
dx_data_addr[i] = static_cast<T>(kZero);
}
auto task = [&](size_t start, size_t end) {
for (size_t n = start; n < end; n++) {
ComputeTask<T>(grad_data_addr, x_data_addr, grid_data_addr, dx_data_addr, dgrid_data_addr, n);
}
};
if (grid_size_ * sizeof(T) < kDataSizeThreshold) {
task(kZero, loop_count);
} else {
CPUKernelUtils::ParallelFor(task, loop_count);
}
}

template <typename T>
T GridSampler3DGradCPUKernel::grid_sampler_compute_source_index_set_grad(T coord, size_t size, std::string padding_mode,
bool align_corners, T *grad_x) {
T grad_clip, grad_refl;
if (align_corners) {
*grad_x = static_cast<T>(size - kOne) / kTwo;
coord = ((coord + kOne) / kTwo) * (size - kOne);
} else {
*grad_x = static_cast<T>(size) / kTwo;
coord = ((coord + kOne) * size - kOne) / kTwo;
}
if (padding_mode == "border") {
coord = clip_coordinates_set_grad(coord, size, &grad_clip);
*grad_x = (*grad_x) * grad_clip;
} else if (padding_mode == "reflection") {
if (align_corners) {
coord = reflect_coordinates_set_grad(coord, kZero, kTwo * (size - kOne), &grad_refl);
} else {
coord = reflect_coordinates_set_grad(coord, -kOne, kTwo * size - kOne, &grad_refl);
}
coord = clip_coordinates_set_grad(coord, size, &grad_clip);
*grad_x = (*grad_x) * grad_refl * grad_clip;
}
return coord;
}

template <typename T>
T GridSampler3DGradCPUKernel::clip_coordinates_set_grad(T x, int64_t clip_limit, T *grad_x) {
if (x <= static_cast<T>(kZero)) {
*grad_x = static_cast<T>(kZero);
return static_cast<T>(kZero);
} else {
T max = static_cast<T>(clip_limit - kOne);
if (x >= max) {
*grad_x = static_cast<T>(kZero);
return max;
} else {
*grad_x = static_cast<T>(kOne);
return x;
}
}
}

template <typename T>
T GridSampler3DGradCPUKernel::reflect_coordinates_set_grad(T x, int64_t twice_low, int64_t twice_high, T *grad_x) {
if (twice_low == twice_high) {
*grad_x = static_cast<T>(kZero);
return static_cast<T>(kZero);
}
int64_t grad_x_mult_;
T min = static_cast<T>(twice_low) / kTwo;
T span = static_cast<T>(twice_high - twice_low) / kTwo;
x = x - min;
if (x < static_cast<T>(kZero)) {
grad_x_mult_ = -kOne;
x = -x;
} else {
grad_x_mult_ = kOne;
}
T extra = std::fmod(x, span);
int64_t flips = static_cast<int64_t>(std::floor(x / span));
if (flips % kTwo == kZero) {
*grad_x = static_cast<T>(grad_x_mult_);
return extra + min;
} else {
*grad_x = static_cast<T>(-grad_x_mult_);
return span - extra + min;
}
}

template <typename T>
void GridSampler3DGradCPUKernel::safe_add_3d(T *data, int64_t d, int64_t h, int64_t w, size_t sD, size_t sH, size_t sW,
size_t D, size_t H, size_t W, T delta) {
if (within_bounds_3d(d, h, w, D, H, W)) {
data[d * sD + h * sH + w * sW] += delta;
}
}

bool GridSampler3DGradCPUKernel::within_bounds_3d(int64_t d, int64_t h, int64_t w, size_t D, size_t H, size_t W) {
int64_t iD = static_cast<int64_t>(D);
int64_t iH = static_cast<int64_t>(H);
int64_t iW = static_cast<int64_t>(W);
return d >= 0 && d < iD && h >= 0 && h < iH && w >= 0 && w < iW;
}
} // namespace kernel
} // namespace mindspore

+ 99
- 0
mindspore/ccsrc/backend/kernel_compiler/cpu/grid_sampler_3d_grad_cpu_kernel.h View File

@@ -0,0 +1,99 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_GRAD_CPU_KERNEL_H_
#define MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_GRAD_CPU_KERNEL_H_
#include <vector>
#include <memory>
#include <string>
#include "backend/kernel_compiler/cpu/cpu_kernel.h"
#include "backend/kernel_compiler/cpu/cpu_kernel_factory.h"

namespace mindspore {
namespace kernel {
class GridSampler3DGradCPUKernel : public CPUKernel {
public:
GridSampler3DGradCPUKernel() = default;
~GridSampler3DGradCPUKernel() override = default;

void InitKernel(const CNodePtr &kernel_node) override;

bool Launch(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &workspace,
const std::vector<AddressPtr> &outputs) override;

template <typename T>
void LaunchKernel(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &outputs);

private:
std::vector<size_t> grad_shape_;
std::vector<size_t> x_shape_;
std::vector<size_t> grid_shape_;
std::vector<size_t> dx_shape_;
std::vector<size_t> dgrid_shape_;
std::vector<size_t> grad_stride_;
std::vector<size_t> x_stride_;
std::vector<size_t> grid_stride_;
std::vector<size_t> dx_stride_;
std::vector<size_t> dgrid_stride_;
std::string interpolation_mode;
std::string padding_mode;
bool align_corners;
size_t dx_size_;
size_t grid_size_;
TypeId dtype_{kTypeUnknown};
template <typename T>
void BilinearKernel(std::vector<T *> addr, std::vector<T> location, std::vector<T> mult, std::vector<size_t> ptr);

template <typename T>
void ComputeTask(T *grad_addr, T *x_addr, T *grid_addr, T *dx_addr, T *dgrid_addr, const size_t &n);

template <typename T>
T grid_sampler_compute_source_index_set_grad(T coord, size_t size, std::string padding_mode, bool align_corners,
T *grad_x);

template <typename T>
T reflect_coordinates_set_grad(T x, int64_t twice_low, int64_t twice_high, T *grad_x);

template <typename T>
T clip_coordinates_set_grad(T x, int64_t clip_limit, T *grad_x);

template <typename T>
void safe_add_3d(T *data, int64_t d, int64_t h, int64_t w, size_t sD, size_t sH, size_t sW, size_t D, size_t H,
size_t W, T delta);

bool within_bounds_3d(int64_t d, int64_t h, int64_t w, size_t D, size_t H, size_t W);
};

MS_REG_CPU_KERNEL(GridSampler3DGrad,
KernelAttr()
.AddInputAttr(kNumberTypeFloat32)
.AddInputAttr(kNumberTypeFloat32)
.AddInputAttr(kNumberTypeFloat32)
.AddOutputAttr(kNumberTypeFloat32)
.AddOutputAttr(kNumberTypeFloat32),
GridSampler3DGradCPUKernel);

MS_REG_CPU_KERNEL(GridSampler3DGrad,
KernelAttr()
.AddInputAttr(kNumberTypeFloat64)
.AddInputAttr(kNumberTypeFloat64)
.AddInputAttr(kNumberTypeFloat64)
.AddOutputAttr(kNumberTypeFloat64)
.AddOutputAttr(kNumberTypeFloat64),
GridSampler3DGradCPUKernel);
} // namespace kernel
} // namespace mindspore

#endif // MINDSPORE_CCSRC_BACKEND_KERNEL_COMPILER_CPU_GRID_SAMPLER_3D_GRAD_CPU_KERNEL_H_

+ 4
- 0
mindspore/core/base/core_ops.h View File

@@ -128,6 +128,8 @@ constexpr auto kConv2DTranspose = "Conv2DTranspose";
constexpr auto kSparseApplyAdadelta = "SparseApplyAdadelta";
constexpr auto kRoll = "Roll";
constexpr auto kTanh = "Tanh";
constexpr auto kGridSampler3D = "GridSampler3D";
constexpr auto kGridSampler3DGrad = "GridSampler3DGrad";

// Others
constexpr auto kEnvironCreate = "EnvironCreate";
@@ -485,6 +487,8 @@ inline const PrimitivePtr kPrimApplyAddSign = std::make_shared<Primitive>("Apply
inline const PrimitivePtr kPrimApplyAdagrad = std::make_shared<Primitive>("ApplyAdagrad");
inline const PrimitivePtr kPrimApplyAdadelta = std::make_shared<Primitive>("ApplyAdadelta");
inline const PrimitivePtr kPrimApplyAdamWithAmsgrad = std::make_shared<Primitive>("ApplyAdamWithAmsgrad");
inline const PrimitivePtr kPrimGridSampler3D = std::make_shared<Primitive>(kGridSampler3D);
inline const PrimitivePtr kPrimGridSampler3DGrad = std::make_shared<Primitive>(kGridSampler3DGrad);

// Comm ops
inline const PrimitivePtr kPrimMirror = std::make_shared<Primitive>("_MirrorOperator");


+ 102
- 0
mindspore/core/ops/grad/grid_sampler_3d_grad.cc View File

@@ -0,0 +1,102 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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.
*/

#include <set>
#include "ops/grad/grid_sampler_3d_grad.h"

namespace mindspore {
namespace ops {
namespace {
const size_t kZero = 0;
const size_t kOne = 1;
const size_t kTwo = 2;
const size_t kThree = 3;
const size_t kFour = 4;
const size_t kFive = 5;

abstract::TupleShapePtr GridSampler3DGradInferShape(const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args) {
auto grad_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kZero]->BuildShape())[kShape];
auto input_x_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kOne]->BuildShape())[kShape];
auto grid_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kTwo]->BuildShape())[kShape];
if (grad_shape.size() != kFive) {
MS_EXCEPTION(ValueError) << "Grad must be a 5-dimensional tensor, but got " << std::to_string(grad_shape.size())
<< "-dimensional tensor.";
}
if (input_x_shape.size() != kFive) {
MS_EXCEPTION(ValueError) << "Input_x must be a 5-dimensional tensor, but got "
<< std::to_string(input_x_shape.size()) << "-dimensional tensor.";
}
if (grid_shape.size() != kFive) {
MS_EXCEPTION(ValueError) << "Grid must be a 5-dimensional tensor, but got " << std::to_string(grid_shape.size())
<< "-dimensional tensor.";
}
if (input_x_shape[kZero] != grid_shape[kZero]) {
MS_EXCEPTION(ValueError) << "The shape of grid is " << input_args[kTwo]->BuildShape()->ToString()
<< " , but the shape of input_x is " << input_args[kOne]->BuildShape()->ToString()
<< " . The first dimension of grid and input_x must be equal.";
}
if (grid_shape[kFour] != kThree) {
MS_EXCEPTION(ValueError) << "The last dimension of grid must be 3, but got " << std::to_string(grid_shape[kFour]);
}
std::vector<int64_t> out_shape = {input_x_shape[kZero], input_x_shape[kOne], grid_shape[kOne], grid_shape[kTwo],
grid_shape[kThree]};
bool shape_error = false;
for (size_t i = kZero; i < kFive; i++) {
if (out_shape[i] != grad_shape[i]) {
shape_error = true;
break;
}
}
if (shape_error) {
MS_EXCEPTION(ValueError) << "The shape of grad, which is the same as that of output, is "
<< input_args[kZero]->BuildShape()->ToString() << ", but the shape of output is ("
<< std::to_string(out_shape[kZero]) << ", " << std::to_string(out_shape[kOne]) << ", "
<< std::to_string(out_shape[kTwo]) << ", " << std::to_string(out_shape[kThree]) << ", "
<< std::to_string(out_shape[kFour]) << ").";
}
abstract::ShapePtr dx_shape = std::make_shared<abstract::Shape>(input_x_shape);
abstract::ShapePtr dgrid_shape = std::make_shared<abstract::Shape>(grid_shape);
return std::make_shared<abstract::TupleShape>(std::vector<abstract::BaseShapePtr>{dx_shape, dgrid_shape});
}

TuplePtr GridSampler3DGradInferType(const PrimitivePtr &primitive, const std::vector<AbstractBasePtr> &input_args) {
std::map<std::string, TypePtr> types;
std::set<TypePtr> valid_types = {kFloat32, kFloat64};
TypePtr grad_type = input_args[kZero]->BuildType();
TypePtr input_x_type = input_args[kOne]->BuildType();
TypePtr grid_type = input_args[kTwo]->BuildType();
(void)types.emplace("grad", grad_type);
(void)types.emplace("input_x", input_x_type);
(void)types.emplace("grid", grid_type);
(void)CheckAndConvertUtils::CheckTensorTypeSame(types, valid_types, primitive->name());
return std::make_shared<Tuple>(std::vector<TypePtr>{input_x_type, grid_type});
}
} // namespace

AbstractBasePtr GridSampler3DGradInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args) {
MS_EXCEPTION_IF_NULL(primitive);
const int64_t input_num = kThree;
CheckAndConvertUtils::CheckInputArgs(input_args, kEqual, input_num, primitive->name());
auto infer_types = GridSampler3DGradInferType(primitive, input_args);
auto infer_shapes = GridSampler3DGradInferShape(primitive, input_args);
return abstract::MakeAbstract(infer_shapes, infer_types);
}

REGISTER_PRIMITIVE_EVAL_IMPL(GridSampler3DGrad, prim::kPrimGridSampler3DGrad, GridSampler3DGradInfer, nullptr, true);
} // namespace ops
} // namespace mindspore

+ 44
- 0
mindspore/core/ops/grad/grid_sampler_3d_grad.h View File

@@ -0,0 +1,44 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_
#define MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "abstract/abstract_value.h"
#include "ops/op_utils.h"
#include "ops/primitive_c.h"
#include "utils/check_convert_utils.h"

namespace mindspore {
namespace ops {
constexpr auto kNameGridSampler3DGrad = "GridSampler3DGrad";
class GridSampler3DGrad : public PrimitiveC {
public:
GridSampler3DGrad() : PrimitiveC(kNameGridSampler3DGrad) { InitIOName({"grad", "input_x", "grid"}, {"dx", "dgrid"}); }
~GridSampler3DGrad() = default;
MS_DECLARE_PARENT(GridSampler3DGrad, PrimitiveC);
};
AbstractBasePtr GridSampler3DGradInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args);
using PrimGridSampler3DGrad = std::shared_ptr<GridSampler3DGrad>;
} // namespace ops
} // namespace mindspore

#endif // MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_

+ 79
- 0
mindspore/core/ops/grid_sampler_3d.cc View File

@@ -0,0 +1,79 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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.
*/

#include <set>
#include "ops/grid_sampler_3d.h"

namespace mindspore {
namespace ops {
namespace {
const size_t kZero = 0;
const size_t kOne = 1;
const size_t kTwo = 2;
const size_t kThree = 3;
const size_t kFour = 4;
const size_t kFive = 5;

abstract::ShapePtr GridSampler3DInferShape(const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args) {
auto input_x_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kZero]->BuildShape())[kShape];
auto grid_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kOne]->BuildShape())[kShape];
if (input_x_shape.size() != kFive) {
MS_EXCEPTION(ValueError) << "Input_x must be a 5-dimensional tensor, but got "
<< std::to_string(input_x_shape.size()) << "-dimensional tensor.";
}
if (grid_shape.size() != kFive) {
MS_EXCEPTION(ValueError) << "Grid must be a 5-dimensional tensor, but got " << std::to_string(grid_shape.size())
<< "-dimensional tensor.";
}
if (input_x_shape[kZero] != grid_shape[kZero]) {
MS_EXCEPTION(ValueError) << "The shape of grid is " << input_args[kOne]->BuildShape()->ToString()
<< " , but the shape of input_x is " << input_args[kZero]->BuildShape()->ToString()
<< " . The first dimension of grid and input_x must be equal.";
}
if (grid_shape[kFour] != kThree) {
MS_EXCEPTION(ValueError) << "The last dimension of grid must be 3, but got " << std::to_string(grid_shape[kFour]);
}
std::vector<int64_t> output_shape = {input_x_shape[kZero], input_x_shape[kOne], grid_shape[kOne], grid_shape[kTwo],
grid_shape[kThree]};
return std::make_shared<abstract::Shape>(output_shape);
}

TypePtr GridSampler3DInferType(const PrimitivePtr &primitive, const std::vector<AbstractBasePtr> &input_args) {
std::map<std::string, TypePtr> types;
std::set<TypePtr> valid_types = {kFloat32, kFloat64};
TypePtr input_x_type = input_args[kZero]->BuildType();
TypePtr grid_type = input_args[kOne]->BuildType();
(void)types.emplace("input_x", input_x_type);
(void)types.emplace("grid", grid_type);
(void)CheckAndConvertUtils::CheckTensorTypeSame(types, valid_types, primitive->name());
return input_x_type;
}
} // namespace

AbstractBasePtr GridSampler3DInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args) {
MS_EXCEPTION_IF_NULL(primitive);
const int64_t input_num = kTwo;
CheckAndConvertUtils::CheckInputArgs(input_args, kEqual, input_num, primitive->name());
auto infer_type = GridSampler3DInferType(primitive, input_args);
auto infer_shape = GridSampler3DInferShape(primitive, input_args);
return abstract::MakeAbstract(infer_shape, infer_type);
}

REGISTER_PRIMITIVE_EVAL_IMPL(GridSampler3D, prim::kPrimGridSampler3D, GridSampler3DInfer, nullptr, true);
} // namespace ops
} // namespace mindspore

+ 44
- 0
mindspore/core/ops/grid_sampler_3d.h View File

@@ -0,0 +1,44 @@
/**
* Copyright 2021 Huawei Technologies Co., Ltd
*
* 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 MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_
#define MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_
#include <map>
#include <memory>
#include <string>
#include <vector>

#include "abstract/abstract_value.h"
#include "ops/op_utils.h"
#include "ops/primitive_c.h"
#include "utils/check_convert_utils.h"

namespace mindspore {
namespace ops {
constexpr auto kNameGridSampler3D = "GridSampler3D";
class GridSampler3D : public PrimitiveC {
public:
GridSampler3D() : PrimitiveC(kNameGridSampler3D) { InitIOName({"input_x", "grid"}, {"output"}); }
~GridSampler3D() = default;
MS_DECLARE_PARENT(GridSampler3D, PrimitiveC);
};
AbstractBasePtr GridSampler3DInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
const std::vector<AbstractBasePtr> &input_args);
using PrimGridSampler3D = std::shared_ptr<GridSampler3D>;
} // namespace ops
} // namespace mindspore

#endif // MINDSPORE_CORE_OPS_GRID_SAMPLER_3D_H_

+ 12
- 0
mindspore/python/mindspore/ops/_grad_experimental/grad_nn_ops.py View File

@@ -84,3 +84,15 @@ def get_bprop_celu(self):
return (dx,)

return bprop


@bprop_getters.register(P.GridSampler3D)
def get_bprop_grid_sampler_3d(self):
"""Grad definition for `GridSampler3D` operation."""
grad = G.GridSampler3DGrad(self.interpolation_mode, self.padding_mode, self.align_corners)

def bprop(input_x, grid, out, dout):
dx, dgrid = grad(dout, input_x, grid)
return dx, dgrid

return bprop

+ 2
- 0
mindspore/python/mindspore/ops/_op_impl/aicpu/__init__.py View File

@@ -95,3 +95,5 @@ from .scatter_elements import _scatter_elements_aicpu
from .non_max_suppression import _non_max_suppression_aicpu
from .square import _square_aicpu
from .lower_bound import _lower_bound_aicpu
from .grid_sampler_3d import _grid_sampler_3d_aicpu
from .grid_sampler_3d_grad import _grid_sampler_3d_grad_aicpu

+ 34
- 0
mindspore/python/mindspore/ops/_op_impl/aicpu/grid_sampler_3d.py View File

@@ -0,0 +1,34 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================

"""GridSampler3D op"""
from mindspore.ops.op_info_register import op_info_register, AiCPURegOp, DataType

grid_sampler_3d_op_info = AiCPURegOp("GridSampler3D") \
.fusion_type("OPAQUE") \
.attr("interpolation_mode", "str") \
.attr("padding_mode", "str") \
.attr("align_corners", "bool") \
.input(0, "input_x", "required") \
.input(1, "grid", "required") \
.output(0, "output", "required") \
.dtype_format(DataType.F32_Default, DataType.F32_Default, DataType.F32_Default) \
.dtype_format(DataType.F64_Default, DataType.F64_Default, DataType.F64_Default) \
.get_op_info()

@op_info_register(grid_sampler_3d_op_info)
def _grid_sampler_3d_aicpu():
"""GridSampler3D aicpu register"""
return

+ 38
- 0
mindspore/python/mindspore/ops/_op_impl/aicpu/grid_sampler_3d_grad.py View File

@@ -0,0 +1,38 @@
# Copyright 2021 Huawei Technologies Co., Ltd
#
# 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.
# ============================================================================

"""GridSampler3DGrad op"""
from mindspore.ops.op_info_register import op_info_register, AiCPURegOp, DataType

grid_sampler_3d_grad_op_info = AiCPURegOp("GridSampler3DGrad") \
.fusion_type("OPAQUE") \
.attr("interpolation_mode", "str") \
.attr("padding_mode", "str") \
.attr("align_corners", "bool") \
.input(0, "grad", "required") \
.input(1, "input_x", "required") \
.input(2, "grid", "required") \
.output(0, "dx", "required") \
.output(1, "dgrid", "required") \
.dtype_format(DataType.F32_Default, DataType.F32_Default, DataType.F32_Default, \
DataType.F32_Default, DataType.F32_Default) \
.dtype_format(DataType.F64_Default, DataType.F64_Default, DataType.F64_Default, \
DataType.F64_Default, DataType.F64_Default) \
.get_op_info()

@op_info_register(grid_sampler_3d_grad_op_info)
def _grid_sampler_3d_grad_aicpu():
"""GridSampler3DGrad aicpu register"""
return

+ 2
- 1
mindspore/python/mindspore/ops/operations/__init__.py View File

@@ -90,7 +90,7 @@ from .nn_ops import (LSTM, SGD, Adam, AdamWeightDecay, FusedSparseAdam, FusedSpa
ApplyAdaMax, ApplyAdadelta, ApplyAdagrad, ApplyAdagradV2, ApplyAdagradDA,
ApplyAddSign, ApplyPowerSign, ApplyGradientDescent, ApplyProximalGradientDescent,
ApplyRMSProp, ApplyCenteredRMSProp, BasicLSTMCell, InTopK, AdaptiveAvgPool2D, SoftShrink,
ApplyAdamWithAmsgrad)
ApplyAdamWithAmsgrad, GridSampler3D)
from . import _quant_ops
from ._quant_ops import *
from .other_ops import (Assign, IOU, BoundingBoxDecode, BoundingBoxEncode,
@@ -129,6 +129,7 @@ from .custom_ops import (Custom)
__all__ = [
'CeLU',
'Ger',
'GridSampler3D',
'Unique',
'ReverseSequence',
'Sort',


+ 49
- 0
mindspore/python/mindspore/ops/operations/_grad_ops.py View File

@@ -2346,3 +2346,52 @@ class ParallelResizeBilinearGrad(PrimitiveWithInfer):
return {'shape': output_shape,
'dtype': x_dtype,
'value': None}


class GridSampler3DGrad(Primitive):
"""
Computes gradients for GridSampler3D operation.

Args:
interpolation_mode (str): An optional string specifying the interpolation method. The optional values are
"bilinear" or "nearest". Default: "bilinear".
padding_mode (str): An optional string specifying the pad method. The optional values are "zeros", "border" or
"reflection". Default: "zeros".
align_corners (bool): An optional bool. If "true", the centers of the corner pixels of the input and output
tensors are aligned. Defaults to "false".

Inputs:
- **grad** (Tensor) - A 5-D tensor whose dtype is float32 or float64 and whose shape is :math:`(N, C, D_{out},
H_{out}, W_{out})`. The shape is inconsistent with the shape of the output result of forward calculation.
- **input_x** (Tensor) - A 5-D tensor whose dtype is the same as `grad` and whose shape is :math:`(N, C,
D_{in}, H_{in}, W_{in})`.
- **grid** (Tensor) - A 5-D tensor whose dtype is the same as `grad` and whose shape is :math:`(N, D_{out},
H_{out}, W_{out}, 3)`.

Outputs:
- **dx** (Tensor) - A 5-D tensor whose dtype and shape are the same as `input_x`.
- **dgrid** (Tensor) - A 5-D tensor whose dtype and shape are the same as `grid`.

Raises:
TypeError: If `grad`, `input_x` or `grid` is not a Tensor.
TypeError: If the dtypes of `grad`, `input_x` and `grid` are inconsistent.
TypeError: If the dtype of `grad`, `input_x` or `grid` is not a valid type.
TypeError: If `align_corners` is not a boolean value.
ValueError: If the rank of `grad`, `input_x` or `grid` is not equal to 5.
ValueError: If the first dimension of `grad`, `input_x` and `grid` are inconsistent.
ValueError: If the last dimension of `grid` is not equal to 3.
ValueError: If `interpolation_mode` is not "bilinear", "nearest" or a string value.
ValueError: If `padding_mode` is not "zeros", "border", "reflection" or a string value.
ValueError: If the shape of `grad` is inconsistent with the shape of the output result of forward calculation.

Supported Platforms:
``CPU``
"""

@prim_attr_register
def __init__(self, interpolation_mode='bilinear', padding_mode='zeros', align_corners=False):
"""Initialize GridSampler3DGrad."""
validator.check_string(interpolation_mode, ['bilinear', 'nearest'], 'interpolation_mode', self.name)
validator.check_string(padding_mode, ['zeros', 'border', 'reflection'], 'padding_mode', self.name)
validator.check_bool(align_corners, 'align_corners', self.name)
self.init_prim_io_names(inputs=['grad', 'input_x', 'grid'], outputs=['dx', 'dgrid'])

+ 79
- 0
mindspore/python/mindspore/ops/operations/nn_ops.py View File

@@ -8982,3 +8982,82 @@ class ApplyAdamWithAmsgrad(Primitive):
validator.check_value_type("beta2", beta2, [float], self.name)
validator.check_value_type("epsilon", epsilon, [float], self.name)
validator.check_value_type("use_locking", use_locking, [bool], self.name)


class GridSampler3D(Primitive):
"""
Given an `input_x` and a flow-field `grid`, computes the `output` using `input_x` values and pixel locations from
`grid`. Only volumetric (5-D) `input_x` is supported.

For `input_x` with shape :math:`(N, C, D_{in}, H_{in}, W_{in})` and `grid` with shape :math:`(N, D_{out}, H_{out},
W_{out}, 3)`, the `output` will have shape :math:`(N, C, D_{out}, H_{out}, W_{out})`.

For each output location `output[n, :, d, h, w]`, the size-3 vector `grid[n, d, h, w]` specifies `input_x` pixel
locations x, y, z, which are used to interpolate the output value `output[n, :, d, h, w]`. And `interpolation_mode`
argument specifies "nearest" or "bilinear" interpolation method to sample the input pixels.

`grid` specifies the sampling pixel locations normalized by the `input_x` spatial dimensions. Therefore, it should
have most values in the range of :math:`[-1, 1]`.

If `grid` has values outside the range of :math:`[-1, 1]`, the corresponding outputs are handled as defined by
`padding_mode`. If `padding_mode` is set to be "zeros", use :math:`0` for out-of-bound grid locations. If
`padding_mode` is set to be "border", use border values for out-of-bound grid locations. If `padding_mode` is set
to be "reflection", use values at locations reflected by the border for out-of-bound grid locations. For location
far away from the border, it will keep being reflected until becoming in bound.

Args:
interpolation_mode (str): An optional string specifying the interpolation method. The optional values are
"bilinear" or "nearest". Default: "bilinear".
padding_mode (str): An optional string specifying the pad method. The optional values are "zeros", "border" or
"reflection". Default: "zeros".
align_corners (bool): An optional bool. If set to `True`, the extrema (-1 and 1) are considered as referring to
the center points of the input’s corner pixels. If set to `False`, they are instead considered as referring
to the corner points of the input’s corner pixels, making the sampling more resolution agnostic. Default:
`False`.

Inputs:
- **input_x** (Tensor) - A 5-D tensor with dtype of float32 or float64 and shape of :math:`(N, C, D_{in},
H_{in}, W_{in})`.
- **grid** (Tensor) - A 5-D tensor whose dtype is the same as `input_x` and whose shape is :math:`(N, D_{out},
H_{out}, W_{out}, 3)`.

Outputs:
A 5-D Tensor whose dtype is the same as `input_x` and whose shape is :math:`(N, C, D_{out}, H_{out}, W_{out})`.

Raises:
TypeError: If `input_x` or `grid` is not a Tensor.
TypeError: If the dtypes of `input_x` and `grid` are inconsistent.
TypeError: If the dtype of `input_x` or `grid` is not a valid type.
TypeError: If `align_corners` is not a boolean value.
ValueError: If the rank of `input_x` or `grid` is not equal to 5.
ValueError: If the first dimension of `input_x` is not equal to that of `grid`.
ValueError: If the last dimension of `grid` is not equal to 3.
ValueError: If `interpolation_mode` is not "bilinear", "nearest" or a string value.
ValueError: If `padding_mode` is not "zeros", "border", "reflection" or a string value.

Supported Platforms:
``CPU``

Examples:
>>> gridsampler = ops.GridSampler3D(interpolation_mode='bilinear', padding_mode='zeros', align_corners=True)
>>> input_x = Tensor(np.arange(32).reshape((2, 2, 2, 2, 2)).astype(np.float32))
>>> grid = Tensor(np.arange(-0.2, 1, 0.1).reshape((2, 2, 1, 1, 3)).astype(np.float32))
>>> output = gridsampler(input_x, grid)
>>> print(output)
[[[[[ 3.3 ]]
[[ 4.35 ]]]
[[[11.300001]]
[[12.349999]]]]
[[[[21.4 ]]
[[22.449999]]]
[[[29.4 ]]
[[30.449999]]]]]
"""

@prim_attr_register
def __init__(self, interpolation_mode='bilinear', padding_mode='zeros', align_corners=False):
"""Initialize GridSampler3D."""
validator.check_string(interpolation_mode, ['bilinear', 'nearest'], 'interpolation_mode', self.name)
validator.check_string(padding_mode, ['zeros', 'border', 'reflection'], 'padding_mode', self.name)
validator.check_bool(align_corners, 'align_corners', self.name)
self.init_prim_io_names(inputs=['input_x', 'grid'], outputs=['output'])

+ 5
- 0
tests/ut/python/ops/test_ops.py View File

@@ -2448,6 +2448,11 @@ test_case_nn_ops = [
Tensor(np.array([[0.3, 0.2], [0.4, 0.1]]).astype(np.float32)),
Tensor(0.99, mstype.float32)],
'skip': ['backward']}),
('GridSampler3D', {
'block': P.GridSampler3D(interpolation_mode='bilinear', padding_mode='zeros', align_corners=False),
'desc_inputs': [Tensor(np.arange(32).reshape((2, 2, 2, 2, 2)).astype(np.float32)),
Tensor(np.arange(-0.2, 1, 0.1).reshape((2, 2, 1, 1, 3)).astype(np.float32))],
'desc_bprop': [Tensor(np.arange(-1, 1, 0.25).reshape((2, 2, 2, 1, 1)).astype(np.float32))]}),
]

test_case_array_ops = [


Loading…
Cancel
Save