ONE - On-device Neural Engine
Loading...
Searching...
No Matches
luci_interpreter::kernels::testing Namespace Reference

Functions

Tensor makeOutputTensor (DataType element_type)
 
Tensor makeOutputTensor (DataType element_type, float scale, int32_t zero_point)
 
std::vector< float > dequantizeTensorData (const Tensor &tensor)
 
Matcher< std::vector< float > > FloatArrayNear (const std::vector< float > &values, float max_abs_error)
 
std::vector< int32_t > extractTensorShape (const Tensor &tensor)
 
template<typename T >
std::vector< T > quantize (const float *data, size_t num_elements, float scale, int32_t zero_point)
 
template<DataType DT>
Tensor makeInputTensor (const Shape &shape, const std::vector< typename DataTypeImpl< DT >::Type > &data, IMemoryManager *memory_manager)
 
template<DataType DT>
Tensor makeInputTensor (const Shape &shape, float scale, int32_t zero_point, const std::vector< float > &data, IMemoryManager *memory_manager)
 Create layer-wise quantized tensor.
 
template<DataType DT>
Tensor makeInputTensor (const Shape &shape, const std::vector< float > &scales, const std::vector< int32_t > &zero_points, int quantized_dimension, const std::vector< float > &data, IMemoryManager *memory_manager)
 Create channel-wise quantized tensor.
 
template<typename T >
constexpr DataType getElementType ()
 
template<typename T >
std::vector< T > extractTensorData (const Tensor &tensor)
 
template<typename T >
std::vector< float > dequantize (const T *data, size_t num_elements, float scale, int32_t zero_point)
 
template<typename T >
std::pair< float, int32_t > quantizationParams (float f_min, float f_max)
 
float getTolerance (float min, float max, int quantize_steps)
 

Function Documentation

◆ dequantize()

template<typename T >
std::vector< float > luci_interpreter::kernels::testing::dequantize ( const T *  data,
size_t  num_elements,
float  scale,
int32_t  zero_point 
)

Definition at line 201 of file TestUtils.h.

202{
203 static_assert(std::is_integral<T>::value, "Integral type expected.");
204 std::vector<float> f;
205 for (size_t i = 0; i < num_elements; ++i)
206 {
207 const T &q = data[i];
208 f.push_back(scale * (q - zero_point));
209 }
210 return f;
211}

References flatbuffers::data().

Referenced by dequantizeTensorData().

◆ dequantizeTensorData()

std::vector< float > luci_interpreter::kernels::testing::dequantizeTensorData ( const Tensor tensor)

Definition at line 39 of file TestUtils.cpp.

40{
41 if (tensor.element_type() == DataType::U8)
42 {
43 std::vector<uint8_t> data = extractTensorData<uint8_t>(tensor);
44 return dequantize(data.data(), data.size(), tensor.scale(), tensor.zero_point());
45 }
46 if (tensor.element_type() == DataType::S8)
47 {
48 std::vector<int8_t> data = extractTensorData<int8_t>(tensor);
49 return dequantize(data.data(), data.size(), tensor.scale(), tensor.zero_point());
50 }
51 else if (tensor.element_type() == DataType::S16)
52 {
53 // S16 quantization is symmetric, so zero point should be zero.
54 for (auto zp : tensor.zero_points())
55 {
56 (void)zp;
57 assert(zp == 0);
58 }
59
60 std::vector<int16_t> data = extractTensorData<int16_t>(tensor);
61 if (tensor.scales().size() == 1)
62 {
63 return dequantize(data.data(), data.size(), tensor.scale(), 0);
64 }
65
66 // quantize_dimension breaks shape into two parts:
67 // inner dimensions that contains continuous data with one quantization type
68 // outer dimensions that contains other dimensions
69 const Shape shape = tensor.shape();
70 const int32_t quantized_dimension = tensor.quantized_dimension();
71 assert(quantized_dimension < shape.num_dims());
72 size_t outer_dims_size = 1;
73 int32_t quant_dim_size = shape.dim(quantized_dimension);
74 size_t inner_dims_size = 1;
75 assert(quant_dim_size == tensor.scales().size());
76
77 for (int i = 0; i < quantized_dimension; ++i)
78 outer_dims_size *= shape.dim(i);
79 for (int i = quantized_dimension + 1; i < shape.num_dims(); ++i)
80 inner_dims_size *= shape.dim(i);
81
82 assert(shape.num_elements() == outer_dims_size * quant_dim_size * inner_dims_size);
83
84 std::vector<float> dequantized_data;
85 dequantized_data.reserve(shape.num_elements());
86 for (size_t outer_it = 0; outer_it < outer_dims_size; ++outer_it)
87 for (int32_t channel = 0; channel < quant_dim_size; ++channel)
88 {
89 float scale = tensor.scales()[channel];
90 size_t offset = inner_dims_size * (quant_dim_size * outer_it + channel);
91 std::vector<float> part_dequantized_data =
92 dequantize(data.data() + offset, inner_dims_size, scale, 0);
93 dequantized_data.insert(dequantized_data.end(), part_dequantized_data.begin(),
94 part_dequantized_data.end());
95 }
96 return dequantized_data;
97 }
98 else
99 {
100 throw std::runtime_error("Unsupported type.");
101 }
102}
__global uchar * offset(const Image *img, int x, int y)
Definition helpers.h:540
std::vector< float > dequantize(const T *data, size_t num_elements, float scale, int32_t zero_point)
Definition TestUtils.h:201
Definition Shape.h:28

