1 /**
2 * Copyright 2020-2021 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
17 #include "src/delegate/npu/op/scale_npu.h"
18 #include <memory>
19 #include "src/delegate/npu/npu_converter_utils.h"
20
21 namespace mindspore {
22 constexpr int INPUT_INDEX = 0;
23 constexpr int SCALE_INDEX = 1;
24 constexpr int BIAS_INDEX = 2;
25
IsSupport(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)26 int ScaleNPUOp::IsSupport(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
27 const std::vector<mindspore::MSTensor> &out_tensors) {
28 auto scale_prim = primitive->value_as_ScaleFusion();
29 if (scale_prim == nullptr) {
30 MS_LOG(ERROR) << "Get null primitive value for op: " << name_;
31 return RET_ERROR;
32 }
33 axis_ = scale_prim->axis();
34 if (axis_ < 0) {
35 axis_ = axis_ + in_tensors[INPUT_INDEX].Shape().size();
36 }
37 if (axis_ != NHWC_C && axis_ != NCHW_C) {
38 if (in_tensors.size() <= BIAS_INDEX) {
39 MS_LOG(INFO) << "Npu Scale op does not support axis: " << axis_ << ", try to convert to Mul op.";
40 use_mul_ = true;
41 } else {
42 MS_LOG(WARNING) << "Npu Scale axis attr only support 1 or channel, now is " << axis_;
43 return RET_NOT_SUPPORT;
44 }
45 }
46 return RET_OK;
47 }
48
Init(const schema::Primitive * primitive,const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors)49 int ScaleNPUOp::Init(const schema::Primitive *primitive, const std::vector<mindspore::MSTensor> &in_tensors,
50 const std::vector<mindspore::MSTensor> &out_tensors) {
51 if (!use_mul_) {
52 // note that Scale only support the default axis(i.e., 1), setting axis is meaningless.
53 op_ = new (std::nothrow) hiai::op::Scale(name_);
54 } else {
55 op_ = new (std::nothrow) hiai::op::Mul(name_);
56 }
57 if (op_ == nullptr) {
58 MS_LOG(ERROR) << name_ << " op is nullptr";
59 return RET_ERROR;
60 }
61
62 auto scale_prim = primitive->value_as_ScaleFusion();
63 if (scale_prim == nullptr) {
64 MS_LOG(ERROR) << "Get null primitive value for op ." << name_;
65 return RET_ERROR;
66 }
67 act_type_ = scale_prim->activation_type();
68 if (act_type_ != schema::ActivationType_NO_ACTIVATION) {
69 auto ret = SetActivation(op_);
70 if (ret != RET_OK) {
71 MS_LOG(ERROR) << "New activation npu operator for op " << name_ << " failed.";
72 return ret;
73 }
74 }
75 return RET_OK;
76 }
77
SetNPUInputs(const std::vector<mindspore::MSTensor> & in_tensors,const std::vector<mindspore::MSTensor> & out_tensors,const std::vector<ge::Operator * > & npu_inputs)78 int ScaleNPUOp::SetNPUInputs(const std::vector<mindspore::MSTensor> &in_tensors,
79 const std::vector<mindspore::MSTensor> &out_tensors,
80 const std::vector<ge::Operator *> &npu_inputs) {
81 MS_ASSERT(in_tensors.size() > SCALE_INDEX);
82 if (use_mul_) {
83 auto ret = ConvertScaleToMul(npu_inputs, op_, in_tensors);
84 if (ret != RET_OK) {
85 MS_LOG(ERROR) << "Convert Scale to Mul failed, op name: " << name_;
86 }
87 return ret;
88 }
89
90 auto scale_op = reinterpret_cast<hiai::op::Scale *>(op_);
91 scale_op->set_input_x(*npu_inputs.at(INPUT_INDEX));
92 scale_op->set_input_scale(*npu_inputs.at(SCALE_INDEX));
93 if (in_tensors.size() > BIAS_INDEX && in_tensors[BIAS_INDEX] != nullptr) {
94 scale_op->set_input_bias(*npu_inputs.at(BIAS_INDEX));
95 }
96 return RET_OK;
97 }
98
GetNPUOp()99 ge::Operator *ScaleNPUOp::GetNPUOp() {
100 if (act_type_ == schema::ActivationType_NO_ACTIVATION) {
101 return op_;
102 } else {
103 return act_;
104 }
105 }
106
SetActivation(const ge::Operator * input)107 int ScaleNPUOp::SetActivation(const ge::Operator *input) {
108 act_ = new (std::nothrow) hiai::op::Activation(name_ + "_act");
109 if (act_ == nullptr) {
110 MS_LOG(ERROR) << "New activation npu operator for op " << name_ << " failed.";
111 return RET_ERROR;
112 }
113 act_->set_input_x(*input);
114
115 auto act_mode = ConverterToNPUActivationMode(act_type_);
116 if (act_mode == ACTIVATION_INVALID) {
117 MS_LOG(ERROR) << "Unsupported activation type for scale op " << name_;
118 return RET_ERROR;
119 }
120 act_->set_attr_mode(act_mode);
121 return RET_OK;
122 }
123
ConvertScaleToMul(const std::vector<ge::Operator * > & npu_inputs,ge::Operator * cur_op,const std::vector<mindspore::MSTensor> & in_tensors)124 int ScaleNPUOp::ConvertScaleToMul(const std::vector<ge::Operator *> &npu_inputs, ge::Operator *cur_op,
125 const std::vector<mindspore::MSTensor> &in_tensors) {
126 auto input_shape = in_tensors[INPUT_INDEX].Shape();
127 auto scale_shape = in_tensors[SCALE_INDEX].Shape();
128 auto mul_op = reinterpret_cast<hiai::op::Mul *>(cur_op);
129 mul_op->set_input_x1(*npu_inputs.at(INPUT_INDEX));
130 if (input_shape.size() == scale_shape.size()) {
131 mul_op->set_input_x2(*npu_inputs.at(SCALE_INDEX));
132 } else {
133 int valid_shape[4] = {1, 1, 1, 1};
134 for (size_t i = 0; i < scale_shape.size(); i++) {
135 valid_shape[axis_ + i] = static_cast<int>(scale_shape[i]);
136 }
137 reshape_ = new (std::nothrow) hiai::op::Reshape(name_ + "_reshape");
138 if (reshape_ == nullptr) {
139 MS_LOG(ERROR) << "New Reshape npu operator for op " << name_ << " failed.";
140 return RET_ERROR;
141 }
142 std::shared_ptr<ge::Tensor> shape_tensor = std::make_shared<ge::Tensor>();
143 if (shape_tensor == nullptr) {
144 MS_LOG(ERROR) << "new shape_tensor failed.";
145 return RET_ERROR;
146 }
147 ge::TensorDesc tensor_desc(ge::Shape({NPU_SHAPE_SIZE}), ge::FORMAT_ND, ge::DT_INT32);
148 shape_tensor->SetTensorDesc(tensor_desc);
149 shape_tensor->SetData(reinterpret_cast<const uint8_t *>(valid_shape), NPU_SHAPE_SIZE * sizeof(int));
150 shape_ = new (std::nothrow) hiai::op::Const(name_ + "_reshape_1");
151 if (shape_ == nullptr) {
152 MS_LOG(ERROR) << "New shape const for op " << name_ << " failed.";
153 return RET_ERROR;
154 }
155 shape_->set_attr_value(shape_tensor);
156 reshape_->set_input_x(*npu_inputs.at(SCALE_INDEX));
157 reshape_->set_input_shape(*shape_);
158 mul_op->set_input_x2(*reshape_);
159 }
160 return RET_OK;
161 }
162
~ScaleNPUOp()163 ScaleNPUOp::~ScaleNPUOp() {
164 if (op_ != nullptr) {
165 delete op_;
166 op_ = nullptr;
167 }
168 if (scale_ != nullptr) {
169 delete scale_;
170 scale_ = nullptr;
171 }
172 if (bias_ != nullptr) {
173 delete bias_;
174 bias_ = nullptr;
175 }
176 if (act_ != nullptr) {
177 delete act_;
178 act_ = nullptr;
179 }
180 if (reshape_ != nullptr) {
181 delete reshape_;
182 reshape_ = nullptr;
183 }
184 if (shape_ != nullptr) {
185 delete shape_;
186 shape_ = nullptr;
187 }
188 }
189 } // namespace mindspore
190