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< floatdequantizeTensorData (const Tensor &tensor)
 
Matcher< std::vector< float > > FloatArrayNear (const std::vector< float > &values, float max_abs_error)
 
Matcher< std::vector< double > > DoubleArrayNear (const std::vector< double > &values, double 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< floatdequantize (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 205 of file TestUtils.h.

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

References flatbuffers::data(), and luci::must_cast().

Referenced by dequantizeTensorData().

◆ dequantizeTensorData()

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

Definition at line 40 of file TestUtils.cpp.

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

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

◆ DoubleArrayNear()

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

Definition at line 116 of file TestUtils.cpp.

118{
119 std::vector<Matcher<double>> matchers;
120 matchers.reserve(values.size());
121 for (const double v : values)
122 {
123 matchers.emplace_back(DoubleNear(v, max_abs_error));
124 }
125 return ElementsAreArray(matchers);
126}

References luci::must_cast().

◆ 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}

References luci::must_cast().

◆ extractTensorShape()

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

Definition at line 128 of file TestUtils.cpp.

129{
130 std::vector<int32_t> result;
131 int dims = tensor.shape().num_dims();
132 for (int i = 0; i < dims; i++)
133 {
134 result.push_back(tensor.shape().dim(i));
135 }
136 return result;
137}

References luci::must_cast().

◆ FloatArrayNear()

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

Definition at line 105 of file TestUtils.cpp.

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

References luci::must_cast().

◆ 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 292 of file TestUtils.h.

293{
294 return ((max - min) / quantize_steps);
295}

References luci::must_cast().

◆ 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 flatbuffers::data(), luci_interpreter::Shape::dim(), luci::must_cast(), 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 flatbuffers::data(), and luci::must_cast().

◆ 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 flatbuffers::data(), and luci::must_cast().

◆ makeOutputTensor() [1/2]

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

Definition at line 33 of file TestUtils.cpp.

33{ 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 35 of file TestUtils.cpp.

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

◆ quantizationParams()

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

Definition at line 218 of file TestUtils.h.

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

References luci::must_cast().

◆ 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 178 of file TestUtils.h.

179{
180 static_assert(std::is_integral<T>::value, "Integral type expected.");
181
182 float q_min{}, q_max{};
183 if (std::is_signed<T>::value)
184 {
185 q_min = -std::numeric_limits<T>::max();
186 q_max = std::numeric_limits<T>::max();
187 }
188 else
189 {
190 q_min = 0;
191 q_max = std::numeric_limits<T>::max();
192 }
193
194 std::vector<T> q;
195 for (size_t i = 0; i < num_elements; ++i)
196 {
197 const auto &f = data[i];
198 q.push_back(static_cast<T>(
199 std::max<float>(q_min, std::min<float>(q_max, std::round(zero_point + (f / scale))))));
200 }
201 return q;
202}
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(), and luci::must_cast().