References flatbuffers::data(), dequantize(), luci_interpreter::Shape::dim(), luci_interpreter::Shape::num_dims(), luci_interpreter::Shape::num_elements(), and offset().

◆ extractTensorData()

template<typename T >
std::vector< T > luci_interpreter::kernels::testing::extractTensorData ( const Tensor tensor)

Definition at line 161 of file TestUtils.h.

162{
163 const auto *data_ptr = tensor.data<T>();
164 return std::vector<T>(data_ptr, data_ptr + tensor.shape().num_elements());
165}

◆ extractTensorShape()

std::vector< int32_t > luci_interpreter::kernels::testing::extractTensorShape ( const Tensor tensor)

Definition at line 115 of file TestUtils.cpp.

116{
117 std::vector<int32_t> result;
118 int dims = tensor.shape().num_dims();
119 for (int i = 0; i < dims; i++)
120 {
121 result.push_back(tensor.shape().dim(i));
122 }
123 return result;
124}

◆ FloatArrayNear()

testing::Matcher< std::vector< float > > luci_interpreter::kernels::testing::FloatArrayNear ( const std::vector< float > &  values,
float  max_abs_error 
)

Definition at line 104 of file TestUtils.cpp.

105{
106 std::vector<Matcher<float>> matchers;
107 matchers.reserve(values.size());
108 for (const float v : values)
109 {
110 matchers.emplace_back(FloatNear(v, max_abs_error));
111 }
112 return ElementsAreArray(matchers);
113}

◆ getElementType()

template<typename T >
constexpr DataType luci_interpreter::kernels::testing::getElementType ( )
constexpr

Definition at line 134 of file TestUtils.h.

135{
136 if (std::is_same<T, float>::value)
137 return DataType::FLOAT32;
138 if (std::is_same<T, double>::value)
139 return DataType::FLOAT64;
140 if (std::is_same<T, uint8_t>::value)
141 return DataType::U8;
142 if (std::is_same<T, uint16_t>::value)
143 return DataType::U16;
144 if (std::is_same<T, uint32_t>::value)
145 return DataType::U32;
146 if (std::is_same<T, uint64_t>::value)
147 return DataType::U64;
148 if (std::is_same<T, int8_t>::value)
149 return DataType::S8;
150 if (std::is_same<T, int16_t>::value)
151 return DataType::S16;
152 if (std::is_same<T, int32_t>::value)
153 return DataType::S32;
154 if (std::is_same<T, int64_t>::value)
155 return DataType::S64;
156 if (std::is_same<T, bool>::value)
157 return DataType::BOOL;
158 return DataType::Unknown;
159}

◆ getTolerance()

float luci_interpreter::kernels::testing::getTolerance ( float  min,
float  max,
int  quantize_steps 
)
inline

Definition at line 288 of file TestUtils.h.

289{
290 return ((max - min) / quantize_steps);
291}

◆ makeInputTensor() [1/3]

template<DataType DT>
Tensor luci_interpreter::kernels::testing::makeInputTensor ( const Shape shape,
const std::vector< float > &  scales,
const std::vector< int32_t > &  zero_points,
int  quantized_dimension,
const std::vector< float > &  data,
IMemoryManager memory_manager 
)

Create channel-wise quantized tensor.

Template Parameters
DTbase integer data type, for example DataType::U8, DataType::S16, DataType::S64
Parameters
shapedesired tensor shape
scalesscales of quantized number
zero_pointszero points of quantized number, should be 0 for signed datatypes
quantize_dimensiondimension to apply quantization along. Usually channels/output channels
datafloating point data for quantization
memory_managermemory manager for allocating memory to tensor
Returns
created tensor

