Files
wehub-resource-sync 8a852e4b4e
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s
chore: import upstream snapshot with attribution
2026-07-13 12:14:16 +08:00

238 lines
8.0 KiB
C++

/* Copyright 2021 The TensorFlow Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================*/
#include "tensorflow/lite/tools/utils.h"
#include <algorithm>
#include <complex>
#include <cstdint>
#include <random>
#include <string>
#include <type_traits>
#include "absl/types/span.h"
#include "Eigen/Core" // from @eigen_archive
#include "tensorflow/lite/c/c_api_types.h"
#include "tensorflow/lite/c/common.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/tools/logging.h"
#include "tensorflow/lite/types/half.h"
namespace tflite {
namespace utils {
namespace {
std::mt19937* get_random_engine() {
static std::mt19937* engine = []() -> std::mt19937* {
return new std::mt19937();
}();
return engine;
}
template <typename T, typename Distribution>
inline InputTensorData CreateInputTensorData(int num_elements,
Distribution distribution) {
InputTensorData tmp;
auto* random_engine = get_random_engine();
tmp.bytes = sizeof(T) * num_elements;
T* raw = new T[num_elements];
std::generate_n(raw, num_elements, [&]() {
if constexpr (std::is_same_v<T, std::complex<float>>) {
return T(distribution(*random_engine), distribution(*random_engine));
} else {
return static_cast<T>(distribution(*random_engine));
}
});
tmp.data = VoidUniquePtr(static_cast<void*>(raw),
[](void* ptr) { delete[] static_cast<T*>(ptr); });
return tmp;
}
// Converts a TfLiteTensor to a float array. Returns an error if the tensor
// dimension is a null pointer.
template <typename TensorType, typename ValueType>
TfLiteStatus ConvertToArray(const TfLiteTensor& tflite_tensor,
absl::Span<ValueType>& values) {
if (tflite_tensor.dims == nullptr) {
return kTfLiteError;
}
int total_elements = 1;
for (int i = 0; i < tflite_tensor.dims->size; i++) {
total_elements *= tflite_tensor.dims->data[i];
}
if (total_elements != values.size()) {
return kTfLiteError;
}
const TensorType* tensor_data =
reinterpret_cast<const TensorType*>(tflite_tensor.data.data);
for (int i = 0; i < total_elements; i++) {
values[i] = static_cast<ValueType>(tensor_data[i]);
}
return kTfLiteOk;
}
} // namespace
InputTensorData CreateRandomTensorData(const TfLiteTensor& tensor,
float low_range, float high_range) {
int num_elements = NumElements(tensor.dims);
return CreateRandomTensorData(tensor.name, tensor.type, num_elements,
low_range, high_range);
}
InputTensorData CreateRandomTensorData(std::string name, TfLiteType type,
int num_elements, float low_range,
float high_range) {
switch (type) {
case kTfLiteComplex64: {
return CreateInputTensorData<std::complex<float>>(
num_elements,
std::uniform_real_distribution<float>(low_range, high_range));
}
case kTfLiteFloat32: {
return CreateInputTensorData<float>(
num_elements,
std::uniform_real_distribution<float>(low_range, high_range));
}
case kTfLiteFloat16: {
return CreateInputTensorData<half>(
num_elements, std::uniform_real_distribution<float>(-0.5f, 0.5f));
}
case kTfLiteFloat64: {
return CreateInputTensorData<double>(
num_elements,
std::uniform_real_distribution<double>(low_range, high_range));
}
case kTfLiteInt64: {
return CreateInputTensorData<int64_t>(
num_elements,
std::uniform_int_distribution<int64_t>(low_range, high_range));
}
case kTfLiteInt32: {
return CreateInputTensorData<int32_t>(
num_elements,
std::uniform_int_distribution<int32_t>(low_range, high_range));
}
case kTfLiteUInt32: {
return CreateInputTensorData<uint32_t>(
num_elements,
std::uniform_int_distribution<uint32_t>(low_range, high_range));
}
case kTfLiteInt16: {
return CreateInputTensorData<int16_t>(
num_elements,
std::uniform_int_distribution<int16_t>(low_range, high_range));
}
case kTfLiteUInt16: {
return CreateInputTensorData<uint16_t>(
num_elements,
std::uniform_int_distribution<uint16_t>(low_range, high_range));
}
case kTfLiteUInt8: {
// std::uniform_int_distribution is specified not to support char types.
return CreateInputTensorData<uint8_t>(
num_elements,
std::uniform_int_distribution<uint32_t>(low_range, high_range));
}
case kTfLiteInt8: {
// std::uniform_int_distribution is specified not to support char types.
return CreateInputTensorData<int8_t>(
num_elements,
std::uniform_int_distribution<int32_t>(low_range, high_range));
}
case kTfLiteString: {
// Don't populate input for string. Instead, return a default-initialized
// `InputTensorData` object directly.
break;
}
case kTfLiteBool: {
// According to std::uniform_int_distribution specification, non-int type
// is not supported.
return CreateInputTensorData<bool>(
num_elements, std::uniform_int_distribution<uint32_t>(0, 1));
}
case kTfLiteBFloat16: {
return CreateInputTensorData<Eigen::bfloat16>(
num_elements, std::uniform_real_distribution<float>(-0.5f, 0.5f));
}
default: {
TFLITE_LOG(FATAL) << "Don't know how to populate tensor " << name
<< " of type " << type;
}
}
return InputTensorData();
}
void GetDataRangesForType(TfLiteType type, float* low_range,
float* high_range) {
if (type == kTfLiteComplex64 || type == kTfLiteFloat32 ||
type == kTfLiteFloat64) {
*low_range = -0.5f;
*high_range = 0.5f;
} else if (type == kTfLiteInt64 || type == kTfLiteUInt64 ||
type == kTfLiteInt32 || type == kTfLiteUInt32) {
*low_range = 0;
*high_range = 99;
} else if (type == kTfLiteUInt8) {
*low_range = 0;
*high_range = 254;
} else if (type == kTfLiteInt8) {
*low_range = -127;
*high_range = 127;
}
}
TfLiteStatus TfLiteTensorToFloat32Array(const TfLiteTensor& tensor,
absl::Span<float> values) {
switch (tensor.type) {
case kTfLiteFloat32:
return ConvertToArray<float, float>(tensor, values);
case kTfLiteFloat64:
return ConvertToArray<double, float>(tensor, values);
case kTfLiteFloat16:
return ConvertToArray<half, float>(tensor, values);
default:
return kTfLiteError;
}
}
TfLiteStatus TfLiteTensorToInt64Array(const TfLiteTensor& tensor,
absl::Span<int64_t> values) {
switch (tensor.type) {
case kTfLiteUInt8:
return ConvertToArray<uint8_t, int64_t>(tensor, values);
case kTfLiteInt8:
return ConvertToArray<int8_t, int64_t>(tensor, values);
case kTfLiteUInt16:
return ConvertToArray<uint16_t, int64_t>(tensor, values);
case kTfLiteInt16:
return ConvertToArray<int16_t, int64_t>(tensor, values);
case kTfLiteInt32:
return ConvertToArray<int32_t, int64_t>(tensor, values);
case kTfLiteUInt32:
return ConvertToArray<uint32_t, int64_t>(tensor, values);
case kTfLiteUInt64:
return ConvertToArray<uint64_t, int64_t>(tensor, values);
case kTfLiteInt64:
return ConvertToArray<int64_t, int64_t>(tensor, values);
default:
return kTfLiteError;
}
}
} // namespace utils
} // namespace tflite