• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2019 Huawei Technologies Co., Ltd
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include "parallel/tensor_layout/util_layout_gen_test.h"
17 #include <cmath>
18 #include <map>
19 #include <tuple>
20 #include <vector>
21 #include <utility>
22 #include <algorithm>
23 #include <iterator>
24 #include "frontend/parallel/tensor_layout/shape_util.h"
25 #include "common/common_test.h"
26 
27 using std::pow;
28 
29 namespace mindspore {
30 namespace parallel {
combine(const Shape & in,int64_t target)31 std::vector<Shape> combine(const Shape &in, int64_t target) {
32   std::vector<Shape> output;
33   for (int64_t i = 0; i < pow(2, in.size()); i++) {
34     size_t temp = 0;
35     size_t count = 0;
36     Shape left;
37     for (size_t j = 0; j < in.size(); j++) {
38       if ((i & (1 << j)) != 0) {
39         left.push_back(j);
40         count++;
41       }
42     }
43     if (count == target) {
44       Shape one_case;
45       for (size_t j = 0; j < count; j++) {
46         temp = in.size() - 1 - left[j];
47         one_case.push_back(in[temp]);
48       }
49       if (one_case.size() > 0) {
50         output.push_back(one_case);
51       }
52     }
53   }
54   return output;
55 }
56 
GenerateValidShapeBySizeAndDim(int64_t pow_size,int64_t dim,std::vector<Shape> * out)57 void GenerateValidShapeBySizeAndDim(int64_t pow_size, int64_t dim, std::vector<Shape> *out) {
58   out->clear();
59   Shape in;
60   for (int64_t i = 1; i < pow_size; i++) {
61     in.push_back(i);
62   }
63   std::vector<Shape> combine_result;
64   combine_result = combine(in, dim - 1);
65   if (combine_result.size() == 0) {
66     int64_t size = exp2(pow_size);
67     Shape item = {size};
68     out->push_back(item);
69   }
70   for (size_t i = 0; i < combine_result.size(); i++) {
71     Shape item;
72     int64_t prev = 0;
73     for (int64_t j = combine_result[i].size() - 1; j >= 0; j--) {
74       item.push_back(exp2(combine_result[i][j] - prev));
75       prev = combine_result[i][j];
76     }
77     item.push_back(exp2(pow_size - prev));
78     out->push_back(item);
79   }
80   return;
81 }
82 
GenerateValidShapeBySize(int64_t pow_size,std::vector<Shape> * out)83 void GenerateValidShapeBySize(int64_t pow_size, std::vector<Shape> *out) {
84   out->clear();
85   for (int64_t dim = 1; dim <= pow_size; dim++) {
86     std::vector<Shape> combine_result;
87     GenerateValidShapeBySizeAndDim(pow_size, dim, &combine_result);
88     for (size_t i = 0; i < combine_result.size(); i++) {
89       out->push_back(combine_result[i]);
90     }
91   }
92   return;
93 }
94 
GenerateTensorMap(const int64_t & map_size,const Shape & pos_index,const Shape & pos_value)95 TensorMap GenerateTensorMap(const int64_t &map_size, const Shape &pos_index, const Shape &pos_value) {
96   TensorMap tensor_map(map_size, -1);
97   for (size_t i = 0; i < pos_index.size() && i < pos_value.size(); i++) {
98     if (pos_index[i] >= map_size) {
99       continue;
100     }
101     tensor_map[pos_index[i]] = pos_value[i];
102   }
103   return tensor_map;
104 }
105 
GenerateValidTensorMap(const DeviceArrangement & device_arrangement,const TensorShape & tensor_shape,std::vector<TensorMap> * tensor_map_list)106 void GenerateValidTensorMap(const DeviceArrangement &device_arrangement, const TensorShape &tensor_shape,
107                             std::vector<TensorMap> *tensor_map_list) {
108   tensor_map_list->clear();
109   int64_t device_size = device_arrangement.size();
110   int64_t shape_size = tensor_shape.size();
111   Shape pos_ind_combine_in;
112   for (int64_t i = 0; i < shape_size; i++) {
113     pos_ind_combine_in.push_back(i);
114   }
115   Shape dev_ind_combine_in;
116   for (int64_t i = 0; i < device_size; i++) {
117     dev_ind_combine_in.push_back(i);
118   }
119   TensorMap none_map(tensor_shape.size(), -1);
120   tensor_map_list->push_back(none_map);
121   for (int64_t pos_num = 1; (pos_num <= shape_size) && (pos_num <= device_size); pos_num++) {
122     std::vector<Shape> pos_index;
123     pos_index = combine(pos_ind_combine_in, pos_num);
124     std::vector<Shape> dev_index;
125     dev_index = combine(dev_ind_combine_in, pos_num);
126     for (size_t l = 0; l < dev_index.size(); l++) {
127       Shape pos_value_combine_in;
128       for (int32_t i = dev_index[l].size() - 1; i >= 0; i--) {
129         pos_value_combine_in.push_back(dev_index[l][i]);
130       }
131       std::vector<Shape> pos_value;
132       Shape::iterator it = pos_value_combine_in.begin();
133       do {
134         Shape pos_value_item;
135         for (size_t m = 0; m < pos_num; m++) {
136           pos_value_item.push_back(pos_value_combine_in[m]);
137         }
138         pos_value.push_back(pos_value_item);
139       } while (next_permutation(it, it + pos_num));
140       for (size_t j = 0; j < pos_index.size(); j++) {
141         for (size_t k = 0; k < pos_value.size(); k++) {
142           TensorMap tensor_map = GenerateTensorMap(shape_size, pos_index[j], pos_value[k]);
143           tensor_map_list->push_back(tensor_map);
144         }
145       }
146     }
147   }
148   return;
149 }
150 
GenerateValidLayoutByDeviceSizeAndTensorSize(int64_t device_pow_size,int64_t tensor_pow_size,int64_t max_device_dim,int64_t max_shape_dim,std::vector<std::tuple<DeviceArrangement,TensorMap,TensorShape>> * layout_list)151 void GenerateValidLayoutByDeviceSizeAndTensorSize(
152   int64_t device_pow_size, int64_t tensor_pow_size, int64_t max_device_dim, int64_t max_shape_dim,
153   std::vector<std::tuple<DeviceArrangement, TensorMap, TensorShape>> *layout_list) {
154   layout_list->clear();
155   std::vector<DeviceArrangement> device_arrangement_list;
156   GenerateValidShapeBySize(device_pow_size, &device_arrangement_list);
157   std::vector<TensorShape> tensor_shape_list;
158   GenerateValidShapeBySize(tensor_pow_size, &tensor_shape_list);
159   for (size_t device_idx = 0; device_idx < device_arrangement_list.size(); device_idx++) {
160     for (size_t shape_idx = 0; shape_idx < tensor_shape_list.size(); shape_idx++) {
161       std::vector<TensorMap> tensor_map_list;
162       GenerateValidTensorMap(device_arrangement_list[device_idx], tensor_shape_list[shape_idx], &tensor_map_list);
163       for (size_t map_idx = 0; map_idx < tensor_map_list.size(); map_idx++) {
164         if (!CheckLayoutValid(device_arrangement_list[device_idx], tensor_map_list[map_idx],
165                               tensor_shape_list[shape_idx])) {
166           continue;
167         }
168         layout_list->push_back(
169           std::make_tuple(device_arrangement_list[device_idx], tensor_map_list[map_idx], tensor_shape_list[shape_idx]));
170       }
171     }
172   }
173   return;
174 }
175 
CheckLayoutValid(const DeviceArrangement & device_arrangement,const TensorMap & tensor_map,const TensorShape & tensor_shape)176 bool CheckLayoutValid(const DeviceArrangement &device_arrangement, const TensorMap &tensor_map,
177                       const TensorShape &tensor_shape) {
178   bool flag = false;
179   if ((tensor_map.size() - ComputeNoneNumber(tensor_map)) > device_arrangement.size()) {
180     return flag;
181   }
182   if (!ShapeIsDividedByDevice(device_arrangement, tensor_map, tensor_shape)) {
183     return flag;
184   }
185   return true;
186 }
187 
ComputeNoneNumber(const TensorMap & tensor_map)188 size_t ComputeNoneNumber(const TensorMap &tensor_map) {
189   size_t num = 0;
190   for (size_t i = 0; i < tensor_map.size(); i++) {
191     if (tensor_map[i] == -1) {
192       num++;
193     }
194   }
195   return num;
196 }
197 
ShapeIsDividedByDevice(const DeviceArrangement & device_arrangement,const TensorMap & tensor_map,const TensorShape & tensor_shape)198 bool ShapeIsDividedByDevice(const DeviceArrangement &device_arrangement, const TensorMap &tensor_map,
199                             const TensorShape &tensor_shape) {
200   bool flag = false;
201   for (uint32_t i = 0; i < tensor_map.size() && i < tensor_shape.size(); i++) {
202     if (tensor_map[i] == -1) {
203       continue;
204     }
205     int64_t dim = device_arrangement[device_arrangement.size() - 1 - tensor_map[i]];
206     if (tensor_shape[i] % dim != 0) {
207       return flag;
208     }
209   }
210   return true;
211 }
212 
IsExpended(const Shape & in1,const Shape & in2)213 bool IsExpended(const Shape &in1, const Shape &in2) {
214   int64_t size = 1;
215   uint32_t ind = 0;
216   for (uint32_t i = 0; i < in1.size(); i++) {
217     size *= in1[i];
218     if (ind >= in2.size()) {
219       return false;
220     }
221     if (size > in2[ind]) {
222       return false;
223     } else if (size < in2[ind]) {
224       continue;
225     } else {
226       ind++;
227       size = 1;
228     }
229   }
230   if (ind != in2.size()) {
231     return false;
232   }
233   return true;
234 }
235 
ComputeAccumDeviceTOAccumShapeMap(const DeviceArrangement & device_arrangement,const TensorMap & tensor_map,const TensorShape & tensor_shape,std::map<int64_t,int64_t> * accum_device_to_accum_shape_map)236 void ComputeAccumDeviceTOAccumShapeMap(const DeviceArrangement &device_arrangement, const TensorMap &tensor_map,
237                                        const TensorShape &tensor_shape,
238                                        std::map<int64_t, int64_t> *accum_device_to_accum_shape_map) {
239   accum_device_to_accum_shape_map->clear();
240   std::vector<int64_t> shape_accum_reverse;
241   Status status = ShapeToAccumulateProductReverse(tensor_shape, &shape_accum_reverse);
242   ASSERT_EQ(Status::SUCCESS, status);
243   std::vector<int64_t> device_accum_reverse;
244   status = ShapeToAccumulateProductReverse(device_arrangement, &device_accum_reverse);
245   ASSERT_EQ(Status::SUCCESS, status);
246   for (int32_t i = 0; i < device_accum_reverse.size(); i++) {
247     auto iter = std::find(tensor_map.begin(), tensor_map.end(), device_accum_reverse.size() - 1 - i);
248     if (iter == tensor_map.end()) {
249       accum_device_to_accum_shape_map->insert(std::make_pair(device_accum_reverse[i], -1));
250     } else {
251       accum_device_to_accum_shape_map->insert(
252         std::make_pair(device_accum_reverse[i], shape_accum_reverse[std::distance(tensor_map.begin(), iter)]));
253     }
254   }
255   return;
256 }
257 
IsLinearValue(int64_t small,int64_t big,int64_t small_value,int64_t big_value,int64_t middle,int64_t middle_value)258 void IsLinearValue(int64_t small, int64_t big, int64_t small_value, int64_t big_value, int64_t middle,
259                    int64_t middle_value) {
260   ASSERT_NE(big, small);
261   int64_t value = (middle - small) * (big_value - small_value) / (big - small) + small_value;
262   ASSERT_EQ(middle_value, value);
263 }
264 
LayoutTransferValidLayoutChangeCheck(const DeviceArrangement & in_device_arrangement,const TensorMap & in_tensor_map,const TensorShape & in_tensor_shape,const DeviceArrangement & out_device_arrangement,const TensorMap & out_tensor_map,const TensorShape & out_tensor_shape)265 void LayoutTransferValidLayoutChangeCheck(const DeviceArrangement &in_device_arrangement,
266                                           const TensorMap &in_tensor_map, const TensorShape &in_tensor_shape,
267                                           const DeviceArrangement &out_device_arrangement,
268                                           const TensorMap &out_tensor_map, const TensorShape &out_tensor_shape) {
269   bool is_expended = IsExpended(out_device_arrangement, in_device_arrangement);
270   ASSERT_EQ(true, is_expended);
271   is_expended = IsExpended(out_tensor_shape, in_tensor_shape);
272   ASSERT_EQ(true, is_expended);
273   std::map<int64_t, int64_t> out_accum_device_to_accum_shape_map;
274   ComputeAccumDeviceTOAccumShapeMap(out_device_arrangement, out_tensor_map, out_tensor_shape,
275                                     &out_accum_device_to_accum_shape_map);
276   std::map<int64_t, int64_t> in_accum_device_to_accum_shape_map;
277   ComputeAccumDeviceTOAccumShapeMap(in_device_arrangement, in_tensor_map, in_tensor_shape,
278                                     &in_accum_device_to_accum_shape_map);
279   std::map<int64_t, int64_t>::iterator in_iter = in_accum_device_to_accum_shape_map.begin();
280   while (in_iter != in_accum_device_to_accum_shape_map.end()) {
281     if (in_iter->second != out_accum_device_to_accum_shape_map[in_iter->first]) {
282       continue;
283     }
284     in_iter++;
285   }
286   std::map<int64_t, int64_t>::iterator out_iter = out_accum_device_to_accum_shape_map.begin();
287   while (out_iter != out_accum_device_to_accum_shape_map.end()) {
288     if (out_accum_device_to_accum_shape_map.find(out_iter->first) == out_accum_device_to_accum_shape_map.end()) {
289       in_iter = in_accum_device_to_accum_shape_map.begin();
290       int64_t small = 1;
291       int64_t big = 1;
292       while (in_iter != in_accum_device_to_accum_shape_map.end()) {
293         if (in_iter->first < out_iter->first) {
294           small = in_iter->second;
295         } else if (in_iter->first > out_iter->first) {
296           big = in_iter->second;
297           break;
298         } else {
299           ASSERT_EQ(true, false);
300         }
301         in_iter++;
302       }
303       if (small == 1) {
304         ASSERT_EQ(true, false);
305       }
306       if (big == 1) {
307         ASSERT_EQ(true, false);
308       }
309       int64_t small_value = in_accum_device_to_accum_shape_map[small];
310       int64_t big_value = in_accum_device_to_accum_shape_map[big];
311       IsLinearValue(small, big, small_value, big_value, out_iter->first, out_iter->second);
312     }
313     out_iter++;
314   }
315 }
316 
ValidLayoutChangeCheck(const DeviceArrangement & in_device_arrangement,const TensorMap & in_tensor_map,const TensorShape & in_tensor_shape,const DeviceArrangement & out_device_arrangement,const TensorMap & out_tensor_map,const TensorShape & out_tensor_shape)317 void ValidLayoutChangeCheck(const DeviceArrangement &in_device_arrangement, const TensorMap &in_tensor_map,
318                             const TensorShape &in_tensor_shape, const DeviceArrangement &out_device_arrangement,
319                             const TensorMap &out_tensor_map, const TensorShape &out_tensor_shape) {
320   LayoutTransferValidLayoutChangeCheck(in_device_arrangement, in_tensor_map, in_tensor_shape, out_device_arrangement,
321                                        out_tensor_map, out_tensor_shape);
322 }
323 
324 }  // namespace parallel
325 }  // namespace mindspore
326