Definition at line 85 of file TestUtils.h.

88{
89 using NativeT = typename DataTypeImpl<DT>::Type;
90 assert(quantized_dimension < shape.num_dims());
91 Tensor tensor(DT, shape, {scales, zero_points, quantized_dimension}, "");
92
93 // quantize_dimension breaks shape into two parts:
94 // inner dimensions that contains continuous data with one quantization type
95 // outer dimensions that contains other dimensions
96 size_t outer_dims_size = 1;
97 int32_t quant_dim_size = shape.dim(quantized_dimension);
98 size_t inner_dims_size = 1;
99 assert(quant_dim_size == scales.size());
100 assert(quant_dim_size == zero_points.size());
101
102 for (int i = 0; i < quantized_dimension; ++i)
103 outer_dims_size *= shape.dim(i);
104 for (int i = quantized_dimension + 1; i < shape.num_dims(); ++i)
105 inner_dims_size *= shape.dim(i);
106
107 assert(shape.num_elements() == outer_dims_size * quant_dim_size * inner_dims_size);
108
109 std::vector<NativeT> quantized_data;
110 quantized_data.reserve(shape.num_elements());
111 for (size_t outer_it = 0; outer_it < outer_dims_size; ++outer_it)
112 for (int32_t channel = 0; channel < quant_dim_size; ++channel)
113 {
114 int32_t zero_point = zero_points[channel];
115 float scale = scales[channel];
116 size_t offset = inner_dims_size * (quant_dim_size * outer_it + channel);
117 std::vector<NativeT> part_quantized_data =
118 quantize<NativeT>(data.data() + offset, inner_dims_size, scale, zero_point);
119 quantized_data.insert(quantized_data.end(), part_quantized_data.begin(),
120 part_quantized_data.end());
121 }
122 assert(quantized_data.size() == shape.num_elements());
123 memory_manager->allocate_memory(tensor);
124 tensor.writeData(quantized_data.data(), quantized_data.size() * sizeof(NativeT));
125 return tensor;
126}
virtual void allocate_memory(luci_interpreter::Tensor &tensor)=0
int32_t dim(int i) const
Definition Tensor.h:41
int32_t num_elements() const
Definition Tensor.h:53
int num_dims() const
Definition Tensor.h:39
C++ scalar type corresponding to each DataType.
Definition DataType.h:58

References luci_interpreter::IMemoryManager::allocate_memory(), flatbuffers::data(), luci_interpreter::Shape::dim(), luci_interpreter::Shape::num_dims(), luci_interpreter::Shape::num_elements(), and offset().

◆ makeInputTensor() [2/3]

template<DataType DT>
Tensor luci_interpreter::kernels::testing::makeInputTensor ( const Shape shape,
const std::vector< typename DataTypeImpl< DT >::Type > &  data,
IMemoryManager memory_manager 
)

Definition at line 41 of file TestUtils.h.

43{
44 Tensor tensor(DT, shape, {}, "");
45 memory_manager->allocate_memory(tensor);
46 tensor.writeData(data.data(), data.size() * sizeof(typename DataTypeImpl<DT>::Type));
47 return tensor;
48}

References luci_interpreter::IMemoryManager::allocate_memory(), and flatbuffers::data().

◆ makeInputTensor() [3/3]

template<DataType DT>
Tensor luci_interpreter::kernels::testing::makeInputTensor ( const Shape shape,
float  scale,
int32_t  zero_point,
const std::vector< float > &  data,
IMemoryManager memory_manager 
)

Create layer-wise quantized tensor.

Template Parameters
DTbase integer data type, for example DataType::U8, DataType::S16, DataType::S64
Parameters
shapedesired tensor shape
scalescale of quantized number
zero_pointzero point of quantized number, should be 0 for signed datatypes
datafloating point data for quantization
memory_managermemory manager for allocating memory to tensor
Returns
created tensor

Definition at line 61 of file TestUtils.h.

63{
64 using NativeT = typename DataTypeImpl<DT>::Type;
65 Tensor tensor(DT, shape, {{scale}, {zero_point}}, "");
66 std::vector<NativeT> quantized_data =
67 quantize<NativeT>(data.data(), data.size(), scale, zero_point);
68 memory_manager->allocate_memory(tensor);
69 tensor.writeData(quantized_data.data(), quantized_data.size() * sizeof(NativeT));
70 return tensor;
71}

References luci_interpreter::IMemoryManager::allocate_memory(), and flatbuffers::data().

◆ makeOutputTensor() [1/2]

