xref: /aosp_15_r20/external/tensorflow/tensorflow/lite/delegates/delegate_test_util.h (revision b6fb3261f9314811a0f4371741dbb8839866f948)
1 /* Copyright 2020 The TensorFlow Authors. All Rights Reserved.
2 
3 Licensed under the Apache License, Version 2.0 (the "License");
4 you may not use this file except in compliance with the License.
5 You may obtain a copy of the License at
6 
7     http://www.apache.org/licenses/LICENSE-2.0
8 
9 Unless required by applicable law or agreed to in writing, software
10 distributed under the License is distributed on an "AS IS" BASIS,
11 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 See the License for the specific language governing permissions and
13 limitations under the License.
14 ==============================================================================*/
15 #ifndef TENSORFLOW_LITE_DELEGATES_DELEGATE_TEST_UTIL_
16 #define TENSORFLOW_LITE_DELEGATES_DELEGATE_TEST_UTIL_
17 
18 #include <stdint.h>
19 
20 #include <memory>
21 #include <utility>
22 #include <vector>
23 
24 #include <gtest/gtest.h>
25 #include "third_party/eigen3/Eigen/Core"
26 #include "tensorflow/lite/interpreter.h"
27 #include "tensorflow/lite/kernels/internal/compatibility.h"
28 #include "tensorflow/lite/kernels/register.h"
29 
30 namespace tflite {
31 namespace delegates {
32 namespace test_utils {
33 
34 // Build a kernel registration for a custom addition op that adds its two
35 // tensor inputs to produce a tensor output.
36 TfLiteRegistration AddOpRegistration();
37 
38 class SimpleDelegate {
39  public:
40   // Create a simple implementation of a TfLiteDelegate. We use the C++ class
41   // SimpleDelegate and it can produce a handle TfLiteDelegate that is
42   // value-copyable and compatible with TfLite.
43   //
44   // Parameters:
45   //   nodes: Indices of the graph nodes that the delegate will handle.
46   //   fail_node_prepare: To simulate failure of Delegate node's Prepare().
47   //   min_ops_per_subset: If >0, partitioning preview is used to choose only
48   //     those subsets with min_ops_per_subset number of nodes.
49   //   fail_node_invoke: To simulate failure of Delegate node's Invoke().
50   //   automatic_shape_propagation: This assumes that the runtime will
51   //     propagate shapes using the original execution plan.
52   //   custom_op: If true, the graph nodes specified in the 'nodes' parameter
53   //     should be custom ops with name "my_add"; if false, they should be
54   //     the builtin ADD operator.
55   //   set_output_tensor_dynamic: If True, this delegate sets output tensor to
56   //     as dynamic during kernel Prepare.
57   explicit SimpleDelegate(const std::vector<int>& nodes,
58                           int64_t delegate_flags = kTfLiteDelegateFlagsNone,
59                           bool fail_node_prepare = false,
60                           int min_ops_per_subset = 0,
61                           bool fail_node_invoke = false,
62                           bool automatic_shape_propagation = false,
63                           bool custom_op = true,
64                           bool set_output_tensor_dynamic = false);
65 
66   static std::unique_ptr<SimpleDelegate> DelegateWithRuntimeShapePropagation(
67       const std::vector<int>& nodes, int64_t delegate_flags,
68       int min_ops_per_subset);
69 
70   static std::unique_ptr<SimpleDelegate> DelegateWithDynamicOutput(
71       const std::vector<int>& nodes);
72 
73   TfLiteRegistration FakeFusedRegistration();
74 
get_tf_lite_delegate()75   TfLiteDelegate* get_tf_lite_delegate() { return &delegate_; }
76 
min_ops_per_subset()77   int min_ops_per_subset() { return min_ops_per_subset_; }
78 
79  private:
80   std::vector<int> nodes_;
81   TfLiteDelegate delegate_;
82   bool fail_delegate_node_prepare_ = false;
83   int min_ops_per_subset_ = 0;
84   bool fail_delegate_node_invoke_ = false;
85   bool automatic_shape_propagation_ = false;
86   bool custom_op_ = true;
87   bool set_output_tensor_dynamic_ = false;
88 };
89 
90 // Base class for single/multiple delegate tests.
91 // Friend of Interpreter to access private methods.
92 class TestDelegation {
93  public:
94   // Returns an empty interpreter that uses the same default delegates that are
95   // normally enabled by default.
NewInterpreterWithDefaultDelegates()96   static std::unique_ptr<Interpreter> NewInterpreterWithDefaultDelegates() {
97     auto interpreter = std::make_unique<Interpreter>();
98     interpreter->lazy_delegate_providers_ =
99         tflite::ops::builtin::BuiltinOpResolver().GetDelegateCreators();
100     return interpreter;
101   }
102 
103  protected:
RemoveAllDelegates()104   TfLiteStatus RemoveAllDelegates() {
105     return interpreter_->RemoveAllDelegates();
106   }
107 
108   void SetUpSubgraph(Subgraph* subgraph);
109   void AddSubgraphs(int subgraphs_to_add,
110                     int* first_new_subgraph_index = nullptr);
111 
112   std::unique_ptr<Interpreter> interpreter_;
113 };
114 
115 // Tests scenarios involving a single delegate.
116 class TestDelegate : public TestDelegation, public ::testing::Test {
117  protected:
118   void SetUp() override;
119 
120   void TearDown() override;
121 
122   TfLiteBufferHandle last_allocated_handle_ = kTfLiteNullBufferHandle;
123 
AllocateBufferHandle()124   TfLiteBufferHandle AllocateBufferHandle() { return ++last_allocated_handle_; }
125 
126   std::unique_ptr<SimpleDelegate> delegate_, delegate2_;
127 };
128 
129 // Tests scenarios involving two delegates, parametrized by the first & second
130 // delegate's flags.
131 class TestTwoDelegates
132     : public TestDelegation,
133       public ::testing::TestWithParam<
134           std::pair<TfLiteDelegateFlags, TfLiteDelegateFlags>> {
135  protected:
136   void SetUp() override;
137 
138   void TearDown() override;
139 
140   std::unique_ptr<SimpleDelegate> delegate_, delegate2_;
141 };
142 
143 // Tests delegate functionality related to FP16 graphs.
144 // Model architecture:
145 // 1->DEQ->2   4->DEQ->5   7->DEQ->8   10->DEQ->11
146 //         |           |           |            |
147 // 0----->ADD->3----->ADD->6----->MUL->9------>ADD-->12
148 // Input: 0, Output:12.
149 // All constants are 2, so the function is: (x + 2 + 2) * 2 + 2 = 2x + 10
150 //
151 // Delegate only supports ADD, so can have up to two delegated partitions.
152 // TODO(b/156707497): Add more cases here once we have landed CPU kernels
153 // supporting FP16.
154 class TestFP16Delegation : public ::testing::TestWithParam<int> {
155  protected:
156   void SetUp() override;
157 
158   void VerifyInvoke();
159 
TearDown()160   void TearDown() override { interpreter_.reset(); }
161 
162  protected:
163   class FP16Delegate {
164    public:
165     // Uses FP16GraphPartitionHelper to accept ADD nodes with fp16 input.
166     explicit FP16Delegate(int num_delegated_subsets,
167                           bool fail_node_prepare = false,
168                           bool fail_node_invoke = false);
169 
170     TfLiteRegistration FakeFusedRegistration();
171 
get_tf_lite_delegate()172     TfLiteDelegate* get_tf_lite_delegate() { return &delegate_; }
173 
num_delegated_subsets()174     int num_delegated_subsets() { return num_delegated_subsets_; }
175 
176    private:
177     TfLiteDelegate delegate_;
178     int num_delegated_subsets_;
179     bool fail_delegate_node_prepare_ = false;
180     bool fail_delegate_node_invoke_ = false;
181   };
182 
183   std::unique_ptr<Interpreter> interpreter_;
184   std::unique_ptr<FP16Delegate> delegate_;
185   Eigen::half float16_const_;
186 };
187 
188 }  // namespace test_utils
189 }  // namespace delegates
190 }  // namespace tflite
191 
192 #endif  // TENSORFLOW_LITE_DELEGATES_DELEGATE_TEST_UTIL_
193