ONE - On-device Neural Engine
Loading...
Searching...
No Matches
SVDF.cpp
Go to the documentation of this file.
1/*
2 * Copyright (c) 2022 Samsung Electronics Co., Ltd. All Rights Reserved
3 * Copyright 2017 The TensorFlow Authors. All Rights Reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18#include "kernels/SVDF.h"
19#include "kernels/Utils.h"
20#include "PALSVDF.h"
21
22#include <tensorflow/lite/kernels/internal/quantization_util.h>
23
24namespace luci_interpreter
25{
26namespace kernels
27{
28
29SVDF::SVDF(const Tensor *input, const Tensor *weight_feature, const Tensor *weight_time,
30 const Tensor *bias, const Tensor *input_activation_state, Tensor *output,
31 Tensor *scratchpad_activation_state, Tensor *scratchpad_1, Tensor *scratchpad_2,
32 Tensor *scratchpad_3, Tensor *scratchpad_4, Tensor *scratchpad_5, Tensor *scratchpad_6,
33 const SVDFParams &params)
35 {output, scratchpad_activation_state, scratchpad_1, scratchpad_2,
36 scratchpad_3, scratchpad_4, scratchpad_5, scratchpad_6},
37 params)
38{
39 // Do nothing
40}
41
43{
44 const Shape &input_shape = input()->shape();
45 const Shape &weight_features_shape = weight_feature()->shape();
46 const Shape &weight_time_shape = weight_time()->shape();
47
48 // Validate Input Tensor:
49 LUCI_INTERPRETER_CHECK(input()->element_type() == loco::DataType::FLOAT32 ||
50 input()->element_type() == loco::DataType::S8);
51 LUCI_INTERPRETER_CHECK(input_shape.num_dims() == 2);
52
53 // Validate inputs and output types
54 if (input()->element_type() == loco::DataType::S8)
55 {
56 LUCI_INTERPRETER_CHECK(weight_feature()->element_type() == loco::DataType::S8);
57 LUCI_INTERPRETER_CHECK(weight_time()->element_type() == loco::DataType::S16 ||
58 weight_time()->element_type() == loco::DataType::S8);
59 if (bias())
60 LUCI_INTERPRETER_CHECK(bias()->element_type() == loco::DataType::S32);
61
62 LUCI_INTERPRETER_CHECK(input_activation_state()->element_type() == loco::DataType::S16 ||
63 input_activation_state()->element_type() == loco::DataType::S8);
64 LUCI_INTERPRETER_CHECK(output()->element_type() == loco::DataType::S8);
65
66 // Note: now tflite support only ReLU activation for integer SVDF
68 }
69 else if (weight_feature()->element_type() == loco::DataType::FLOAT32)
70 {
71 LUCI_INTERPRETER_CHECK(weight_feature()->element_type() == loco::DataType::FLOAT32);
72 LUCI_INTERPRETER_CHECK(weight_time()->element_type() == loco::DataType::FLOAT32);
73 LUCI_INTERPRETER_CHECK(input_activation_state()->element_type() == loco::DataType::FLOAT32);
74 if (bias())
75 LUCI_INTERPRETER_CHECK(bias()->element_type() == loco::DataType::FLOAT32);
76 LUCI_INTERPRETER_CHECK(output()->element_type() == loco::DataType::FLOAT32);
77 }
78 else if ((weight_feature()->element_type() == loco::DataType::U8 ||
79 weight_feature()->element_type() == loco::DataType::S8) &&
80 input()->element_type() == loco::DataType::FLOAT32)
81 {
82 // TODO:: support hybrid SVDF op
83 throw std::runtime_error("Hybrid type is not currently supported");
84 }
85 else
86 {
87 throw std::runtime_error("luci-intp SVDF Unsupported type.");
88 }
89
90 // Check all the parameters of tensor match within themselves and match the
91 // input configuration.
92 const int rank = params().svdf_rank;
93 const int batch_size = input_shape.dim(0);
94 const int num_filters = weight_features_shape.dim(0);
95 LUCI_INTERPRETER_CHECK(rank != 0);
96 LUCI_INTERPRETER_CHECK(num_filters % rank == 0);
97
98 const int num_units = num_filters / rank;
99 const int memory_size = weight_time_shape.dim(1);
100
101 // Validate Weight_Feature Input Tensor:
102 LUCI_INTERPRETER_CHECK(weight_features_shape.num_dims() == 2);
103 LUCI_INTERPRETER_CHECK(weight_features_shape.dim(1) == input_shape.dim(1));
104
105 // Validate Weight_Time Input Tensor:
106 LUCI_INTERPRETER_CHECK(weight_time_shape.num_dims() == 2);
107 LUCI_INTERPRETER_CHECK(weight_time_shape.dim(0) == num_filters);
108
109 // Validate Bias
110 if (bias())
111 LUCI_INTERPRETER_CHECK(bias()->shape().dim(0) == num_units);
112
113 // Validate Input Activation State
114 LUCI_INTERPRETER_CHECK(input_activation_state()->shape().num_dims() == 2);
115 LUCI_INTERPRETER_CHECK(input_activation_state()->shape().dim(0) == batch_size);
116 LUCI_INTERPRETER_CHECK(input_activation_state()->shape().dim(1) == memory_size * num_filters);
117
118 // Resize scratchpad_state to input_activation_state
119 auto scratchpad_activation_state = getOutputTensors()[1];
120 scratchpad_activation_state->resize({batch_size, memory_size * num_filters});
121
122 // Resize output tensor
123 output()->resize({batch_size, num_units});
124
125 luci_interpreter_pal::SetupScratchpadTensor(
126 input()->element_type(), weight_feature()->element_type(), getOutputTensors()[2],
128 getOutputTensors()[7], input_shape, weight_time_shape, batch_size, num_filters, num_units);
129}
130
131void SVDF::execute() const
132{
133 switch (weight_feature()->element_type())
134 {
135 case loco::DataType::FLOAT32:
136 evalFloat();
137 break;
138 case loco::DataType::S8:
139 {
140 if (input()->element_type() == loco::DataType::S8)
141 evalInteger();
142 else
143 // TODO:: support hybrid SVDF op
144 throw std::runtime_error("Hybrid type is not currently supported");
145 break;
146 }
147 default:
148 throw std::runtime_error("Unsupported type");
149 }
150}
151
152void SVDF::evalInteger() const
153{
154 const auto effective_scale_1 = static_cast<double>(input()->scale() * weight_feature()->scale() /
156 const auto effective_scale_2 = static_cast<double>(input_activation_state()->scale() *
157 weight_time()->scale() / output()->scale());
158
159 int32_t effective_scale_1_a;
160 int effective_scale_1_b;
161 int32_t effective_scale_2_a;
162 int effective_scale_2_b;
163
164 tflite::QuantizeMultiplier(effective_scale_1, &effective_scale_1_a, &effective_scale_1_b);
165 tflite::QuantizeMultiplier(effective_scale_2, &effective_scale_2_a, &effective_scale_2_b);
166
167 TfLiteSVDFParams params_svdf{};
168 params_svdf.asymmetric_quantize_inputs = params().asymmetric_quantize_inputs;
169 params_svdf.rank = params().svdf_rank;
170 params_svdf.activation = getTfLiteActivation(params().activation);
171
172 auto scratchpad_activation_state = getOutputTensors()[1];
173 // Note: it is expected that activation_state input variable tensor reset to zero,
174 // also expected that this variable tensor doesn't have buffer
175 auto scratchpad_data = getTensorData<int16_t>(scratchpad_activation_state);
176 std::fill_n(scratchpad_data, scratchpad_activation_state->shape().num_elements(), 0);
177
178 auto scratchpad = getOutputTensors()[2];
179 auto output_temp = getOutputTensors()[3];
180
181 int32_t input_zp = input()->zero_point();
182 int32_t output_zp = output()->zero_point();
183 luci_interpreter_pal::IntegerSVDF(
184 params_svdf, getTensorShape(input()), getTensorData<int8_t>(input()),
185 getTensorShape(weight_feature()), getTensorData<int8_t>(weight_feature()),
186 getTensorShape(weight_time()), getTensorData<int16_t>(weight_time()), getTensorShape(bias()),
187 getTensorData<int32_t>(bias()), scratchpad_data, getTensorShape(output()),
188 getTensorData<int8_t>(output()), getTensorData<int32_t>(scratchpad),
189 getTensorData<int32_t>(output_temp), effective_scale_1_a, effective_scale_1_b,
190 effective_scale_2_a, effective_scale_2_b, input_zp, output_zp);
191}
192
193void SVDF::evalFloat() const
194{
195 TfLiteSVDFParams params_svdf{};
196 params_svdf.asymmetric_quantize_inputs = params().asymmetric_quantize_inputs;
197 params_svdf.rank = params().svdf_rank;
198 params_svdf.activation = getTfLiteActivation(params().activation);
199
200 auto scratchpad_activation_state = getOutputTensors()[1];
201 // Note: it is expected that activation_state input variable tensor reset to zero,
202 // also expected that this variable tensor doesn't have buffer
203 auto scratchpad_data = getTensorData<float>(scratchpad_activation_state);
204 std::fill_n(scratchpad_data, scratchpad_activation_state->shape().num_elements(), 0);
205
206 auto scratchpad_1 = getOutputTensors()[2];
207
208 luci_interpreter_pal::FloatSVDF(
209 params_svdf, getTensorShape(input()), getTensorData<float>(input()),
210 getTensorShape(weight_feature()), getTensorData<float>(weight_feature()),
211 getTensorShape(weight_time()), getTensorData<float>(weight_time()), getTensorShape(bias()),
212 getTensorData<float>(bias()), getTensorData<float>(scratchpad_1), scratchpad_data,
213 getTensorShape(output()), getTensorData<float>(output()));
214}
215
216} // namespace kernels
217} // namespace luci_interpreter
const std::vector< Tensor * > & getOutputTensors() const
Definition Kernel.h:40
int32_t dim(int i) const
Definition Tensor.h:41
int num_dims() const
Definition Tensor.h:39
void resize(const Shape &new_shape)
Definition Tensor.cpp:56
const Shape & shape() const
Definition Tensor.h:107
float scale() const
Definition Tensor.h:109
int32_t zero_point() const
Definition Tensor.h:115
const Tensor * input() const
Definition SVDF.h:37
void execute() const override
Definition SVDF.cpp:131
SVDF(const Tensor *input, const Tensor *weight_feature, const Tensor *weight_time, const Tensor *bias, const Tensor *input_activation_state, Tensor *output, Tensor *scratchpad_activation_state, Tensor *scratchpad_1, Tensor *scratchpad_2, Tensor *scratchpad_3, Tensor *scratchpad_4, Tensor *scratchpad_5, Tensor *scratchpad_6, const SVDFParams &params)
Definition SVDF.cpp:29
const Tensor * input_activation_state() const
Definition SVDF.h:41
const Tensor * bias() const
Definition SVDF.h:40
const Tensor * weight_feature() const
Definition SVDF.h:38
const Tensor * weight_time() const
Definition SVDF.h:39
Tensor * output() const
Definition SVDF.h:43
void configure() override
Definition SVDF.cpp:42
#define LUCI_INTERPRETER_CHECK(cond)
Definition Utils.h:36
TfLiteFusedActivation getTfLiteActivation(Activation activation)
Definition Utils.cpp:30
tflite::RuntimeShape getTensorShape(const Tensor *tensor)
Definition Utils.h:194