chore: import upstream snapshot with attribution
cffconvert / validate (push) Has been skipped
License Check / license-check (push) Failing after 2s

This commit is contained in:
wehub-resource-sync
2026-07-13 12:14:16 +08:00
commit 8a852e4b4e
36502 changed files with 9277225 additions and 0 deletions
@@ -0,0 +1,67 @@
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_cc//cc:cc_test.bzl", "cc_test")
package(
# copybara:uncomment default_applicable_licenses = ["//tensorflow:LICENSE"],
default_visibility = ["//visibility:public"],
licenses = ["notice"],
)
cc_library(
name = "tfl_tensor_ref",
srcs = ["tfl_tensor_ref.cc"],
hdrs = ["tfl_tensor_ref.h"],
deps = [
"//tensorflow/lite:array",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/ml_adjacent:lib",
"//tensorflow/lite/kernels:kernel_util",
"//tensorflow/lite/kernels/internal:compatibility",
],
)
cc_test(
name = "tfl_tensor_ref_test",
srcs = ["tfl_tensor_ref_test.cc"],
deps = [
":tfl_tensor_ref",
"//tensorflow/lite:util",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/ml_adjacent:lib",
"//tensorflow/lite/kernels:kernel_util",
"//tensorflow/lite/kernels:test_util",
"//tensorflow/lite/kernels/internal:compatibility",
"@com_google_absl//absl/types:span",
"@com_google_googletest//:gtest_main",
],
)
cc_library(
name = "extern_call",
srcs = ["extern_call.cc"],
hdrs = ["extern_call.h"],
deps = [
":tfl_tensor_ref",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/experimental/ml_adjacent:lib",
"//tensorflow/lite/experimental/ml_adjacent/algo:crop",
"//tensorflow/lite/experimental/ml_adjacent/algo:resize",
"//tensorflow/lite/kernels:kernel_util",
],
)
cc_test(
name = "extern_call_test",
srcs = ["extern_call_test.cc"],
deps = [
":extern_call",
"//tensorflow/lite/core/c:c_api_types",
"//tensorflow/lite/core/c:common",
"//tensorflow/lite/kernels:test_util",
"//tensorflow/lite/schema:schema_fbs",
"@com_google_googletest//:gtest_main",
],
)
@@ -0,0 +1,106 @@
/* Copyright 2023 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/experimental/ml_adjacent/tflite/extern_call.h"
#include <cstdint>
#include <memory>
#include <vector>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/experimental/ml_adjacent/algo/crop.h"
#include "tensorflow/lite/experimental/ml_adjacent/algo/resize.h"
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
#include "tensorflow/lite/experimental/ml_adjacent/tflite/tfl_tensor_ref.h"
#include "tensorflow/lite/kernels/kernel_util.h"
namespace tflite {
namespace extern_call {
namespace {
using ::ml_adj::algo::Algo;
using ::ml_adj::algo::InputPack;
using ::ml_adj::algo::OutputPack;
using ::ml_adj::data::MutableTflTensorRef;
using ::ml_adj::data::TflTensorRef;
// UniquePtr wrapper around vectors that hold the inputs/outputs to
// library's `Algo`s.
template <typename PackType>
struct PackDeleter {
void operator()(PackType* pack) {
if (pack == nullptr) return;
for (auto* d : *pack) {
if (d == nullptr) continue;
delete d;
}
delete pack;
}
};
template <typename PackType>
using UniquePack = std::unique_ptr<PackType, PackDeleter<PackType>>;
constexpr uint8_t kNumFuncs = 2;
static const Algo* const kReg[kNumFuncs] = {ml_adj::crop::Impl_CenterCrop(),
ml_adj::resize::Impl_Resize()};
TfLiteStatus Prepare(TfLiteContext* context, TfLiteNode* node) {
for (int i = 0; i < NumOutputs(node); ++i) {
TfLiteTensor* output;
TF_LITE_ENSURE_OK(context, GetOutputSafe(context, node, i, &output));
SetTensorToDynamic(output);
}
return kTfLiteOk;
}
TfLiteStatus Eval(TfLiteContext* context, TfLiteNode* node) {
UniquePack<InputPack> lib_inputs(new InputPack());
for (int i = 0; i < NumInputs(node); ++i) {
const TfLiteTensor* input;
TF_LITE_ENSURE_OK(context, GetInputSafe(context, node, i, &input));
lib_inputs->push_back(new TflTensorRef(input));
}
UniquePack<OutputPack> lib_outputs(new OutputPack());
for (int i = 0; i < NumOutputs(node); ++i) {
TfLiteTensor* output;
TF_LITE_ENSURE_OK(context, GetOutputSafe(context, node, i, &output));
lib_outputs->push_back(new MutableTflTensorRef(output, context));
}
TF_LITE_ENSURE_EQ(context, node->custom_initial_data_size,
sizeof(ExternCallOptions));
const auto* const options =
reinterpret_cast<const ExternCallOptions*>(node->custom_initial_data);
TF_LITE_ENSURE(context,
options->func_id >= 0 && options->func_id < kNumFuncs);
const Algo* const algo = kReg[options->func_id];
algo->process(*lib_inputs, *lib_outputs);
return kTfLiteOk;
}
} // namespace
TfLiteRegistration* Register_EXTERN_CALL() {
static TfLiteRegistration r = {nullptr, nullptr, Prepare, Eval};
return &r;
}
} // namespace extern_call
} // namespace tflite
@@ -0,0 +1,37 @@
/* Copyright 2023 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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_EXTERN_CALL_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_EXTERN_CALL_H_
#include <cstdint>
#include "tensorflow/lite/core/c/common.h"
namespace tflite::extern_call {
// Compile time options passed to this kernel at runtime.
struct ExternCallOptions {
// A single custom op is used to represent a call to an arbitrary function
// in the library. The function that is called is encoded in `func_id`.
// Because of compiler op def, these will be encded at compile time
// as `char[]` and will serialize `uint8_t`, so we match this type.
uint8_t func_id;
};
TfLiteRegistration* Register_EXTERN_CALL();
} // namespace tflite::extern_call
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_EXTERN_CALL_H_
@@ -0,0 +1,90 @@
/* Copyright 2023 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/experimental/ml_adjacent/tflite/extern_call.h"
#include <cstdint>
#include <vector>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/kernels/test_util.h"
#include "tensorflow/lite/schema/schema_generated.h"
namespace tflite {
class ExternCallModel : public SingleOpModel {
public:
ExternCallModel(std::vector<TensorData> inputs,
std::vector<TensorData> outputs, uint8_t func_id) {
std::vector<std::vector<int>> input_shapes;
for (const auto& data : inputs) {
input_ids_.push_back(AddInput(data));
input_shapes.push_back(GetShape(input_ids_.back()));
}
for (const auto& data : outputs) {
output_ids_.push_back(AddOutput(data));
}
SetCustomOp("ExternCall", {func_id}, extern_call::Register_EXTERN_CALL);
BuildInterpreter(input_shapes);
}
const TfLiteTensor* Output(int output_id) {
return interpreter_->tensor(output_ids_[output_id]);
}
private:
std::vector<int> input_ids_;
std::vector<int> output_ids_;
};
namespace {
// This custom op is a simple wrapper and most of the meaningful logic
// with be tested in the contained `Algo` implementations. It is
// sufficient to just test that calling these `Algo` succeeds.
// TODO(b/290283768) If the complexity if this custom op grows consider
// devising a mechanism allowing for a "mock" `Algo` to call from these tests.
TEST(ExternCallTest, CropFunc) {
std::vector<TensorData> inputs = {{TensorType_FLOAT32, {1, 5, 5, 1}},
{TensorType_FLOAT64, {}}};
std::vector<TensorData> output = {{TensorType_FLOAT32, {}}};
ExternCallModel model(inputs, output, 0);
model.PopulateTensor<double>(1, {0.5});
ASSERT_EQ(model.Invoke(), kTfLiteOk);
ASSERT_NE(model.Output(0), nullptr);
ASSERT_THAT(model.Output(0), DimsAre({1, 3, 3, 1}));
}
TEST(ExternCallTest, ResizeTest) {
std::vector<TensorData> inputs = {{TensorType_FLOAT32, {1, 5, 5, 1}},
{TensorType_UINT32, {2}}};
std::vector<TensorData> output = {{TensorType_FLOAT32, {}}};
ExternCallModel model(inputs, output, 1);
model.PopulateTensor<uint32_t>(1, {3, 3});
ASSERT_EQ(model.Invoke(), kTfLiteOk);
ASSERT_NE(model.Output(0), nullptr);
ASSERT_THAT(model.Output(0), DimsAre({1, 3, 3, 1}));
}
} // namespace
} // namespace tflite
@@ -0,0 +1,93 @@
/* Copyright 2023 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/experimental/ml_adjacent/tflite/tfl_tensor_ref.h"
#include <cstddef>
#include <vector>
#include "tensorflow/lite/array.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
#include "tensorflow/lite/kernels/internal/compatibility.h"
#include "tensorflow/lite/kernels/kernel_util.h"
namespace ml_adj {
namespace data {
using ::tflite::BuildTfLiteArray;
using ::tflite::TfLiteArrayUniquePtr;
using ::tflite::TfLiteTypeGetSize;
namespace {
etype_t TflToLibType(const TfLiteType tfl_type) {
switch (tfl_type) {
case kTfLiteFloat32:
return etype_t::f32;
case kTfLiteInt32:
return etype_t::i32;
case kTfLiteFloat64:
return etype_t::f64;
default:
return etype_t::i32;
}
}
} // namespace
TflTensorRef::TflTensorRef(const TfLiteTensor* tfl_tensor)
: DataRef(TflToLibType(tfl_tensor->type)), tfl_tensor_(tfl_tensor) {
dims_.assign(tfl_tensor->dims->data,
tfl_tensor->dims->data + tfl_tensor->dims->size);
}
const void* TflTensorRef::Data() const { return tfl_tensor_->data.data; }
ind_t TflTensorRef::NumElements() const {
return tfl_tensor_->bytes / TfLiteTypeGetSize(tfl_tensor_->type);
}
size_t TflTensorRef::Bytes() const { return tfl_tensor_->bytes; }
MutableTflTensorRef::MutableTflTensorRef(TfLiteTensor* tfl_tensor,
TfLiteContext* tfl_ctx)
: MutableDataRef(TflToLibType(tfl_tensor->type)),
tfl_tensor_(tfl_tensor),
tfl_ctx_(tfl_ctx) {
dims_.assign(tfl_tensor->dims->data,
tfl_tensor->dims->data + tfl_tensor->dims->size);
}
void MutableTflTensorRef::Resize(dims_t&& dims) {
TfLiteArrayUniquePtr<int> arr =
BuildTfLiteArray(std::vector<int>(dims.begin(), dims.end()));
TFLITE_CHECK_EQ(tfl_ctx_->ResizeTensor(tfl_ctx_, tfl_tensor_, arr.release()),
kTfLiteOk);
dims_ = dims;
}
const void* MutableTflTensorRef::Data() const { return tfl_tensor_->data.data; }
ind_t MutableTflTensorRef::NumElements() const {
return tfl_tensor_->bytes / TfLiteTypeGetSize(tfl_tensor_->type);
}
size_t MutableTflTensorRef::Bytes() const { return tfl_tensor_->bytes; }
void* MutableTflTensorRef::Data() { return tfl_tensor_->data.data; }
} // namespace data
} // namespace ml_adj
@@ -0,0 +1,74 @@
/* Copyright 2023 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.
==============================================================================*/
#ifndef TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_TFL_TENSOR_REF_H_
#define TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_TFL_TENSOR_REF_H_
#include <cstddef>
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
namespace ml_adj::data {
// Immutable wrapper of `TfLiteTensor`.
class TflTensorRef : public DataRef {
public:
explicit TflTensorRef(const TfLiteTensor* tfl_tensor);
// TODO(b/290283768) Implement copy and move semantics.
TflTensorRef(const TflTensorRef&) = delete;
TflTensorRef(TflTensorRef&&) = delete;
TflTensorRef& operator=(const TflTensorRef&) = delete;
TflTensorRef& operator=(TflTensorRef&&) = delete;
const void* Data() const override;
ind_t NumElements() const override;
size_t Bytes() const override;
private:
const TfLiteTensor* const tfl_tensor_;
};
// Mutable wrapper of `TfLiteTensor`.
class MutableTflTensorRef : public MutableDataRef {
public:
MutableTflTensorRef(TfLiteTensor* tfl_tensor, TfLiteContext* tfl_ctx);
// TODO(b/290283768) Implement copy and move semantics.
MutableTflTensorRef(const MutableTflTensorRef&) = delete;
MutableTflTensorRef(MutableTflTensorRef&&) = delete;
MutableTflTensorRef& operator=(const MutableTflTensorRef&) = delete;
MutableTflTensorRef& operator=(MutableTflTensorRef&&) = delete;
const void* Data() const override;
ind_t NumElements() const override;
size_t Bytes() const override;
void Resize(dims_t&& dims) override;
void* Data() override;
private:
TfLiteTensor* const tfl_tensor_;
TfLiteContext* tfl_ctx_;
};
} // namespace ml_adj::data
#endif // TENSORFLOW_LITE_EXPERIMENTAL_ML_ADJACENT_TFLITE_TFL_TENSOR_REF_H_
@@ -0,0 +1,156 @@
/* Copyright 2023 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/experimental/ml_adjacent/tflite/tfl_tensor_ref.h"
#include <algorithm>
#include <cstddef>
#include <memory>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "absl/types/span.h"
#include "tensorflow/lite/core/c/c_api_types.h"
#include "tensorflow/lite/core/c/common.h"
#include "tensorflow/lite/experimental/ml_adjacent/lib.h"
#include "tensorflow/lite/kernels/internal/compatibility.h"
#include "tensorflow/lite/kernels/kernel_util.h"
#include "tensorflow/lite/kernels/test_util.h"
#include "tensorflow/lite/util.h"
namespace ml_adj {
namespace data {
namespace {
using ::testing::Each;
using ::tflite::BuildTfLiteTensor;
using ::tflite::DimsAre;
using ::tflite::NumElements;
using ::tflite::TensorUniquePtr;
// Mock implementation of `ResizeTensor`.
TfLiteStatus SimpleResizeTensor(TfLiteContext*, TfLiteTensor* tensor,
TfLiteIntArray* new_size) {
TFLITE_CHECK(tensor->type == kTfLiteFloat32);
size_t num_bytes = NumElements(new_size) * sizeof(float);
TF_LITE_ENSURE_STATUS(TfLiteTensorRealloc(num_bytes, tensor));
if (tensor->dims != nullptr) {
TfLiteIntArrayFree(tensor->dims);
}
tensor->dims = new_size;
return kTfLiteOk;
}
std::unique_ptr<TfLiteContext> MakeSimpleContext() {
auto ctx = std::make_unique<TfLiteContext>();
ctx->ResizeTensor = SimpleResizeTensor;
return ctx;
}
TEST(ImmutableTensorRefTest, ConstructsAndManifestsTensorData) {
TensorUniquePtr tfl_tensor =
BuildTfLiteTensor(kTfLiteFloat32, {2, 2}, kTfLiteDynamic);
std::fill(tfl_tensor->data.f, tfl_tensor->data.f + 4, 2.0f);
TflTensorRef ref(tfl_tensor.get());
ASSERT_EQ(ref.Type(), etype_t::f32);
ASSERT_EQ(ref.Dims(), (dims_t{2, 2}));
ASSERT_EQ(ref.Bytes(), 4 * sizeof(float));
absl::Span<const float> data(reinterpret_cast<const float*>(ref.Data()), 4);
EXPECT_THAT(data, Each(2.0f));
}
TEST(MutableTensorRefTest, ConstructsAndManifestsTensorData) {
TensorUniquePtr tfl_tensor =
BuildTfLiteTensor(kTfLiteFloat32, {2, 2}, kTfLiteDynamic);
std::fill(tfl_tensor->data.f, tfl_tensor->data.f + 4, 2.0f);
MutableTflTensorRef ref(tfl_tensor.get(), nullptr);
ASSERT_EQ(ref.Type(), etype_t::f32);
ASSERT_EQ(ref.Dims(), (dims_t{2, 2}));
ASSERT_EQ(ref.Bytes(), 4 * sizeof(float));
absl::Span<const float> data(reinterpret_cast<const float*>(ref.Data()), 4);
EXPECT_THAT(data, Each(2.0f));
}
TEST(MutableTensorRefTest, TensorRefWritesDataToTensor) {
TensorUniquePtr tfl_tensor =
BuildTfLiteTensor(kTfLiteFloat32, {3, 3}, kTfLiteDynamic);
MutableTflTensorRef ref(tfl_tensor.get(), nullptr);
ASSERT_EQ(ref.Type(), etype_t::f32);
ASSERT_EQ(ref.Dims(), (dims_t{3, 3}));
ASSERT_EQ(ref.Bytes(), 9 * sizeof(float));
absl::Span<float> data(reinterpret_cast<float*>(ref.Data()), 9);
std::fill(data.begin(), data.end(), 3.0f);
EXPECT_THAT(absl::Span<const float>(tfl_tensor->data.f, 9), Each(3.0f));
}
TEST(MutableTensorRefTest, ResizeIncreaseSize) {
TensorUniquePtr tfl_tensor =
BuildTfLiteTensor(kTfLiteFloat32, {2, 3}, kTfLiteDynamic);
std::unique_ptr<TfLiteContext> ctx = MakeSimpleContext();
MutableTflTensorRef ref(tfl_tensor.get(), ctx.get());
ASSERT_EQ(ref.Type(), etype_t::f32);
ASSERT_EQ(ref.Dims(), (dims_t{2, 3}));
ASSERT_EQ(ref.Bytes(), 6 * sizeof(float));
ref.Resize({3, 3});
ASSERT_EQ(ref.Dims(), (dims_t{3, 3}));
ASSERT_EQ(ref.Bytes(), 9 * sizeof(float));
// Sanitizers will check buffer is correct size.
absl::Span<float> ref_data(reinterpret_cast<float*>(ref.Data()), 9);
// Check underlying tensor is also resized.
ASSERT_THAT(tfl_tensor.get(), DimsAre({3, 3}));
ASSERT_EQ(tfl_tensor->bytes, ref.Bytes());
// Check share same buffer.
ASSERT_EQ(ref.Data(), tfl_tensor->data.data);
}
TEST(MutableTensorRefTest, ResizeDecreasesSize) {
TensorUniquePtr tfl_tensor =
BuildTfLiteTensor(kTfLiteFloat32, {2, 3}, kTfLiteDynamic);
std::unique_ptr<TfLiteContext> ctx = MakeSimpleContext();
MutableTflTensorRef ref(tfl_tensor.get(), ctx.get());
ASSERT_EQ(ref.Type(), etype_t::f32);
ASSERT_EQ(ref.Dims(), (dims_t{2, 3}));
ASSERT_EQ(ref.Bytes(), 6 * sizeof(float));
ref.Resize({2, 2});
ASSERT_EQ(ref.Dims(), (dims_t{2, 2}));
ASSERT_EQ(ref.Bytes(), 4 * sizeof(float));
// Sanitizers will check buffer is correct size.
absl::Span<float> ref_data(reinterpret_cast<float*>(ref.Data()), 4);
// Check underlying tensor is also resized.
ASSERT_THAT(tfl_tensor.get(), DimsAre({2, 2}));
ASSERT_EQ(tfl_tensor->bytes, ref.Bytes());
// Check share same buffer.
ASSERT_EQ(ref.Data(), tfl_tensor->data.data);
}
} // namespace
} // namespace data
} // namespace ml_adj