1 /* Copyright 2016 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 #include "tensorflow/core/example/feature_util.h"
16
17 #include <vector>
18
19 #include "tensorflow/core/example/example.pb.h"
20 #include "tensorflow/core/platform/test.h"
21 #include "tensorflow/core/platform/types.h"
22
23 namespace tensorflow {
24 namespace {
25
26 const float kTolerance = 1e-5;
27
TEST(GetFeatureValuesInt64Test,ReadsASingleValue)28 TEST(GetFeatureValuesInt64Test, ReadsASingleValue) {
29 Example example;
30 (*example.mutable_features()->mutable_feature())["tag"]
31 .mutable_int64_list()
32 ->add_value(42);
33
34 auto tag = GetFeatureValues<protobuf_int64>("tag", example);
35
36 ASSERT_EQ(1, tag.size());
37 EXPECT_EQ(42, tag.Get(0));
38 }
39
TEST(GetFeatureValuesInt64Test,ReadsASingleValueFromFeature)40 TEST(GetFeatureValuesInt64Test, ReadsASingleValueFromFeature) {
41 Feature feature;
42 feature.mutable_int64_list()->add_value(42);
43
44 auto values = GetFeatureValues<protobuf_int64>(feature);
45
46 ASSERT_EQ(1, values.size());
47 EXPECT_EQ(42, values.Get(0));
48 }
49
TEST(GetFeatureValuesInt64Test,WritesASingleValue)50 TEST(GetFeatureValuesInt64Test, WritesASingleValue) {
51 Example example;
52
53 GetFeatureValues<protobuf_int64>("tag", &example)->Add(42);
54
55 ASSERT_EQ(1,
56 example.features().feature().at("tag").int64_list().value_size());
57 EXPECT_EQ(42, example.features().feature().at("tag").int64_list().value(0));
58 }
59
TEST(GetFeatureValuesInt64Test,WritesASingleValueToFeature)60 TEST(GetFeatureValuesInt64Test, WritesASingleValueToFeature) {
61 Feature feature;
62
63 GetFeatureValues<protobuf_int64>(&feature)->Add(42);
64
65 ASSERT_EQ(1, feature.int64_list().value_size());
66 EXPECT_EQ(42, feature.int64_list().value(0));
67 }
68
TEST(GetFeatureValuesInt64Test,CheckUntypedFieldExistence)69 TEST(GetFeatureValuesInt64Test, CheckUntypedFieldExistence) {
70 Example example;
71 ASSERT_FALSE(HasFeature("tag", example));
72
73 GetFeatureValues<protobuf_int64>("tag", &example)->Add(0);
74
75 EXPECT_TRUE(HasFeature("tag", example));
76 }
77
TEST(GetFeatureValuesInt64Test,CheckTypedFieldExistence)78 TEST(GetFeatureValuesInt64Test, CheckTypedFieldExistence) {
79 Example example;
80
81 GetFeatureValues<float>("tag", &example)->Add(3.14);
82 ASSERT_FALSE(HasFeature<protobuf_int64>("tag", example));
83
84 GetFeatureValues<protobuf_int64>("tag", &example)->Add(42);
85
86 EXPECT_TRUE(HasFeature<protobuf_int64>("tag", example));
87 auto tag_ro = GetFeatureValues<protobuf_int64>("tag", example);
88 ASSERT_EQ(1, tag_ro.size());
89 EXPECT_EQ(42, tag_ro.Get(0));
90 }
91
TEST(GetFeatureValuesInt64Test,CopyIterableToAField)92 TEST(GetFeatureValuesInt64Test, CopyIterableToAField) {
93 Example example;
94 std::vector<int> values{1, 2, 3};
95
96 std::copy(values.begin(), values.end(),
97 protobuf::RepeatedFieldBackInserter(
98 GetFeatureValues<protobuf_int64>("tag", &example)));
99
100 auto tag_ro = GetFeatureValues<protobuf_int64>("tag", example);
101 ASSERT_EQ(3, tag_ro.size());
102 EXPECT_EQ(1, tag_ro.Get(0));
103 EXPECT_EQ(2, tag_ro.Get(1));
104 EXPECT_EQ(3, tag_ro.Get(2));
105 }
106
TEST(GetFeatureValuesFloatTest,ReadsASingleValueFromFeature)107 TEST(GetFeatureValuesFloatTest, ReadsASingleValueFromFeature) {
108 Feature feature;
109 feature.mutable_float_list()->add_value(3.14);
110
111 auto values = GetFeatureValues<float>(feature);
112
113 ASSERT_EQ(1, values.size());
114 EXPECT_NEAR(3.14, values.Get(0), kTolerance);
115 }
116
TEST(GetFeatureValuesFloatTest,ReadsASingleValue)117 TEST(GetFeatureValuesFloatTest, ReadsASingleValue) {
118 Example example;
119 (*example.mutable_features()->mutable_feature())["tag"]
120 .mutable_float_list()
121 ->add_value(3.14);
122
123 auto tag = GetFeatureValues<float>("tag", example);
124
125 ASSERT_EQ(1, tag.size());
126 EXPECT_NEAR(3.14, tag.Get(0), kTolerance);
127 }
128
TEST(GetFeatureValuesFloatTest,WritesASingleValueToFeature)129 TEST(GetFeatureValuesFloatTest, WritesASingleValueToFeature) {
130 Feature feature;
131
132 GetFeatureValues<float>(&feature)->Add(3.14);
133
134 ASSERT_EQ(1, feature.float_list().value_size());
135 EXPECT_NEAR(3.14, feature.float_list().value(0), kTolerance);
136 }
137
TEST(GetFeatureValuesFloatTest,WritesASingleValue)138 TEST(GetFeatureValuesFloatTest, WritesASingleValue) {
139 Example example;
140
141 GetFeatureValues<float>("tag", &example)->Add(3.14);
142
143 ASSERT_EQ(1,
144 example.features().feature().at("tag").float_list().value_size());
145 EXPECT_NEAR(3.14,
146 example.features().feature().at("tag").float_list().value(0),
147 kTolerance);
148 }
149
TEST(GetFeatureValuesFloatTest,CheckTypedFieldExistence)150 TEST(GetFeatureValuesFloatTest, CheckTypedFieldExistence) {
151 Example example;
152
153 GetFeatureValues<protobuf_int64>("tag", &example)->Add(42);
154 ASSERT_FALSE(HasFeature<float>("tag", example));
155
156 GetFeatureValues<float>("tag", &example)->Add(3.14);
157
158 EXPECT_TRUE(HasFeature<float>("tag", example));
159 auto tag_ro = GetFeatureValues<float>("tag", example);
160 ASSERT_EQ(1, tag_ro.size());
161 EXPECT_NEAR(3.14, tag_ro.Get(0), kTolerance);
162 }
163
TEST(GetFeatureValuesFloatTest,CheckTypedFieldExistenceForDeprecatedMethod)164 TEST(GetFeatureValuesFloatTest, CheckTypedFieldExistenceForDeprecatedMethod) {
165 Example example;
166
167 GetFeatureValues<protobuf_int64>("tag", &example)->Add(42);
168 ASSERT_FALSE(ExampleHasFeature<float>("tag", example));
169
170 GetFeatureValues<float>("tag", &example)->Add(3.14);
171
172 EXPECT_TRUE(ExampleHasFeature<float>("tag", example));
173 auto tag_ro = GetFeatureValues<float>("tag", example);
174 ASSERT_EQ(1, tag_ro.size());
175 EXPECT_NEAR(3.14, tag_ro.Get(0), kTolerance);
176 }
177
TEST(GetFeatureValuesStringTest,ReadsASingleValueFromFeature)178 TEST(GetFeatureValuesStringTest, ReadsASingleValueFromFeature) {
179 Feature feature;
180 feature.mutable_bytes_list()->add_value("FOO");
181
182 auto values = GetFeatureValues<string>(feature);
183
184 ASSERT_EQ(1, values.size());
185 EXPECT_EQ("FOO", values.Get(0));
186 }
187
TEST(GetFeatureValuesStringTest,ReadsASingleValue)188 TEST(GetFeatureValuesStringTest, ReadsASingleValue) {
189 Example example;
190 (*example.mutable_features()->mutable_feature())["tag"]
191 .mutable_bytes_list()
192 ->add_value("FOO");
193
194 auto tag = GetFeatureValues<string>("tag", example);
195
196 ASSERT_EQ(1, tag.size());
197 EXPECT_EQ("FOO", tag.Get(0));
198 }
199
TEST(GetFeatureValuesStringTest,WritesASingleValueToFeature)200 TEST(GetFeatureValuesStringTest, WritesASingleValueToFeature) {
201 Feature feature;
202
203 *GetFeatureValues<string>(&feature)->Add() = "FOO";
204
205 ASSERT_EQ(1, feature.bytes_list().value_size());
206 EXPECT_EQ("FOO", feature.bytes_list().value(0));
207 }
208
TEST(GetFeatureValuesStringTest,WritesASingleValue)209 TEST(GetFeatureValuesStringTest, WritesASingleValue) {
210 Example example;
211
212 *GetFeatureValues<string>("tag", &example)->Add() = "FOO";
213
214 ASSERT_EQ(1,
215 example.features().feature().at("tag").bytes_list().value_size());
216 EXPECT_EQ("FOO",
217 example.features().feature().at("tag").bytes_list().value(0));
218 }
219
TEST(GetFeatureValuesStringTest,CheckTypedFieldExistence)220 TEST(GetFeatureValuesStringTest, CheckTypedFieldExistence) {
221 Example example;
222
223 GetFeatureValues<protobuf_int64>("tag", &example)->Add(42);
224 ASSERT_FALSE(HasFeature<string>("tag", example));
225
226 *GetFeatureValues<string>("tag", &example)->Add() = "FOO";
227
228 EXPECT_TRUE(HasFeature<string>("tag", example));
229 auto tag_ro = GetFeatureValues<string>("tag", example);
230 ASSERT_EQ(1, tag_ro.size());
231 EXPECT_EQ("FOO", tag_ro.Get(0));
232 }
233
TEST(AppendFeatureValuesTest,FloatValuesFromContainer)234 TEST(AppendFeatureValuesTest, FloatValuesFromContainer) {
235 Example example;
236
237 std::vector<double> values{1.1, 2.2, 3.3};
238 AppendFeatureValues(values, "tag", &example);
239
240 auto tag_ro = GetFeatureValues<float>("tag", example);
241 ASSERT_EQ(3, tag_ro.size());
242 EXPECT_NEAR(1.1, tag_ro.Get(0), kTolerance);
243 EXPECT_NEAR(2.2, tag_ro.Get(1), kTolerance);
244 EXPECT_NEAR(3.3, tag_ro.Get(2), kTolerance);
245 }
246
TEST(AppendFeatureValuesTest,FloatValuesUsingInitializerList)247 TEST(AppendFeatureValuesTest, FloatValuesUsingInitializerList) {
248 Example example;
249
250 AppendFeatureValues({1.1, 2.2, 3.3}, "tag", &example);
251
252 auto tag_ro = GetFeatureValues<float>("tag", example);
253 ASSERT_EQ(3, tag_ro.size());
254 EXPECT_NEAR(1.1, tag_ro.Get(0), kTolerance);
255 EXPECT_NEAR(2.2, tag_ro.Get(1), kTolerance);
256 EXPECT_NEAR(3.3, tag_ro.Get(2), kTolerance);
257 }
258
TEST(SetFeatureValuesTest,FloatValuesUsingInitializerList)259 TEST(SetFeatureValuesTest, FloatValuesUsingInitializerList) {
260 Example example;
261
262 // The first set of values should be overwritten by the second.
263 AppendFeatureValues({1.1, 2.2, 3.3}, "tag", &example);
264 SetFeatureValues({10.1, 20.2, 30.3}, "tag", &example);
265
266 auto tag_ro = GetFeatureValues<float>("tag", example);
267 ASSERT_EQ(3, tag_ro.size());
268 EXPECT_NEAR(10.1, tag_ro.Get(0), kTolerance);
269 EXPECT_NEAR(20.2, tag_ro.Get(1), kTolerance);
270 EXPECT_NEAR(30.3, tag_ro.Get(2), kTolerance);
271 }
272
TEST(AppendFeatureValuesTest,Int64ValuesUsingInitializerList)273 TEST(AppendFeatureValuesTest, Int64ValuesUsingInitializerList) {
274 Example example;
275
276 std::vector<protobuf_int64> values{1, 2, 3};
277 AppendFeatureValues(values, "tag", &example);
278
279 auto tag_ro = GetFeatureValues<protobuf_int64>("tag", example);
280 ASSERT_EQ(3, tag_ro.size());
281 EXPECT_EQ(1, tag_ro.Get(0));
282 EXPECT_EQ(2, tag_ro.Get(1));
283 EXPECT_EQ(3, tag_ro.Get(2));
284 }
285
TEST(AppendFeatureValuesTest,StringValuesUsingInitializerList)286 TEST(AppendFeatureValuesTest, StringValuesUsingInitializerList) {
287 Example example;
288
289 AppendFeatureValues({"FOO", "BAR", "BAZ"}, "tag", &example);
290
291 auto tag_ro = GetFeatureValues<string>("tag", example);
292 ASSERT_EQ(3, tag_ro.size());
293 EXPECT_EQ("FOO", tag_ro.Get(0));
294 EXPECT_EQ("BAR", tag_ro.Get(1));
295 EXPECT_EQ("BAZ", tag_ro.Get(2));
296 }
297
TEST(AppendFeatureValuesTest,StringVariablesUsingInitializerList)298 TEST(AppendFeatureValuesTest, StringVariablesUsingInitializerList) {
299 Example example;
300
301 string string1("FOO");
302 string string2("BAR");
303 string string3("BAZ");
304
305 AppendFeatureValues({string1, string2, string3}, "tag", &example);
306
307 auto tag_ro = GetFeatureValues<string>("tag", example);
308 ASSERT_EQ(3, tag_ro.size());
309 EXPECT_EQ("FOO", tag_ro.Get(0));
310 EXPECT_EQ("BAR", tag_ro.Get(1));
311 EXPECT_EQ("BAZ", tag_ro.Get(2));
312 }
313
TEST(GetFeatureTest,WritesAVectorToFeature)314 TEST(GetFeatureTest, WritesAVectorToFeature) {
315 Example example;
316
317 Feature* feature = GetFeature("tag", &example);
318 AppendFeatureValues<float>({1.1, 2.2, 3.3}, feature);
319
320 auto tag_ro = GetFeatureValues<float>("tag", example);
321
322 ASSERT_EQ(3, tag_ro.size());
323 EXPECT_NEAR(1.1, tag_ro.Get(0), kTolerance);
324 EXPECT_NEAR(2.2, tag_ro.Get(1), kTolerance);
325 EXPECT_NEAR(3.3, tag_ro.Get(2), kTolerance);
326 }
327
TEST(GetFeatureTest,ReadsAVectorFromFeature)328 TEST(GetFeatureTest, ReadsAVectorFromFeature) {
329 Example example;
330
331 AppendFeatureValues<float>({1.1, 2.2, 3.3}, "tag", &example);
332
333 const Feature& feature = GetFeature("tag", example);
334 auto tag_ro = GetFeatureValues<float>(feature);
335
336 ASSERT_EQ(3, tag_ro.size());
337 EXPECT_NEAR(1.1, tag_ro.Get(0), kTolerance);
338 EXPECT_NEAR(2.2, tag_ro.Get(1), kTolerance);
339 EXPECT_NEAR(3.3, tag_ro.Get(2), kTolerance);
340 }
341
TEST(SequenceExampleTest,ReadsASingleValueFromContext)342 TEST(SequenceExampleTest, ReadsASingleValueFromContext) {
343 SequenceExample se;
344 (*se.mutable_context()->mutable_feature())["tag"]
345 .mutable_int64_list()
346 ->add_value(42);
347
348 auto values = GetFeatureValues<protobuf_int64>("tag", se.context());
349
350 ASSERT_EQ(1, values.size());
351 EXPECT_EQ(42, values.Get(0));
352 }
353
TEST(SequenceExampleTest,WritesASingleValueToContext)354 TEST(SequenceExampleTest, WritesASingleValueToContext) {
355 SequenceExample se;
356
357 GetFeatureValues<protobuf_int64>("tag", se.mutable_context())->Add(42);
358
359 ASSERT_EQ(1, se.context().feature().at("tag").int64_list().value_size());
360 EXPECT_EQ(42, se.context().feature().at("tag").int64_list().value(0));
361 }
362
TEST(SequenceExampleTest,AppendFeatureValuesToContextSingleArg)363 TEST(SequenceExampleTest, AppendFeatureValuesToContextSingleArg) {
364 SequenceExample se;
365
366 AppendFeatureValues({1.1, 2.2, 3.3}, "tag", se.mutable_context());
367
368 auto tag_ro = GetFeatureValues<float>("tag", se.context());
369 ASSERT_EQ(3, tag_ro.size());
370 EXPECT_NEAR(1.1, tag_ro.Get(0), kTolerance);
371 EXPECT_NEAR(2.2, tag_ro.Get(1), kTolerance);
372 EXPECT_NEAR(3.3, tag_ro.Get(2), kTolerance);
373 }
374
TEST(SequenceExampleTest,CheckTypedFieldExistence)375 TEST(SequenceExampleTest, CheckTypedFieldExistence) {
376 SequenceExample se;
377
378 GetFeatureValues<float>("tag", se.mutable_context())->Add(3.14);
379 ASSERT_FALSE(HasFeature<protobuf_int64>("tag", se.context()));
380
381 GetFeatureValues<protobuf_int64>("tag", se.mutable_context())->Add(42);
382
383 EXPECT_TRUE(HasFeature<protobuf_int64>("tag", se.context()));
384 auto tag_ro = GetFeatureValues<protobuf_int64>("tag", se.context());
385 ASSERT_EQ(1, tag_ro.size());
386 EXPECT_EQ(42, tag_ro.Get(0));
387 }
388
TEST(SequenceExampleTest,ReturnsExistingFeatureLists)389 TEST(SequenceExampleTest, ReturnsExistingFeatureLists) {
390 SequenceExample se;
391 (*se.mutable_feature_lists()->mutable_feature_list())["tag"]
392 .mutable_feature()
393 ->Add();
394
395 auto feature = GetFeatureList("tag", se);
396
397 ASSERT_EQ(1, feature.size());
398 }
399
TEST(SequenceExampleTest,CreatesNewFeatureLists)400 TEST(SequenceExampleTest, CreatesNewFeatureLists) {
401 SequenceExample se;
402
403 GetFeatureList("tag", &se)->Add();
404
405 EXPECT_EQ(1, se.feature_lists().feature_list().at("tag").feature_size());
406 }
407
TEST(SequenceExampleTest,CheckFeatureListExistence)408 TEST(SequenceExampleTest, CheckFeatureListExistence) {
409 SequenceExample se;
410 ASSERT_FALSE(HasFeatureList("tag", se));
411
412 GetFeatureList("tag", &se)->Add();
413
414 ASSERT_TRUE(HasFeatureList("tag", se));
415 }
416
TEST(SequenceExampleTest,AppendFeatureValuesWithInitializerList)417 TEST(SequenceExampleTest, AppendFeatureValuesWithInitializerList) {
418 SequenceExample se;
419
420 AppendFeatureValues({1, 2, 3}, "ids", se.mutable_context());
421 AppendFeatureValues({"cam1-0", "cam2-0"},
422 GetFeatureList("images", &se)->Add());
423 AppendFeatureValues({"cam1-1", "cam2-2"},
424 GetFeatureList("images", &se)->Add());
425
426 EXPECT_EQ(se.DebugString(),
427 "context {\n"
428 " feature {\n"
429 " key: \"ids\"\n"
430 " value {\n"
431 " int64_list {\n"
432 " value: 1\n"
433 " value: 2\n"
434 " value: 3\n"
435 " }\n"
436 " }\n"
437 " }\n"
438 "}\n"
439 "feature_lists {\n"
440 " feature_list {\n"
441 " key: \"images\"\n"
442 " value {\n"
443 " feature {\n"
444 " bytes_list {\n"
445 " value: \"cam1-0\"\n"
446 " value: \"cam2-0\"\n"
447 " }\n"
448 " }\n"
449 " feature {\n"
450 " bytes_list {\n"
451 " value: \"cam1-1\"\n"
452 " value: \"cam2-2\"\n"
453 " }\n"
454 " }\n"
455 " }\n"
456 " }\n"
457 "}\n");
458 }
459
TEST(SequenceExampleTest,AppendFeatureValuesWithVectors)460 TEST(SequenceExampleTest, AppendFeatureValuesWithVectors) {
461 SequenceExample se;
462
463 std::vector<float> readings{1.0, 2.5, 5.0};
464 AppendFeatureValues(readings, GetFeatureList("movie_ratings", &se)->Add());
465
466 EXPECT_EQ(se.DebugString(),
467 "feature_lists {\n"
468 " feature_list {\n"
469 " key: \"movie_ratings\"\n"
470 " value {\n"
471 " feature {\n"
472 " float_list {\n"
473 " value: 1\n"
474 " value: 2.5\n"
475 " value: 5\n"
476 " }\n"
477 " }\n"
478 " }\n"
479 " }\n"
480 "}\n");
481 }
482
TEST(SequenceExampleTest,SetContextFeatureValuesWithInitializerList)483 TEST(SequenceExampleTest, SetContextFeatureValuesWithInitializerList) {
484 SequenceExample se;
485
486 // The first set of values should be overwritten by the second.
487 SetFeatureValues({101, 102, 103}, "ids", se.mutable_context());
488 SetFeatureValues({1, 2, 3}, "ids", se.mutable_context());
489
490 // These values should be appended without overwriting.
491 AppendFeatureValues({4, 5, 6}, "ids", se.mutable_context());
492
493 EXPECT_EQ(se.DebugString(),
494 "context {\n"
495 " feature {\n"
496 " key: \"ids\"\n"
497 " value {\n"
498 " int64_list {\n"
499 " value: 1\n"
500 " value: 2\n"
501 " value: 3\n"
502 " value: 4\n"
503 " value: 5\n"
504 " value: 6\n"
505 " }\n"
506 " }\n"
507 " }\n"
508 "}\n");
509 }
510
TEST(SequenceExampleTest,SetFeatureValuesWithInitializerList)511 TEST(SequenceExampleTest, SetFeatureValuesWithInitializerList) {
512 SequenceExample se;
513
514 // The first set of values should be overwritten by the second.
515 AppendFeatureValues({1, 2, 3}, "ids", se.mutable_context());
516 SetFeatureValues({4, 5, 6}, "ids", se.mutable_context());
517
518 // Two distinct features are added to the same feature list, so both will
519 // coexist in the output.
520 AppendFeatureValues({"cam1-0", "cam2-0"},
521 GetFeatureList("images", &se)->Add());
522 SetFeatureValues({"cam1-1", "cam2-1"}, GetFeatureList("images", &se)->Add());
523
524 // The first set of values should be overwritten by the second.
525 AppendFeatureValues({"cam1-0", "cam2-0"},
526 GetFeatureList("more-images", &se)->Add());
527 SetFeatureValues({"cam1-1", "cam2-1"},
528 GetFeatureList("more-images", &se)->Mutable(0));
529
530 EXPECT_EQ(se.DebugString(),
531 "context {\n"
532 " feature {\n"
533 " key: \"ids\"\n"
534 " value {\n"
535 " int64_list {\n"
536 " value: 4\n"
537 " value: 5\n"
538 " value: 6\n"
539 " }\n"
540 " }\n"
541 " }\n"
542 "}\n"
543 "feature_lists {\n"
544 " feature_list {\n"
545 " key: \"images\"\n"
546 " value {\n"
547 " feature {\n"
548 " bytes_list {\n"
549 " value: \"cam1-0\"\n"
550 " value: \"cam2-0\"\n"
551 " }\n"
552 " }\n"
553 " feature {\n"
554 " bytes_list {\n"
555 " value: \"cam1-1\"\n"
556 " value: \"cam2-1\"\n"
557 " }\n"
558 " }\n"
559 " }\n"
560 " }\n"
561 " feature_list {\n"
562 " key: \"more-images\"\n"
563 " value {\n"
564 " feature {\n"
565 " bytes_list {\n"
566 " value: \"cam1-1\"\n"
567 " value: \"cam2-1\"\n"
568 " }\n"
569 " }\n"
570 " }\n"
571 " }\n"
572 "}\n");
573 }
574
575 } // namespace
576 } // namespace tensorflow
577