!37129 MaxPoolWithArgmax & MaxPoolGradWithArgmax CPU Operator
Merge pull request !37129 from ivanshan_8170/max_pool_with_argmax
This commit is contained in:
commit
805e418791
|
@ -0,0 +1,193 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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 "plugin/device/cpu/kernel/max_pool_grad_with_argmax_cpu_kernel.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "plugin/device/cpu/hal/device/cpu_device_address.h"
|
||||||
|
#include "mindspore/core/ops/grad/max_pool_grad_with_argmax.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace kernel {
|
||||||
|
namespace {
|
||||||
|
constexpr size_t kMaxPoolGradWithArgmaxInputsNum = 3;
|
||||||
|
constexpr size_t kMaxPoolGradWithArgmaxOutputsNum = 1;
|
||||||
|
constexpr size_t kDimLowerLimit = 4;
|
||||||
|
constexpr size_t kInputDims = 4;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool MaxPoolGradWithArgmaxCpuKernelMod::Init(const BaseOperatorPtr &base_operator,
|
||||||
|
const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs) {
|
||||||
|
kernel_name_ = base_operator->name();
|
||||||
|
auto kernel_ptr = std::dynamic_pointer_cast<ops::MaxPoolGradWithArgmax>(base_operator);
|
||||||
|
if (kernel_ptr == nullptr) {
|
||||||
|
MS_LOG(ERROR) << "Cast op from BaseOperator to MaxPoolingGradWithArgmax failed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
stride_height_ = LongToInt(kernel_ptr->get_strides()[kDim2]);
|
||||||
|
stride_width_ = LongToInt(kernel_ptr->get_strides()[kDim3]);
|
||||||
|
if (stride_height_ < 1 || stride_width_ < 1) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected strides to be Union[int, tuple[int]] with value no less than 1 "
|
||||||
|
"but got the window height: "
|
||||||
|
<< stride_height_ << ", and the window width: " << stride_height_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pad_mode_ = kernel_ptr->get_pad_mode();
|
||||||
|
// pair = [is_match, index]
|
||||||
|
auto kernel_attr = GetKernelAttrFromTensors(inputs, outputs);
|
||||||
|
auto pair = MatchKernelAttr(kernel_attr, GetOpSupport());
|
||||||
|
if (!pair.first) {
|
||||||
|
MS_LOG(ERROR) << "For '" << kernel_name_ << "' does not support this kernel type: " << kernel_attr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
kernel_func_ = func_list_[pair.second].second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MaxPoolGradWithArgmaxCpuKernelMod::ResizedInputSize(const std::vector<KernelTensorPtr> &inputs) {
|
||||||
|
auto x_shape = inputs[kDim0]->GetShapeVector();
|
||||||
|
if (x_shape.size() != kInputDims) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_ << "', the input 'x' must be 4-dimensional.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < x_shape.size(); i++) {
|
||||||
|
if (x_shape[i] <= 0) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected input 'x' has non-empty spatial dimensions, "
|
||||||
|
"but 'x' has sizes "
|
||||||
|
<< x_shape[i] << " wit the dimension " << i << " being empty.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
batch_ = LongToInt(x_shape[kDim0]);
|
||||||
|
channel_ = LongToInt(x_shape[kDim1]);
|
||||||
|
x_height_ = LongToInt(x_shape[kDim2]);
|
||||||
|
x_width_ = LongToInt(x_shape[kDim3]);
|
||||||
|
|
||||||
|
auto dy_shape = inputs[kDim1]->GetShapeVector();
|
||||||
|
// check the spatial dimensions of dy if needed
|
||||||
|
for (size_t i = 0; i < dy_shape.size(); i++) {
|
||||||
|
if (dy_shape[i] <= 0) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected input 'dy' has non-empty spatial dimensions, "
|
||||||
|
"but 'dy' has sizes "
|
||||||
|
<< dy_shape[i] << " wit the dimension " << i << " being empty.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dy_height_ = LongToInt(dy_shape[kDim2]);
|
||||||
|
dy_width_ = LongToInt(dy_shape[kDim3]);
|
||||||
|
auto index_shape = inputs[kDim2]->GetShapeVector();
|
||||||
|
for (size_t i = 0; i < index_shape.size(); i++) {
|
||||||
|
if (index_shape[i] <= 0) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected input 'index' has non-empty spatial dimensions, "
|
||||||
|
"but 'index' has sizes "
|
||||||
|
<< index_shape[i] << " wit the dimension " << i << " being empty.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x_shape.size() < kDimLowerLimit || dy_shape.size() < kDimLowerLimit) {
|
||||||
|
MS_LOG(EXCEPTION) << "For '" << kernel_name_ << "', the dimension of 'x' and 'dy' cannot be less than 4, but got "
|
||||||
|
<< "the dimension of 'x': " << x_shape.size() << ", the dimension of 'dy': " << dy_shape.size();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaxPoolGradWithArgmaxCpuKernelMod::Resize(const BaseOperatorPtr &base_operator,
|
||||||
|
const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs,
|
||||||
|
const std::map<uint32_t, tensor::TensorPtr> &) {
|
||||||
|
CHECK_KERNEL_INPUTS_NUM(inputs.size(), kMaxPoolGradWithArgmaxInputsNum, kernel_name_);
|
||||||
|
CHECK_KERNEL_OUTPUTS_NUM(outputs.size(), kMaxPoolGradWithArgmaxOutputsNum, kernel_name_);
|
||||||
|
if (int ret = KernelMod::Resize(base_operator, inputs, outputs); ret != KRET_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
auto kernel_ptr = std::dynamic_pointer_cast<ops::MaxPoolGradWithArgmax>(base_operator);
|
||||||
|
if (kernel_ptr == nullptr) {
|
||||||
|
MS_LOG(ERROR) << "Cast op from BaseOperator to MaxPoolingGradWithArgmax failed.";
|
||||||
|
return KRET_RESIZE_FAILED;
|
||||||
|
}
|
||||||
|
if (!ResizedInputSize(inputs)) {
|
||||||
|
return KRET_RESIZE_FAILED;
|
||||||
|
}
|
||||||
|
return KRET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename S>
|
||||||
|
bool MaxPoolGradWithArgmaxCpuKernelMod::LaunchKernel(const std::vector<kernel::AddressPtr> &inputs,
|
||||||
|
const std::vector<kernel::AddressPtr> &outputs) {
|
||||||
|
auto *input = reinterpret_cast<T *>(inputs.at(kDim0)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(input);
|
||||||
|
auto *grad = reinterpret_cast<T *>(inputs.at(kDim1)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(grad);
|
||||||
|
auto *index = reinterpret_cast<S *>(inputs.at(kDim2)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(index);
|
||||||
|
auto *output = reinterpret_cast<T *>(outputs.at(kDim0)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(output);
|
||||||
|
const int c = this->channel_;
|
||||||
|
const int xCHW = c * this->x_height_ * this->x_width_;
|
||||||
|
const int dyCHW = c * this->dy_height_ * this->dy_width_;
|
||||||
|
const int outputLength = this->batch_ * xCHW;
|
||||||
|
auto init = [output](size_t start, size_t end) {
|
||||||
|
const T zero = static_cast<T>(0);
|
||||||
|
for (size_t i = start; i < end; ++i) {
|
||||||
|
output[i] = zero;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ParallelLaunchAutoSearch(init, outputLength, this, ¶llel_search_info_);
|
||||||
|
const int length = this->batch_ * dyCHW;
|
||||||
|
auto task = [input, output, grad, index, &xCHW, &dyCHW](size_t start, size_t end) {
|
||||||
|
for (size_t i = start; i < end; ++i) {
|
||||||
|
const int idx = static_cast<int>(index[i]);
|
||||||
|
const int posn = i / dyCHW;
|
||||||
|
*(output + posn * xCHW + idx) += grad[i];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ParallelLaunchAutoSearch(task, length, this, ¶llel_search_info_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<KernelAttr, MaxPoolGradWithArgmaxCpuKernelMod::MaxPoolGradWithArgmaxFunc>>
|
||||||
|
MaxPoolGradWithArgmaxCpuKernelMod::func_list_ = {
|
||||||
|
{KernelAttr()
|
||||||
|
.AddInputAttr(kNumberTypeFloat32)
|
||||||
|
.AddInputAttr(kNumberTypeFloat32)
|
||||||
|
.AddInputAttr(kNumberTypeInt32)
|
||||||
|
.AddOutputAttr(kNumberTypeFloat32),
|
||||||
|
&MaxPoolGradWithArgmaxCpuKernelMod::LaunchKernel<float, int32_t>},
|
||||||
|
{KernelAttr()
|
||||||
|
.AddInputAttr(kNumberTypeFloat32)
|
||||||
|
.AddInputAttr(kNumberTypeFloat32)
|
||||||
|
.AddInputAttr(kNumberTypeInt64)
|
||||||
|
.AddOutputAttr(kNumberTypeFloat32),
|
||||||
|
&MaxPoolGradWithArgmaxCpuKernelMod::LaunchKernel<float, int64_t>},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<KernelAttr> MaxPoolGradWithArgmaxCpuKernelMod::GetOpSupport() {
|
||||||
|
std::vector<KernelAttr> support_list;
|
||||||
|
std::transform(func_list_.begin(), func_list_.end(), std::back_inserter(support_list),
|
||||||
|
[](const std::pair<KernelAttr, MaxPoolGradWithArgmaxFunc> &pair) { return pair.first; });
|
||||||
|
return support_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
MS_KERNEL_FACTORY_REG(NativeCpuKernelMod, MaxPoolGradWithArgmax, MaxPoolGradWithArgmaxCpuKernelMod);
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,71 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_GRAD_WITH_ARGMAX_CPU_KERNEL_H_
|
||||||
|
#define MINDSPORE_CCSRC_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_GRAD_WITH_ARGMAX_CPU_KERNEL_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <vector>
|
||||||
|
#include <utility>
|
||||||
|
#include "mindspore/core/ops/grad/max_pool_grad_with_argmax.h"
|
||||||
|
#include "plugin/device/cpu/kernel/cpu_kernel.h"
|
||||||
|
#include "plugin/factory/ms_factory.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace kernel {
|
||||||
|
class MaxPoolGradWithArgmaxCpuKernelMod : public NativeCpuKernelMod {
|
||||||
|
public:
|
||||||
|
MaxPoolGradWithArgmaxCpuKernelMod() {}
|
||||||
|
~MaxPoolGradWithArgmaxCpuKernelMod() override = default;
|
||||||
|
|
||||||
|
bool Launch(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &workspace,
|
||||||
|
const std::vector<AddressPtr> &outputs) override {
|
||||||
|
return kernel_func_(this, inputs, outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Init(const BaseOperatorPtr &base_operator, const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs) override;
|
||||||
|
|
||||||
|
int Resize(const BaseOperatorPtr &base_operator, const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs, const std::map<uint32_t, tensor::TensorPtr> &) override;
|
||||||
|
bool ResizedInputSize(const std::vector<KernelTensorPtr> &inputs);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<KernelAttr> GetOpSupport() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T, typename S>
|
||||||
|
bool LaunchKernel(const std::vector<kernel::AddressPtr> &inputs, const std::vector<kernel::AddressPtr> &outputs);
|
||||||
|
|
||||||
|
using MaxPoolGradWithArgmaxFunc =
|
||||||
|
std::function<bool(MaxPoolGradWithArgmaxCpuKernelMod *, const std::vector<kernel::AddressPtr> &,
|
||||||
|
const std::vector<kernel::AddressPtr> &)>;
|
||||||
|
|
||||||
|
static std::vector<std::pair<KernelAttr, MaxPoolGradWithArgmaxFunc>> func_list_;
|
||||||
|
MaxPoolGradWithArgmaxFunc kernel_func_;
|
||||||
|
int batch_ = 0;
|
||||||
|
int channel_ = 0;
|
||||||
|
int x_height_ = 0;
|
||||||
|
int x_width_ = 0;
|
||||||
|
int dy_height_ = 0;
|
||||||
|
int dy_width_ = 0;
|
||||||
|
int stride_height_ = 1;
|
||||||
|
int stride_width_ = 1;
|
||||||
|
PadMode pad_mode_ = PadMode::VALID;
|
||||||
|
};
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace mindspore
|
||||||
|
#endif // MINDSPORE_CCSRC_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_GRAD_WITH_ARGMAX_CPU_KERNEL_H_
|
|
@ -0,0 +1,230 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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 "plugin/device/cpu/kernel/max_pool_with_argmax_cpu_kernel.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "plugin/device/cpu/hal/device/cpu_device_address.h"
|
||||||
|
#include "mindspore/core/ops/max_pool_with_argmax.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace kernel {
|
||||||
|
namespace {
|
||||||
|
constexpr size_t kMaxPoolWithArgmaxInputsNum = 1;
|
||||||
|
constexpr size_t kMaxPoolWithArgmaxOutputsNum = 2;
|
||||||
|
constexpr size_t kInputRank = 4;
|
||||||
|
constexpr int kPadHalf = 2;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
bool MaxPoolWithArgmaxCpuKernelMod::Init(const BaseOperatorPtr &base_operator,
|
||||||
|
const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs) {
|
||||||
|
kernel_name_ = base_operator->name();
|
||||||
|
auto kernel_ptr = std::dynamic_pointer_cast<ops::MaxPoolWithArgmax>(base_operator);
|
||||||
|
data_format_ = kernel_ptr->get_format();
|
||||||
|
window_height_ = LongToInt(kernel_ptr->get_kernel_size()[kDim1]);
|
||||||
|
window_width_ = LongToInt(kernel_ptr->get_kernel_size()[kDim2]);
|
||||||
|
if (window_height_ < 1 || window_width_ < 1) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected kernel_size to be Union[int, tuple[int]] with value no "
|
||||||
|
"less than 1 "
|
||||||
|
"but got the window height: "
|
||||||
|
<< window_height_ << ", and the window width: " << window_width_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
stride_height_ = LongToInt(kernel_ptr->get_strides()[kDim1]);
|
||||||
|
stride_width_ = LongToInt(kernel_ptr->get_strides()[kDim2]);
|
||||||
|
if (stride_height_ < 1 || stride_width_ < 1) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected strides to be Union[int, tuple[int]] with value no "
|
||||||
|
"less than 1 "
|
||||||
|
"but got the window height: "
|
||||||
|
<< window_height_ << ", and the window width: " << window_width_;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
pad_mode_ = kernel_ptr->get_pad_mode();
|
||||||
|
if (pad_mode_ == PadMode::SAME) {
|
||||||
|
int tmp_height = (input_height_ / stride_height_) * stride_height_ == input_height_
|
||||||
|
? (input_height_ / stride_height_)
|
||||||
|
: (input_height_ / stride_height_) + 1;
|
||||||
|
pad_height_ = std::max<int>(0, (tmp_height - 1) * stride_height_ + window_height_ - input_height_);
|
||||||
|
int tmp_width = (input_width_ / stride_width_) * stride_width_ == input_width_ ? (input_width_ / stride_width_)
|
||||||
|
: (input_width_ / stride_width_) + 1;
|
||||||
|
pad_width_ = std::max<int>(0, (tmp_width - 1) * stride_width_ + window_width_ - input_width_);
|
||||||
|
pad_top_ = pad_height_ / kPadHalf;
|
||||||
|
pad_left_ = pad_width_ / kPadHalf;
|
||||||
|
}
|
||||||
|
auto kernel_attr = GetKernelAttrFromTensors(inputs, outputs);
|
||||||
|
// pair = [is_match, index]
|
||||||
|
auto pair = MatchKernelAttr(kernel_attr, GetOpSupport());
|
||||||
|
if (!pair.first) {
|
||||||
|
MS_LOG(ERROR) << "For '" << kernel_name_ << "' does not support this kernel type: " << kernel_attr;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
kernel_func_ = func_list_[pair.second].second;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MaxPoolWithArgmaxCpuKernelMod::ResizedInputSize(const std::vector<KernelTensorPtr> &inputs) {
|
||||||
|
auto x_shape = inputs[kIndex0]->GetShapeVector();
|
||||||
|
if (x_shape.size() != kInputRank) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_ << "', the input 'x' must be 4-dimensional.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (size_t i = 0; i < x_shape.size(); i++) {
|
||||||
|
if (x_shape[i] <= 0) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected input have non-empty spatial dimensions, "
|
||||||
|
"but input has sizes "
|
||||||
|
<< x_shape[i] << " wit h dimension " << i << " being empty.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
batch_ = LongToInt(x_shape[kDim0]);
|
||||||
|
if (data_format_ == Format::NHWC) {
|
||||||
|
channel_ = LongToInt(x_shape[kDim3]);
|
||||||
|
input_height_ = LongToInt(x_shape[kDim1]);
|
||||||
|
input_width_ = LongToInt(x_shape[kDim2]);
|
||||||
|
} else {
|
||||||
|
// data_format_ == Format::NCHW
|
||||||
|
channel_ = LongToInt(x_shape[kDim1]);
|
||||||
|
input_height_ = LongToInt(x_shape[kDim2]);
|
||||||
|
input_width_ = LongToInt(x_shape[kDim3]);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool MaxPoolWithArgmaxCpuKernelMod::ResizedOutputSize(const std::vector<KernelTensorPtr> &outputs) {
|
||||||
|
auto output_shape = outputs[kIndex0]->GetShapeVector();
|
||||||
|
output_height_ = LongToInt(output_shape[kDim2]);
|
||||||
|
output_width_ = LongToInt(output_shape[kDim3]);
|
||||||
|
std::vector<int64_t> mask_shape = outputs[kIndex1]->GetShapeVector();
|
||||||
|
if (mask_shape != output_shape) {
|
||||||
|
MS_EXCEPTION(ValueError) << "For '" << kernel_name_
|
||||||
|
<< "', expected output and mask have the same shape "
|
||||||
|
"but output has shape "
|
||||||
|
<< output_shape << ", and mask shape: " << mask_shape;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int MaxPoolWithArgmaxCpuKernelMod::Resize(const BaseOperatorPtr &base_operator,
|
||||||
|
const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs,
|
||||||
|
const std::map<uint32_t, tensor::TensorPtr> &inputsOnHost) {
|
||||||
|
CHECK_KERNEL_INPUTS_NUM(inputs.size(), kMaxPoolWithArgmaxInputsNum, kernel_name_);
|
||||||
|
CHECK_KERNEL_OUTPUTS_NUM(outputs.size(), kMaxPoolWithArgmaxOutputsNum, kernel_name_);
|
||||||
|
if (int ret = KernelMod::Resize(base_operator, inputs, outputs, inputsOnHost); ret != KRET_OK) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
auto kernel_ptr = std::dynamic_pointer_cast<ops::MaxPoolWithArgmax>(base_operator);
|
||||||
|
if (kernel_ptr == nullptr) {
|
||||||
|
MS_LOG(ERROR) << "Cast op from BaseOperator to MaxPoolWithArgmax failed.";
|
||||||
|
return KRET_RESIZE_FAILED;
|
||||||
|
}
|
||||||
|
if (!ResizedInputSize(inputs)) {
|
||||||
|
return KRET_RESIZE_FAILED;
|
||||||
|
}
|
||||||
|
if (!ResizedOutputSize(outputs)) {
|
||||||
|
return KRET_RESIZE_FAILED;
|
||||||
|
}
|
||||||
|
return KRET_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool MaxPoolWithArgmaxCpuKernelMod::LaunchKernel(const std::vector<kernel::AddressPtr> &inputs,
|
||||||
|
const std::vector<kernel::AddressPtr> &outputs) {
|
||||||
|
auto *x = reinterpret_cast<T *>(inputs.at(kIndex0)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(x);
|
||||||
|
auto *output = reinterpret_cast<T *>(outputs.at(kIndex0)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(output);
|
||||||
|
auto *mask = reinterpret_cast<int32_t *>(outputs.at(kIndex1)->addr);
|
||||||
|
MS_EXCEPTION_IF_NULL(mask);
|
||||||
|
int cWeight, hWeight, wWeight;
|
||||||
|
if (data_format_ == Format::NHWC) {
|
||||||
|
cWeight = 1;
|
||||||
|
wWeight = channel_ * cWeight;
|
||||||
|
hWeight = input_height_ * wWeight;
|
||||||
|
} else {
|
||||||
|
// data_format == NCHW
|
||||||
|
wWeight = 1;
|
||||||
|
hWeight = input_width_ * wWeight;
|
||||||
|
cWeight = input_height_ * hWeight;
|
||||||
|
}
|
||||||
|
const int batch = this->batch_;
|
||||||
|
const int channel = this->channel_;
|
||||||
|
const int i_h = this->input_height_;
|
||||||
|
const int i_w = this->input_width_;
|
||||||
|
const int s_h = this->stride_height_;
|
||||||
|
const int s_w = this->stride_width_;
|
||||||
|
const int w_h = this->window_height_;
|
||||||
|
const int w_w = this->window_width_;
|
||||||
|
const int pad_top = this->pad_top_;
|
||||||
|
const int pad_left = this->pad_left_;
|
||||||
|
const int o_h = this->output_height_;
|
||||||
|
const int o_w = this->output_width_;
|
||||||
|
const size_t length = batch * channel * o_h * o_w;
|
||||||
|
|
||||||
|
auto task = [x, output, mask, &batch, &channel, &i_h, &i_w, &s_h, &s_w, &w_h, &w_w, &pad_top, &pad_left, &o_h, &o_w,
|
||||||
|
&wWeight, &hWeight, &cWeight](size_t start, size_t end) {
|
||||||
|
for (size_t i = start; i < end; ++i) {
|
||||||
|
const int posn = i / (channel * o_h * o_w);
|
||||||
|
const int posc = i / (o_h * o_w) % channel;
|
||||||
|
const int posh = i / o_w % o_h;
|
||||||
|
const int posw = i % o_w;
|
||||||
|
int hstart = posh * s_h - pad_top;
|
||||||
|
int wstart = posw * s_w - pad_left;
|
||||||
|
const int hend = std::min<int>(hstart + w_h, i_h);
|
||||||
|
const int wend = std::min<int>(wstart + w_w, i_w);
|
||||||
|
hstart = std::max<int>(hstart, 0);
|
||||||
|
wstart = std::max<int>(wstart, 0);
|
||||||
|
int32_t inputStart = posn * channel * i_h * i_w;
|
||||||
|
int32_t maxIdx = posc * cWeight + hstart * hWeight + wstart * wWeight;
|
||||||
|
T maxData = x[inputStart + maxIdx];
|
||||||
|
for (int hcur = hstart; hcur < hend; ++hcur) {
|
||||||
|
for (int wcur = wstart; wcur < wend; ++wcur) {
|
||||||
|
int32_t inputIdx = posc * cWeight + hcur * hWeight + wcur * wWeight;
|
||||||
|
T inputData = x[inputStart + inputIdx];
|
||||||
|
if (inputData > maxData) {
|
||||||
|
maxIdx = inputIdx;
|
||||||
|
maxData = inputData;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
output[i] = maxData;
|
||||||
|
mask[i] = maxIdx - posc * cWeight;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
ParallelLaunchAutoSearch(task, length, this, ¶llel_search_info_);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::pair<KernelAttr, MaxPoolWithArgmaxCpuKernelMod::MaxPoolWithArgmaxFunc>>
|
||||||
|
MaxPoolWithArgmaxCpuKernelMod::func_list_ = {
|
||||||
|
{KernelAttr().AddInputAttr(kNumberTypeFloat32).AddOutputAttr(kNumberTypeFloat32).AddOutputAttr(kNumberTypeInt32),
|
||||||
|
&MaxPoolWithArgmaxCpuKernelMod::LaunchKernel<float>},
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<KernelAttr> MaxPoolWithArgmaxCpuKernelMod::GetOpSupport() {
|
||||||
|
std::vector<KernelAttr> support_list;
|
||||||
|
std::transform(func_list_.begin(), func_list_.end(), std::back_inserter(support_list),
|
||||||
|
[](const std::pair<KernelAttr, MaxPoolWithArgmaxFunc> &pair) { return pair.first; });
|
||||||
|
return support_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
MS_KERNEL_FACTORY_REG(NativeCpuKernelMod, MaxPoolWithArgmax, MaxPoolWithArgmaxCpuKernelMod);
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,79 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_WITH_ARGMAX_CPU_KERNEL_H_
|
||||||
|
#define MINDSPORE_CCSRC_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_WITH_ARGMAX_CPU_KERNEL_H_
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
#include "mindspore/core/ops/max_pool_with_argmax.h"
|
||||||
|
#include "plugin/device/cpu/kernel/cpu_kernel.h"
|
||||||
|
#include "plugin/factory/ms_factory.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace kernel {
|
||||||
|
class MaxPoolWithArgmaxCpuKernelMod : public NativeCpuKernelMod {
|
||||||
|
public:
|
||||||
|
MaxPoolWithArgmaxCpuKernelMod() {}
|
||||||
|
~MaxPoolWithArgmaxCpuKernelMod() override = default;
|
||||||
|
|
||||||
|
bool Launch(const std::vector<AddressPtr> &inputs, const std::vector<AddressPtr> &workspace,
|
||||||
|
const std::vector<AddressPtr> &outputs) override {
|
||||||
|
return kernel_func_(this, inputs, outputs);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Init(const BaseOperatorPtr &base_operator, const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs) override;
|
||||||
|
|
||||||
|
int Resize(const BaseOperatorPtr &base_operator, const std::vector<KernelTensorPtr> &inputs,
|
||||||
|
const std::vector<KernelTensorPtr> &outputs,
|
||||||
|
const std::map<uint32_t, tensor::TensorPtr> &inputsOnHost) override;
|
||||||
|
bool ResizedInputSize(const std::vector<KernelTensorPtr> &inputs);
|
||||||
|
bool ResizedOutputSize(const std::vector<KernelTensorPtr> &outputs);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
std::vector<KernelAttr> GetOpSupport() override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
bool LaunchKernel(const std::vector<kernel::AddressPtr> &inputs, const std::vector<kernel::AddressPtr> &outputs);
|
||||||
|
|
||||||
|
using MaxPoolWithArgmaxFunc = std::function<bool(
|
||||||
|
MaxPoolWithArgmaxCpuKernelMod *, const std::vector<kernel::AddressPtr> &, const std::vector<kernel::AddressPtr> &)>;
|
||||||
|
|
||||||
|
static std::vector<std::pair<KernelAttr, MaxPoolWithArgmaxFunc>> func_list_;
|
||||||
|
MaxPoolWithArgmaxFunc kernel_func_;
|
||||||
|
int batch_ = 0;
|
||||||
|
int channel_ = 0;
|
||||||
|
int input_height_ = 0;
|
||||||
|
int input_width_ = 0;
|
||||||
|
int window_height_ = 1;
|
||||||
|
int window_width_ = 1;
|
||||||
|
int stride_height_ = 1;
|
||||||
|
int stride_width_ = 1;
|
||||||
|
PadMode pad_mode_ = PadMode::VALID;
|
||||||
|
Format data_format_ = Format::NCHW;
|
||||||
|
int pad_height_ = 0;
|
||||||
|
int pad_width_ = 0;
|
||||||
|
int pad_top_ = 0;
|
||||||
|
int pad_left_ = 0;
|
||||||
|
int output_height_ = 0;
|
||||||
|
int output_width_ = 0;
|
||||||
|
};
|
||||||
|
} // namespace kernel
|
||||||
|
} // namespace mindspore
|
||||||
|
#endif // MINDSPORE_CCSRC_PLUGIN_DEVICE_CPU_KERNEL_MAX_POOL_WITH_ARGMAX_CPU_KERNEL_H_
|
|
@ -0,0 +1,101 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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 "ops/grad/max_pool_grad_with_argmax.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include "ops/op_utils.h"
|
||||||
|
#include "utils/check_convert_utils.h"
|
||||||
|
#include "abstract/ops/primitive_infer_map.h"
|
||||||
|
#include "mindapi/src/helper.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace ops {
|
||||||
|
void MaxPoolGradWithArgmax::set_pad_mode(const PadMode &pad_mode) {
|
||||||
|
int64_t swi = pad_mode;
|
||||||
|
(void)this->AddAttr(kPadMode, api::MakeValue(swi));
|
||||||
|
}
|
||||||
|
|
||||||
|
PadMode MaxPoolGradWithArgmax::get_pad_mode() const {
|
||||||
|
auto value_ptr = GetAttr(kPadMode);
|
||||||
|
MS_EXCEPTION_IF_NULL(value_ptr);
|
||||||
|
auto mode_str = GetValue<std::string>(value_ptr);
|
||||||
|
std::transform(mode_str.begin(), mode_str.end(), mode_str.begin(), ::toupper);
|
||||||
|
MS_EXCEPTION_IF_CHECK_FAIL((mode_str == "SAME" || mode_str == "VALID"),
|
||||||
|
"MaxPoolGradWithArgmax only supports pad mode 'SAME' or 'VALID', but get " + mode_str);
|
||||||
|
return mode_str == "SAME" ? PadMode::SAME : PadMode::VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolGradWithArgmax::set_kernel_size(const std::vector<int64_t> &kernel_size) {
|
||||||
|
(void)this->AddAttr(
|
||||||
|
kKernelSize, api::MakeValue(CheckAndConvertUtils::CheckPositiveVector(kKernelSize, kernel_size, this->name())));
|
||||||
|
}
|
||||||
|
std::vector<int64_t> MaxPoolGradWithArgmax::get_kernel_size() const {
|
||||||
|
return GetValue<std::vector<int64_t>>(GetAttr(kKernelSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolGradWithArgmax::set_strides(const std::vector<int64_t> &strides) {
|
||||||
|
(void)this->AddAttr(kStrides,
|
||||||
|
api::MakeValue(CheckAndConvertUtils::CheckPositiveVector(kStrides, strides, this->name())));
|
||||||
|
}
|
||||||
|
std::vector<int64_t> MaxPoolGradWithArgmax::get_strides() const {
|
||||||
|
return GetValue<std::vector<int64_t>>(GetAttr(kStrides));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolGradWithArgmax::Init(const std::vector<int64_t> &kernel_size, const std::vector<int64_t> &stride,
|
||||||
|
const PadMode &pad_mode, const Format &format) {
|
||||||
|
this->set_pad_mode(pad_mode);
|
||||||
|
this->set_kernel_size(kernel_size);
|
||||||
|
this->set_strides(stride);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
abstract::ShapePtr MaxPoolGradWithArgmaxInferShape(const PrimitivePtr &primitive,
|
||||||
|
const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
auto x_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kDim0]->BuildShape())[kShape];
|
||||||
|
constexpr int64_t kXRank = 4;
|
||||||
|
CheckAndConvertUtils::CheckInteger("x_rank", SizeToLong(x_shape.size()), kEqual, kXRank, kNameMaxPoolGradWithArgmax);
|
||||||
|
return std::make_shared<abstract::Shape>(x_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr MaxPoolGradWithArgmaxInferType(const PrimitivePtr &prim, const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
auto name = prim->name();
|
||||||
|
const std::set<TypePtr> valid_grad_types = {kFloat32, kFloat16};
|
||||||
|
auto grad_type = input_args[kDim1]->BuildType();
|
||||||
|
auto inferred_type = CheckAndConvertUtils::CheckTensorTypeValid("x", grad_type, valid_grad_types, name);
|
||||||
|
return inferred_type;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
MIND_API_OPERATOR_IMPL(MaxPoolGradWithArgmax, BaseOperator);
|
||||||
|
|
||||||
|
AbstractBasePtr MaxPoolGradWithArgmaxInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
|
||||||
|
const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
MS_EXCEPTION_IF_NULL(primitive);
|
||||||
|
const int64_t input_num = 3;
|
||||||
|
CheckAndConvertUtils::CheckInputArgs(input_args, kEqual, input_num, primitive->name());
|
||||||
|
auto maxpool_with_argmax_infer_type = MaxPoolGradWithArgmaxInferType(primitive, input_args);
|
||||||
|
auto maxpool_with_argmax_infer_shape = MaxPoolGradWithArgmaxInferShape(primitive, input_args);
|
||||||
|
return std::make_shared<abstract::AbstractTensor>(maxpool_with_argmax_infer_type, maxpool_with_argmax_infer_shape);
|
||||||
|
}
|
||||||
|
|
||||||
|
REGISTER_PRIMITIVE_EVAL_IMPL(MaxPoolGradWithArgmax, prim::kPrimMaxPoolGradWithArgmax, MaxPoolGradWithArgmaxInfer,
|
||||||
|
nullptr, true);
|
||||||
|
} // namespace ops
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,63 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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_GRAD_MAX_POOL_GRAD_WITH_ARGMAX_H_
|
||||||
|
#define MINDSPORE_CORE_OPS_GRAD_MAX_POOL_GRAD_WITH_ARGMAX_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "ops/base_operator.h"
|
||||||
|
#include "mindapi/base/types.h"
|
||||||
|
#include "mindapi/base/format.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace ops {
|
||||||
|
constexpr auto kNameMaxPoolGradWithArgmax = "MaxPoolGradWithArgmax";
|
||||||
|
/// \brief Max pooling operation.
|
||||||
|
class MIND_API MaxPoolGradWithArgmax : public BaseOperator {
|
||||||
|
public:
|
||||||
|
MIND_API_BASE_MEMBER(MaxPoolGradWithArgmax);
|
||||||
|
/// \brief Constructor.
|
||||||
|
MaxPoolGradWithArgmax() : BaseOperator(kNameMaxPoolGradWithArgmax) {
|
||||||
|
InitIOName({"input", "grad", "argmax"}, {"output"});
|
||||||
|
}
|
||||||
|
/// \brief Init. Refer to the parameters of Python API @ref mindspore.ops.MaxPoolWithArgmax for the inputs.
|
||||||
|
void Init(const std::vector<int64_t> &kernel_size = {1}, const std::vector<int64_t> &stride = {1},
|
||||||
|
const PadMode &pad_mode = VALID, const Format &format = NCHW);
|
||||||
|
/// \brief Set pad_mode.
|
||||||
|
void set_pad_mode(const PadMode &pad_mode);
|
||||||
|
/// \brief Set kernel_size.
|
||||||
|
void set_kernel_size(const std::vector<int64_t> &kernel_size);
|
||||||
|
/// \brief Set strides.
|
||||||
|
void set_strides(const std::vector<int64_t> &strides);
|
||||||
|
|
||||||
|
/// \return kernel_size.
|
||||||
|
std::vector<int64_t> get_kernel_size() const;
|
||||||
|
|
||||||
|
/// \return pad_mode
|
||||||
|
PadMode get_pad_mode() const;
|
||||||
|
|
||||||
|
/// \return strides.
|
||||||
|
std::vector<int64_t> get_strides() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract::AbstractBasePtr MaxPoolGradWithArgmaxInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
|
||||||
|
const std::vector<abstract::AbstractBasePtr> &input_args);
|
||||||
|
} // namespace ops
|
||||||
|
} // namespace mindspore
|
||||||
|
|
||||||
|
#endif // MINDSPORE_CORE_OPS_MAX_POOL_GRAD_WITH_ARGMAX_H_
|
|
@ -0,0 +1,188 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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 "ops/max_pool_with_argmax.h"
|
||||||
|
#include <string>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <memory>
|
||||||
|
#include <set>
|
||||||
|
#include <vector>
|
||||||
|
#include "ops/op_utils.h"
|
||||||
|
#include "utils/check_convert_utils.h"
|
||||||
|
#include "abstract/ops/primitive_infer_map.h"
|
||||||
|
#include "mindapi/src/helper.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace ops {
|
||||||
|
constexpr auto kPadmodeSame = "1";
|
||||||
|
constexpr auto kPadModeValid = "2";
|
||||||
|
constexpr auto kSAME = "SAME";
|
||||||
|
constexpr auto kVALID = "VALID";
|
||||||
|
void MaxPoolWithArgmax::set_pad_mode(const PadMode &pad_mode) {
|
||||||
|
int64_t swi = pad_mode;
|
||||||
|
(void)this->AddAttr(kPadMode, api::MakeValue(swi));
|
||||||
|
}
|
||||||
|
|
||||||
|
PadMode MaxPoolWithArgmax::get_pad_mode() const {
|
||||||
|
auto value_ptr = GetAttr(kPadMode);
|
||||||
|
MS_EXCEPTION_IF_NULL(value_ptr);
|
||||||
|
auto mode_str = GetValue<std::string>(value_ptr);
|
||||||
|
std::transform(mode_str.begin(), mode_str.end(), mode_str.begin(), ::toupper);
|
||||||
|
MS_EXCEPTION_IF_CHECK_FAIL((mode_str == kSAME || mode_str == kVALID),
|
||||||
|
"MaxPoolWithArgmax only supports pad mode 'SAME' or 'VALID', but get " + mode_str);
|
||||||
|
return mode_str == kSAME ? PadMode::SAME : PadMode::VALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolWithArgmax::set_kernel_size(const std::vector<int64_t> &kernel_size) {
|
||||||
|
(void)this->AddAttr(
|
||||||
|
kKernelSize, api::MakeValue(CheckAndConvertUtils::CheckPositiveVector(kKernelSize, kernel_size, this->name())));
|
||||||
|
}
|
||||||
|
std::vector<int64_t> MaxPoolWithArgmax::get_kernel_size() const {
|
||||||
|
return GetValue<std::vector<int64_t>>(GetAttr(kKernelSize));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolWithArgmax::set_strides(const std::vector<int64_t> &strides) {
|
||||||
|
(void)this->AddAttr(kStrides,
|
||||||
|
api::MakeValue(CheckAndConvertUtils::CheckPositiveVector(kStrides, strides, this->name())));
|
||||||
|
}
|
||||||
|
std::vector<int64_t> MaxPoolWithArgmax::get_strides() const {
|
||||||
|
return GetValue<std::vector<int64_t>>(GetAttr(kStrides));
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolWithArgmax::set_format(const Format &format) {
|
||||||
|
int64_t f = format;
|
||||||
|
(void)this->AddAttr(kFormat, api::MakeValue(f));
|
||||||
|
}
|
||||||
|
Format MaxPoolWithArgmax::get_format() const {
|
||||||
|
auto value_ptr = GetAttr(kFormat);
|
||||||
|
MS_EXCEPTION_IF_NULL(value_ptr);
|
||||||
|
auto format_str = GetValue<std::string>(value_ptr);
|
||||||
|
std::transform(format_str.begin(), format_str.end(), format_str.begin(), ::toupper);
|
||||||
|
MS_EXCEPTION_IF_CHECK_FAIL((format_str == kFormatNHWC || format_str == kFormatNCHW),
|
||||||
|
"MaxPoolWithArgmax only supports data format 'NHWC' or 'NCHW', but get " + format_str);
|
||||||
|
return format_str == kFormatNHWC ? Format::NHWC : Format::NCHW;
|
||||||
|
}
|
||||||
|
|
||||||
|
void MaxPoolWithArgmax::Init(const std::vector<int64_t> &kernel_size, const std::vector<int64_t> &stride,
|
||||||
|
const PadMode &pad_mode, const Format &format) {
|
||||||
|
this->set_pad_mode(pad_mode);
|
||||||
|
this->set_kernel_size(kernel_size);
|
||||||
|
this->set_strides(stride);
|
||||||
|
this->set_format(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
abstract::TupleShapePtr MaxPoolWithArgmaxInferShape(const PrimitivePtr &primitive,
|
||||||
|
const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
auto op_name = primitive->name();
|
||||||
|
auto in_shape = CheckAndConvertUtils::ConvertShapePtrToShapeMap(input_args[kDim0]->BuildShape())[kShape];
|
||||||
|
Format format = Format(CheckAndConvertUtils::GetAndCheckFormat(primitive->GetAttr(kFormat)));
|
||||||
|
const int64_t x_rank = 4;
|
||||||
|
(void)CheckAndConvertUtils::CheckInteger("x_rank", SizeToLong(in_shape.size()), kEqual, x_rank, op_name);
|
||||||
|
auto kernel_size = GetValue<std::vector<int64_t>>(primitive->GetAttr(kKernelSize));
|
||||||
|
auto mode_str = primitive->GetAttr(kPadMode)->ToString();
|
||||||
|
std::transform(mode_str.begin(), mode_str.end(), mode_str.begin(), ::toupper);
|
||||||
|
PadMode pad_mode = PadMode::PAD;
|
||||||
|
if (mode_str == kPadmodeSame || mode_str == kSAME) {
|
||||||
|
pad_mode = PadMode::SAME;
|
||||||
|
} else if (mode_str == kPadModeValid || mode_str == kVALID) {
|
||||||
|
pad_mode = PadMode::VALID;
|
||||||
|
}
|
||||||
|
MS_EXCEPTION_IF_CHECK_FAIL((pad_mode == PadMode::SAME || pad_mode == PadMode::VALID),
|
||||||
|
"MaxPoolWithArgmax only supports pad mode 'SANE' or 'VALID', but get " + mode_str);
|
||||||
|
auto strides = GetValue<std::vector<int64_t>>(primitive->GetAttr(kStrides));
|
||||||
|
const int64_t attr_size = 4;
|
||||||
|
(void)CheckAndConvertUtils::CheckInteger("kernel size", SizeToLong(kernel_size.size()), kEqual, attr_size, op_name);
|
||||||
|
(void)CheckAndConvertUtils::CheckInteger("strides size", SizeToLong(strides.size()), kEqual, attr_size, op_name);
|
||||||
|
|
||||||
|
int64_t batch = 0, in_h = 0, in_w = 0, channel = 0;
|
||||||
|
int64_t kernel_h = 0, kernel_w = 0;
|
||||||
|
int64_t stride_h = 0, stride_w = 0;
|
||||||
|
kernel_h = kernel_size[kDim1];
|
||||||
|
kernel_w = kernel_size[kDim2];
|
||||||
|
stride_h = strides[kDim1];
|
||||||
|
stride_w = strides[kDim2];
|
||||||
|
if (format == Format::NCHW) {
|
||||||
|
batch = in_shape[kDim0];
|
||||||
|
channel = in_shape[kDim1];
|
||||||
|
in_h = in_shape[kDim2];
|
||||||
|
in_w = in_shape[kDim3];
|
||||||
|
} else if (format == Format::NHWC) {
|
||||||
|
batch = in_shape[kDim0];
|
||||||
|
in_h = in_shape[kDim1];
|
||||||
|
in_w = in_shape[kDim2];
|
||||||
|
channel = in_shape[kDim3];
|
||||||
|
}
|
||||||
|
int64_t out_h = abstract::Shape::SHP_ANY;
|
||||||
|
int64_t out_w = abstract::Shape::SHP_ANY;
|
||||||
|
if (pad_mode == PadMode::VALID) {
|
||||||
|
out_h = static_cast<int64_t>(std::ceil((in_h - (kernel_h - 1)) / static_cast<float>(stride_h)));
|
||||||
|
out_w = static_cast<int64_t>(std::ceil((in_w - (kernel_w - 1)) / static_cast<float>(stride_w)));
|
||||||
|
} else if (pad_mode == PadMode::SAME) {
|
||||||
|
out_h = static_cast<int64_t>(std::ceil(in_h / static_cast<float>(stride_h)));
|
||||||
|
out_w = static_cast<int64_t>(std::ceil(in_w / static_cast<float>(stride_w)));
|
||||||
|
}
|
||||||
|
std::vector<int64_t> out_shape = {batch, channel, out_h, out_w};
|
||||||
|
|
||||||
|
// Process attr mapping problems from mindspore to tbe
|
||||||
|
// kernel_size -> ksize
|
||||||
|
// pad_mode -> padding
|
||||||
|
std::vector<int64_t> ksize = {kernel_size[kDim0], kernel_size[kDim1], kernel_size[kDim2], kernel_size[kDim3]};
|
||||||
|
if (format == NHWC) {
|
||||||
|
(void)primitive->AddAttr("ksize", MakeValue(ksize));
|
||||||
|
(void)primitive->AddAttr("data_format", MakeValue(kFormatNHWC));
|
||||||
|
} else if (format == NCHW) {
|
||||||
|
(void)primitive->AddAttr("ksize", MakeValue(ksize));
|
||||||
|
(void)primitive->AddAttr("data_format", MakeValue(kFormatNCHW));
|
||||||
|
}
|
||||||
|
if (pad_mode == PadMode::VALID) {
|
||||||
|
(void)primitive->AddAttr(kPadding, MakeValue(kVALID));
|
||||||
|
} else if (pad_mode == PadMode::SAME) {
|
||||||
|
(void)primitive->AddAttr(kPadding, MakeValue(kSAME));
|
||||||
|
}
|
||||||
|
ShapeVector shape = out_shape;
|
||||||
|
ShapeVector argmax_shape = shape;
|
||||||
|
std::vector<abstract::BaseShapePtr> shape_list = {std::make_shared<abstract::Shape>(shape),
|
||||||
|
std::make_shared<abstract::Shape>(argmax_shape)};
|
||||||
|
return std::make_shared<abstract::TupleShape>(shape_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
TypePtr MaxPoolWithArgmaxInferType(const PrimitivePtr &primitive, const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
if (std::any_of(input_args.begin(), input_args.end(), [](const AbstractBasePtr &a) { return a == nullptr; })) {
|
||||||
|
MS_EXCEPTION(TypeError) << "For '" << primitive->name()
|
||||||
|
<< "', the input args used for infer shape and type is necessary, but missing it.";
|
||||||
|
}
|
||||||
|
const std::set<TypePtr> valid_types = {kFloat32, kFloat16};
|
||||||
|
auto input_type = input_args[kDim0]->BuildType();
|
||||||
|
(void)CheckAndConvertUtils::CheckTensorTypeValid("input", input_type, valid_types, primitive->name());
|
||||||
|
std::vector<TypePtr> type_list = {input_type, kInt32};
|
||||||
|
return std::make_shared<Tuple>(type_list);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
MIND_API_OPERATOR_IMPL(MaxPoolWithArgmax, BaseOperator);
|
||||||
|
AbstractBasePtr MaxPoolWithArgmaxInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
|
||||||
|
const std::vector<AbstractBasePtr> &input_args) {
|
||||||
|
MS_EXCEPTION_IF_NULL(primitive);
|
||||||
|
const int64_t input_num = 1;
|
||||||
|
(void)CheckAndConvertUtils::CheckInputArgs(input_args, kEqual, input_num, primitive->name());
|
||||||
|
auto infer_type = MaxPoolWithArgmaxInferType(primitive, input_args);
|
||||||
|
auto infer_shape = MaxPoolWithArgmaxInferShape(primitive, input_args);
|
||||||
|
return abstract::MakeAbstract(infer_shape, infer_type);
|
||||||
|
}
|
||||||
|
REGISTER_PRIMITIVE_EVAL_IMPL(MaxPoolWithArgmax, prim::kPrimMaxPoolWithArgmax, MaxPoolWithArgmaxInfer, nullptr, true);
|
||||||
|
} // namespace ops
|
||||||
|
} // namespace mindspore
|
|
@ -0,0 +1,66 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2022 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_MAX_POOL_WITH_ARGMAX_H_
|
||||||
|
#define MINDSPORE_CORE_OPS_MAX_POOL_WITH_ARGMAX_H_
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
#include "ops/base_operator.h"
|
||||||
|
#include "mindapi/base/types.h"
|
||||||
|
#include "mindapi/base/format.h"
|
||||||
|
|
||||||
|
namespace mindspore {
|
||||||
|
namespace ops {
|
||||||
|
constexpr auto kNameMaxPoolWithArgmax = "MaxPoolWithArgmax";
|
||||||
|
/// \brief Max pooling operation. Refer to Python API @ref mindspore.ops.MaxPoolWithArgmax for more details
|
||||||
|
class MIND_API MaxPoolWithArgmax : public BaseOperator {
|
||||||
|
public:
|
||||||
|
MIND_API_BASE_MEMBER(MaxPoolWithArgmax);
|
||||||
|
/// \brief Constructor.
|
||||||
|
MaxPoolWithArgmax() : BaseOperator(kNameMaxPoolWithArgmax) { InitIOName({"x"}, {"output", "mask"}); }
|
||||||
|
/// \brief Init. Refer to the parameters of Python API @ref mindspore.ops.MaxPoolWithArgmax for the inputs.
|
||||||
|
void Init(const std::vector<int64_t> &kernel_size = {1}, const std::vector<int64_t> &stride = {1},
|
||||||
|
const PadMode &pad_mode = VALID, const Format &format = NCHW);
|
||||||
|
/// \brief Set pad_mode.
|
||||||
|
void set_pad_mode(const PadMode &pad_mode);
|
||||||
|
/// \brief Set kernel_size.
|
||||||
|
void set_kernel_size(const std::vector<int64_t> &kernel_size);
|
||||||
|
/// \brief Set strides.
|
||||||
|
void set_strides(const std::vector<int64_t> &strides);
|
||||||
|
/// \brief Set format.
|
||||||
|
void set_format(const Format &format);
|
||||||
|
|
||||||
|
/// \return kernel_size.
|
||||||
|
std::vector<int64_t> get_kernel_size() const;
|
||||||
|
|
||||||
|
/// \return pad_mode
|
||||||
|
PadMode get_pad_mode() const;
|
||||||
|
|
||||||
|
/// \return strides.
|
||||||
|
std::vector<int64_t> get_strides() const;
|
||||||
|
|
||||||
|
/// \return format.
|
||||||
|
Format get_format() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract::AbstractBasePtr MaxPoolWithArgmaxInfer(const abstract::AnalysisEnginePtr &, const PrimitivePtr &primitive,
|
||||||
|
const std::vector<abstract::AbstractBasePtr> &input_args);
|
||||||
|
} // namespace ops
|
||||||
|
} // namespace mindspore
|
||||||
|
|
||||||
|
#endif // MINDSPORE_CORE_OPS_MAX_POOL_WITH_ARGMAX_H_
|
|
@ -1539,9 +1539,9 @@ class DepthwiseConv2dNative(PrimitiveWithInfer):
|
||||||
pad_top, pad_bottom, pad_left, pad_right = self.padding
|
pad_top, pad_bottom, pad_left, pad_right = self.padding
|
||||||
|
|
||||||
h_out = 1 + (x_shape[2] + pad_top + pad_bottom - kernel_size_h - (kernel_size_h - 1) * (dilation_h - 1)) \
|
h_out = 1 + (x_shape[2] + pad_top + pad_bottom - kernel_size_h - (kernel_size_h - 1) * (dilation_h - 1)) \
|
||||||
/ stride_h
|
/ stride_h
|
||||||
w_out = 1 + (x_shape[3] + pad_left + pad_right - kernel_size_w - (kernel_size_w - 1) * (dilation_w - 1)) \
|
w_out = 1 + (x_shape[3] + pad_left + pad_right - kernel_size_w - (kernel_size_w - 1) * (dilation_w - 1)) \
|
||||||
/ stride_w
|
/ stride_w
|
||||||
h_out = math.floor(h_out)
|
h_out = math.floor(h_out)
|
||||||
w_out = math.floor(w_out)
|
w_out = math.floor(w_out)
|
||||||
|
|
||||||
|
@ -1838,6 +1838,7 @@ class MaxPoolWithArgmax(_Pool):
|
||||||
|
|
||||||
- valid: Adopts the way of discarding. The possible largest height and width of output
|
- valid: Adopts the way of discarding. The possible largest height and width of output
|
||||||
will be returned without padding. Extra pixels will be discarded.
|
will be returned without padding. Extra pixels will be discarded.
|
||||||
|
|
||||||
data_format (str) : The optional value for data format, is 'NHWC' or 'NCHW'.
|
data_format (str) : The optional value for data format, is 'NHWC' or 'NCHW'.
|
||||||
Default: 'NCHW'.
|
Default: 'NCHW'.
|
||||||
|
|
||||||
|
@ -1858,7 +1859,7 @@ class MaxPoolWithArgmax(_Pool):
|
||||||
TypeError: If `x` is not a Tensor.
|
TypeError: If `x` is not a Tensor.
|
||||||
|
|
||||||
Supported Platforms:
|
Supported Platforms:
|
||||||
``Ascend`` ``GPU``
|
``Ascend`` ``GPU`` ``CPU``
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
>>> x = Tensor(np.arange(1 * 3 * 3 * 4).reshape((1, 3, 3, 4)), mindspore.float32)
|
>>> x = Tensor(np.arange(1 * 3 * 3 * 4).reshape((1, 3, 3, 4)), mindspore.float32)
|
||||||
|
|
|
@ -0,0 +1,157 @@
|
||||||
|
# Copyright 2022 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.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
import mindspore as ms
|
||||||
|
from mindspore import Tensor
|
||||||
|
import mindspore.context as context
|
||||||
|
import mindspore.nn as nn
|
||||||
|
from mindspore.ops.operations import _grad_ops as G
|
||||||
|
|
||||||
|
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
|
||||||
|
|
||||||
|
|
||||||
|
class MaxPoolGradWithArgmax(nn.Cell):
|
||||||
|
def __init__(self, kernel_size, strides, pad_mode):
|
||||||
|
super(MaxPoolGradWithArgmax, self).__init__()
|
||||||
|
self.grad = G.MaxPoolGradWithArgmax(kernel_size=kernel_size, strides=strides, pad_mode=pad_mode)
|
||||||
|
|
||||||
|
def construct(self, x, grad, argmax):
|
||||||
|
return self.grad(x, grad, argmax)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_grad_with_argmax():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolGradWithArgmax cpu version.
|
||||||
|
Description: comparing to gpu version
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[
|
||||||
|
[0, 1, 2, 3, 4, 5],
|
||||||
|
[6, 7, 8, 9, 10, 11],
|
||||||
|
[12, 13, 14, 15, 16, 17],
|
||||||
|
[18, 19, 20, 21, 22, 23],
|
||||||
|
[24, 25, 26, 27, 28, 29],
|
||||||
|
[30, 31, 32, 33, 34, 35]
|
||||||
|
]]]).astype(np.float32))
|
||||||
|
dy = Tensor(np.array([[[
|
||||||
|
[0.7, 0.9, 0.11],
|
||||||
|
[0.19, 0.21, 0.23],
|
||||||
|
[0.31, 0.33, 0.35]
|
||||||
|
]]]).astype(np.float32))
|
||||||
|
index = Tensor(np.array([[[
|
||||||
|
[7, 9, 11],
|
||||||
|
[19, 21, 23],
|
||||||
|
[31, 33, 35]
|
||||||
|
]]]).astype(np.int32))
|
||||||
|
expect_result = (np.array([[[
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.7, 0., 0.9, 0., 0.11],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.19, 0., 0.21, 0., 0.23],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.31, 0., 0.33, 0., 0.35]]]]).astype(np.float32))
|
||||||
|
grad_max_pool = MaxPoolGradWithArgmax(kernel_size=2, strides=2, pad_mode="VALID")
|
||||||
|
actual_output = grad_max_pool(x, dy, index)
|
||||||
|
assert (actual_output.asnumpy() == expect_result).all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_grad_with_argmax_fp16():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolGradWithArgmax cpu version.
|
||||||
|
Description: comparing to gpu version float16
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[
|
||||||
|
[0, 1, 2, 3, 4, 5],
|
||||||
|
[6, 7, 8, 9, 10, 11],
|
||||||
|
[12, 13, 14, 15, 16, 17],
|
||||||
|
[18, 19, 20, 21, 22, 23],
|
||||||
|
[24, 25, 26, 27, 28, 29],
|
||||||
|
[30, 31, 32, 33, 34, 35]
|
||||||
|
]]]).astype(np.float16))
|
||||||
|
dy = Tensor(np.array([[[
|
||||||
|
[0.7, 0.9, 0.11],
|
||||||
|
[0.19, 0.21, 0.23],
|
||||||
|
[0.31, 0.33, 0.35]
|
||||||
|
]]]).astype(np.float16))
|
||||||
|
index = Tensor(np.array([[[
|
||||||
|
[7, 9, 11],
|
||||||
|
[19, 21, 23],
|
||||||
|
[31, 33, 35]
|
||||||
|
]]]).astype(np.int32))
|
||||||
|
expect_result = np.array([[[
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.7, 0., 0.9, 0., 0.11],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.19, 0., 0.21, 0., 0.23],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.31, 0., 0.33, 0., 0.35]
|
||||||
|
]]]).astype(np.float16)
|
||||||
|
grad_max_pool = MaxPoolGradWithArgmax(kernel_size=2, strides=2, pad_mode="VALID")
|
||||||
|
actual_output = grad_max_pool(x, dy, index)
|
||||||
|
assert (actual_output.asnumpy() == expect_result).all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_grad_with_argmax_x_dynamic_shape():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolGradWithArgmax cpu version.
|
||||||
|
Description: comparing to gpu version float16
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[
|
||||||
|
[0, 1, 2, 3, 4, 5],
|
||||||
|
[6, 7, 8, 9, 10, 11],
|
||||||
|
[12, 13, 14, 15, 16, 17],
|
||||||
|
[18, 19, 20, 21, 22, 23],
|
||||||
|
[24, 25, 26, 27, 28, 29],
|
||||||
|
[30, 31, 32, 33, 34, 35]
|
||||||
|
]]]), dtype=ms.float16)
|
||||||
|
dy = Tensor(np.array([[[
|
||||||
|
[0.7, 0.9, 0.11],
|
||||||
|
[0.19, 0.21, 0.23],
|
||||||
|
[0.31, 0.33, 0.35]
|
||||||
|
]]]), dtype=ms.float16)
|
||||||
|
index = Tensor(np.array([[[
|
||||||
|
[7, 9, 11],
|
||||||
|
[19, 21, 23],
|
||||||
|
[31, 33, 35]
|
||||||
|
]]]), dtype=ms.int32)
|
||||||
|
expect_result = np.array([[[
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.7, 0., 0.9, 0., 0.11],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.19, 0., 0.21, 0., 0.23],
|
||||||
|
[0., 0., 0., 0., 0., 0.],
|
||||||
|
[0., 0.31, 0., 0.33, 0., 0.35]
|
||||||
|
]]]).astype(np.float16)
|
||||||
|
grad_max_pool = MaxPoolGradWithArgmax(kernel_size=2, strides=2, pad_mode="VALID")
|
||||||
|
x_dyn = Tensor(shape=[x.shape[0], None, x.shape[2], x.shape[3]], dtype=ms.float16)
|
||||||
|
dy_dyn = Tensor(shape=[dy.shape[0], None, None, dy.shape[3]], dtype=ms.float16)
|
||||||
|
index_dyn = Tensor(shape=[index.shape[0], index.shape[1], index.shape[2], None], dtype=ms.int32)
|
||||||
|
grad_max_pool.set_inputs(x_dyn, dy_dyn, index_dyn)
|
||||||
|
actual_output = grad_max_pool(x, dy, index)
|
||||||
|
assert (actual_output.asnumpy() == expect_result).all()
|
|
@ -0,0 +1,179 @@
|
||||||
|
# Copyright 2022 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.
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import pytest
|
||||||
|
import mindspore as ms
|
||||||
|
from mindspore import Tensor
|
||||||
|
import mindspore.context as context
|
||||||
|
import mindspore.nn as nn
|
||||||
|
import mindspore.ops.operations as P
|
||||||
|
|
||||||
|
|
||||||
|
context.set_context(mode=context.GRAPH_MODE, device_target="CPU")
|
||||||
|
|
||||||
|
|
||||||
|
class MaxPoolWithArgmaxOp(nn.Cell):
|
||||||
|
def __init__(self, kernel_size=1, strides=1, pad_mode="valid", data_format="NCHW"):
|
||||||
|
super(MaxPoolWithArgmaxOp, self).__init__()
|
||||||
|
self.max_pool_op = P.MaxPoolWithArgmax(
|
||||||
|
kernel_size=kernel_size, strides=strides, pad_mode=pad_mode, data_format=data_format)
|
||||||
|
|
||||||
|
def construct(self, x):
|
||||||
|
return self.max_pool_op(x)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_with_argmax_valid():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolWithArgmax cpu op.
|
||||||
|
Description: document test with 'VALID' padding
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[[10, 1, 2, 3, -4, -5],
|
||||||
|
[6, 7, 8, 9, -10, -11],
|
||||||
|
[12, 13, 24, -15, -16, -17],
|
||||||
|
[18, 19, 20, 21, 22, 23],
|
||||||
|
[32, 25, 26, 27, 28, 40],
|
||||||
|
[30, 31, 35, 33, 34, 35]]]]).astype(np.float32))
|
||||||
|
maxpool_with_argmax = MaxPoolWithArgmaxOp(kernel_size=2, strides=2, pad_mode="valid", data_format="NCHW")
|
||||||
|
actual_output, argmax = maxpool_with_argmax(x)
|
||||||
|
expect_output = np.array([[[[10, 9, -4],
|
||||||
|
[19, 24, 23],
|
||||||
|
[32, 35, 40]]]]).astype(np.float32)
|
||||||
|
expect_argmax = np.array([[[[0, 9, 4],
|
||||||
|
[19, 14, 23],
|
||||||
|
[24, 32, 29]]]]).astype(np.int32)
|
||||||
|
assert (actual_output.asnumpy() == expect_output).all()
|
||||||
|
assert (argmax.asnumpy() == expect_argmax).all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_with_argmax_same():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolWithArgmax cpu.
|
||||||
|
Description: document test with 'SAME' padding
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[[0, 1, 2, 3, -4, -5],
|
||||||
|
[6, 7, 8, 9, -10, -11],
|
||||||
|
[12, 13, 14, -15, -16, -17],
|
||||||
|
[18, 19, 20, 21, 22, 23],
|
||||||
|
[24, 25, 26, 27, 28, 29],
|
||||||
|
[30, 31, 32, 33, 34, 35]]]]).astype(np.float32))
|
||||||
|
maxpool_with_argmax = MaxPoolWithArgmaxOp(kernel_size=3, strides=2, pad_mode="same", data_format="NCHW")
|
||||||
|
actual_output, argmax = maxpool_with_argmax(x)
|
||||||
|
expect_output = np.array([[[[14, 14, -4],
|
||||||
|
[26, 28, 29],
|
||||||
|
[32, 34, 35]]]])
|
||||||
|
expect_argmax = np.array([[[[14, 14, 4],
|
||||||
|
[26, 28, 29],
|
||||||
|
[32, 34, 35]]]])
|
||||||
|
assert (actual_output.asnumpy() == expect_output).all()
|
||||||
|
assert (argmax.asnumpy() == expect_argmax).all()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_with_argmax_pytorch():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolWithArgmax op.
|
||||||
|
Description: comparing to pytorch's maxpool2d with 'VALID' padding
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[[80., 70., -19.],
|
||||||
|
[14., 46., -67.],
|
||||||
|
[15., -41., -80.]],
|
||||||
|
[[-80., 62., 85.],
|
||||||
|
[-3., -68., 35.],
|
||||||
|
[84., 54., 32.]]],
|
||||||
|
[[[-65., 57., 10.],
|
||||||
|
[-1., 38., -43.],
|
||||||
|
[36., -64., 5.]],
|
||||||
|
[[32., 8., 70.],
|
||||||
|
[-20., -92., -31.],
|
||||||
|
[-73., -27., -87.]]]]).astype(np.float32))
|
||||||
|
maxpool_with_argmax = MaxPoolWithArgmaxOp(kernel_size=2, strides=1, pad_mode="valid", data_format="NCHW")
|
||||||
|
actual_output, argmax = maxpool_with_argmax(x)
|
||||||
|
expect_output = np.array([[[[80., 70.],
|
||||||
|
[46., 46.]],
|
||||||
|
[[62., 85.],
|
||||||
|
[84., 54.]]],
|
||||||
|
[[[57., 57.],
|
||||||
|
[38., 38.]],
|
||||||
|
[[32., 70.],
|
||||||
|
[-20., -27.]]]])
|
||||||
|
expect_argmax = np.array([[[[0, 1],
|
||||||
|
[4, 4]],
|
||||||
|
[[1, 2],
|
||||||
|
[6, 7]]],
|
||||||
|
[[[1, 1],
|
||||||
|
[4, 4]],
|
||||||
|
[[0, 2],
|
||||||
|
[3, 7]]]])
|
||||||
|
assert (actual_output.asnumpy() == expect_output).all()
|
||||||
|
assert (argmax.asnumpy() == expect_argmax).all()
|
||||||
|
assert np.allclose(actual_output.asnumpy(), expect_output)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.level0
|
||||||
|
@pytest.mark.platform_x86_cpu
|
||||||
|
@pytest.mark.env_onecard
|
||||||
|
def test_maxpool_with_argmax_dynamic_shape():
|
||||||
|
"""
|
||||||
|
Feature: test maxPoolWithArgmax op with dynamic shapes.
|
||||||
|
Description: input x has the dynamic shapes
|
||||||
|
Expectation: expect correct result.
|
||||||
|
"""
|
||||||
|
x = Tensor(np.array([[[[80., 70., -19.],
|
||||||
|
[14., 46., -67.],
|
||||||
|
[15., -41., -80.]],
|
||||||
|
[[-80., 62., 85.],
|
||||||
|
[-3., -68., 35.],
|
||||||
|
[84., 54., 32.]]],
|
||||||
|
[[[-65., 57., 10.],
|
||||||
|
[-1., 38., -43.],
|
||||||
|
[36., -64., 5.]],
|
||||||
|
[[32., 8., 70.],
|
||||||
|
[-20., -92., -31.],
|
||||||
|
[-73., -27., -87.]]]]), dtype=ms.float32)
|
||||||
|
x_dyn = Tensor(shape=[2, None, 3, 3], dtype=ms.float32)
|
||||||
|
maxpool_with_argmax = MaxPoolWithArgmaxOp(kernel_size=2, strides=1, pad_mode="valid", data_format="NCHW")
|
||||||
|
maxpool_with_argmax.set_inputs(x_dyn)
|
||||||
|
actual_output, argmax = maxpool_with_argmax(x)
|
||||||
|
expect_output = np.array([[[[80., 70.],
|
||||||
|
[46., 46.]],
|
||||||
|
[[62., 85.],
|
||||||
|
[84., 54.]]],
|
||||||
|
[[[57., 57.],
|
||||||
|
[38., 38.]],
|
||||||
|
[[32., 70.],
|
||||||
|
[-20., -27.]]]])
|
||||||
|
expect_argmax = np.array([[[[0, 1],
|
||||||
|
[4, 4]],
|
||||||
|
[[1, 2],
|
||||||
|
[6, 7]]],
|
||||||
|
[[[1, 1],
|
||||||
|
[4, 4]],
|
||||||
|
[[0, 2],
|
||||||
|
[3, 7]]]])
|
||||||
|
assert (actual_output.asnumpy() == expect_output).all()
|
||||||
|
assert (argmax.asnumpy() == expect_argmax).all()
|
Loading…
Reference in New Issue