mindspore2022/mindspore/ccsrc/kernel/cpu/reduce_cpu_kernel.cc

162 lines
6.0 KiB
C++

/**
* Copyright 2020 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 <map>
#include <string>
#include <vector>
#include "kernel/cpu/reduce_cpu_kernel.h"
#include "device/cpu/cpu_device_address.h"
namespace mindspore {
namespace kernel {
const size_t kReduceTypeMax = 0;
const size_t kReduceTypeMean = 1;
const size_t kReduceTypeSum = 2;
const size_t kMaxDim = 100;
void ReduceCPUKernel::InitKernel(const CNodePtr &kernel_node) {
MS_EXCEPTION_IF_NULL(kernel_node);
std::string kernel_name = AnfAlgo::GetCNodeName(kernel_node);
if (kernel_name == "ReduceMax") {
reduce_type_ = kReduceTypeMax;
} else if (kernel_name == "ReduceMean") {
reduce_type_ = kReduceTypeMean;
} else if (kernel_name == "ReduceSum") {
reduce_type_ = kReduceTypeSum;
} else {
MS_LOG(EXCEPTION) << "Array reduce kernel type " << kernel_name << " is not supported.";
}
shape_ = AnfAlgo::GetInputDeviceShape(kernel_node, 0);
auto axis_addr = AnfAlgo::GetCNodePrimitive(kernel_node)->GetAttr(AXIS);
if (axis_addr->isa<ValueTuple>()) {
auto attr_axis = AnfAlgo::GetNodeAttr<std::vector<int>>(kernel_node, AXIS);
if (attr_axis.size() > shape_.size()) {
MS_LOG(EXCEPTION) << "invalid axis size: " << axis_.size();
} else if (attr_axis.empty()) {
axis_.push_back(shape_.size() - 1);
} else {
for (auto axis : attr_axis) {
if (IntToSize(axis) >= (shape_.size())) {
MS_LOG(EXCEPTION) << "axis value is oversize.";
}
axis < 0 ? axis_.push_back(axis + shape_.size()) : axis_.push_back(axis);
}
}
} else if (axis_addr->isa<Int32Imm>()) {
int axis = AnfAlgo::GetNodeAttr<int>(kernel_node, AXIS);
if (axis >= 0 && IntToSize(axis) >= shape_.size()) {
MS_LOG(EXCEPTION) << "axis value is oversize.";
}
axis < 0 ? axis_.push_back(axis + shape_.size()) : axis_.push_back(axis);
} else {
MS_LOG(EXCEPTION) << "Attribute axis type is invalid.";
}
for (size_t i = 0; i < shape_.size(); ++i) {
if (shape_[i] <= 0) {
MS_LOG(EXCEPTION) << "shape value is invalid.";
}
left_dims_ *= shape_[i];
}
for (size_t i = 0; i < axis_.size(); ++i) {
stride_ *= shape_[axis_[i]];
}
if (stride_ <= 0) {
MS_LOG(EXCEPTION) << "stride_ must greater than zero.";
}
left_dims_ = left_dims_ / stride_;
}
bool ReduceCPUKernel::Launch(const std::vector<kernel::AddressPtr> &inputs,
const std::vector<kernel::AddressPtr> & /*workspaces*/,
const std::vector<kernel::AddressPtr> &outputs) {
if (inputs.empty() || outputs.empty()) {
MS_LOG(EXCEPTION) << "input or output empty!";
}
size_t out_float_size = left_dims_ * sizeof(float);
size_t in_float_size = stride_ * out_float_size;
if (inputs[0]->size != in_float_size || outputs[0]->size != out_float_size) {
MS_LOG(EXCEPTION) << "invalid input or output data size!";
}
auto input = reinterpret_cast<float *>(inputs[0]->addr);
auto output = reinterpret_cast<float *>(outputs[0]->addr);
int size = inputs[0]->size / sizeof(float);
std::vector<float> new_input(IntToSize(size), 0.0);
std::vector<size_t> transpose_axis;
for (size_t i = 0; i < shape_.size(); ++i) {
bool insert = true;
for (size_t j = 0; j < axis_.size(); ++j) {
if (axis_[j] == i) {
insert = false;
break;
}
}
if (insert) {
transpose_axis.push_back(i);
}
}
(void)transpose_axis.insert(transpose_axis.end(), axis_.begin(), axis_.end());
Transpose(size, input, shape_, transpose_axis, SizeToInt(shape_.size()), &new_input[0]);
if (reduce_type_ == kReduceTypeMax) {
for (size_t i = 0; i < left_dims_; ++i) {
float value = new_input[i * stride_];
for (size_t k = 0; k < stride_; ++k) {
if (value < new_input[i * stride_ + k]) {
value = new_input[i * stride_ + k];
}
}
output[i] = value;
}
} else {
for (size_t i = 0; i < left_dims_; ++i) {
float value = 0.0;
for (size_t k = 0; k < stride_; ++k) {
value += new_input[i * stride_ + k];
}
if (reduce_type_ == kReduceTypeMean) {
output[i] = value / stride_;
} else {
output[i] = value;
}
}
}
return true;
}
void ReduceCPUKernel::Transpose(const int size, const float *input, const std::vector<size_t> &input_shape,
const std::vector<size_t> &input_axis, const int shape_size, float *output) {
int pos_array[kMaxDim];
int size_offset[kMaxDim];
size_offset[0] = size / SizeToInt(input_shape[0]);
for (int i = 1; i < shape_size; i++) {
size_offset[i] = size_offset[i - 1] / SizeToInt(input_shape[i]);
}
for (int position = 0; position < size; position += 1) {
int temp_position = position;
pos_array[0] = temp_position / size_offset[0];
for (int i = 1; i < shape_size; i++) {
temp_position -= pos_array[i - 1] * size_offset[i - 1];
pos_array[i] = temp_position / size_offset[i];
}
int new_position = pos_array[SizeToInt(input_axis[shape_size - 1])];
int new_position_size = 1;
for (int j = shape_size - 2; j >= 0; j--) {
new_position_size *= SizeToInt(input_shape[SizeToInt(input_axis[j + 1])]);
new_position += pos_array[SizeToInt(input_axis[j])] * new_position_size;
}
output[new_position] = input[position];
}
return;
}
} // namespace kernel
} // namespace mindspore