Skip to content

Commit

Permalink
Sync from tflite-micro at fe3c984.
Browse files Browse the repository at this point in the history
Signed-off-by: CFU-Playground-Bot <[email protected]>
  • Loading branch information
cfu-playground-bot committed Feb 14, 2023
1 parent 32b752c commit 327604a
Show file tree
Hide file tree
Showing 47 changed files with 3,480 additions and 3,523 deletions.
2 changes: 1 addition & 1 deletion conf/tflite-micro.version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
8746ec9
fe3c984
28 changes: 24 additions & 4 deletions third_party/tflite-micro/tensorflow/lite/core/c/common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -219,11 +219,11 @@ TfLiteStatus TfLiteTensorCopy(const TfLiteTensor* src, TfLiteTensor* dst) {
return kTfLiteOk;
}

void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor,
bool preserve_data) {
TfLiteStatus TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor,
bool preserve_data) {
if (tensor->allocation_type != kTfLiteDynamic &&
tensor->allocation_type != kTfLitePersistentRo) {
return;
return kTfLiteOk;
}
#ifdef TF_LITE_TENSORFLOW_PROFILER
tflite::PauseHeapMonitoring(/*pause=*/true);
Expand Down Expand Up @@ -258,9 +258,15 @@ void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor,
tflite::PauseHeapMonitoring(/*pause=*/false);
#endif
tensor->bytes = num_bytes;
if (tensor->data.data == nullptr && num_bytes != 0) {
// We are done allocating but tensor is pointing to null and a valid size
// was requested, so we error.
return kTfLiteError;
}
return kTfLiteOk;
}

void TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor) {
TfLiteStatus TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor) {
return TfLiteTensorResizeMaybeCopy(num_bytes, tensor, true);
}
#endif // TF_LITE_STATIC_MEMORY
Expand Down Expand Up @@ -331,4 +337,18 @@ void TfLiteOpaqueDelegateDelete(TfLiteOpaqueDelegate* opaque_delegate) {
delete tflite_delegate;
}

void* TfLiteOpaqueDelegateGetData(const TfLiteOpaqueDelegate* delegate) {
if (!delegate) return nullptr;

// The following cast is safe only because this code is part of the
// TF Lite runtime implementation. Apps using TF Lite should not rely on
// 'TfLiteOpaqueDelegate' and 'TfLiteDelegate' being equivalent.
const auto* tflite_delegate =
reinterpret_cast<const TfLiteDelegate*>(delegate);

if (!tflite_delegate->opaque_delegate_builder) return tflite_delegate->data_;

return tflite_delegate->opaque_delegate_builder->data;
}

} // extern "C"
36 changes: 27 additions & 9 deletions third_party/tflite-micro/tensorflow/lite/core/c/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ limitations under the License.
#ifndef TENSORFLOW_LITE_CORE_C_COMMON_H_
#define TENSORFLOW_LITE_CORE_C_COMMON_H_

#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
Expand Down Expand Up @@ -648,23 +649,26 @@ void TfLiteTensorReset(TfLiteType type, const char* name, TfLiteIntArray* dims,
TfLiteStatus TfLiteTensorCopy(const TfLiteTensor* src, TfLiteTensor* dst);

// Change the size of the memory block owned by `tensor` to `num_bytes`.
// Tensors with allocation types other than kTfLiteDynamic will be ignored.
// Tensors with allocation types other than `kTfLiteDynamic` will be ignored and
// a kTfLiteOk will be returned.
// `tensor`'s internal data buffer will be assigned a pointer
// which can safely be passed to free or realloc if `num_bytes` is zero.
// Behaviour is undefined if `tensor` is NULL.
// If `preserve_data` is true, tensor data will be unchanged in the range from
// the start of the region up to the minimum of the old and new sizes.
void TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor,
bool preserve_data);
// the start of the region up to the minimum of the old and new sizes. In the
// case of NULL tensor, or an error allocating new memory, returns
// `kTfLiteError`.
TfLiteStatus TfLiteTensorResizeMaybeCopy(size_t num_bytes, TfLiteTensor* tensor,
bool preserve_data);

// Change the size of the memory block owned by `tensor` to `num_bytes`.
// Tensors with allocation types other than kTfLiteDynamic will be ignored.
// Tensors with allocation types other than kTfLiteDynamic will be ignored and
// a kTfLiteOk will be returned.
// `tensor`'s internal data buffer will be assigned a pointer
// which can safely be passed to free or realloc if `num_bytes` is zero.
// Behaviour is undefined if `tensor` is NULL.
// Tensor data will be unchanged in the range from the start of the region up to
// the minimum of the old and new sizes.
void TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor);
// the minimum of the old and new sizes. In the case
// of NULL tensor, or an error allocating new memory, returns `kTfLiteError`.
TfLiteStatus TfLiteTensorRealloc(size_t num_bytes, TfLiteTensor* tensor);
#endif // TF_LITE_STATIC_MEMORY