Tensor luci_interpreter::kernels::testing::makeOutputTensor ( DataType  element_type)

Definition at line 32 of file TestUtils.cpp.

32{ return Tensor(element_type, {}, {}, ""); }

◆ makeOutputTensor() [2/2]

Tensor luci_interpreter::kernels::testing::makeOutputTensor ( DataType  element_type,
float  scale,
int32_t  zero_point 
)

Definition at line 34 of file TestUtils.cpp.

35{
36 return Tensor(element_type, {}, {{scale}, {zero_point}}, "");
37}

◆ quantizationParams()

template<typename T >
std::pair< float, int32_t > luci_interpreter::kernels::testing::quantizationParams ( float  f_min,
float  f_max 
)

Definition at line 214 of file TestUtils.h.

215{
216 static_assert(std::is_integral<T>::value, "Integral type expected.");
217 int32_t zero_point = 0;
218 float scale = 0;
219 const T qmin = std::numeric_limits<T>::lowest();
220 const T qmax = std::numeric_limits<T>::max();
221 const float qmin_double = qmin;
222 const float qmax_double = qmax;
223 // 0 should always be a representable value. Let's assume that the initial
224 // min,max range contains 0.
225 assert(f_max >= 0);
226 assert(f_min <= 0);
227 if (f_min == f_max)
228 {
229 // Special case where the min,max range is a point. Should be {0}.
230 assert(f_max == 0);
231 assert(f_min == 0);
232 return {scale, zero_point};
233 }
234
235 // General case.
236 //
237 // First determine the scale.
238 scale = (f_max - f_min) / (qmax_double - qmin_double);
239
240 // Zero-point computation.
241 // First the initial floating-point computation. The zero-point can be
242 // determined from solving an affine equation for any known pair
243 // (real value, corresponding quantized value).
244 // We know two such pairs: (rmin, qmin) and (rmax, qmax).
245 // The arithmetic error on the zero point computed from either pair
246 // will be roughly machine_epsilon * (sum of absolute values of terms)
247 // so we want to use the variant that adds the smaller terms.
248 const float zero_point_from_min = qmin_double - f_min / scale;
249 const float zero_point_from_max = qmax_double - f_max / scale;
250
251 const float zero_point_from_min_error = std::abs(qmin_double) + std::abs(f_min / scale);
252
253 const float zero_point_from_max_error = std::abs(qmax_double) + std::abs(f_max / scale);
254
255 const float zero_point_double = zero_point_from_min_error < zero_point_from_max_error
256 ? zero_point_from_min
257 : zero_point_from_max;
258
259 // Now we need to nudge the zero point to be an integer
260 // (our zero points are integer, and this is motivated by the requirement
261 // to be able to represent the real value "0" exactly as a quantized value,
262 // which is required in multiple places, for example in Im2col with SAME
263 // padding).
264
265 T nudged_zero_point = 0;
266 if (zero_point_double < qmin_double)
267 {
268 nudged_zero_point = qmin;
269 }
270 else if (zero_point_double > qmax_double)
271 {
272 nudged_zero_point = qmax;
273 }
274 else
275 {
276 nudged_zero_point = static_cast<T>(std::round(zero_point_double));
277 }
278
279 // The zero point should always be in the range of quantized value,
280 // // [qmin, qmax].
281 assert(qmax >= nudged_zero_point);
282 assert(qmin <= nudged_zero_point);
283 zero_point = nudged_zero_point;
284 // finally, return the values
285 return {scale, zero_point};
286}

◆ quantize()

template<typename T >
std::vector< T > luci_interpreter::kernels::testing::quantize ( const float *  data,
size_t  num_elements,
float  scale,
int32_t  zero_point 
)

Definition at line 174 of file TestUtils.h.

175{
176 static_assert(std::is_integral<T>::value, "Integral type expected.");
177
178 float q_min{}, q_max{};
179 if (std::is_signed<T>::value)
180 {
181 q_min = -std::numeric_limits<T>::max();
182 q_max = std::numeric_limits<T>::max();
183 }
184 else
185 {
186 q_min = 0;
187 q_max = std::numeric_limits<T>::max();
188 }
189
190 std::vector<T> q;
191 for (size_t i = 0; i < num_elements; ++i)
192 {
193 const auto &f = data[i];
194 q.push_back(static_cast<T>(
195 std::max<float>(q_min, std::min<float>(q_max, std::round(zero_point + (f / scale))))));
196 }
197 return q;
198}
uint32_t num_elements(const Shape &shape)
The number of elements of a feature map of a given shape.
Definition Shape.h:59

References flatbuffers::data().