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 <functional> 17 #include <memory> 18 19 #include "tensorflow/core/framework/allocator.h" 20 #include "tensorflow/core/framework/fake_input.h" 21 #include "tensorflow/core/framework/node_def_builder.h" 22 #include "tensorflow/core/framework/op_kernel.h" 23 #include "tensorflow/core/framework/summary.pb.h" 24 #include "tensorflow/core/framework/tensor.h" 25 #include "tensorflow/core/framework/types.h" 26 #include "tensorflow/core/framework/types.pb.h" 27 #include "tensorflow/core/kernels/ops_testutil.h" 28 #include "tensorflow/core/kernels/ops_util.h" 29 #include "tensorflow/core/lib/core/status_test_util.h" 30 #include "tensorflow/core/lib/histogram/histogram.h" 31 #include "tensorflow/core/lib/strings/strcat.h" 32 #include "tensorflow/core/platform/env.h" 33 #include "tensorflow/core/platform/logging.h" 34 #include "tensorflow/core/platform/protobuf.h" 35 #include "tensorflow/core/platform/test.h" 36 37 namespace tensorflow { 38 namespace { 39 40 static void EXPECT_SummaryMatches(const Summary& actual, 41 const string& expected_str) { 42 Summary expected; 43 CHECK(protobuf::TextFormat::ParseFromString(expected_str, &expected)); 44 EXPECT_EQ(expected.DebugString(), actual.DebugString()); 45 } 46 47 class SummaryScalarOpTest : public OpsTestBase { 48 protected: 49 void MakeOp(DataType dt) { 50 TF_ASSERT_OK(NodeDefBuilder("myop", "ScalarSummary") 51 .Input(FakeInput()) 52 .Input(FakeInput(dt)) 53 .Finalize(node_def())); 54 TF_ASSERT_OK(InitOp()); 55 } 56 }; 57 58 TEST_F(SummaryScalarOpTest, SimpleFloat) { 59 MakeOp(DT_FLOAT); 60 61 // Feed and run 62 AddInputFromArray<string>(TensorShape({3}), {"tag1", "tag2", "tag3"}); 63 AddInputFromArray<float>(TensorShape({3}), {1.0f, -0.73f, 10000.0f}); 64 TF_ASSERT_OK(RunOpKernel()); 65 66 // Check the output size. 67 Tensor* out_tensor = GetOutput(0); 68 ASSERT_EQ(0, out_tensor->dims()); 69 Summary summary; 70 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 71 EXPECT_SummaryMatches(summary, R"( 72 value { tag: 'tag1' simple_value: 1.0 } 73 value { tag: 'tag2' simple_value: -0.73 } 74 value { tag: 'tag3' simple_value: 10000.0 } 75 )"); 76 } 77 78 TEST_F(SummaryScalarOpTest, SimpleDouble) { 79 MakeOp(DT_DOUBLE); 80 81 // Feed and run 82 AddInputFromArray<string>(TensorShape({3}), {"tag1", "tag2", "tag3"}); 83 AddInputFromArray<double>(TensorShape({3}), {1.0, -0.73, 10000.0}); 84 TF_ASSERT_OK(RunOpKernel()); 85 86 // Check the output size. 87 Tensor* out_tensor = GetOutput(0); 88 ASSERT_EQ(0, out_tensor->dims()); 89 Summary summary; 90 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 91 EXPECT_SummaryMatches(summary, R"( 92 value { tag: 'tag1' simple_value: 1.0 } 93 value { tag: 'tag2' simple_value: -0.73 } 94 value { tag: 'tag3' simple_value: 10000.0 } 95 )"); 96 } 97 98 TEST_F(SummaryScalarOpTest, SimpleHalf) { 99 MakeOp(DT_HALF); 100 101 // Feed and run 102 AddInputFromList<string>(TensorShape({3}), {"tag1", "tag2", "tag3"}); 103 AddInputFromList<Eigen::half>(TensorShape({3}), {1.0, -2.0, 10000.0}); 104 TF_ASSERT_OK(RunOpKernel()); 105 106 // Check the output size. 107 Tensor* out_tensor = GetOutput(0); 108 ASSERT_EQ(0, out_tensor->dims()); 109 Summary summary; 110 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 111 EXPECT_SummaryMatches(summary, R"( 112 value { tag: 'tag1' simple_value: 1.0 } 113 value { tag: 'tag2' simple_value: -2.0 } 114 value { tag: 'tag3' simple_value: 10000.0 } 115 )"); 116 } 117 118 TEST_F(SummaryScalarOpTest, Error_MismatchedSize) { 119 MakeOp(DT_FLOAT); 120 121 // Feed and run 122 AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"}); 123 AddInputFromArray<float>(TensorShape({3}), {1.0f, -0.73f, 10000.0f}); 124 Status s = RunOpKernel(); 125 EXPECT_TRUE(StringPiece(s.ToString()).contains("not the same shape")) << s; 126 } 127 128 TEST_F(SummaryScalarOpTest, Error_WrongDimsTags) { 129 MakeOp(DT_FLOAT); 130 131 // Feed and run 132 AddInputFromArray<string>(TensorShape({2, 1}), {"tag1", "tag2"}); 133 AddInputFromArray<float>(TensorShape({2}), {1.0f, -0.73f}); 134 Status s = RunOpKernel(); 135 EXPECT_TRUE( 136 StringPiece(s.ToString()).contains("tags and values not the same shape")) 137 << s; 138 } 139 140 TEST_F(SummaryScalarOpTest, Error_WrongDimsValues) { 141 MakeOp(DT_FLOAT); 142 143 // Feed and run 144 AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"}); 145 AddInputFromArray<float>(TensorShape({2, 1}), {1.0f, -0.73f}); 146 Status s = RunOpKernel(); 147 EXPECT_TRUE( 148 StringPiece(s.ToString()).contains("tags and values not the same shape")) 149 << s; 150 } 151 152 // -------------------------------------------------------------------------- 153 // SummaryHistoOp 154 // -------------------------------------------------------------------------- 155 class SummaryHistoOpTest : public OpsTestBase { 156 protected: 157 void MakeOp(DataType dt) { 158 TF_ASSERT_OK(NodeDefBuilder("myop", "HistogramSummary") 159 .Input(FakeInput()) 160 .Input(FakeInput(dt)) 161 .Finalize(node_def())); 162 TF_ASSERT_OK(InitOp()); 163 } 164 }; 165 166 TEST_F(SummaryHistoOpTest, SimpleFloat) { 167 MakeOp(DT_FLOAT); 168 169 // Feed and run 170 AddInputFromArray<string>(TensorShape({}), {"taghisto"}); 171 AddInputFromArray<float>(TensorShape({3, 2}), 172 {0.1f, -0.7f, 4.1f, 4., 5.f, 4.f}); 173 TF_ASSERT_OK(RunOpKernel()); 174 175 // Check the output size. 176 Tensor* out_tensor = GetOutput(0); 177 ASSERT_EQ(0, out_tensor->dims()); 178 Summary summary; 179 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 180 ASSERT_EQ(summary.value_size(), 1); 181 EXPECT_EQ(summary.value(0).tag(), "taghisto"); 182 histogram::Histogram histo; 183 EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo())); 184 EXPECT_EQ( 185 "Count: 6 Average: 2.7500 StdDev: 2.20\n" 186 "Min: -0.7000 Median: 3.9593 Max: 5.0000\n" 187 "------------------------------------------------------\n" 188 "[ -0.76, -0.69 ) 1 16.667% 16.667% ###\n" 189 "[ 0.093, 0.1 ) 1 16.667% 33.333% ###\n" 190 "[ 3.8, 4.2 ) 3 50.000% 83.333% ##########\n" 191 "[ 4.6, 5.1 ) 1 16.667% 100.000% ###\n", 192 histo.ToString()); 193 } 194 195 TEST_F(SummaryHistoOpTest, SimpleDouble) { 196 MakeOp(DT_DOUBLE); 197 198 // Feed and run 199 AddInputFromArray<string>(TensorShape({}), {"taghisto"}); 200 AddInputFromArray<double>(TensorShape({3, 2}), {0.1, -0.7, 4.1, 4., 5., 4.}); 201 TF_ASSERT_OK(RunOpKernel()); 202 203 // Check the output size. 204 Tensor* out_tensor = GetOutput(0); 205 ASSERT_EQ(0, out_tensor->dims()); 206 Summary summary; 207 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 208 ASSERT_EQ(summary.value_size(), 1); 209 EXPECT_EQ(summary.value(0).tag(), "taghisto"); 210 histogram::Histogram histo; 211 EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo())); 212 EXPECT_EQ( 213 "Count: 6 Average: 2.7500 StdDev: 2.20\n" 214 "Min: -0.7000 Median: 3.9593 Max: 5.0000\n" 215 "------------------------------------------------------\n" 216 "[ -0.76, -0.69 ) 1 16.667% 16.667% ###\n" 217 "[ 0.093, 0.1 ) 1 16.667% 33.333% ###\n" 218 "[ 3.8, 4.2 ) 3 50.000% 83.333% ##########\n" 219 "[ 4.6, 5.1 ) 1 16.667% 100.000% ###\n", 220 histo.ToString()); 221 } 222 223 TEST_F(SummaryHistoOpTest, SimpleHalf) { 224 MakeOp(DT_HALF); 225 226 // Feed and run 227 AddInputFromList<string>(TensorShape({}), {"taghisto"}); 228 AddInputFromList<Eigen::half>(TensorShape({3, 2}), 229 {0.1, -0.7, 4.1, 4., 5., 4.}); 230 TF_ASSERT_OK(RunOpKernel()); 231 232 // Check the output size. 233 Tensor* out_tensor = GetOutput(0); 234 ASSERT_EQ(0, out_tensor->dims()); 235 Summary summary; 236 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 237 ASSERT_EQ(summary.value_size(), 1); 238 EXPECT_EQ(summary.value(0).tag(), "taghisto"); 239 histogram::Histogram histo; 240 EXPECT_TRUE(histo.DecodeFromProto(summary.value(0).histo())); 241 EXPECT_EQ( 242 "Count: 6 Average: 2.7502 StdDev: 2.20\n" 243 "Min: -0.7002 Median: 3.9593 Max: 5.0000\n" 244 "------------------------------------------------------\n" 245 "[ -0.76, -0.69 ) 1 16.667% 16.667% ###\n" 246 "[ 0.093, 0.1 ) 1 16.667% 33.333% ###\n" 247 "[ 3.8, 4.2 ) 3 50.000% 83.333% ##########\n" 248 "[ 4.6, 5.1 ) 1 16.667% 100.000% ###\n", 249 histo.ToString()); 250 } 251 252 TEST_F(SummaryHistoOpTest, Error_WrongDimsTags) { 253 MakeOp(DT_FLOAT); 254 255 // Feed and run 256 AddInputFromArray<string>(TensorShape({2, 1}), {"tag1", "tag2"}); 257 AddInputFromArray<float>(TensorShape({2}), {1.0f, -0.73f}); 258 Status s = RunOpKernel(); 259 EXPECT_TRUE(StringPiece(s.ToString()).contains("tags must be scalar")) << s; 260 } 261 262 TEST_F(SummaryHistoOpTest, Error_TooManyTagValues) { 263 MakeOp(DT_FLOAT); 264 265 // Feed and run 266 AddInputFromArray<string>(TensorShape({2}), {"tag1", "tag2"}); 267 AddInputFromArray<float>(TensorShape({2, 1}), {1.0f, -0.73f}); 268 Status s = RunOpKernel(); 269 EXPECT_TRUE(StringPiece(s.ToString()).contains("tags must be scalar")) << s; 270 } 271 272 // -------------------------------------------------------------------------- 273 // SummaryMergeOp 274 // -------------------------------------------------------------------------- 275 class SummaryMergeOpTest : public OpsTestBase { 276 protected: 277 void MakeOp(int num_inputs) { 278 TF_ASSERT_OK(NodeDefBuilder("myop", "MergeSummary") 279 .Input(FakeInput(num_inputs)) 280 .Finalize(node_def())); 281 TF_ASSERT_OK(InitOp()); 282 } 283 }; 284 285 TEST_F(SummaryMergeOpTest, Simple) { 286 MakeOp(1); 287 288 // Feed and run 289 Summary s1; 290 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 291 "value { tag: \"tag1\" simple_value: 1.0 } " 292 "value { tag: \"tag2\" simple_value: -0.73 } ", 293 &s1)); 294 Summary s2; 295 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 296 "value { tag: \"tag3\" simple_value: 10000.0 }", &s2)); 297 Summary s3; 298 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 299 "value { tag: \"tag4\" simple_value: 11.0 }", &s3)); 300 301 AddInputFromArray<string>( 302 TensorShape({3}), 303 {s1.SerializeAsString(), s2.SerializeAsString(), s3.SerializeAsString()}); 304 TF_ASSERT_OK(RunOpKernel()); 305 306 // Check the output size. 307 Tensor* out_tensor = GetOutput(0); 308 ASSERT_EQ(0, out_tensor->dims()); 309 Summary summary; 310 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 311 312 EXPECT_SummaryMatches(summary, 313 "value { tag: \"tag1\" simple_value: 1.0 } " 314 "value { tag: \"tag2\" simple_value: -0.73 } " 315 "value { tag: \"tag3\" simple_value: 10000.0 }" 316 "value { tag: \"tag4\" simple_value: 11.0 }"); 317 } 318 319 TEST_F(SummaryMergeOpTest, Simple_MultipleInputs) { 320 MakeOp(3); 321 322 // Feed and run 323 Summary s1; 324 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 325 "value { tag: \"tag1\" simple_value: 1.0 } " 326 "value { tag: \"tag2\" simple_value: -0.73 } ", 327 &s1)); 328 Summary s2; 329 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 330 "value { tag: \"tag3\" simple_value: 10000.0 }", &s2)); 331 Summary s3; 332 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 333 "value { tag: \"tag4\" simple_value: 11.0 }", &s3)); 334 335 AddInputFromArray<string>(TensorShape({}), {s1.SerializeAsString()}); 336 AddInputFromArray<string>(TensorShape({}), {s2.SerializeAsString()}); 337 AddInputFromArray<string>(TensorShape({}), {s3.SerializeAsString()}); 338 TF_ASSERT_OK(RunOpKernel()); 339 340 // Check the output size. 341 Tensor* out_tensor = GetOutput(0); 342 ASSERT_EQ(0, out_tensor->dims()); 343 Summary summary; 344 ParseProtoUnlimited(&summary, out_tensor->scalar<string>()()); 345 346 EXPECT_SummaryMatches(summary, 347 "value { tag: \"tag1\" simple_value: 1.0 } " 348 "value { tag: \"tag2\" simple_value: -0.73 } " 349 "value { tag: \"tag3\" simple_value: 10000.0 }" 350 "value { tag: \"tag4\" simple_value: 11.0 }"); 351 } 352 353 TEST_F(SummaryMergeOpTest, Error_MismatchedSize) { 354 MakeOp(1); 355 356 // Feed and run 357 Summary s1; 358 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 359 "value { tag: \"tag1\" simple_value: 1.0 } " 360 "value { tag: \"tagduplicate\" simple_value: -0.73 } ", 361 &s1)); 362 Summary s2; 363 ASSERT_TRUE(protobuf::TextFormat::ParseFromString( 364 "value { tag: \"tagduplicate\" simple_value: 1.0 } ", &s2)); 365 AddInputFromArray<string>(TensorShape({2}), 366 {s1.SerializeAsString(), s2.SerializeAsString()}); 367 Status s = RunOpKernel(); 368 EXPECT_TRUE(StringPiece(s.ToString()).contains("Duplicate tag")) << s; 369 } 370 371 } // namespace 372 } // namespace tensorflow 373