// WARNING: This is an experimental interface that is subject to change.
Expand Down Expand Up @@ -1135,6 +1139,20 @@ TfLiteOpaqueDelegate* TfLiteOpaqueDelegateCreate(
// 'delegate' is a null pointer.
void TfLiteOpaqueDelegateDelete(TfLiteOpaqueDelegate* delegate);

// Returns a pointer to the data associated with the provided opaque 'delegate'.
//
// A null pointer will be returned when:
// - The 'delegate' is null.
// - The 'data' field of the 'TfLiteOpaqueDelegateBuilder' used to construct the
// 'delegate' was null.
// - Or in case of any other error.
// - The 'delegate' has been constructed via a 'TfLiteOpaqueDelegateBuilder',
// but the 'data' field of the 'TfLiteOpaqueDelegateBuilder' is null.
//
// The data_ field of 'delegate' will be returned if the
// 'opaque_delegate_builder' field is null.
void* TfLiteOpaqueDelegateGetData(const TfLiteOpaqueDelegate* delegate);

#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus
Expand Down
181 changes: 113 additions & 68 deletions third_party/tflite-micro/tensorflow/lite/kernels/internal/common.h
Original file line number Diff line number Diff line change
Expand Up @@ -377,40 +377,49 @@ inline Integer FloorLog2(Integer n) {
}
}

