1 /* Copyright 2015 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
16 #include <string.h>
17
18 #include <fstream>
19 #include <vector>
20
21 #include "tensorflow/core/debug/debug_io_utils.h"
22 #include "tensorflow/core/debug/debug_node_key.h"
23 #include "tensorflow/core/framework/fake_input.h"
24 #include "tensorflow/core/framework/node_def_builder.h"
25 #include "tensorflow/core/framework/summary.pb.h"
26 #include "tensorflow/core/framework/tensor.h"
27 #include "tensorflow/core/framework/tensor_testutil.h"
28 #include "tensorflow/core/framework/types.h"
29 #include "tensorflow/core/framework/types.pb.h"
30 #include "tensorflow/core/kernels/ops_testutil.h"
31 #include "tensorflow/core/kernels/ops_util.h"
32 #include "tensorflow/core/lib/core/status_test_util.h"
33 #include "tensorflow/core/lib/io/path.h"
34 #include "tensorflow/core/lib/strings/strcat.h"
35 #include "tensorflow/core/platform/env.h"
36 #include "tensorflow/core/platform/test.h"
37 #include "tensorflow/core/util/event.pb.h"
38
39 namespace tensorflow {
40
41 class DebugIdentityOpTest : public OpsTestBase {
42 protected:
Init(DataType input_type,const std::vector<string> & debug_urls)43 Status Init(DataType input_type, const std::vector<string>& debug_urls) {
44 env_ = Env::Default();
45
46 TF_CHECK_OK(NodeDefBuilder("op", "DebugIdentity")
47 .Input(FakeInput(input_type))
48 .Attr("tensor_name", "FakeTensor:0")
49 .Attr("debug_urls", debug_urls)
50 .Finalize(node_def()));
51 return InitOp();
52 }
53
Init(DataType input_type)54 Status Init(DataType input_type) {
55 std::vector<string> empty_debug_urls;
56 return Init(input_type, empty_debug_urls);
57 }
58
59 Env* env_;
60 };
61
TEST_F(DebugIdentityOpTest,Int32Success_6)62 TEST_F(DebugIdentityOpTest, Int32Success_6) {
63 TF_ASSERT_OK(Init(DT_INT32));
64 AddInputFromArray<int32>(TensorShape({6}), {1, 2, 3, 4, 5, 6});
65 TF_ASSERT_OK(RunOpKernel());
66 Tensor expected(allocator(), DT_INT32, TensorShape({6}));
67 test::FillValues<int32>(&expected, {1, 2, 3, 4, 5, 6});
68 // Verify the identity output
69 test::ExpectTensorEqual<int32>(expected, *GetOutput(0));
70 }
71
TEST_F(DebugIdentityOpTest,Int32Success_6_FileURLs)72 TEST_F(DebugIdentityOpTest, Int32Success_6_FileURLs) {
73 const int kNumDumpDirs = 3;
74
75 const string tmp_dir = testing::TmpDir();
76
77 std::vector<string> dump_roots;
78 std::vector<string> debug_urls;
79 for (int i = 0; i < kNumDumpDirs; ++i) {
80 const string dump_root = strings::StrCat(tmp_dir, "_", i);
81 dump_roots.push_back(dump_root);
82
83 debug_urls.push_back(strings::StrCat("file://", dump_root));
84 }
85
86 uint64 wall_time = Env::Default()->NowMicros();
87
88 TF_ASSERT_OK(Init(DT_INT32, debug_urls));
89 AddInputFromArray<int32>(TensorShape({6}), {1, 2, 3, 4, 5, 6});
90 TF_ASSERT_OK(RunOpKernel());
91 Tensor expected(allocator(), DT_INT32, TensorShape({6}));
92 test::FillValues<int32>(&expected, {1, 2, 3, 4, 5, 6});
93 // Verify the identity output
94 test::ExpectTensorEqual<int32>(expected, *GetOutput(0));
95
96 for (int i = 0; i < kNumDumpDirs; ++i) {
97 ASSERT_TRUE(env_->FileExists(dump_roots[i]).ok());
98 ASSERT_TRUE(env_->IsDirectory(dump_roots[i]).ok());
99
100 std::vector<string> device_roots;
101 FileSystem* fs = nullptr;
102 TF_ASSERT_OK(Env::Default()->GetFileSystemForFile(dump_roots[i], &fs));
103 std::vector<string> children;
104 TF_ASSERT_OK(fs->GetChildren(dump_roots[i], &children));
105
106 const string kDeviceDirPrefix = strings::StrCat(
107 DebugNodeKey::kMetadataFilePrefix, DebugNodeKey::kDeviceTag);
108 for (const string child : children) {
109 if (!strncmp(child.c_str(), kDeviceDirPrefix.c_str(),
110 kDeviceDirPrefix.size())) {
111 device_roots.push_back(io::JoinPath(dump_roots[i], child));
112 }
113 }
114 ASSERT_EQ(1, device_roots.size());
115
116 const string& device_root = device_roots[0];
117 TF_ASSERT_OK(Env::Default()->GetFileSystemForFile(device_root, &fs));
118 TF_ASSERT_OK(fs->GetChildren(device_root, &children));
119
120 int dump_files_found = 0;
121 for (const string child : children) {
122 dump_files_found++;
123
124 // Try reading the file into a Event proto.
125 const string dump_file_path = io::JoinPath(device_root, child);
126 std::fstream ifs(dump_file_path, std::ios::in | std::ios::binary);
127 Event event;
128 event.ParseFromIstream(&ifs);
129 ifs.close();
130
131 ASSERT_GE(event.wall_time(), wall_time);
132 ASSERT_EQ(1, event.summary().value().size());
133 ASSERT_EQ(strings::StrCat("FakeTensor", ":", 0, ":", "DebugIdentity"),
134 event.summary().value(0).node_name());
135
136 Tensor tensor_prime(DT_INT32);
137 ASSERT_TRUE(tensor_prime.FromProto(event.summary().value(0).tensor()));
138
139 // Verify tensor shape and value from the dump file.
140 ASSERT_EQ(TensorShape({6}), tensor_prime.shape());
141
142 for (int j = 0; j < 6; ++j) {
143 ASSERT_EQ(j + 1, tensor_prime.flat<int32>()(j));
144 }
145 }
146
147 ASSERT_EQ(1, dump_files_found);
148
149 // Remove temporary dump directory and file.
150 int64_t undeleted_files = 0;
151 int64_t undeleted_dirs = 0;
152 ASSERT_TRUE(env_->DeleteRecursively(dump_roots[i], &undeleted_files,
153 &undeleted_dirs)
154 .ok());
155 ASSERT_EQ(0, undeleted_files);
156 ASSERT_EQ(0, undeleted_dirs);
157 }
158 }
159
TEST_F(DebugIdentityOpTest,Int32Success_2_3)160 TEST_F(DebugIdentityOpTest, Int32Success_2_3) {
161 TF_ASSERT_OK(Init(DT_INT32));
162 AddInputFromArray<int32>(TensorShape({2, 3}), {1, 2, 3, 4, 5, 6});
163 TF_ASSERT_OK(RunOpKernel());
164 Tensor expected(allocator(), DT_INT32, TensorShape({2, 3}));
165 test::FillValues<int32>(&expected, {1, 2, 3, 4, 5, 6});
166 test::ExpectTensorEqual<int32>(expected, *GetOutput(0));
167 }
168
TEST_F(DebugIdentityOpTest,StringSuccess)169 TEST_F(DebugIdentityOpTest, StringSuccess) {
170 TF_ASSERT_OK(Init(DT_STRING));
171 AddInputFromArray<tstring>(TensorShape({6}), {"A", "b", "C", "d", "E", "f"});
172 TF_ASSERT_OK(RunOpKernel());
173 Tensor expected(allocator(), DT_STRING, TensorShape({6}));
174 test::FillValues<tstring>(&expected, {"A", "b", "C", "d", "E", "f"});
175 test::ExpectTensorEqual<tstring>(expected, *GetOutput(0));
176 }
177
178 // Tests for DebugNanCountOp
179 class DebugNanCountOpTest : public OpsTestBase {
180 protected:
Init(DataType input_type)181 Status Init(DataType input_type) {
182 TF_CHECK_OK(NodeDefBuilder("op", "DebugNanCount")
183 .Input(FakeInput(input_type))
184 .Attr("tensor_name", "FakeTensor:0")
185 .Finalize(node_def()));
186 return InitOp();
187 }
188 };
189
TEST_F(DebugNanCountOpTest,Float_has_NaNs)190 TEST_F(DebugNanCountOpTest, Float_has_NaNs) {
191 TF_ASSERT_OK(Init(DT_FLOAT));
192 AddInputFromArray<float>(TensorShape({6}),
193 {1.1, std::numeric_limits<float>::quiet_NaN(), 3.3,
194 std::numeric_limits<float>::quiet_NaN(),
195 std::numeric_limits<float>::quiet_NaN(), 6.6});
196 TF_ASSERT_OK(RunOpKernel());
197
198 // Verify the NaN-count debug signal
199 Tensor expected_nan_count(allocator(), DT_INT64, TensorShape({1}));
200 test::FillValues<int64>(&expected_nan_count, {3});
201 test::ExpectTensorEqual<int64>(expected_nan_count, *GetOutput(0));
202 }
203
TEST_F(DebugNanCountOpTest,Float_no_NaNs)204 TEST_F(DebugNanCountOpTest, Float_no_NaNs) {
205 TF_ASSERT_OK(Init(DT_FLOAT));
206 AddInputFromArray<float>(
207 TensorShape({6}),
208 {1.1, 2.2, 3.3, std::numeric_limits<float>::infinity(), 5.5, 6.6});
209 TF_ASSERT_OK(RunOpKernel());
210
211 Tensor expected_nan_count(allocator(), DT_INT64, TensorShape({1}));
212 test::FillValues<int64>(&expected_nan_count, {0});
213 test::ExpectTensorEqual<int64>(expected_nan_count, *GetOutput(0));
214 }
215
TEST_F(DebugNanCountOpTest,Double_has_NaNs)216 TEST_F(DebugNanCountOpTest, Double_has_NaNs) {
217 TF_ASSERT_OK(Init(DT_DOUBLE));
218 AddInputFromArray<double>(TensorShape({6}),
219 {1.1, std::numeric_limits<double>::quiet_NaN(), 3.3,
220 std::numeric_limits<double>::quiet_NaN(),
221 std::numeric_limits<double>::quiet_NaN(), 6.6});
222 TF_ASSERT_OK(RunOpKernel());
223
224 Tensor expected_nan_count(allocator(), DT_INT64, TensorShape({1}));
225 test::FillValues<int64>(&expected_nan_count, {3});
226 test::ExpectTensorEqual<int64>(expected_nan_count, *GetOutput(0));
227 }
228
TEST_F(DebugNanCountOpTest,Double_no_NaNs)229 TEST_F(DebugNanCountOpTest, Double_no_NaNs) {
230 TF_ASSERT_OK(Init(DT_DOUBLE));
231 AddInputFromArray<double>(
232 TensorShape({6}),
233 {1.1, 2.2, 3.3, std::numeric_limits<double>::infinity(), 5.5, 6.6});
234 TF_ASSERT_OK(RunOpKernel());
235
236 Tensor expected_nan_count(allocator(), DT_INT64, TensorShape({1}));
237 test::FillValues<int64>(&expected_nan_count, {0});
238 test::ExpectTensorEqual<int64>(expected_nan_count, *GetOutput(0));
239 }
240
241 // Tests for DebugNumericSummaryOp
242 class DebugNumericSummaryOpTest : public OpsTestBase {
243 protected:
Init(DataType input_type)244 Status Init(DataType input_type) {
245 TF_CHECK_OK(NodeDefBuilder("op", "DebugNumericSummary")
246 .Input(FakeInput(input_type))
247 .Attr("tensor_name", "FakeTensor:0")
248 .Finalize(node_def()));
249 return InitOp();
250 }
251
InitGated(DataType input_type,const std::vector<string> & debug_urls)252 Status InitGated(DataType input_type, const std::vector<string>& debug_urls) {
253 TF_CHECK_OK(NodeDefBuilder("op", "DebugNumericSummary")
254 .Input(FakeInput(input_type))
255 .Attr("tensor_name", "FakeTensor:0")
256 .Attr("gated_grpc", true)
257 .Attr("debug_urls", debug_urls)
258 .Finalize(node_def()));
259 return InitOp();
260 }
261
262 #if defined(PLATFORM_GOOGLE)
ClearEnabledWatchKeys()263 void ClearEnabledWatchKeys() { DebugGrpcIO::ClearEnabledWatchKeys(); }
264 #endif
265 };
266
TEST_F(DebugNumericSummaryOpTest,Float_full_house)267 TEST_F(DebugNumericSummaryOpTest, Float_full_house) {
268 TF_ASSERT_OK(Init(DT_FLOAT));
269 AddInputFromArray<float>(
270 TensorShape({18}),
271 {std::numeric_limits<float>::quiet_NaN(),
272 std::numeric_limits<float>::quiet_NaN(), 0.0f, 0.0f, 0.0f, -1.0f, -3.0f,
273 3.0f, 7.0f, -std::numeric_limits<float>::infinity(),
274 -std::numeric_limits<float>::infinity(),
275 std::numeric_limits<float>::infinity(),
276 std::numeric_limits<float>::infinity(),
277 std::numeric_limits<float>::infinity(),
278 std::numeric_limits<float>::infinity(),
279 std::numeric_limits<float>::infinity(),
280 std::numeric_limits<float>::quiet_NaN(),
281 std::numeric_limits<float>::quiet_NaN()});
282 TF_ASSERT_OK(RunOpKernel());
283
284 Tensor expected(allocator(), DT_DOUBLE, TensorShape({15}));
285 test::FillValues<double>(
286 &expected,
287 {1.0, // Is initialized.
288 18.0, // Total element count.
289 4.0, // nan count.
290 2.0, // -inf count.
291 2.0, // negative number count (excluding -inf).
292 3.0, // zero count.
293 2.0, // positive number count (excluding +inf).
294 5.0, // +inf count.
295 -3.0, // minimum of non-inf and non-nan elements.
296 7.0, // maximum of non-inf and non-nan elements.
297 0.85714285714, // mean of non-inf and non-nan elements.
298 8.97959183673, // variance of non-inf and non-nan elements.
299 static_cast<double>(DT_FLOAT), // dtype.
300 1.0, // Number of dimensions.
301 18.0}); // Dimension size.
302
303 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
304 }
305
TEST_F(DebugNumericSummaryOpTest,Double_full_house)306 TEST_F(DebugNumericSummaryOpTest, Double_full_house) {
307 TF_ASSERT_OK(Init(DT_DOUBLE));
308 AddInputFromArray<double>(
309 TensorShape({18}),
310 {std::numeric_limits<double>::quiet_NaN(),
311 std::numeric_limits<double>::quiet_NaN(), 0.0, 0.0, 0.0, -1.0, -3.0, 3.0,
312 7.0, -std::numeric_limits<double>::infinity(),
313 -std::numeric_limits<double>::infinity(),
314 std::numeric_limits<double>::infinity(),
315 std::numeric_limits<double>::infinity(),
316 std::numeric_limits<double>::infinity(),
317 std::numeric_limits<double>::infinity(),
318 std::numeric_limits<double>::infinity(),
319 std::numeric_limits<double>::quiet_NaN(),
320 std::numeric_limits<double>::quiet_NaN()});
321 TF_ASSERT_OK(RunOpKernel());
322
323 Tensor expected(allocator(), DT_DOUBLE, TensorShape({15}));
324 test::FillValues<double>(
325 &expected,
326 {1.0, // Is initialized.
327 18.0, // Total element count.
328 4.0, // nan count.
329 2.0, // -inf count.
330 2.0, // negative count (excluding -inf).
331 3.0, // zero count.
332 2.0, // positive count (excluding +inf).
333 5.0, // +inf count.
334 -3.0, // minimum of non-inf and non-nan elements.
335 7.0, // maximum of non-inf and non-nan elements.
336 0.85714285714, // mean of non-inf and non-nan elements.
337 8.97959183673, // variance of non-inf and non-nan elements.
338 static_cast<double>(DT_DOUBLE), // dtype.
339 1.0, // Number of dimensions.
340 18.0}); // Dimension size.
341
342 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
343 }
344
TEST_F(DebugNumericSummaryOpTest,Float_only_valid_values)345 TEST_F(DebugNumericSummaryOpTest, Float_only_valid_values) {
346 TF_ASSERT_OK(Init(DT_FLOAT));
347 AddInputFromArray<float>(TensorShape({2, 3}),
348 {0.0f, 0.0f, -1.0f, 3.0f, 3.0f, 7.0f});
349 TF_ASSERT_OK(RunOpKernel());
350
351 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
352 test::FillValues<double>(
353 &expected,
354 {1.0, // Is initialized.
355 6.0, // Total element count.
356 0.0, // nan count.
357 0.0, // -inf count.
358 1.0, // negative count (excluding -inf).
359 2.0, // zero count.
360 3.0, // positive count (excluding +inf).
361 0.0, // +inf count.
362 -1.0, // minimum of non-inf and non-nan elements.
363 7.0, // maximum of non-inf and non-nan elements.
364 2.0, // mean of non-inf and non-nan elements.
365 7.33333333333, // variance of non-inf and non-nan elements.
366 static_cast<double>(DT_FLOAT), // dtype
367 2.0, // Number of dimensions.
368 2.0, 3.0}); // Dimension sizes.
369
370 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
371 }
372
TEST_F(DebugNumericSummaryOpTest,Float_all_Inf_or_NaN)373 TEST_F(DebugNumericSummaryOpTest, Float_all_Inf_or_NaN) {
374 TF_ASSERT_OK(Init(DT_FLOAT));
375 AddInputFromArray<float>(TensorShape({3, 3}),
376 {std::numeric_limits<float>::quiet_NaN(),
377 std::numeric_limits<float>::quiet_NaN(),
378 -std::numeric_limits<float>::infinity(),
379 -std::numeric_limits<float>::infinity(),
380 std::numeric_limits<float>::infinity(),
381 std::numeric_limits<float>::infinity(),
382 std::numeric_limits<float>::infinity(),
383 std::numeric_limits<float>::quiet_NaN(),
384 std::numeric_limits<float>::quiet_NaN()});
385 TF_ASSERT_OK(RunOpKernel());
386
387 Tensor output_tensor = *GetOutput(0);
388 const double* output = output_tensor.template flat<double>().data();
389
390 // Use ASSERT_NEAR below because test::ExpectTensorNear does not work with
391 // NaNs.
392 ASSERT_NEAR(1.0, output[0], 1e-8); // Is initialized.
393 ASSERT_NEAR(9.0, output[1], 1e-8); // Total element count.
394 ASSERT_NEAR(4.0, output[2], 1e-8); // nan count.
395 ASSERT_NEAR(2.0, output[3], 1e-8); // -inf count.
396 ASSERT_NEAR(0.0, output[4], 1e-8); // negative count (excluding -inf).
397 ASSERT_NEAR(0.0, output[5], 1e-8); // zero count.
398 ASSERT_NEAR(0.0, output[6], 1e-8); // positive count (excluding +inf).
399 ASSERT_NEAR(3.0, output[7], 1e-8); // +inf count.
400 // Due to the absence of any non-inf and non-nan values, the output of min,
401 // max, mean and var are all degenerate.
402 ASSERT_EQ(std::numeric_limits<float>::infinity(), output[8]);
403 ASSERT_EQ(-std::numeric_limits<float>::infinity(), output[9]);
404 ASSERT_TRUE(Eigen::numext::isnan(output[10]));
405 ASSERT_TRUE(Eigen::numext::isnan(output[11]));
406 ASSERT_EQ(static_cast<double>(DT_FLOAT), output[12]);
407 ASSERT_EQ(2.0, output[13]);
408 ASSERT_EQ(3.0, output[14]);
409 ASSERT_EQ(3.0, output[15]);
410 }
411
TEST_F(DebugNumericSummaryOpTest,Many_dimensions_tensor_shape)412 TEST_F(DebugNumericSummaryOpTest, Many_dimensions_tensor_shape) {
413 TF_ASSERT_OK(Init(DT_FLOAT));
414 AddInputFromArray<float>(TensorShape({1, 3, 1, 1, 1, 1, 1}),
415 {std::numeric_limits<float>::quiet_NaN(),
416 -std::numeric_limits<float>::infinity(), -8.0});
417 TF_ASSERT_OK(RunOpKernel());
418
419 Tensor expected(allocator(), DT_DOUBLE, TensorShape({21}));
420 test::FillValues<double>(&expected,
421 {1.0, // Is initialized.
422 3.0, // Total element count.
423 1.0, // nan count.
424 1.0, // -inf count.
425 1.0, // negative number count (excluding -inf).
426 0.0, // zero count.
427 0.0, // positive number count (excluding +inf).
428 0.0, // +inf count.
429 -8.0, // minimum of non-inf and non-nan elements.
430 -8.0, // maximum of non-inf and non-nan elements.
431 -8.0, // mean of non-inf and non-nan elements.
432 0.0, // variance of non-inf and non-nan elements.
433 static_cast<double>(DT_FLOAT), // dtype.
434 7.0, // Number of dimensions.
435 1.0,
436 3.0,
437 1.0,
438 1.0,
439 1.0,
440 1.0,
441 1.0}); // Dimension sizes.
442
443 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
444 }
445
TEST_F(DebugNumericSummaryOpTest,Scalar_tensor_shape)446 TEST_F(DebugNumericSummaryOpTest, Scalar_tensor_shape) {
447 TF_ASSERT_OK(Init(DT_FLOAT));
448 AddInputFromArray<float>(TensorShape({}), {42.0});
449 TF_ASSERT_OK(RunOpKernel());
450
451 Tensor expected(allocator(), DT_DOUBLE, TensorShape({14}));
452 test::FillValues<double>(&expected,
453 {1.0, // Is initialized.
454 1.0, // Total element count.
455 0.0, // nan count.
456 0.0, // -inf count.
457 0.0, // negative number count (excluding -inf).
458 0.0, // zero count.
459 1.0, // positive number count (excluding +inf).
460 0.0, // +inf count.
461 42.0, // minimum of non-inf and non-nan elements.
462 42.0, // maximum of non-inf and non-nan elements.
463 42.0, // mean of non-inf and non-nan elements.
464 0.0, // variance of non-inf and non-nan elements.
465 static_cast<double>(DT_FLOAT), // dtype.
466 0.0}); // Number of dimensions.
467
468 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
469 }
470
TEST_F(DebugNumericSummaryOpTest,Int16Success)471 TEST_F(DebugNumericSummaryOpTest, Int16Success) {
472 TF_ASSERT_OK(Init(DT_INT16));
473 AddInputFromArray<int16>(TensorShape({4, 1}), {-1, -3, 3, 7});
474 TF_ASSERT_OK(RunOpKernel());
475
476 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
477 test::FillValues<double>(&expected,
478 {1.0, // Is initialized.
479 4.0, // Total element count.
480 0.0, // nan count.
481 0.0, // -inf count.
482 2.0, // negative count (excluding -inf).
483 0.0, // zero count.
484 2.0, // positive count (excluding +inf).
485 0.0, // +inf count.
486 -3.0, // minimum of non-inf and non-nan elements.
487 7.0, // maximum of non-inf and non-nan elements.
488 1.5, // mean of non-inf and non-nan elements.
489 14.75, // variance of non-inf and non-nan elements.
490 static_cast<double>(DT_INT16), // dtype.
491 2.0, // Number of dimensions.
492 4.0, 1.0}); // Dimension sizes.
493
494 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
495 }
496
TEST_F(DebugNumericSummaryOpTest,Int32Success)497 TEST_F(DebugNumericSummaryOpTest, Int32Success) {
498 TF_ASSERT_OK(Init(DT_INT32));
499 AddInputFromArray<int32>(TensorShape({2, 3}), {0, 0, -1, 3, 3, 7});
500 TF_ASSERT_OK(RunOpKernel());
501
502 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
503 test::FillValues<double>(
504 &expected,
505 {1.0, // Is initialized.
506 6.0, // Total element count.
507 0.0, // nan count.
508 0.0, // -inf count.
509 1.0, // negative count (excluding -inf).
510 2.0, // zero count.
511 3.0, // positive count (excluding +inf).
512 0.0, // +inf count.
513 -1.0, // minimum of non-inf and non-nan elements.
514 7.0, // maximum of non-inf and non-nan elements.
515 2.0, // mean of non-inf and non-nan elements.
516 7.33333333333, // variance of non-inf and non-nan elements.
517 static_cast<double>(DT_INT32), // dtype.
518 2.0, // Number of dimensions.
519 2.0, 3.0}); // Dimension sizes.
520
521 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
522 }
523
TEST_F(DebugNumericSummaryOpTest,Int64Success)524 TEST_F(DebugNumericSummaryOpTest, Int64Success) {
525 TF_ASSERT_OK(Init(DT_INT64));
526 AddInputFromArray<int64>(TensorShape({2, 2, 2}), {0, 0, -1, 3, 3, 7, 0, 0});
527 TF_ASSERT_OK(RunOpKernel());
528
529 Tensor expected(allocator(), DT_DOUBLE, TensorShape({17}));
530 test::FillValues<double>(&expected,
531 {1.0, // Is initialized.
532 8.0, // Total element count.
533 0.0, // nan count.
534 0.0, // -inf count.
535 1.0, // negative count (excluding -inf).
536 4.0, // zero count.
537 3.0, // positive count (excluding +inf).
538 0.0, // +inf count.
539 -1.0, // minimum of non-inf and non-nan elements.
540 7.0, // maximum of non-inf and non-nan elements.
541 1.5, // mean of non-inf and non-nan elements.
542 6.25, // variance of non-inf and non-nan elements.
543 static_cast<double>(DT_INT64), // dtype.
544 3.0, // Number of dimensions.
545 2.0, 2.0, 2.0}); // Dimension sizes.
546
547 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
548 }
549
TEST_F(DebugNumericSummaryOpTest,UInt8Success)550 TEST_F(DebugNumericSummaryOpTest, UInt8Success) {
551 TF_ASSERT_OK(Init(DT_UINT8));
552 AddInputFromArray<uint8>(TensorShape({1, 5}), {0, 10, 30, 30, 70});
553 TF_ASSERT_OK(RunOpKernel());
554
555 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
556 test::FillValues<double>(&expected,
557 {1.0, // Is initialized.
558 5.0, // Total element count.
559 0.0, // nan count.
560 0.0, // -inf count.
561 0.0, // negative count (excluding -inf).
562 1.0, // zero count.
563 4.0, // positive count (excluding +inf).
564 0.0, // +inf count.
565 0.0, // minimum of non-inf and non-nan elements.
566 70.0, // maximum of non-inf and non-nan elements.
567 28.0, // mean of non-inf and non-nan elements.
568 576.0, // variance of non-inf and non-nan elements.
569 static_cast<double>(DT_UINT8), // dtypes.
570 2.0, // Number of dimensions.
571 1.0, 5.0}); // Dimension sizes.
572
573 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
574 }
575
TEST_F(DebugNumericSummaryOpTest,BoolSuccess)576 TEST_F(DebugNumericSummaryOpTest, BoolSuccess) {
577 TF_ASSERT_OK(Init(DT_BOOL));
578 AddInputFromArray<bool>(TensorShape({2, 3}),
579 {false, false, true, true, true, false});
580 TF_ASSERT_OK(RunOpKernel());
581
582 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
583 test::FillValues<double>(&expected,
584 {1.0, // Is initialized.
585 6.0, // Total element count.
586 0.0, // nan count.
587 0.0, // -inf count.
588 0.0, // negative count (excluding -inf).
589 3.0, // zero count.
590 3.0, // positive count (excluding +inf).
591 0.0, // +inf count.
592 0.0, // minimum of non-inf and non-nan elements.
593 1.0, // maximum of non-inf and non-nan elements.
594 0.5, // mean of non-inf and non-nan elements.
595 0.25, // variance of non-inf and non-nan elements.
596 static_cast<double>(DT_BOOL), // dtype.
597 2.0, // Number of dimensions.
598 2.0, 3.0}); // Dimension sizes.
599
600 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
601 }
602
603 #if defined(PLATFORM_GOOGLE)
TEST_F(DebugNumericSummaryOpTest,DisabledDueToEmptyEnabledSet)604 TEST_F(DebugNumericSummaryOpTest, DisabledDueToEmptyEnabledSet) {
605 ClearEnabledWatchKeys();
606
607 std::vector<string> debug_urls({"grpc://server:3333"});
608 TF_ASSERT_OK(InitGated(DT_FLOAT, debug_urls));
609 AddInputFromArray<float>(TensorShape({2, 2}), {1.0, 3.0, 3.0, 7.0});
610 TF_ASSERT_OK(RunOpKernel());
611
612 Tensor expected_disabled(allocator(), DT_DOUBLE, TensorShape({0}));
613 test::ExpectTensorNear<double>(expected_disabled, *GetOutput(0), 1e-8);
614 }
615
TEST_F(DebugNumericSummaryOpTest,DisabledDueToNonMatchingWatchKey)616 TEST_F(DebugNumericSummaryOpTest, DisabledDueToNonMatchingWatchKey) {
617 ClearEnabledWatchKeys();
618 DebugGrpcIO::SetDebugNodeKeyGrpcState(
619 "grpc://server:3333", "FakeTensor:1:DebugNumeriSummary",
620 EventReply::DebugOpStateChange::READ_ONLY);
621
622 std::vector<string> debug_urls({"grpc://server:3333"});
623 TF_ASSERT_OK(InitGated(DT_FLOAT, debug_urls));
624 AddInputFromArray<float>(TensorShape({2, 2}), {1.0, 3.0, 3.0, 7.0});
625 TF_ASSERT_OK(RunOpKernel());
626
627 Tensor expected_disabled(allocator(), DT_DOUBLE, TensorShape({0}));
628 test::ExpectTensorNear<double>(expected_disabled, *GetOutput(0), 1e-8);
629 }
630 #endif
631
632 // Tests for DebugNumericSummaryOp
633 class DebugNumericSummaryOpCustomLowerBoundTest : public OpsTestBase {
634 protected:
Init(DataType input_type)635 Status Init(DataType input_type) {
636 TF_CHECK_OK(NodeDefBuilder("op", "DebugNumericSummary")
637 .Input(FakeInput(input_type))
638 .Attr("tensor_name", "FakeTensor:0")
639 .Attr("lower_bound", -1.2f)
640 .Finalize(node_def()));
641 return InitOp();
642 }
643 };
644
TEST_F(DebugNumericSummaryOpCustomLowerBoundTest,Float_full_house)645 TEST_F(DebugNumericSummaryOpCustomLowerBoundTest, Float_full_house) {
646 TF_ASSERT_OK(Init(DT_FLOAT));
647 AddInputFromArray<float>(
648 TensorShape({18}),
649 {std::numeric_limits<float>::quiet_NaN(),
650 std::numeric_limits<float>::quiet_NaN(), 0.0f, 0.0f, 0.0f, -1.0f, -3.0f,
651 3.0f, 7.0f, -std::numeric_limits<float>::infinity(),
652 -std::numeric_limits<float>::infinity(),
653 std::numeric_limits<float>::infinity(),
654 std::numeric_limits<float>::infinity(),
655 std::numeric_limits<float>::infinity(),
656 std::numeric_limits<float>::infinity(),
657 std::numeric_limits<float>::infinity(),
658 std::numeric_limits<float>::quiet_NaN(),
659 std::numeric_limits<float>::quiet_NaN()});
660 TF_ASSERT_OK(RunOpKernel());
661
662 Tensor expected(allocator(), DT_DOUBLE, TensorShape({15}));
663 test::FillValues<double>(
664 &expected,
665 {1.0, // Is initialized.
666 18.0, // Total element count.
667 4.0, // nan count.
668 3.0, // -inf count.
669 1.0, // negative number count (excluding -inf).
670 3.0, // zero count.
671 2.0, // positive number count (excluding +inf).
672 5.0, // +inf count.
673 -3.0, // minimum of non-inf and non-nan elements.
674 7.0, // maximum of non-inf and non-nan elements.
675 0.85714285714, // mean of non-inf and non-nan elements.
676 8.97959183673, // variance of non-inf and non-nan elements.
677 static_cast<double>(DT_FLOAT), // dtype.
678 1.0, // Number of dimensions.
679 18.0}); // Dimension sizes.
680
681 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
682 }
683
684 // Tests for DebugNumericSummaryOp
685 class DebugNumericSummaryOpCustomLowerUpperBoundsTest : public OpsTestBase {
686 protected:
Init(DataType input_type)687 Status Init(DataType input_type) {
688 TF_CHECK_OK(NodeDefBuilder("op", "DebugNumericSummary")
689 .Input(FakeInput(input_type))
690 .Attr("tensor_name", "FakeTensor:0")
691 .Attr("lower_bound", -0.5f)
692 .Attr("upper_bound", 3.6f)
693 .Finalize(node_def()));
694 return InitOp();
695 }
696 };
697
TEST_F(DebugNumericSummaryOpCustomLowerUpperBoundsTest,Int32Success)698 TEST_F(DebugNumericSummaryOpCustomLowerUpperBoundsTest, Int32Success) {
699 TF_ASSERT_OK(Init(DT_INT32));
700 AddInputFromArray<int32>(TensorShape({2, 3}), {0, 0, -1, 3, 3, 7});
701 TF_ASSERT_OK(RunOpKernel());
702
703 Tensor expected(allocator(), DT_DOUBLE, TensorShape({16}));
704 test::FillValues<double>(
705 &expected,
706 {1.0, // Is initialized.
707 6.0, // Total element count.
708 0.0, // nan count.
709 1.0, // -inf count.
710 0.0, // negative count (excluding -inf).
711 2.0, // zero count.
712 2.0, // positive count (excluding +inf).
713 1.0, // +inf count.
714 -1.0, // minimum of non-inf and non-nan elements.
715 7.0, // maximum of non-inf and non-nan elements.
716 2.0, // mean of non-inf and non-nan elements.
717 7.33333333333, // variance of non-inf and non-nan elements.
718 static_cast<double>(DT_INT32), // dtype.
719 2.0, // Number of dimensions.
720 2.0, 3.0}); // Dimension sizes.
721
722 test::ExpectTensorNear<double>(expected, *GetOutput(0), 1e-8);
723 }
724
725 } // namespace tensorflow
726