@@ -27,60 +27,110 @@ namespace {
27
27
28
28
using ::testing::ElementsAre;
29
29
30
+ using flatbuffers::Offset;
31
+ using flatbuffers::Vector;
30
32
class ImportTest : public ::testing::Test {
31
33
protected:
32
34
template <typename T>
33
- flatbuffers::Offset<flatbuffers::Vector<unsigned char >> CreateDataVector (
34
- const std::vector<T>& data) {
35
+ Offset<Vector<unsigned char >> CreateDataVector (const std::vector<T>& data) {
35
36
return builder_.CreateVector (reinterpret_cast <const uint8_t *>(data.data ()),
36
37
sizeof (T) * data.size ());
37
38
}
38
- // This is a very simplistic model. We are not interested in testing all the
39
- // details here, since tf.mini's testing framework will be exercising all the
40
- // conversions multiple times, and the conversion of operators is tested by
41
- // separate unittests.
42
- void BuildTestModel () {
43
- // The tensors
39
+
40
+ Offset<Vector<Offset<::tflite::Buffer>>> BuildBuffers () {
41
+ auto buf0 = ::tflite::CreateBuffer (builder_, CreateDataVector<float >({}));
42
+ auto buf1 = ::tflite::CreateBuffer (
43
+ builder_, CreateDataVector<float >({1 .0f , 2 .0f , 3 .0f , 4 .0f }));
44
+ auto buf2 =
45
+ ::tflite::CreateBuffer (builder_, CreateDataVector<float >({3 .0f , 4 .0f }));
46
+ return builder_.CreateVector (
47
+ std::vector<Offset<::tflite::Buffer>>({buf0, buf1, buf2}));
48
+ }
49
+
50
+ Offset<Vector<Offset<::tflite::Tensor>>> BuildTensors () {
44
51
auto q = ::tflite::CreateQuantizationParameters (
45
52
builder_,
46
53
/* min=*/ builder_.CreateVector <float >({0 .1f }),
47
54
/* max=*/ builder_.CreateVector <float >({0 .2f }),
48
55
/* scale=*/ builder_.CreateVector <float >({0 .3f }),
49
56
/* zero_point=*/ builder_.CreateVector <int64_t >({100ll }));
50
- auto buf0 = ::tflite::CreateBuffer (builder_, CreateDataVector<float >({}));
51
- auto buf1 =
52
- ::tflite::CreateBuffer (builder_, CreateDataVector<float >({1 .0f , 2 .0f }));
53
- auto buf2 =
54
- ::tflite::CreateBuffer (builder_, CreateDataVector<float >({3 .0f }));
55
- auto buffers = builder_.CreateVector (
56
- std::vector<flatbuffers::Offset<::tflite::Buffer>>({buf0, buf1, buf2}));
57
- auto t1 = ::tflite::CreateTensor (builder_,
58
- builder_.CreateVector <int >({1 , 2 , 3 , 4 }),
59
- ::tflite::TensorType_FLOAT32, 1 ,
60
- builder_.CreateString (" tensor_one" ), q);
57
+ auto t1 =
58
+ ::tflite::CreateTensor (builder_, builder_.CreateVector<int >({1 , 2 , 2 }),
59
+ ::tflite::TensorType_FLOAT32, 1,
60
+ builder_.CreateString(" tensor_one" ), q);
61
61
auto t2 =
62
62
::tflite::CreateTensor (builder_, builder_.CreateVector<int >({2 , 1 }),
63
63
::tflite::TensorType_FLOAT32, 2,
64
64
builder_.CreateString(" tensor_two" ), q);
65
- auto tensors = builder_.CreateVector (
66
- std::vector<flatbuffers::Offset<::tflite::Tensor>>({t1, t2}));
67
-
68
- // The operator codes.
69
- auto c1 =
70
- ::tflite::CreateOperatorCode (builder_, ::tflite::BuiltinOperator_CUSTOM,
71
- builder_.CreateString(" custom_op_one" ));
72
- auto c2 = ::tflite::CreateOperatorCode (
73
- builder_, ::tflite::BuiltinOperator_CONV_2D, 0 );
74
- auto opcodes = builder_.CreateVector (
75
- std::vector<flatbuffers::Offset<::tflite::OperatorCode>>({c1, c2}));
76
-
77
- auto subgraph = ::tflite::CreateSubGraph (builder_, tensors, 0 , 0 , 0 );
78
- std::vector<flatbuffers::Offset<::tflite::SubGraph>> subgraph_vector (
79
- {subgraph});
80
- auto subgraphs = builder_.CreateVector (subgraph_vector);
65
+ return builder_.CreateVector (
66
+ std::vector<Offset<::tflite::Tensor>>({t1, t2}));
67
+ }
68
+
69
+ Offset<Vector<Offset<::tflite::OperatorCode>>> BuildOpCodes (
70
+ std::initializer_list<::tflite::BuiltinOperator> op_codes) {
71
+ std::vector<Offset<::tflite::OperatorCode>> op_codes_vector;
72
+ for (auto op : op_codes) {
73
+ op_codes_vector.push_back (::tflite::CreateOperatorCode (builder_, op, 0 ));
74
+ }
75
+ return builder_.CreateVector (op_codes_vector);
76
+ }
77
+
78
+ Offset<Vector<Offset<::tflite::OperatorCode>>> BuildOpCodes () {
79
+ return BuildOpCodes ({::tflite::BuiltinOperator_MAX_POOL_2D,
80
+ ::tflite::BuiltinOperator_CONV_2D});
81
+ }
82
+
83
+ Offset<Vector<Offset<::tflite::Operator>>> BuildOperators (
84
+ std::initializer_list<int > inputs, std::initializer_list<int > outputs) {
85
+ auto is = builder_.CreateVector <int >(inputs);
86
+ if (inputs.size () == 0 ) is = 0 ;
87
+ auto os = builder_.CreateVector <int >(outputs);
88
+ if (outputs.size () == 0 ) os = 0 ;
89
+ auto op = ::tflite::CreateOperator (
90
+ builder_, 0 , is, os, ::tflite::BuiltinOptions_Conv2DOptions,
91
+ ::tflite::CreateConv2DOptions (builder_, ::tflite::Padding_VALID, 1 , 1 ,
92
+ ::tflite::ActivationFunctionType_NONE)
93
+ .Union(),
94
+ /* custom_options=*/ 0, ::tflite::CustomOptionsFormat_FLEXBUFFERS);
95
+
96
+ return builder_.CreateVector (std::vector<Offset<::tflite::Operator>>({op}));
97
+ }
98
+
99
+ Offset<Vector<Offset<::tflite::Operator>>> BuildOperators () {
100
+ return BuildOperators ({0 }, {1 });
101
+ }
102
+
103
+ Offset<Vector<Offset<::tflite::SubGraph>>> BuildSubGraphs (
104
+ Offset<Vector<Offset<::tflite::Tensor>>> tensors,
105
+ Offset<Vector<Offset<::tflite::Operator>>> operators,
106
+ int num_sub_graphs = 1 ) {
107
+ std::vector<int32_t > inputs = {0 };
108
+ std::vector<int32_t > outputs = {1 };
109
+ std::vector<Offset<::tflite::SubGraph>> v;
110
+ for (int i = 0 ; i < num_sub_graphs; ++i) {
111
+ v.push_back (::tflite::CreateSubGraph (
112
+ builder_, tensors, builder_.CreateVector (inputs),
113
+ builder_.CreateVector (outputs), operators,
114
+ builder_.CreateString (" subgraph" )));
115
+ }
116
+ return builder_.CreateVector (v);
117
+ }
118
+
119
+ // This is a very simplistic model. We are not interested in testing all the
120
+ // details here, since tf.mini's testing framework will be exercising all the
121
+ // conversions multiple times, and the conversion of operators is tested by
122
+ // separate unittests.
123
+ void BuildTestModel () {
124
+ auto buffers = BuildBuffers ();
125
+ auto tensors = BuildTensors ();
126
+ auto opcodes = BuildOpCodes ();
127
+ auto operators = BuildOperators ();
128
+ auto subgraphs = BuildSubGraphs (tensors, operators);
81
129
auto s = builder_.CreateString (" " );
82
- builder_.Finish (::tflite::CreateModel (builder_, TFLITE_SCHEMA_VERSION,
83
- opcodes, subgraphs, s, buffers));
130
+
131
+ ::tflite::FinishModelBuffer (
132
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION,
133
+ opcodes, subgraphs, s, buffers));
84
134
85
135
input_model_ = ::tflite::GetModel (builder_.GetBufferPointer ());
86
136
}
@@ -89,7 +139,6 @@ class ImportTest : public ::testing::Test {
89
139
builder_.GetSize ());
90
140
}
91
141
flatbuffers::FlatBufferBuilder builder_;
92
- // const uint8_t* buffer_ = nullptr;
93
142
const ::tflite::Model* input_model_ = nullptr ;
94
143
};
95
144
@@ -106,7 +155,7 @@ TEST_F(ImportTest, LoadOperatorsTable) {
106
155
107
156
details::OperatorsTable operators;
108
157
details::LoadOperatorsTable (*input_model_, &operators);
109
- EXPECT_THAT (operators, ElementsAre (" custom_op_one " , " CONV_2D" ));
158
+ EXPECT_THAT (operators, ElementsAre (" MAX_POOL_2D " , " CONV_2D" ));
110
159
}
111
160
112
161
TEST_F (ImportTest, Tensors) {
@@ -118,9 +167,9 @@ TEST_F(ImportTest, Tensors) {
118
167
Array& a1 = model->GetArray (" tensor_one" );
119
168
EXPECT_EQ (ArrayDataType::kFloat , a1.data_type );
120
169
EXPECT_THAT (a1.GetBuffer <ArrayDataType::kFloat >().data ,
121
- ElementsAre (1 .0f , 2 .0f ));
170
+ ElementsAre (1 .0f , 2 .0f , 3 . 0f , 4 . 0f ));
122
171
ASSERT_TRUE (a1.has_shape ());
123
- EXPECT_THAT (a1.shape ().dims (), ElementsAre (1 , 2 , 3 , 4 ));
172
+ EXPECT_THAT (a1.shape ().dims (), ElementsAre (1 , 2 , 2 ));
124
173
125
174
const auto & mm = a1.minmax ;
126
175
ASSERT_TRUE (mm.get ());
@@ -133,6 +182,80 @@ TEST_F(ImportTest, Tensors) {
133
182
EXPECT_EQ (100 , q->zero_point );
134
183
}
135
184
185
+ TEST_F (ImportTest, NoBuffers) {
186
+ auto buffers = 0 ;
187
+ auto tensors = BuildTensors ();
188
+ auto opcodes = BuildOpCodes ();
189
+ auto operators = BuildOperators ();
190
+ auto subgraphs = BuildSubGraphs (tensors, operators);
191
+ auto comment = builder_.CreateString (" " );
192
+ ::tflite::FinishModelBuffer (
193
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
194
+ subgraphs, comment, buffers));
195
+ EXPECT_DEATH (Import (ModelFlags (), InputModelAsString ()),
196
+ " Missing 'buffers' section." );
197
+ }
198
+
199
+ TEST_F (ImportTest, NoInputs) {
200
+ auto buffers = BuildBuffers ();
201
+ auto tensors = BuildTensors ();
202
+ auto opcodes = BuildOpCodes ();
203
+ auto operators = BuildOperators ({}, {1 });
204
+ auto subgraphs = BuildSubGraphs (tensors, operators);
205
+ auto comment = builder_.CreateString (" " );
206
+ ::tflite::FinishModelBuffer (
207
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
208
+ subgraphs, comment, buffers));
209
+ EXPECT_DEATH (Import (ModelFlags (), InputModelAsString ()),
210
+ " Missing 'inputs' for operator." );
211
+ }
212
+
213
+ TEST_F (ImportTest, NoOutputs) {
214
+ auto buffers = BuildBuffers ();
215
+ auto tensors = BuildTensors ();
216
+ auto opcodes = BuildOpCodes ();
217
+ auto operators = BuildOperators ({0 }, {});
218
+ auto subgraphs = BuildSubGraphs (tensors, operators);
219
+ auto comment = builder_.CreateString (" " );
220
+ ::tflite::FinishModelBuffer (
221
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
222
+ subgraphs, comment, buffers));
223
+ EXPECT_DEATH (Import (ModelFlags (), InputModelAsString ()),
224
+ " Missing 'outputs' for operator." );
225
+ }
226
+
227
+ TEST_F (ImportTest, InvalidOpCode) {
228
+ auto buffers = BuildBuffers ();
229
+ auto tensors = BuildTensors ();
230
+ auto opcodes = BuildOpCodes ({static_cast <::tflite::BuiltinOperator>(-1 ),
231
+ ::tflite::BuiltinOperator_CONV_2D});
232
+ auto operators = BuildOperators ();
233
+ auto subgraphs = BuildSubGraphs (tensors, operators);
234
+ auto comment = builder_.CreateString (" " );
235
+ ::tflite::FinishModelBuffer (
236
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
237
+ subgraphs, comment, buffers));
238
+ EXPECT_DEATH (Import (ModelFlags (), InputModelAsString ()),
239
+ " Operator id '-1' is out of range." );
240
+ }
241
+
242
+ TEST_F (ImportTest, MultipleSubGraphs) {
243
+ auto buffers = BuildBuffers ();
244
+ auto tensors = BuildTensors ();
245
+ auto opcodes = BuildOpCodes ();
246
+ auto operators = BuildOperators ();
247
+ auto subgraphs = BuildSubGraphs (tensors, operators, 2 );
248
+ auto comment = builder_.CreateString (" " );
249
+ ::tflite::FinishModelBuffer (
250
+ builder_, ::tflite::CreateModel(builder_, TFLITE_SCHEMA_VERSION, opcodes,
251
+ subgraphs, comment, buffers));
252
+
253
+ input_model_ = ::tflite::GetModel (builder_.GetBufferPointer ());
254
+
255
+ EXPECT_DEATH (Import (ModelFlags (), InputModelAsString ()),
256
+ " Number of subgraphs in tflite should be exactly 1." );
257
+ }
258
+
136
259
// TODO(ahentz): still need tests for Operators and IOTensors.
137
260
138
261
} // namespace
0 commit comments