forked from huawei/mindspore2022
162 lines
6.0 KiB
C++
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
|