mindspore2022/mindspore/ccsrc/parallel/tensor_layout/arrangement.cc

250 lines
7.8 KiB
C++

/**
* Copyright 2019 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 "parallel/tensor_layout/arrangement.h"
#include <algorithm>
#include <iostream>
#include <utility>
#include "common/utils.h"
#include "parallel/status.h"
#include "parallel/tensor_layout/shape_util.h"
#include "utils/convert_utils.h"
#include "utils/log_adapter.h"
namespace mindspore {
namespace parallel {
Status Arrangement::Init(const std::vector<int32_t>& array) {
Status status = Array::Init(array);
if (status != Status::SUCCESS) {
return Status::FAILED;
}
if (!IsValidArrangement()) {
MS_LOG(ERROR) << "invalid arrangement " << this->ToString();
return Status::FAILED;
}
ComputeSize();
return Status::SUCCESS;
}
bool Arrangement::IsValidArrangement() {
return !std::any_of(array_.begin(), array_.end(), [](int32_t value) { return value <= 0; });
}
void Arrangement::ComputeSize() {
size_ = 1;
for (auto& value : array_) {
size_ *= value;
}
}
/*
* if GetDimSize() = 0, return []
* if value <= array_[0], return [value]
* if array_[0] < value <= size_[i], return [shape[0], shape[1], ..., shape[i-1], value/size_[i-1]],
* where size_[i-1] = shape[0] * shape[1] * ... * shape[i-1],
* if value > size_, return []
*/
std::vector<int32_t> Arrangement::GetFrontElementByValue(int32_t value) const {
std::vector<int32_t> out;
if (GetDimSize() == 0) {
return out;
}
if (value <= size_) {
int32_t size = 1;
uint32_t shape_list_idx = 0;
while (size < value) {
size *= array_[shape_list_idx];
if (size <= value) {
out.push_back(array_[shape_list_idx]);
} else {
if (size == 0) {
MS_LOG(ERROR) << "The size is 0";
out.clear();
return out;
}
out.push_back(value * array_[shape_list_idx] / size);
}
shape_list_idx++;
}
}
return out;
}
std::shared_ptr<Arrangement> Arrangement::GetExpandedShapeByExpandListRemoveLeft(
const std::vector<Arrangement>& expand_list) const {
if (expand_list.size() != GetDimSize()) {
return nullptr;
}
std::vector<int32_t> new_shape;
for (uint32_t i = 0; i < expand_list.size(); i++) {
std::vector<int32_t> expand_shape = expand_list[i].GetFrontElementByValue(GetDimByIdx(i));
if (expand_shape.empty()) {
new_shape.push_back(GetDimByIdx(i));
} else {
(void)new_shape.insert(new_shape.end(), expand_shape.begin(), expand_shape.end());
}
}
Arrangement arrangement_new;
(void)arrangement_new.Init(new_shape);
return std::make_shared<Arrangement>(arrangement_new);
}
/*
* example:
* expand_shape = [4, 2, 2, 2]
* array_ = [8, 4],
* arrangement_list = [[4, 2], [2, 2]]
*/
std::shared_ptr<std::vector<Arrangement>> Arrangement::GetExpandShapeList(const Arrangement& expand_shape) const {
int32_t size = 1;
uint32_t ind = 0;
std::vector<Arrangement> arrangement_list;
std::vector<int32_t> shape;
for (uint32_t i = 0; i < expand_shape.GetDimSize(); i++) {
size *= expand_shape.GetDimByIdx(i);
if (size > GetDimByIdx(ind)) {
MS_LOG(ERROR) << "invalid expand_shape";
return nullptr;
} else if (size < GetDimByIdx(ind)) {
shape.push_back(expand_shape.GetDimByIdx(i));
continue;
} else {
shape.push_back(expand_shape.GetDimByIdx(i));
Arrangement arrangement;
(void)arrangement.Init(shape);
arrangement_list.push_back(arrangement);
shape.clear();
ind++;
size = 1;
}
}
if (ind != GetDimSize()) {
MS_LOG(ERROR) << "invalid expand_shape";
return nullptr;
}
auto arrangement_new = std::make_shared<std::vector<Arrangement>>(arrangement_list);
return arrangement_new;
}
std::shared_ptr<std::pair<std::vector<Arrangement>, Arrangement>> Arrangement::GetExpandShapeListPair(
const Arrangement& expand_shape) const {
std::shared_ptr<std::vector<Arrangement>> expand_shape_list_ptr = GetExpandShapeList(expand_shape);
if (expand_shape_list_ptr == nullptr) {
return nullptr;
}
std::vector<int32_t> expand_num_list_shape;
(void)std::transform(expand_shape_list_ptr->begin(), expand_shape_list_ptr->end(),
std::back_inserter(expand_num_list_shape),
[](const Arrangement& arr) { return SizeToInt(arr.GetDimSize()); });
Arrangement expand_num_list;
Status status = expand_num_list.Init(expand_num_list_shape);
if (status != Status::SUCCESS) {
return nullptr;
}
auto out_value = std::make_pair(*expand_shape_list_ptr, expand_num_list);
return std::make_shared<std::pair<std::vector<Arrangement>, Arrangement>>(out_value);
}
std::vector<int32_t> Arrangement::ComputeReverseAccumulateSumInReverseOrder() const {
std::vector<int32_t> shape_accum;
int32_t size = 0;
for (auto iter = array_.end() - 1; iter >= array_.begin(); --iter) {
shape_accum.push_back(size);
size += *iter;
}
return shape_accum;
}
std::shared_ptr<Arrangement> Arrangement::GetExpandedShapeByExpandListReserveLeft(
const std::vector<Arrangement>& expand_list) const {
if (expand_list.size() != GetDimSize()) {
return nullptr;
}
std::vector<int32_t> new_shape;
for (uint32_t i = 0; i < expand_list.size(); i++) {
if (expand_list[i].GetDimSize() >= 1) {
int32_t size = 1;
for (uint32_t k = 0; k < expand_list[i].GetDimSize() - 1; k++) {
new_shape.push_back(expand_list[i].GetDimByIdx(k));
size *= expand_list[i].GetDimByIdx(k);
}
new_shape.push_back(GetDimByIdx(i) / size);
} else {
new_shape.push_back(GetDimByIdx(i));
}
}
Arrangement arrangement_new;
(void)arrangement_new.Init(new_shape);
return std::make_shared<Arrangement>(arrangement_new);
}
std::shared_ptr<Arrangement> Arrangement::GetUnifiedShape(const Arrangement& in2) const {
std::vector<int64_t> in1_accum;
Status status = ShapeToAccumulateProduct(array_, &in1_accum);
if (status != Status::SUCCESS) {
return nullptr;
}
std::vector<int64_t> in2_accum;
status = ShapeToAccumulateProduct(in2.array(), &in2_accum);
if (status != Status::SUCCESS) {
return nullptr;
}
std::vector<int64_t> out_accum;
status = UnifyAccumulateProduct(in1_accum, in2_accum, &out_accum);
if (status != Status::SUCCESS) {
return nullptr;
}
std::vector<int32_t> out_shape;
status = AccumulateProductToShape(out_accum, &out_shape);
if (status != Status::SUCCESS) {
return nullptr;
}
Arrangement out;
status = out.Init(out_shape);
if (status != Status::SUCCESS) {
return nullptr;
}
return std::make_shared<Arrangement>(out);
}
std::vector<size_t> Arrangement::GetSqueezeIdx() const {
std::vector<size_t> out;
for (size_t i = 0; i < GetDimSize(); i++) {
if (GetDimByIdx(SizeToUint(i)) == 1) {
out.push_back(i);
}
}
return out;
}
Arrangement Arrangement::GetSqueezeArrangement() const {
std::vector<int32_t> out_shape(array_.size());
auto it = std::copy_if(array_.begin(), array_.end(), out_shape.begin(), [](int32_t value) { return value != 1; });
out_shape.resize(LongToSize(std::distance(out_shape.begin(), it)));
// if all elements are 1, out_shape = {1}
if (out_shape.empty()) {
MS_LOG(ERROR) << "out_shape size is 0, this may not happen under current situation";
out_shape.push_back(1);
}
Arrangement out;
(void)out.Init(out_shape);
return out;
}
} // namespace parallel
} // namespace mindspore