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