1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "lrn_builder.h"
17 
18 #include "mindir.h"
19 #include "ops_registry.h"
20 
21 namespace OHOS {
22 namespace NeuralNetworkRuntime {
23 namespace Ops {
24 static const int INPUT_NUM = 1;
25 static const int OUTPUT_NUM = 1;
26 static const int PARAM_MAX_NUM = 5;
27 static const int SCALAR_LENGTH = 1;
28 static const std::string OP_NAME = "LRN";
29 static const std::unordered_map<int, std::string> normRegionList = {{0, "ACROSS_CHANNELS"}};
30 
LRNBuilder()31 LRNBuilder::LRNBuilder() {}
32 
~LRNBuilder()33 LRNBuilder::~LRNBuilder() {}
34 
SetDepthRadius(const std::shared_ptr<NNTensor> & tensor)35 OH_NN_ReturnCode LRNBuilder::SetDepthRadius(const std::shared_ptr<NNTensor>& tensor)
36 {
37     if (tensor->GetDataType() != OH_NN_INT64) {
38         LOGE("[LRN] The depthRadius should be type OH_NN_INT64.");
39         return OH_NN_INVALID_PARAMETER;
40     }
41 
42     if (tensor->GetElementCount() != SCALAR_LENGTH) {
43         LOGE("[LRN] The depthRadius should be scalar.");
44         return OH_NN_INVALID_PARAMETER;
45     }
46 
47     void* buffer = tensor->GetBuffer();
48     if (buffer == nullptr) {
49         LOGE("[LRN] Tensor buffer is nullptr.");
50         return OH_NN_INVALID_PARAMETER;
51     }
52     m_depthRadius = *(static_cast<const int64_t*>(buffer));
53 
54     return OH_NN_SUCCESS;
55 }
56 
SetBias(const std::shared_ptr<NNTensor> & tensor)57 OH_NN_ReturnCode LRNBuilder::SetBias(const std::shared_ptr<NNTensor>& tensor)
58 {
59     if (tensor->GetDataType() != OH_NN_FLOAT32) {
60         LOGE("[LRN] The bias should be type OH_NN_FLOAT32.");
61         return OH_NN_INVALID_PARAMETER;
62     }
63 
64     if (tensor->GetElementCount() != SCALAR_LENGTH) {
65         LOGE("[LRN] The bias should be scalar.");
66         return OH_NN_INVALID_PARAMETER;
67     }
68 
69     void* buffer = tensor->GetBuffer();
70     if (buffer == nullptr) {
71         LOGE("[LRN] Tensor buffer is nullptr.");
72         return OH_NN_INVALID_PARAMETER;
73     }
74     m_bias = *(static_cast<const float*>(buffer));
75 
76     return OH_NN_SUCCESS;
77 }
78 
SetAlpha(const std::shared_ptr<NNTensor> & tensor)79 OH_NN_ReturnCode LRNBuilder::SetAlpha(const std::shared_ptr<NNTensor>& tensor)
80 {
81     if (tensor->GetDataType() != OH_NN_FLOAT32) {
82         LOGE("[LRN] The alpha should be type OH_NN_FLOAT32.");
83         return OH_NN_INVALID_PARAMETER;
84     }
85 
86     if (tensor->GetElementCount() != SCALAR_LENGTH) {
87         LOGE("[LRN] The alpha should be scalar.");
88         return OH_NN_INVALID_PARAMETER;
89     }
90 
91     void* buffer = tensor->GetBuffer();
92     if (buffer == nullptr) {
93         LOGE("[LRN] Tensor buffer is nullptr.");
94         return OH_NN_INVALID_PARAMETER;
95     }
96     m_alpha = *(static_cast<const float*>(buffer));
97 
98     return OH_NN_SUCCESS;
99 }
100 
SetBeta(const std::shared_ptr<NNTensor> & tensor)101 OH_NN_ReturnCode LRNBuilder::SetBeta(const std::shared_ptr<NNTensor>& tensor)
102 {
103     if (tensor->GetDataType() != OH_NN_FLOAT32) {
104         LOGE("[LRN] The beta should be type OH_NN_FLOAT32.");
105         return OH_NN_INVALID_PARAMETER;
106     }
107 
108     if (tensor->GetElementCount() != SCALAR_LENGTH) {
109         LOGE("[LRN] The beta should be scalar.");
110         return OH_NN_INVALID_PARAMETER;
111     }
112 
113     void* buffer = tensor->GetBuffer();
114     if (buffer == nullptr) {
115         LOGE("[LRN] Tensor buffer is nullptr.");
116         return OH_NN_INVALID_PARAMETER;
117     }
118     m_beta = *(static_cast<const float*>(buffer));
119 
120     return OH_NN_SUCCESS;
121 }
122 
SetNormRegion(const std::shared_ptr<NNTensor> & tensor)123 OH_NN_ReturnCode LRNBuilder::SetNormRegion(const std::shared_ptr<NNTensor>& tensor)
124 {
125     if (tensor->GetDataType() != OH_NN_INT32) {
126         LOGE("[LRN] The normRegion should be type OH_NN_INT32.");
127         return OH_NN_INVALID_PARAMETER;
128     }
129 
130     if (tensor->GetElementCount() != SCALAR_LENGTH) {
131         LOGE("[LRN] The beta should be scalar.");
132         return OH_NN_INVALID_PARAMETER;
133     }
134 
135     void* buffer = tensor->GetBuffer();
136     if (buffer == nullptr) {
137         LOGE("[LRN] Tensor buffer is nullptr.");
138         return OH_NN_INVALID_PARAMETER;
139     }
140     int normRegionKey = *(static_cast<int*>(buffer));
141     auto it = normRegionList.find(normRegionKey);
142     if (it != normRegionList.end()) {
143         m_normRegion = it->second;
144     } else {
145         LOGE("[LRN] The normRegion should between [0, 0], but get %d.", normRegionKey);
146         LOGE("[LRN] normRegion value: 0-ACROSS_CHANNELS");
147         return OH_NN_INVALID_PARAMETER;
148     }
149 
150     return OH_NN_SUCCESS;
151 }
152 
Build(const std::vector<uint32_t> & paramsIndex,const std::vector<uint32_t> & inputsIndex,const std::vector<uint32_t> & outputsIndex,const std::vector<std::shared_ptr<NNTensor>> & allTensors)153 OH_NN_ReturnCode LRNBuilder::Build(const std::vector<uint32_t>& paramsIndex,
154                                    const std::vector<uint32_t>& inputsIndex,
155                                    const std::vector<uint32_t>& outputsIndex,
156                                    const std::vector<std::shared_ptr<NNTensor>>& allTensors)
157 {
158     if (m_isBuild) {
159         LOGE("[LRN] Build failed, the LRN operation has been build. cannot build again.");
160         return OH_NN_OPERATION_FORBIDDEN;
161     }
162 
163     auto ret = CheckIOIndex(inputsIndex, outputsIndex, allTensors, INPUT_NUM, OUTPUT_NUM);
164     if (ret != OH_NN_SUCCESS) {
165         LOGE("[LRN] Build failed, passed invalid input or output index.");
166         return ret;
167     }
168 
169     m_inputsIndex = inputsIndex;
170     m_outputsIndex = outputsIndex;
171 
172     ret = CheckParamIndex(paramsIndex, allTensors, PARAM_MAX_NUM);
173     if (ret != OH_NN_SUCCESS) {
174         LOGE("[LRN] Build failed, passed invalid input or output index.");
175         return ret;
176     }
177 
178     for (int i : paramsIndex) {
179         std::shared_ptr<NNTensor> tensor = allTensors[i];
180         tensor->IdentifyOpParameter();
181         if (m_paramMap.find(tensor->GetType()) != m_paramMap.end()) {
182             ret = (this->*(m_paramMap[tensor->GetType()]))(tensor);
183         } else {
184             LOGE("[LRN] Build failed, param invalid, type=%d", tensor->GetType());
185             return OH_NN_INVALID_PARAMETER;
186         }
187 
188         if (ret != OH_NN_SUCCESS) {
189             LOGE("[LRN] Build failed, passed invalid param.");
190             return ret;
191         }
192     }
193 
194     m_name = OP_NAME;
195     m_isBuild = true;
196     return OH_NN_SUCCESS;
197 }
198 
GetPrimitive()199 LiteGraphPrimitvePtr LRNBuilder::GetPrimitive()
200 {
201     if (!m_isBuild) {
202         LOGE("[LRN] GetPrimitive failed, cannot get primitive before call build.");
203         return {nullptr, DestroyLiteGraphPrimitive};
204     }
205 
206     void* primitive = mindspore::lite::MindIR_LRN_CreatePrimitive(m_depthRadius, m_bias, m_alpha,
207                                                                   m_beta, m_normRegion);
208     LiteGraphPrimitvePtr graphPrimitivePtr(primitive, DestroyLiteGraphPrimitive) ;
209     return graphPrimitivePtr;
210 }
211 
212 REGISTER_OPS(LRNBuilder, OH_NN_OPS_LRN);
213 } // namespace Ops
214 } // namespace NeuralNetworkRuntime
215 } // namespace OHOS