// The size of the LUT depends on the type of input. For uint8 and int8 inputs
// we use a 256 entries LUT to map all the values in the (u)int8 range. For
// int16 inputs the high 9 bits are used for indexing and the 7 remaining bits
// are used for interpolation. We thus use a 513-entries LUT for int16 cases,
// 512 for the 9-bit indexing and 1 extra entry to interpolate the last value.
template <typename T>
constexpr int LUTSize() {
static_assert(std::is_same<T, uint8_t>::value ||
std::is_same<T, int8_t>::value ||
std::is_same<T, int16_t>::value,
"Only LUTs with uint8, int8 or int16 inputs are supported.");
// As per c++11: constexpr methods cannot have more than one return statement.
return (std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value)
? 256
: 513;
namespace detail {

// LUTPopulate takes an optional type-erased transform_params to allow passing
// extra parameters to the transform function pointer. const void* is used
// instead of std::function to be compatible with TFLite Micro
template <typename FloatT, typename Func>
inline typename std::enable_if<std::is_same<Func, FloatT (*)(FloatT)>::value,
FloatT>::type
LUTTransform(Func transform, const void* /*transform_params*/, FloatT value) {
static_assert(std::is_floating_point<FloatT>::value,
"FloatT must be a floating-point type.");
return transform(value);
}

template <typename FloatT, typename Func>
inline typename std::enable_if<
std::is_same<Func, FloatT (*)(FloatT, const void*)>::value, FloatT>::type
LUTTransform(Func transform, const void* transform_params, FloatT value) {
static_assert(std::is_floating_point<FloatT>::value,
"FloatT must be a floating-point type.");
return transform(value, transform_params);
}

// Use the same LUT generation code for both uint8_t and int8_t. Int8_t indexes
// will be directly casted to uint8_t, the int8 LUT will thus be ordered as [0,
// 1, ..., 127, -128, ..., -2, -1] instead of [-128, -127, ..., -1, 0, 1, ...,
// 126, 127].
template <typename T>
inline typename std::enable_if<std::is_same<T, uint8_t>::value ||
std::is_same<T, int8_t>::value,
void>::type
LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,
int32_t output_zero_point, float (*transform)(float), T* lut) {
template <typename T, typename Func>
inline void LUTPopulateInt8(float input_scale, int32_t input_zero_point,
float output_scale, int32_t output_zero_point,
Func transform, const void* transform_params,
T* lut) {
static_assert(
std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value,
"T must be an uint8 or int8 type.");
uint8_t* lut_uint8 = reinterpret_cast<uint8_t*>(lut);
const float inverse_scale = 1 / output_scale;
int32_t maxval = std::numeric_limits<T>::max();
int32_t minval = std::numeric_limits<T>::min();
for (int32_t val = minval; val <= maxval; ++val) {
const float dequantized = input_scale * (val - input_zero_point);
const float transformed = transform(dequantized);
const float transformed =
LUTTransform(transform, transform_params, dequantized);
const float rescaled = TfLiteRound(transformed * inverse_scale);
const int32_t quantized =
static_cast<int32_t>(rescaled + output_zero_point);
Expand All @@ -421,10 +430,11 @@ LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,

// Keep floating-point type configurable for backward compatibility. float
// should be used for FloatT by default.
template <typename T, typename FloatT>
inline typename std::enable_if<std::is_same<T, int16_t>::value, void>::type
LUTPopulate(FloatT input_scale, int32_t input_zero_point, FloatT output_scale,
int32_t output_zero_point, FloatT (*transform)(FloatT), T* lut) {
template <typename FloatT, typename Func>
inline void LUTPopulateInt16(FloatT input_scale, int32_t input_zero_point,
FloatT output_scale, int32_t output_zero_point,
Func transform, const void* transform_params,
int16_t* lut) {
static_assert(std::is_floating_point<FloatT>::value,
"FloatT must be a floating-point type.");
const FloatT input_min =
Expand All @@ -440,16 +450,21 @@ LUTPopulate(FloatT input_scale, int32_t input_zero_point, FloatT output_scale,
const FloatT step = (input_max - input_min) / nb_steps;
const FloatT half_step = step / 2;
const FloatT output_scaling_inv =
static_cast<FloatT>(std::numeric_limits<T>::max() -
std::numeric_limits<T>::min() + 1) /
static_cast<FloatT>(std::numeric_limits<int16_t>::max() -
std::numeric_limits<int16_t>::min() + 1) /
(output_max - output_min);
const FloatT table_min = static_cast<FloatT>(std::numeric_limits<T>::min());
const FloatT table_max = static_cast<FloatT>(std::numeric_limits<T>::max());
const FloatT table_min =
static_cast<FloatT>(std::numeric_limits<int16_t>::min());
const FloatT table_max =
static_cast<FloatT>(std::numeric_limits<int16_t>::max());

for (int i = 0; i < nb_steps; i++) {
const FloatT val = transform(input_min + i * step);
const FloatT val_midpoint = transform(input_min + i * step + half_step);
const FloatT val_next = transform(input_min + (i + 1) * step);
const FloatT val =
LUTTransform<FloatT>(transform, transform_params, input_min + i * step);
const FloatT val_midpoint = LUTTransform<FloatT>(
transform, transform_params, input_min + i * step + half_step);
const FloatT val_next = LUTTransform<FloatT>(transform, transform_params,
input_min + (i + 1) * step);

const FloatT sample_val = TfLiteRound(val * output_scaling_inv);
const FloatT midpoint_interp_val =
Expand All @@ -460,54 +475,84 @@ LUTPopulate(FloatT input_scale, int32_t input_zero_point, FloatT output_scale,
const FloatT midpoint_err = midpoint_interp_val - midpoint_val;
const FloatT bias = TfLiteRound(midpoint_err / 2);

lut[i] = static_cast<T>(std::min<FloatT>(
lut[i] = static_cast<int16_t>(std::min<FloatT>(
std::max<FloatT>(sample_val - bias, table_min), table_max));
}

lut[nb_steps] = static_cast<T>(std::min<FloatT>(
std::max<FloatT>(TfLiteRound(transform(input_max) * output_scaling_inv),
lut[nb_steps] = static_cast<int16_t>(std::min<FloatT>(
std::max<FloatT>(TfLiteRound(LUTTransform<FloatT>(
transform, transform_params, input_max) *
output_scaling_inv),
table_min),
table_max));
}

} // namespace detail

template <typename T>
inline typename std::enable_if<std::is_same<T, uint8_t>::value ||
std::is_same<T, int8_t>::value,
void>::type
LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,
int32_t output_zero_point, float (*transform)(float), T* lut) {
detail::LUTPopulateInt8(input_scale, input_zero_point, output_scale,
output_zero_point, transform, nullptr, lut);
}

template <typename T>
inline typename std::enable_if<std::is_same<T, uint8_t>::value ||
std::is_same<T, int8_t>::value,
void>::type
LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,
int32_t output_zero_point, float (*transform)(float, const void*),
const void* transform_params, T* lut) {
detail::LUTPopulateInt8(input_scale, input_zero_point, output_scale,
output_zero_point, transform, transform_params, lut);
}

template <typename T>
inline typename std::enable_if<std::is_same<T, int16_t>::value, void>::type
LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,
int32_t output_zero_point, float (*transform)(float), T* lut) {
LUTPopulate<T, float>(input_scale, input_zero_point, output_scale,
output_zero_point, transform, lut);
detail::LUTPopulateInt16<float>(input_scale, input_zero_point, output_scale,
output_zero_point, transform, nullptr, lut);
}

template <typename T>
inline typename std::enable_if<std::is_same<T, int16_t>::value, void>::type
LUTPopulate(float input_scale, int32_t input_zero_point, float output_scale,
int32_t output_zero_point, float (*transform)(float, const void*),
const void* transform_params, T* lut) {
detail::LUTPopulateInt16<float>(input_scale, input_zero_point, output_scale,
output_zero_point, transform,
transform_params, lut);
}

// Deprecated and will be removed in future, please use LUTPopulate instead
template <typename FloatT, typename LutInT, typename LutOutT>
inline void gen_lut(FloatT (*func)(FloatT), FloatT input_min, FloatT input_max,
FloatT output_min, FloatT output_max, LutOutT* lut) {
static_assert(std::is_same<LutInT, LutOutT>::value,
"Input and output type of the LUT must be the same.");
static_assert(std::is_same<LutInT, int16_t>::value,
"Only int16_t type LUT are supported.");
static_assert(std::is_same<FloatT, float>::value,
"Only float type is supported for FloatT.");
using T = LutInT;

const auto zero_point = [](float min, float max, float scale) {
// Symmetric int16 LUT, we know the zero-point will not overflow an int32_t
// and zero-point from min will be the same as from max.
return static_cast<int32_t>(
static_cast<float>(std::numeric_limits<T>::min()) - min / scale);
};

const float scale = static_cast<float>(std::numeric_limits<T>::max() -
std::numeric_limits<T>::min());
const float input_scale = (input_max - input_min) / scale;
const FloatT output_scale = (output_max - output_min) / scale;
const int32_t input_zero_point =
zero_point(input_min, input_max, input_scale);
const int32_t output_zero_point =
zero_point(output_min, output_max, output_scale);

return LUTPopulate<T, float>(input_scale, input_zero_point, output_scale,
output_zero_point, func, lut);
// Deprecated, avoid usage and prefer the float version. Kept for
// backward-compatiblity.
template <typename T>
inline typename std::enable_if<std::is_same<T, int16_t>::value, void>::type
LUTPopulate(double input_scale, int32_t input_zero_point, double output_scale,
int32_t output_zero_point, double (*transform)(double), T* lut) {
detail::LUTPopulateInt16<double>(input_scale, input_zero_point, output_scale,
output_zero_point, transform, nullptr, lut);
}

// The size of the LUT depends on the type of input. For uint8 and int8 inputs a
// simple 256 entries LUT is used. For int16 inputs the high 9 bits are used for
// indexing and the 7 remaining bits are used for interpolation. We thus use a
// 513-entries LUT for int16 cases, 512 for the 9-bit indexing and 1 extra entry
// to interpolate the last value.
template <typename T>
constexpr int LUTSize() {
static_assert(std::is_same<T, uint8_t>::value ||
std::is_same<T, int8_t>::value ||
std::is_same<T, int16_t>::value,
"Only LUTs with uint8, int8 or int16 inputs are supported.");
// As per c++11: constexpr methods cannot have more than one return statement.
return (std::is_same<T, uint8_t>::value || std::is_same<T, int8_t>::value)
? 256
: 513;
}

// int16_t -> int16_t table lookup with interpolation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ limitations under the License.
#include <algorithm>

#include "tensorflow/lite/kernels/internal/common.h"
#include "tensorflow/lite/kernels/internal/portable_tensor_utils.h"

namespace tflite {
namespace reference_integer_ops {
Expand Down Expand Up @@ -134,20 +133,6 @@ inline void ConvPerChannel(
}
}

inline void ConvPerChannelWithPackedInt4Weights(
const ConvParams& params, const int32_t* output_multiplier,
const int32_t* output_shift, const RuntimeShape& input_shape,
const int8_t* input_data, const RuntimeShape& filter_shape,
const int8_t* filter_input, int8_t* unpacked_filter_data,
const RuntimeShape& bias_shape, const int32_t* bias_data,
const RuntimeShape& output_shape, int8_t* output_data) {
TFLITE_DCHECK(unpacked_filter_data != nullptr);
tflite::tensor_utils::UnpackDenseInt4IntoInt8(
filter_input, filter_shape.FlatSize(), unpacked_filter_data);
ConvPerChannel(params, output_multiplier, output_shift, input_shape,
input_data, filter_shape, unpacked_filter_data, bias_shape,
bias_data, output_shape, output_data);
}

// Fixed-point per-channel-quantization convolution reference kernel.
// 16-bit data and 8-bit filter
Expand Down
Loading

0 comments on commit 327604a

Please sign in to comment.