• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright 2020 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 "src/runtime/kernel/arm/fp32/sparse_to_dense_fp32.h"
17 #include <vector>
18 #include <limits>
19 #include "include/errorcode.h"
20 #include "nnacl/fp32/sparse_to_dense_fp32.h"
21 #include "schema/model_generated.h"
22 #include "schema/ops_generated.h"
23 #include "src/kernel_registry.h"
24 
25 using mindspore::kernel::KERNEL_ARCH;
26 using mindspore::lite::KernelRegistrar;
27 using mindspore::lite::RET_ERROR;
28 using mindspore::lite::RET_OK;
29 using mindspore::schema::PrimitiveType_SparseToDense;
30 
31 namespace mindspore::kernel {
Init()32 int SparseToDenseCPUKernel::Init() {
33   MS_CHECK_TRUE_RET(in_tensors_.size() == kInputSize2, RET_ERROR);
34   CHECK_NULL_RETURN(in_tensors_[0]);
35   CHECK_NULL_RETURN(in_tensors_[1]);
36   CHECK_NULL_RETURN(in_tensors_[DIMENSION_2D]);
37   MS_CHECK_TRUE_RET(out_tensors_.size() == 1, RET_ERROR);
38   CHECK_NULL_RETURN(out_tensors_.front());
39   auto input2 = in_tensors_.at(2);
40   auto input3 = in_tensors_.at(3);
41   sparse_values = reinterpret_cast<float *>(input2->MutableData());
42   CHECK_NULL_RETURN(sparse_values);
43   CHECK_NULL_RETURN(input3->MutableData());
44   default_value = reinterpret_cast<float *>(input3->MutableData())[0];
45   if (input2->ElementsNum() == 1) {
46     isScalar = true;
47   }
48   if (!InferShapeDone()) {
49     return RET_OK;
50   }
51   return ReSize();
52 }
53 
ReSize()54 int SparseToDenseCPUKernel::ReSize() {
55   auto output0 = out_tensors_.at(0);
56   std::vector<int> out_shape_tensor = output0->shape();
57   auto output_shape_tmp = reinterpret_cast<int *>(out_shape_tensor.data());
58   int output_dim = static_cast<int>(output0->shape().size());
59   MS_CHECK_TRUE_MSG(output_dim <= DIMENSION_4D, RET_ERROR, "output_dim should <= 4");
60   for (int i = 0; i < DIMENSION_4D - output_dim; i++) {
61     output_shape[i] = 1;
62   }
63   for (int i = 0; i < output_dim; i++) {
64     output_shape[i + DIMENSION_4D - output_dim] = output_shape_tmp[i];
65   }
66   output_num = output0->ElementsNum();
67   return RET_OK;
68 }
69 
DoExcute(int task_id)70 int SparseToDenseCPUKernel::DoExcute(int task_id) {
71   int real_dst_count = MSMIN(index_num - task_id * count_unit_, count_unit_);
72   if (real_dst_count <= 0) {
73     return RET_OK;
74   }
75   int index_start = task_id * count_unit_;
76   int index_end = index_start + real_dst_count;
77   MS_CHECK_FALSE_MSG(index_num == 0, RET_ERROR, "div zero");
78   int out_width = output_num / index_num;
79   CHECK_NULL_RETURN(sparse_indices_vect);
80   CHECK_NULL_RETURN(sparse_values);
81   CHECK_NULL_RETURN(output_data);
82   SparseToDense(sparse_indices_vect, output_shape, sparse_values, default_value, output_data, isScalar, index_start,
83                 index_end, out_width);
84   return RET_OK;
85 }
86 
SparseToDenseRun(void * cdata,int task_id,float lhs_scale,float rhs_scale)87 int SparseToDenseRun(void *cdata, int task_id, float lhs_scale, float rhs_scale) {
88   auto s2ddata = reinterpret_cast<SparseToDenseCPUKernel *>(cdata);
89   auto ret = s2ddata->DoExcute(task_id);
90   if (ret != RET_OK) {
91     MS_LOG(ERROR) << "SparseToDenseRun error task_id[" << task_id << "] error_code[" << ret << "]";
92     return RET_ERROR;
93   }
94   return RET_OK;
95 }
96 
GenerateIndices()97 int SparseToDenseCPUKernel::GenerateIndices() {
98   auto input0 = in_tensors_.at(0);
99   index_num = input0->shape().at(0);
100   if (index_num >= std::numeric_limits<int>::max() / static_cast<int>(sizeof(int *))) {
101     MS_LOG(ERROR) << "Input dim is invalid, dim: " << index_num;
102     return RET_ERROR;
103   }
104   sparse_indices_vect =
105     reinterpret_cast<int **>(ctx_->allocator->Malloc(sizeof(int *) * static_cast<size_t>(index_num)));
106   if (sparse_indices_vect == nullptr) {
107     MS_LOG(ERROR) << "Null pointer reference: sparse_indices_vect.";
108     return RET_ERROR;
109   }
110   index_dim = static_cast<int>(input0->shape().size());
111   int *sparse_indices = reinterpret_cast<int *>(input0->MutableData());
112   CHECK_NULL_RETURN(sparse_indices);
113   switch (index_dim) {
114     case 0:
115     case 1: {
116       for (int i = 0; i < index_num; i++) {
117         sparse_indices_vect[i] = new int[DIMENSION_4D];
118         if (sparse_indices_vect[i] == nullptr) {
119           MS_LOG(ERROR) << "Null pointer reference: sparse_indices_vect[" << i << "].";
120           return RET_ERROR;
121         }
122         for (int j = 0; j < DIMENSION_4D - 1; j++) {
123           sparse_indices_vect[i][j] = 0;
124         }
125         sparse_indices_vect[i][DIMENSION_4D - 1] = sparse_indices[i];
126       }
127       break;
128     }
129     case 2: {
130       int true_dims = input0->shape().at(1);
131       MS_ASSERT(true_dims <= DIMENSION_4D);
132       for (int i = 0; i < index_num; i++) {
133         sparse_indices_vect[i] = new int[DIMENSION_4D];
134         if (sparse_indices_vect[i] == nullptr) {
135           MS_LOG(ERROR) << "Null pointer reference: sparse_indices_vect[" << i << "].";
136           return RET_ERROR;
137         }
138         for (int j = 0; j < DIMENSION_4D - true_dims; j++) {
139           sparse_indices_vect[i][j] = 0;
140         }
141         for (int j = 0; j < true_dims; j++) {
142           sparse_indices_vect[i][j + DIMENSION_4D - true_dims] = sparse_indices[i * true_dims + j];
143         }
144       }
145       break;
146     }
147     default: {
148       MS_LOG(ERROR) << "Indices dimensions is " << index_dim << ", which must be 0, 1 or 2";
149       return RET_ERROR;
150     }
151   }
152   return RET_OK;
153 }
154 
IndicesValidCheck() const155 int SparseToDenseCPUKernel::IndicesValidCheck() const {
156   int d1 = output_shape[1] * output_shape[2] * output_shape[3];
157   int d2 = output_shape[2] * output_shape[3];
158   int d3 = output_shape[3];
159   int index_before = -1;
160   for (int i = 0; i < index_num; i++) {
161     int index = d1 * sparse_indices_vect[i][0] + d2 * sparse_indices_vect[i][1] + d3 * sparse_indices_vect[i][2] +
162                 sparse_indices_vect[i][3];
163     if (index <= index_before) {
164       return RET_ERROR;
165     }
166     index_before = index;
167   }
168   return RET_OK;
169 }
170 
Run()171 int SparseToDenseCPUKernel::Run() {
172   auto ret = GenerateIndices();
173   if (ret != RET_OK) {
174     MS_LOG(ERROR) << "Generate Indices failed.";
175     return RET_ERROR;
176   }
177   if (s2d_param->validate_indices_ == true) {
178     auto ret2 = IndicesValidCheck();
179     if (ret2 != RET_OK) {
180       MS_LOG(ERROR) << "The sparse indices is not valid.";
181       return RET_ERROR;
182     }
183   }
184   output_data = reinterpret_cast<float *>(out_tensors_.at(0)->MutableData());
185   CHECK_NULL_RETURN(output_data);
186   MS_CHECK_FALSE_MSG(thread_count_ == 0, RET_ERROR, "div zero");
187   count_unit_ = thread_count_ > 1 ? UP_DIV(index_num, thread_count_) : index_num;
188   ret = ParallelLaunch(this->ms_context_, SparseToDenseRun, this, s2d_param->thread_num_);
189   if (ret != RET_OK) {
190     MS_LOG(ERROR) << "SparseToDenseRun error: error_code[" << ret << "]";
191     return RET_ERROR;
192   }
193 
194   if (sparse_indices_vect != nullptr) {
195     for (int i = 0; i < index_num; i++) {
196       if (sparse_indices_vect[i] != nullptr) {
197         delete[] sparse_indices_vect[i];
198       }
199     }
200     ctx_->allocator->Free(sparse_indices_vect);
201     sparse_indices_vect = nullptr;
202   }
203 
204   return RET_OK;
205 }
206 
207 REG_KERNEL(kCPU, kNumberTypeFloat32, PrimitiveType_SparseToDense, LiteKernelCreator<SparseToDenseCPUKernel>)
208 REG_KERNEL(kCPU, kNumberTypeInt32, PrimitiveType_SparseToDense, LiteKernelCreator<SparseToDenseCPUKernel>)
209 }  // namespace mindspore::kernel
210