1 /* Copyright 2016 The TensorFlow Authors. All Rights Reserved. 2 3 Licensed under the Apache License, Version 2.0 (the "License"); 4 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 "tensorflow/core/framework/node_def_builder.h" 17 #include "tensorflow/core/framework/node_def_util.h" 18 #include "tensorflow/core/framework/op.h" 19 #include "tensorflow/core/framework/shape_inference.h" 20 #include "tensorflow/core/framework/shape_inference_testutil.h" 21 #include "tensorflow/core/framework/tensor.pb.h" 22 #include "tensorflow/core/framework/tensor_shape.pb.h" 23 #include "tensorflow/core/framework/tensor_testutil.h" 24 #include "tensorflow/core/lib/core/status_test_util.h" 25 #include "tensorflow/core/platform/test.h" 26 #include "tensorflow/core/public/version.h" 27 28 namespace tensorflow { 29 30 TEST(ArrayOpsTest, Pack_ShapeFn) { 31 ShapeInferenceTestOp op("Pack"); 32 auto set_axis = [&op](int axis) { 33 int n = 3; 34 std::vector<NodeDefBuilder::NodeOut> src_list; 35 src_list.reserve(n); 36 for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT); 37 TF_ASSERT_OK(NodeDefBuilder("test", "Pack") 38 .Input(src_list) 39 .Attr("N", n) 40 .Attr("axis", axis) 41 .Finalize(&op.node_def)); 42 }; 43 44 set_axis(0); 45 INFER_OK(op, "?;?;?", "?"); 46 47 for (int axis : {0, -3}) { 48 set_axis(axis); 49 INFER_OK(op, "?;?;?", "?"); 50 INFER_OK(op, "[1,3];[1,3];?", "[3,d0_0|d1_0,d0_1|d1_1]"); 51 INFER_OK(op, "[?,3];[1,3];?", "[3,d1_0,d0_1|d1_1]"); 52 INFER_OK(op, "[?,?];[1,3];?", "[3,d1_0,d1_1]"); 53 } 54 for (int axis : {1, -2}) { 55 set_axis(axis); 56 INFER_OK(op, "?;?;?", "?"); 57 INFER_OK(op, "[1,3];[1,3];?", "[d0_0|d1_0,3,d0_1|d1_1]"); 58 INFER_OK(op, "[?,3];[1,3];?", "[d1_0,3,d0_1|d1_1]"); 59 INFER_OK(op, "[?,?];[1,3];?", "[d1_0,3,d1_1]"); 60 } 61 for (int axis : {2, -1}) { 62 set_axis(axis); 63 INFER_OK(op, "?;?;?", "?"); 64 INFER_OK(op, "[1,3];[1,3];?", "[d0_0|d1_0,d0_1|d1_1,3]"); 65 INFER_OK(op, "[?,3];[1,3];?", "[d1_0,d0_1|d1_1,3]"); 66 INFER_OK(op, "[?,?];[1,3];?", "[d1_0,d1_1,3]"); 67 } 68 69 set_axis(-4); 70 INFER_ERROR("Invalid axis: -4; must be in [-3,3)", op, "[1,3];[1,3];?"); 71 set_axis(3); 72 INFER_ERROR("Invalid axis: 3; must be in [-3,3)", op, "[1,3];[1,3];?"); 73 74 set_axis(0); 75 76 // Check that both components of error message are there. 77 INFER_ERROR("Shapes must be equal rank, but are 3 and 2", op, 78 "[1,2,3];?;[1,4]"); 79 INFER_ERROR("From merging shape 0 with other shapes.", op, "[1,2,3];?;[1,4]"); 80 } 81 82 TEST(ArrayOpsTest, UnPack_ShapeFn) { 83 ShapeInferenceTestOp op("Unpack"); 84 auto set_axis_and_num = [&op](int axis, int num) { 85 TF_ASSERT_OK(NodeDefBuilder("test", "Unpack") 86 .Input("a", 0, DT_FLOAT) 87 .Attr("axis", axis) 88 .Attr("num", num) 89 .Finalize(&op.node_def)); 90 }; 91 92 set_axis_and_num(0, 1); 93 INFER_OK(op, "?", "?"); 94 95 for (int axis : {0, -3}) { 96 set_axis_and_num(axis, 1); 97 INFER_OK(op, "?", "?"); 98 INFER_OK(op, "[1,2,3]", "[d0_1,d0_2]"); 99 INFER_OK(op, "[?,?,?]", "[d0_1,d0_2]"); 100 } 101 for (int axis : {1, -2}) { 102 set_axis_and_num(axis, 2); 103 INFER_OK(op, "[1,2,3]", "[d0_0,d0_2];[d0_0,d0_2]"); 104 INFER_OK(op, "[?,?,?]", "[d0_0,d0_2];[d0_0,d0_2]"); 105 } 106 for (int axis : {2, -1}) { 107 set_axis_and_num(axis, 3); 108 INFER_OK(op, "[1,2,3]", "[d0_0,d0_1];[d0_0,d0_1];[d0_0,d0_1]"); 109 INFER_OK(op, "[?,?,?]", "[d0_0,d0_1];[d0_0,d0_1];[d0_0,d0_1]"); 110 } 111 112 set_axis_and_num(2, 2); 113 INFER_ERROR("Dimension must be 2 but is 3", op, "[1,2,3]"); 114 115 set_axis_and_num(-4, 3); 116 INFER_ERROR("Invalid axis: -4; must be in [-3,3)", op, "[1,2,3]"); 117 set_axis_and_num(3, 3); 118 INFER_ERROR("Invalid axis: 3; must be in [-3,3)", op, "[1,2,3]"); 119 } 120 121 TEST(ArrayOpsTest, Const_ShapeFn) { 122 ShapeInferenceTestOp op("Const"); 123 TensorProto tensor_proto; 124 auto* shape_proto = tensor_proto.mutable_tensor_shape(); 125 auto rebuild_node_def = [&op, &tensor_proto]() { 126 TF_ASSERT_OK(NodeDefBuilder("test", "Const") 127 .Attr("value", tensor_proto) 128 .Finalize(&op.node_def)); 129 }; 130 131 TensorShape{}.AsProto(shape_proto); 132 rebuild_node_def(); 133 INFER_OK(op, "", "[]"); 134 TensorShape{1, 2, 3, 4}.AsProto(shape_proto); 135 rebuild_node_def(); 136 INFER_OK(op, "", "[1,2,3,4]"); 137 138 shape_proto->add_dim()->set_size(-1); 139 rebuild_node_def(); 140 INFER_ERROR("Shape [1,2,3,4,?] is not fully defined", op, ""); 141 } 142 143 TEST(ArrayOpsTest, UnchangedShapes_ShapeFn) { 144 for (const char* op_name : { 145 "CheckNumerics", 146 "Identity", 147 "RefIdentity", 148 "QuantizeAndDequantize", 149 "StopGradient", 150 "ZerosLike", 151 "OnesLike", 152 }) { 153 ShapeInferenceTestOp op(op_name); 154 INFER_OK(op, "?", "in0"); 155 INFER_OK(op, "[]", "in0"); 156 INFER_OK(op, "[1,2,?,4,5]", "in0"); 157 } 158 159 // inputs 1 and 2 are ignored; input 0 is transferred to output 0. 160 ShapeInferenceTestOp op("MatrixBandPart"); 161 INFER_OK(op, "?;?;?", "in0"); 162 INFER_OK(op, "[];?;?", "in0"); 163 INFER_OK(op, "[1,2,?,4,5];?;?", "in0"); 164 } 165 166 TEST(ArrayOpsTest, GuaranteeConst_ShapeFn) { 167 ShapeInferenceTestOp op("GuaranteeConst"); 168 INFER_OK(op, "?", "in0"); 169 INFER_OK(op, "[]", "in0"); 170 INFER_OK(op, "[1,2,?,4,5]", "in0"); 171 } 172 173 TEST(ArrayOpsTest, Identity_ShapeFnHandles) { 174 const char* op_name = "Identity"; 175 ShapeInferenceTestOp op(op_name); 176 // Check that handle dtypes are preserved. 177 const OpRegistrationData* op_reg_data; 178 TF_ASSERT_OK(OpRegistry::Global()->LookUp(op.name, &op_reg_data)); 179 std::vector< 180 std::unique_ptr<std::vector<std::pair<TensorShapeProto, DataType>>>> 181 handle_data; 182 handle_data.emplace_back( 183 new std::vector<std::pair<TensorShapeProto, DataType>>{ 184 {TensorShapeProto(), DT_BOOL}}); 185 shape_inference::InferenceContext c(TF_GRAPH_DEF_VERSION, &op.node_def, 186 op_reg_data->op_def, {TensorShapeProto()}, 187 {}, {}, handle_data); 188 TF_ASSERT_OK(c.construction_status()); 189 ASSERT_TRUE(op_reg_data->shape_inference_fn != nullptr); 190 TF_ASSERT_OK(c.Run(op_reg_data->shape_inference_fn)); 191 192 const auto* shapes_and_types = c.output_handle_shapes_and_types(0); 193 ASSERT_TRUE(shapes_and_types != nullptr); 194 ASSERT_EQ(1, shapes_and_types->size()); 195 EXPECT_EQ((*shapes_and_types)[0].dtype, DT_BOOL); 196 } 197 198 TEST(ArrayOpsTest, Diag_ShapeFn) { 199 ShapeInferenceTestOp op("Diag"); 200 INFER_OK(op, "?", "?"); 201 INFER_OK(op, "[1,?,3]", "[d0_0,d0_1,d0_2,d0_0,d0_1,d0_2]"); 202 INFER_OK(op, "[?,1,2,3]", "[d0_0,d0_1,d0_2,d0_3,d0_0,d0_1,d0_2,d0_3]"); 203 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[]"); 204 } 205 206 TEST(ArrayOpsTest, DiagPart_ShapeFn) { 207 ShapeInferenceTestOp op("DiagPart"); 208 INFER_OK(op, "?", "?"); 209 INFER_OK(op, "[1,?,?,4]", "[d0_0,d0_3]"); 210 INFER_OK(op, "[1,?,3,?,4,3]", "[d0_0,d0_4,d0_2|d0_5]"); 211 INFER_OK(op, "[1,2,3,?,?,?,?,4]", "[d0_0,d0_1,d0_2,d0_7]"); 212 INFER_ERROR("Input must have even and non-zero rank", op, "[]"); 213 INFER_ERROR("Input must have even and non-zero rank", op, "[?]"); 214 INFER_ERROR("Input must have even and non-zero rank", op, "[1,2,3]"); 215 INFER_ERROR("Dimensions must be equal, but are 2 and 10", op, "[1,2,?,10]"); 216 } 217 218 TEST(ArrayOpsTest, MatrixDiag_ShapeFn) { 219 ShapeInferenceTestOp op("MatrixDiag"); 220 INFER_OK(op, "?", "?"); 221 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[]"); 222 INFER_OK(op, "[?]", "[d0_0,d0_0]"); 223 INFER_OK(op, "[1,?,?,4]", "[d0_0,d0_1,d0_2,d0_3,d0_3]"); 224 } 225 226 TEST(ArrayOpsTest, MatrixDiagPart_ShapeFn) { 227 ShapeInferenceTestOp op("MatrixDiagPart"); 228 INFER_OK(op, "?", "?"); 229 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, "[?]"); 230 INFER_OK(op, "[?,1,2,2]", "[d0_0,d0_1,d0_2|d0_3]"); 231 INFER_OK(op, "[?,1,2,3]", "[d0_0,d0_1,d0_2]"); 232 INFER_OK(op, "[?,1,3,2]", "[d0_0,d0_1,d0_3]"); 233 } 234 235 TEST(ArrayOpsTest, Reverse_ShapeFn) { 236 ShapeInferenceTestOp op("Reverse"); 237 INFER_OK(op, "?;?", "in0"); 238 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]"); 239 INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[?,2]"); 240 INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4]"); 241 INFER_ERROR("reverse does not work on tensors with more than 8 dimensions", 242 op, "[1,2,3,4,5,6,7,8,9];[9]"); 243 INFER_OK(op, "[1,2,3,?];[4]", "in0"); 244 INFER_OK(op, "[1,2,3,?,5,6,7,8];[8]", "in0"); 245 } 246 247 TEST(ArrayOpsTest, ReverseV2_ShapeFn) { 248 ShapeInferenceTestOp op("ReverseV2"); 249 INFER_OK(op, "?;?", "in0"); 250 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]"); 251 INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[?,2]"); 252 INFER_OK(op, "[1,2,3];[2]", "in0"); 253 INFER_ERROR("reverse does not work on tensors with more than 8 dimensions", 254 op, "[1,2,3,4,5,6,7,8,9];[9]"); 255 INFER_OK(op, "[1,2,3,?];[4]", "in0"); 256 INFER_OK(op, "[1,2,3,?,5,6,7,8];[8]", "in0"); 257 } 258 259 TEST(ArrayOpsTest, Fill_ShapeFn) { 260 ShapeInferenceTestOp op("Fill"); 261 AddNodeAttr("index_type", DT_INT32, &op.node_def); 262 op.input_tensors.resize(2); 263 INFER_OK(op, "?;?", "?"); 264 INFER_OK(op, "[?];?", "?"); 265 INFER_OK(op, "[4];?", "[?,?,?,?]"); 266 267 Tensor in_t = test::AsTensor<int32>({1, 2, 3, 4}); 268 op.input_tensors[0] = &in_t; 269 INFER_OK(op, "[4];?", "[1,2,3,4]"); 270 } 271 272 TEST(ArrayOpsTest, Gather_ShapeFn) { 273 ShapeInferenceTestOp op("Gather"); 274 INFER_OK(op, "?;?", "?"); 275 INFER_OK(op, "[1,?,2];[3]", "[d1_0,d0_1,d0_2]"); 276 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[];[1,2,3]"); 277 } 278 279 TEST(ArrayOpsTest, GatherV2_ShapeFn) { 280 ShapeInferenceTestOp op("GatherV2"); 281 282 // Tests when axis is unknown. 283 INFER_OK(op, "?;?;?", "?"); 284 INFER_OK(op, "[1,2,3];[3];[]", "[?,?,?]"); 285 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, 286 "[];[1,2,3];[]"); 287 288 // Non-scalar axis. 289 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];[1,2,3];[1]"); 290 291 // Test when axis dim is known. 292 Tensor axis_dim_t; 293 op.input_tensors.resize(3); 294 op.input_tensors[2] = &axis_dim_t; 295 296 // Out of range axis. 297 axis_dim_t = test::AsScalar(1); 298 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 299 "[1];[1,2];[]"); 300 301 // Rank 0 indices. 302 axis_dim_t = test::AsScalar(0); 303 INFER_OK(op, "[1,2,3];[];[]", "[d0_1,d0_2]"); 304 axis_dim_t = test::AsScalar(1); 305 INFER_OK(op, "[1,2,3];[];[]", "[d0_0,d0_2]"); 306 axis_dim_t = test::AsScalar(2); 307 INFER_OK(op, "[1,2,3];[];[]", "[d0_0,d0_1]"); 308 309 // Rank 1 indices. 310 axis_dim_t = test::AsScalar(0); 311 INFER_OK(op, "[1,2,3];[5];[]", "[d1_0,d0_1,d0_2]"); 312 axis_dim_t = test::AsScalar(1); 313 INFER_OK(op, "[1,2,3];[5];[]", "[d0_0,d1_0,d0_2]"); 314 axis_dim_t = test::AsScalar(2); 315 INFER_OK(op, "[1,2,3];[5];[]", "[d0_0,d0_1,d1_0]"); 316 317 // Rank 2 indices. 318 axis_dim_t = test::AsScalar(0); 319 INFER_OK(op, "[1,2,3];[5,6];[]", "[d1_0,d1_1,d0_1,d0_2]"); 320 axis_dim_t = test::AsScalar(1); 321 INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d1_0,d1_1,d0_2]"); 322 axis_dim_t = test::AsScalar(2); 323 INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d0_1,d1_0,d1_1]"); 324 325 // Negative axis. 326 axis_dim_t = test::AsScalar(-3); 327 INFER_OK(op, "[1,2,3];[5,6];[]", "[d1_0,d1_1,d0_1,d0_2]"); 328 axis_dim_t = test::AsScalar(-2); 329 INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d1_0,d1_1,d0_2]"); 330 axis_dim_t = test::AsScalar(-1); 331 INFER_OK(op, "[1,2,3];[5,6];[]", "[d0_0,d0_1,d1_0,d1_1]"); 332 } 333 334 TEST(ArrayOpsTest, GatherNd_ShapeFn) { 335 ShapeInferenceTestOp op("GatherNd"); 336 337 // Inputs are (params, indices). 338 INFER_OK(op, "?;?", "?"); 339 INFER_OK(op, "[1,?,3,?];[?,0]", "[d1_0,d0_0,d0_1,d0_2,d0_3]"); 340 INFER_OK(op, "[1,?,3,?];[?,4]", "[d1_0]"); 341 342 // params.rank >= indices.dim(-1). 343 INFER_ERROR("indices.shape[-1] must be <= params.rank", op, "[1,2,3];[4]"); 344 } 345 346 TEST(ArrayOpsTest, Shape_ShapeFn) { 347 ShapeInferenceTestOp op("Shape"); 348 INFER_OK(op, "?", "[?]"); 349 INFER_OK(op, "[?]", "[1]"); 350 INFER_OK(op, "[?,2,3,4,5]", "[5]"); 351 } 352 353 TEST(ArrayOpsTest, ShapeN_ShapeFn) { 354 ShapeInferenceTestOp op("ShapeN"); 355 int n = 3; 356 std::vector<NodeDefBuilder::NodeOut> src_list; 357 src_list.reserve(n); 358 for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT); 359 TF_ASSERT_OK(NodeDefBuilder("test", "ShapeN") 360 .Input(src_list) 361 .Attr("N", n) 362 .Finalize(&op.node_def)); 363 INFER_OK(op, "?;?;?", "[?];[?];[?]"); 364 INFER_OK(op, "[?];[?];[?]", "[1];[1];[1]"); 365 INFER_OK(op, "[?,2,3,4,5];?;[1,?,3]", "[5];[?];[3]"); 366 } 367 368 TEST(ArrayOpsTest, Unique_ShapeFn) { 369 ShapeInferenceTestOp op("Unique"); 370 INFER_OK(op, "?", "[?];in0"); 371 INFER_OK(op, "[1,2,3,?,5]", "[?];in0"); 372 } 373 374 TEST(ArrayOpsTest, UniqueWithCounts_ShapeFn) { 375 ShapeInferenceTestOp op("UniqueWithCounts"); 376 INFER_OK(op, "?", "[?];in0;[?]"); 377 INFER_OK(op, "[1,2,3,?,5]", "[?];in0;[?]"); 378 } 379 380 TEST(ArrayOpsTest, InvertPermutation_ShapeFn) { 381 ShapeInferenceTestOp op("InvertPermutation"); 382 INFER_OK(op, "?", "[?]"); 383 INFER_OK(op, "[1]", "in0"); 384 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[]"); 385 } 386 387 TEST(ArrayOpsTest, PadD_ShapeFn) { 388 for (const char* op_name : {"Pad", "MirrorPad"}) { 389 ShapeInferenceTestOp op(op_name); 390 op.input_tensors.resize(2); 391 392 // Inputs are input and paddings. 393 394 INFER_OK(op, "?;?", "?"); 395 396 // Check shape of paddings. 397 INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;[1,2,3]"); 398 INFER_ERROR("Dimension must be 2 but is 4", op, "?;[1,4]"); 399 400 // input.rank and paddings.dim(0) are equal. This is the number of dims in 401 // output. 402 INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4,2]"); 403 INFER_OK(op, "[1,2,3];?", "[?,?,?]"); 404 INFER_OK(op, "?;[3,2]", "[?,?,?]"); 405 406 // Make the paddings tensor known and verify padding values get added. 407 // E.g., if padding is ((1,10),(2,20),(3,30)) then values 11,22,23 are added 408 // to input dims to get output. 409 Tensor paddings_t(DT_INT64, TensorShape{3, 2}); 410 test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30}); 411 op.input_tensors[1] = &paddings_t; 412 INFER_OK(op, "[100,200,300];[3,2]", "[111,222,333]"); 413 INFER_OK(op, "[100,?,300];[3,2]", "[111,?,333]"); 414 INFER_OK(op, "?;[3,2]", "[?,?,?]"); 415 INFER_OK(op, "?;?", "[?,?,?]"); 416 } 417 } 418 419 TEST(ArrayOpsTest, PadV2_ShapeFn) { 420 ShapeInferenceTestOp op("PadV2"); 421 op.input_tensors.resize(3); 422 423 // Inputs are input, paddings and constant_values. 424 425 INFER_OK(op, "?;?;?", "?"); 426 427 // Check shape of paddings. 428 INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;[1,2,3];?"); 429 INFER_ERROR("Dimension must be 2 but is 4", op, "?;[1,4];?"); 430 431 // input.rank and paddings.dim(0) are equal. This is the number of dims in 432 // output. 433 INFER_ERROR("Shape must be rank 4 but is rank 3", op, "[1,2,3];[4,2];[]"); 434 INFER_OK(op, "[1,2,3];?;[]", "[?,?,?]"); 435 INFER_OK(op, "?;[3,2];[]", "[?,?,?]"); 436 437 // Make the paddings tensor known and verify padding values get added. 438 // E.g., if padding is ((1,10),(2,20),(3,30)) then values 11,22,23 are added 439 // to input dims to get output. 440 Tensor paddings_t(DT_INT64, TensorShape{3, 2}); 441 test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30}); 442 op.input_tensors[1] = &paddings_t; 443 INFER_OK(op, "[100,200,300];[3,2];[]", "[111,222,333]"); 444 INFER_OK(op, "[100,?,300];[3,2];[]", "[111,?,333]"); 445 INFER_OK(op, "?;[3,2];[]", "[?,?,?]"); 446 INFER_OK(op, "?;?;[]", "[?,?,?]"); 447 } 448 449 TEST(ArrayOpsTest, MirrorPadGrad_ShapeFn) { 450 ShapeInferenceTestOp op("MirrorPadGrad"); 451 op.input_tensors.resize(2); 452 453 // Inputs are input and paddings. 454 INFER_OK(op, "?;?", "?"); 455 456 // First padding dimension is unknown, so rank is unknown. 457 INFER_OK(op, "?;[?,4]", "?"); 458 459 // Input tensor rank doesn't match paddings dimension. 460 INFER_ERROR("must be rank 3 but is rank 2", op, "[?,?];[3,2]"); 461 462 // Paddings tensor is not a [rank x 2] matrix. 463 INFER_ERROR("Dimension 1 in both shapes must be equal, but are 3 and 2", op, 464 "[?,?,?];[3,3]"); 465 466 // Paddings tensor is unknown, but rank is known, so the output 467 // shape is a rank 3 unknown shape. 468 INFER_OK(op, "[?,?,?];[3,2]", "[?,?,?]"); 469 470 // Make the paddings tensor known and verify padding values get 471 // subtracted. E.g., if padding is ((1,10),(2,20),(3,30)) then 472 // values 11,22,23 are subtracted to input dims to get output. 473 Tensor paddings_t(DT_INT64, TensorShape{3, 2}); 474 test::FillValues<int64>(&paddings_t, {1, 10, 2, 20, 3, 30}); 475 op.input_tensors[1] = &paddings_t; 476 477 INFER_OK(op, "[111,222,333];[3,2]", "[100,200,300]"); 478 INFER_OK(op, "[111,?,333];[3,2]", "[100,?,300]"); 479 } 480 481 TEST(ArrayOpsTest, BroadcastArgs_ShapeFn) { 482 ShapeInferenceTestOp op("BroadcastArgs"); 483 INFER_OK(op, "?;?", "[?]"); 484 INFER_OK(op, "[123];[1]", "[123]"); 485 INFER_OK(op, "[1];[123]", "[123]"); 486 INFER_OK(op, "[123];[121]", "[123]"); 487 488 // Rank checks 489 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?"); 490 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]"); 491 } 492 493 TEST(ArrayOpsTest, BroadcastGradientArgs_ShapeFn) { 494 ShapeInferenceTestOp op("BroadcastGradientArgs"); 495 // Output is always two unknown vectors. 496 INFER_OK(op, "?;?", "[?];[?]"); 497 INFER_OK(op, "[123];[456]", "[?];[?]"); 498 499 // Rank checks 500 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?"); 501 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]"); 502 } 503 504 TEST(ArrayOpsTest, ListDiff_ShapeFn) { 505 ShapeInferenceTestOp op("BroadcastGradientArgs"); 506 // Output is always two matching unknown vectors. 507 INFER_OK(op, "?;?", "[?];[?]"); 508 INFER_OK(op, "[123];[456]", "[?];[?]"); 509 510 // Rank checks 511 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "[];?"); 512 INFER_ERROR("Shape must be rank 1 but is rank 0", op, "?;[]"); 513 } 514 515 TEST(ArrayOpsTest, MatrixSetDiag_ShapeFn) { 516 ShapeInferenceTestOp op("MatrixSetDiag"); 517 518 // Inputs are input and diagonal. 519 520 // Rank checks. 521 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, "[1];?"); 522 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "?;[]"); 523 INFER_ERROR("Shape must be at least rank 1 but is rank 0", op, "[2,2];[]"); 524 INFER_ERROR("Shape must be rank 1 but is rank 2", op, "[2,2];[2,2]"); 525 526 // diagonal[-1] must match smallest matrix dimension. 527 INFER_ERROR("Dimensions must be equal, but are 2 and 3", op, "[2,3];[3]"); 528 529 // Output matches input. 530 INFER_OK(op, "?;?", "in0"); 531 INFER_OK(op, "[1,2,2];[1,2]", "in0"); 532 INFER_OK(op, "[1,2,3];?", "in0"); 533 INFER_OK(op, "[1,3,2];?", "in0"); 534 INFER_OK(op, "[1,?,2];[?,?]", "in0"); 535 INFER_OK(op, "[1,?,?];[?,2]", "in0"); 536 537 // Infer batch shape from diag when input is not fully specified. 538 INFER_OK(op, "?;[1,2]", "[d1_0,?,?]"); 539 INFER_OK(op, "[?,?,3];[1,2]", "[d1_0,d0_1,d0_2]"); 540 INFER_OK(op, "[?,3,?];[1,2]", "[d1_0,d0_1,d0_2]"); 541 INFER_OK(op, "[?,3,2];[1,2]", "[d1_0,d0_1,d0_2]"); 542 } 543 544 TEST(ArrayOpsTest, ExpandDims_ShapeFn) { 545 ShapeInferenceTestOp op("ExpandDims"); 546 op.input_tensors.resize(2); 547 548 // With unknown dim tensor value, output is unknown. 549 INFER_OK(op, "?;?", "?"); 550 Tensor dim_t; 551 op.input_tensors[1] = &dim_t; 552 553 // Expand at front of tensor. 554 for (int32 idx : {0, -4}) { 555 dim_t = test::AsScalar<int32>(idx); 556 INFER_OK(op, "?;?", "?"); 557 INFER_OK(op, "[5,?,7];?", "[1,d0_0,d0_1,d0_2]"); 558 } 559 560 // Expand at middle of tensor. 561 for (int32 idx : {1, -3}) { 562 dim_t = test::AsScalar<int32>(idx); 563 INFER_OK(op, "?;?", "?"); 564 INFER_OK(op, "[5,?,7];?", "[d0_0,1,d0_1,d0_2]"); 565 566 // Repeat with int64. 567 dim_t = test::AsScalar<int64>(idx); 568 INFER_OK(op, "?;?", "?"); 569 INFER_OK(op, "[5,?,7];?", "[d0_0,1,d0_1,d0_2]"); 570 } 571 for (int32 idx : {2, -2}) { 572 dim_t = test::AsScalar<int32>(idx); 573 INFER_OK(op, "?;?", "?"); 574 INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,1,d0_2]"); 575 576 // Repeat with int64. 577 dim_t = test::AsScalar<int64>(idx); 578 INFER_OK(op, "?;?", "?"); 579 INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,1,d0_2]"); 580 } 581 582 for (int32 idx : {3, -1}) { 583 // Expand at the end. 584 dim_t = test::AsScalar<int32>(idx); 585 INFER_OK(op, "?;?", "?"); 586 INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,d0_2,1]"); 587 588 // Repeat with int64. 589 dim_t = test::AsScalar<int64>(idx); 590 INFER_OK(op, "?;?", "?"); 591 INFER_OK(op, "[5,?,7];?", "[d0_0,d0_1,d0_2,1]"); 592 } 593 for (int32 idx : {4, -5}) { 594 // Invalid idx. 595 dim_t = test::AsScalar<int32>(idx); 596 INFER_ERROR("not in the interval [-4, 3]", op, "[5,?,7];?"); 597 dim_t = test::AsScalar<int64>(idx); 598 INFER_ERROR("not in the interval [-4, 3]", op, "[5,?,7];?"); 599 } 600 601 // Expand using an input vector tensor. 602 std::vector<int32> dims; 603 dims.push_back(0); 604 dim_t = test::AsTensor<int32>(dims); 605 INFER_OK(op, "?;?", "?"); 606 INFER_OK(op, "[5,?,7];?", "[1,d0_0,d0_1,d0_2]"); 607 608 // Expand using too many input elements. 609 dims.push_back(1); 610 dim_t = test::AsTensor<int32>(dims); 611 INFER_ERROR("'dim' input must be a tensor with a single", op, "?;?"); 612 INFER_ERROR("'dim' input must be a tensor with a single", op, "[5,6,7];?"); 613 614 // Examples from ExpandDims doc. 615 dim_t = test::AsScalar<int32>(0); 616 INFER_OK(op, "[2];[]", "[1,d0_0]"); 617 dim_t = test::AsScalar<int32>(1); 618 INFER_OK(op, "[2];[]", "[d0_0,1]"); 619 dim_t = test::AsScalar<int32>(-1); 620 INFER_OK(op, "[2];[]", "[d0_0,1]"); 621 } 622 623 TEST(ArrayOpsTest, ImmutableConst_ShapeFn) { 624 ShapeInferenceTestOp op("ImmutableConst"); 625 626 TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst") 627 .Attr("dtype", DT_FLOAT) 628 .Attr("shape", TensorShape({1, 2, 3})) 629 .Attr("memory_region_name", "test_region") 630 .Finalize(&op.node_def)); 631 INFER_OK(op, "", "[1,2,3]"); 632 633 TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst") 634 .Attr("dtype", DT_FLOAT) 635 .Attr("shape", TensorShape({})) 636 .Attr("memory_region_name", "test_region") 637 .Finalize(&op.node_def)); 638 INFER_OK(op, "", "[]"); 639 640 TF_ASSERT_OK(NodeDefBuilder("test", "ImmutableConst") 641 .Attr("dtype", DT_FLOAT) 642 .Attr("shape", "invalid") 643 .Attr("memory_region_name", "test_region") 644 .Finalize(&op.node_def)); 645 INFER_ERROR("AttrValue had value with type 'string' when 'shape' expected", 646 op, ""); 647 } 648 649 TEST(ArrayOpsTest, Concat_ShapeFn) { 650 ShapeInferenceTestOp op("Concat"); 651 auto set_n = [&op](int n) { 652 std::vector<NodeDefBuilder::NodeOut> src_list; 653 src_list.reserve(n); 654 for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT); 655 TF_ASSERT_OK(NodeDefBuilder("test", "Concat") 656 .Input({"concat_dim", 0, DT_INT32}) 657 .Input(src_list) 658 .Attr("n", n) 659 .Finalize(&op.node_def)); 660 }; 661 662 // Confirm dimension[0] of the input (the concat_dim) is a scalar. 663 set_n(2); 664 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?;?"); 665 666 // Test with the input concat_dim tensor not known. This takes the known rank 667 // of the inputs and makes a tensor of that many unknown dims. 668 set_n(7); 669 INFER_OK(op, "?;?;?;?;[1,2,3];?;[3,2,1];?", "[?,?,?]"); 670 set_n(4); 671 INFER_OK(op, "?;?;?;[1,2,3,4];[4,3,2,1]", "[?,?,?,?]"); 672 INFER_OK(op, "?;?;?;?;?", "?"); // output rank unknown 673 INFER_ERROR("Can't concatenate scalars (use tf.stack instead)", op, 674 "?;?;?;[];[]"); 675 INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;?;?;[1,2];[1,2,3]"); 676 677 // Test when the concat_dim tensor is known. The concatenated dimension is 678 // summed across all input tensors, and other dimensions are merged. 679 Tensor concat_dim_t; 680 op.input_tensors.push_back(&concat_dim_t); 681 set_n(2); 682 683 // Sum dim 0, merge the other two dims. 684 for (int concat_dim : {0, -3}) { 685 concat_dim_t = test::AsScalar(concat_dim); 686 INFER_OK(op, "[];[100,2,?];[10,?,3]", "[110,d1_1,d2_2]"); 687 INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op, 688 "[];[100,2,5];[10,?,3]"); 689 // concat_dim can't be summed, as one value is unknown. 690 INFER_OK(op, "[];[100,2,?];[?,?,3]", "[?,d1_1,d2_2]"); 691 INFER_OK(op, "[];[?,2,?];[10,?,3]", "[?,d1_1,d2_2]"); 692 } 693 694 // Test with a higher concat_dim. 695 for (bool use_negative : {false, true}) { 696 concat_dim_t = test::AsScalar(use_negative ? -2 : 1); 697 INFER_OK(op, "[];[1,100,?];[?,10,3]", "[d1_0,110,d2_2]"); 698 concat_dim_t = test::AsScalar(use_negative ? -1 : 1); 699 INFER_OK(op, "[];[1,100];[?,10]", "[d1_0,110]"); 700 INFER_OK(op, "[];[?,100];[1,10]", "[d2_0,110]"); 701 702 // concat_dim is out of bounds. 703 concat_dim_t = test::AsScalar(use_negative ? -2 : 1); 704 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 705 "[];[100];[10,?]"); 706 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 707 "[];[100,5];[10]"); 708 } 709 710 // concat_dim is too low. 711 concat_dim_t = test::AsScalar(-2); 712 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 713 "[];[100];[10,?]"); 714 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 715 "[];[100,5];[10]"); 716 717 // Repeat successful case with several unknown inputs. 718 set_n(5); 719 concat_dim_t = test::AsScalar(1); 720 INFER_OK(op, "[];?;[1,100,?];[?,?,?];[?,10,3];?", "[d2_0,?,d4_2]"); 721 } 722 723 TEST(ArrayOpsTest, ConcatV2_ShapeFn) { 724 ShapeInferenceTestOp op("ConcatV2"); 725 auto set_n = [&op](int n) { 726 std::vector<NodeDefBuilder::NodeOut> src_list; 727 src_list.reserve(n); 728 for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_FLOAT); 729 TF_ASSERT_OK(NodeDefBuilder("test", "ConcatV2") 730 .Input(src_list) 731 .Input({"axis", 0, DT_INT32}) 732 .Attr("n", n) 733 .Finalize(&op.node_def)); 734 }; 735 736 // Confirm dimension[0] of the input (the concat_dim) is a scalar. 737 set_n(2); 738 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "?;?;[1]"); 739 740 // Test with the input concat_dim tensor not known. This takes the known rank 741 // of the inputs and makes a tensor of that many unknown dims. 742 set_n(7); 743 INFER_OK(op, "?;?;?;?;[1,2,3];?;[3,2,1];?", "[?,?,?]"); 744 set_n(4); 745 INFER_OK(op, "?;?;[1,2,3,4];[4,3,2,1];?", "[?,?,?,?]"); 746 INFER_OK(op, "?;?;?;?;?", "?"); // output rank unknown 747 INFER_ERROR("Can't concatenate scalars (use tf.stack instead)", op, 748 "?;?;[];[];?"); 749 INFER_ERROR("Shape must be rank 2 but is rank 3", op, "?;?;[1,2];[1,2,3];?"); 750 751 // Test when the concat_dim tensor is known. The concatenated dimension is 752 // summed across all input tensors, and other dimensions are merged. 753 Tensor concat_dim_t; 754 op.input_tensors.resize(3); 755 op.input_tensors[2] = &concat_dim_t; 756 757 set_n(2); 758 759 // Invalid concat dim value. 760 // concat_dim_t = test::AsScalar(-1); 761 // INFER_ERROR("Expected concat_dim >= 0, but got -1", op, "?;?;?"); 762 763 // Sum dim 0, merge the other two dims. 764 concat_dim_t = test::AsScalar(0); 765 INFER_OK(op, "[100,2,?];[10,?,3];[]", "[110,d0_1,d1_2]"); 766 INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op, 767 "[100,2,5];[10,?,3];[]"); 768 // concat_dim can't be summed, as one value is unknown. 769 INFER_OK(op, "[100,2,?];[?,?,3];[]", "[?,d0_1,d1_2]"); 770 INFER_OK(op, "[?,2,?];[10,?,3];[]", "[?,d0_1,d1_2]"); 771 772 // Test with a higher concat_dim. 773 concat_dim_t = test::AsScalar(1); 774 INFER_OK(op, "[1,100,?];[?,10,3];[]", "[d0_0,110,d1_2]"); 775 INFER_OK(op, "[1,100];[?,10];[]", "[d0_0,110]"); 776 INFER_OK(op, "[?,100];[1,10];[]", "[d1_0,110]"); 777 // concat_dim is too high. 778 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 779 "[100];[10,?];[]"); 780 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 781 "[100,5];[10];[]"); 782 // concat_dim is too low. 783 concat_dim_t = test::AsScalar(-2); 784 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 785 "[100];[10,?];[]"); 786 INFER_ERROR("Shape must be at least rank 2 but is rank 1", op, 787 "[100,5];[10];[]"); 788 789 // Repeat successful case with several unknown inputs. 790 op.input_tensors.resize(6); 791 op.input_tensors[3] = nullptr; 792 op.input_tensors[5] = &concat_dim_t; 793 concat_dim_t = test::AsScalar(1); 794 795 set_n(5); 796 INFER_OK(op, "?;[1,100,?];[?,?,?];[?,10,3];?;[]", "[d1_0,?,d3_2]"); 797 } 798 799 TEST(ArrayOpsTest, ConcatOffset_ShapeFn) { 800 ShapeInferenceTestOp op("ConcatOffset"); 801 802 const int n = 4; 803 std::vector<NodeDefBuilder::NodeOut> src_list; 804 src_list.reserve(n); 805 for (int i = 0; i < n; ++i) src_list.emplace_back("a", 0, DT_INT32); 806 TF_ASSERT_OK(NodeDefBuilder("test", "ConcatOffset") 807 .Input({"concat_dim", 0, DT_INT32}) 808 .Input(src_list) 809 .Attr("n", n) 810 .Finalize(&op.node_def)); 811 INFER_OK(op, "?;?;?;?;?", "in1;in2;in3;in4"); 812 } 813 814 TEST(ArrayOpsTest, Reshape_ShapeFn) { 815 ShapeInferenceTestOp op("Reshape"); 816 op.input_tensors.resize(2); 817 818 // No valid shape provided. 819 INFER_OK(op, "?;?", "?"); 820 INFER_OK(op, "[?];?", "?"); 821 INFER_OK(op, "[?];[?]", "?"); 822 INFER_OK(op, "[4];[?]", "?"); 823 824 // All dimensions provided. 825 Tensor new_shape = test::AsTensor<int32>({1, 2, 3}); 826 op.input_tensors[1] = &new_shape; 827 INFER_OK(op, "[?];[3]", "[1,2,3]"); 828 INFER_OK(op, "[6];[3]", "[1,2,3]"); 829 // The number of elements should match for the reshape to succeed. 830 INFER_ERROR( 831 "Cannot reshape a tensor with 12 elements to shape [1,2,3] (6 elements)", 832 op, "[3,4];[3]"); 833 834 // Unknown dimensions. 835 // Flatten: 836 new_shape = test::AsTensor<int32>({-1}); 837 INFER_OK(op, "[?];[1]", "[?]"); 838 INFER_OK(op, "[2,2];[1]", "[4]"); 839 // The first dimension is inferred: 840 new_shape = test::AsTensor<int32>({2, -1}); 841 INFER_OK(op, "[3,4];[2]", "[2,6]"); 842 // The total number of elements must be evenly divisible by the known 843 // dimensions. 844 INFER_ERROR("Dimension size must be evenly divisible by 2 but is 7", op, 845 "[7];[2]"); 846 // Multiple missing dimensions cannot be inferred. 847 new_shape = test::AsTensor<int32>({-1, -1, 2}); 848 INFER_OK(op, "[8];[3]", "[?,?,2]"); 849 850 // Reshaping to a scalar. 851 new_shape = test::AsTensor<int32>({}); 852 INFER_OK(op, "[1];[0]", "[]"); 853 INFER_ERROR( 854 "Cannot reshape a tensor with 2 elements to shape [] (1 elements)", op, 855 "[1,2];[0]"); 856 857 // Reshaping a tensor with no elements. 858 new_shape = test::AsTensor<int32>({-1}); 859 INFER_OK(op, "[0];[1]", "[0]"); 860 new_shape = test::AsTensor<int32>({-1, 6}); 861 INFER_OK(op, "[0,2];[1]", "[0,6]"); 862 new_shape = test::AsTensor<int32>({0, -1}); 863 INFER_OK(op, "[0,2];[1]", "[0,?]"); 864 } 865 866 TEST(ArrayOpsTest, QuantizedReshape_ShapeFn) { 867 ShapeInferenceTestOp op("QuantizedReshape"); 868 op.input_tensors.resize(2); 869 870 // First test a subset of the Reshape_ShapeFn tests. Not all are tested, as 871 // QuantizedReshape uses the same code for the reshape part of the operation. 872 INFER_OK(op, "?;?;?;?", "?;[];[]"); 873 INFER_OK(op, "[?];?;?;?", "?;[];[]"); 874 INFER_OK(op, "[?];[?];?;?", "?;[];[]"); 875 INFER_OK(op, "[4];[?];?;?", "?;[];[]"); 876 Tensor new_shape = test::AsTensor<int32>({1, 2, 3}); 877 op.input_tensors[1] = &new_shape; 878 INFER_OK(op, "[?];[3];?;?", "[1,2,3];[];[]"); 879 INFER_OK(op, "[6];[3];?;?", "[1,2,3];[];[]"); 880 INFER_ERROR( 881 "Cannot reshape a tensor with 12 elements to shape [1,2,3] (6 elements)", 882 op, "[3,4];[3];?;?"); 883 884 // Test the scalar rank checks on input_min and input_max. 885 INFER_ERROR("must be rank 0", op, "?;?;[1];?"); 886 INFER_ERROR("must be rank 0", op, "?;?;?;[1]"); 887 } 888 889 TEST(ArrayOpsTest, Placeholder_ShapeFn) { 890 { 891 // 2D shape 892 ShapeInferenceTestOp op("Placeholder"); 893 TensorShape shape({1, 2}); 894 TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder") 895 .Attr("shape", shape) 896 .Attr("dtype", DT_FLOAT) 897 .Finalize(&op.node_def)); 898 INFER_OK(op, "", "[1,2]"); 899 } 900 901 { 902 // Scalar shapes are supported 903 ShapeInferenceTestOp op("Placeholder"); 904 TensorShape shape({}); 905 TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder") 906 .Attr("shape", shape) 907 .Attr("dtype", DT_FLOAT) 908 .Finalize(&op.node_def)); 909 INFER_OK(op, "", "[]"); 910 } 911 912 { 913 // Partial shape 914 ShapeInferenceTestOp op("Placeholder"); 915 const int64 dims[2] = {1, -1}; 916 PartialTensorShape shape; 917 TF_ASSERT_OK(PartialTensorShape::MakePartialShape(dims, 2, &shape)); 918 TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder") 919 .Attr("shape", shape) 920 .Attr("dtype", DT_FLOAT) 921 .Finalize(&op.node_def)); 922 INFER_OK(op, "", "[1,?]"); 923 } 924 925 { 926 // Unknown shape 927 ShapeInferenceTestOp op("Placeholder"); 928 PartialTensorShape shape; 929 TF_ASSERT_OK(NodeDefBuilder("test", "Placeholder") 930 .Attr("shape", shape) 931 .Attr("dtype", DT_FLOAT) 932 .Finalize(&op.node_def)); 933 INFER_OK(op, "", "?"); 934 } 935 } 936 937 TEST(ArrayOpsTest, Transpose_ShapeFn) { 938 ShapeInferenceTestOp op("Transpose"); 939 op.input_tensors.resize(2); 940 941 // Missing shape information. 942 INFER_OK(op, "?;?", "?"); 943 INFER_OK(op, "?;[?]", "?"); 944 INFER_OK(op, "?;[2]", "[?,?]"); 945 INFER_OK(op, "[?];?", "[?]"); 946 INFER_OK(op, "[?,?];[2]", "[?,?]"); 947 INFER_ERROR("Dimension must be 3 but is 2", op, "[1,2,3];[2]"); 948 Tensor perm = test::AsTensor<int32>({0}); 949 op.input_tensors[1] = &perm; 950 INFER_OK(op, "[?];[?]", "[d0_0]"); 951 perm = test::AsTensor<int32>({1, 0}); 952 INFER_OK(op, "?;[2]", "[?,?]"); 953 INFER_OK(op, "[?,?];[2]", "[d0_1,d0_0]"); 954 INFER_OK(op, "[1,?];[2]", "[d0_1,d0_0]"); 955 956 // Invalid arguments. 957 perm = test::AsTensor<int32>({1, 2}); 958 INFER_ERROR("perm dim 2 is out of range of input rank 2", op, "[1,2];[2]"); 959 perm = test::AsTensor<int32>({0}); 960 INFER_ERROR("Dimension must be 2 but is 1", op, "[1,2];[1]"); 961 962 // Larger valid cases. 963 perm = test::AsTensor<int32>({1, 0, 3, 4, 2}); 964 INFER_OK(op, "[0,1,2,3,4];[5]", "[d0_1,d0_0,d0_3,d0_4,d0_2]"); 965 INFER_OK(op, "[0,?,2,3,4];[5]", "[d0_1,d0_0,d0_3,d0_4,d0_2]"); 966 } 967 968 TEST(ArrayOpsTest, Bitcast_ShapeFn) { 969 ShapeInferenceTestOp op("Bitcast"); 970 auto rebuild_node_def = [&op](DataType input_type, DataType output_type) { 971 TF_ASSERT_OK(NodeDefBuilder("test", "Bitcast") 972 .Input("input", 0, input_type) 973 .Attr("type", output_type) 974 .Finalize(&op.node_def)); 975 }; 976 977 rebuild_node_def(DT_FLOAT, DT_INT32); 978 // No valid shape provided, so output is unknown. 979 INFER_OK(op, "?", "?"); 980 981 // Bitcasting from two equal sizes propagates shape. 982 INFER_OK(op, "[1,2]", "in0"); 983 984 // Bitcasting from smaller to larger reduces the size of the last dimension. 985 rebuild_node_def(DT_INT32, DT_INT64); 986 INFER_OK(op, "[1,2]", "[d0_0]"); // last dimension matches divisor. 987 // TODO(vrv): Seems like a bug, or at least, too lenient. 988 INFER_OK(op, "[1,?]", "[d0_0]"); 989 // 4 is divisible by 2, but the shape function signature requires 990 // that the last dimension matches the last value exactly. 991 INFER_ERROR("does not match", op, "[1,4]"); 992 INFER_ERROR("does not match", op, "[1,3]"); 993 994 // Bitcasting from a larger type to a smaller type extends the dimension 995 rebuild_node_def(DT_INT64, DT_INT32); 996 INFER_OK(op, "[4,5]", "[d0_0,d0_1,2]"); 997 rebuild_node_def(DT_COMPLEX128, DT_INT32); 998 INFER_OK(op, "[4,5]", "[d0_0,d0_1,4]"); 999 rebuild_node_def(DT_COMPLEX128, DT_HALF); 1000 INFER_OK(op, "[4,5]", "[d0_0,d0_1,8]"); 1001 rebuild_node_def(DT_COMPLEX128, DT_INT8); 1002 INFER_OK(op, "[4,5]", "[d0_0,d0_1,16]"); 1003 1004 // Bitcasting from a POD or quantized datatype is not allowed. 1005 rebuild_node_def(DT_STRING, DT_INT32); 1006 INFER_ERROR("one of the type sizes is zero", op, "[1,2,3]"); 1007 rebuild_node_def(DT_INT32, DT_STRING); 1008 INFER_ERROR("one of the type sizes is zero", op, "[1,2,3]"); 1009 } 1010 1011 TEST(ArrayOpsTest, Squeeze_ShapeFn) { 1012 ShapeInferenceTestOp op("Squeeze"); 1013 1014 auto rebuild_node_def = [&op](const std::vector<int32>& squeeze_dims) { 1015 TF_ASSERT_OK(NodeDefBuilder("test", "Squeeze") 1016 .Input("input", 0, DT_FLOAT) 1017 .Attr("squeeze_dims", squeeze_dims) 1018 .Finalize(&op.node_def)); 1019 }; 1020 1021 // Default squeeze_dims = [] 1022 rebuild_node_def({}); 1023 1024 // No valid shape provided, so output is unknown. 1025 INFER_OK(op, "?", "?"); 1026 1027 INFER_OK(op, "[1,4,1,5,1]", "[d0_1,d0_3]"); 1028 1029 // Squeezing all dimensions, but see some unknown values. 1030 INFER_OK(op, "[1,?,1,?,1]", "?"); 1031 1032 // Test simple squeeze of an explicit dimension 1033 rebuild_node_def({1}); 1034 INFER_OK(op, "[4,1,5]", "[d0_0,d0_2]"); 1035 // Squeezing unknown dim explicitly, assumes it's 1 at runtime. 1036 INFER_OK(op, "[4,?,5]", "[d0_0,d0_2]"); 1037 1038 // Attempt to squeeze non-one dimension 1039 INFER_ERROR("Can not squeeze dim[1]", op, "[4,6,5]"); 1040 1041 // Squeeze multiple dimensions 1042 rebuild_node_def({1, 2}); 1043 INFER_OK(op, "[4,1,1,5]", "[d0_0,d0_3]"); 1044 rebuild_node_def({1, -2}); 1045 INFER_OK(op, "[4,1,1,5]", "[d0_0,d0_3]"); 1046 1047 // Negative squeeze dim 1048 rebuild_node_def({-2}); 1049 INFER_OK(op, "[4,1,5]", "[d0_0,d0_2]"); 1050 1051 // Test validation of squeeze dimensions 1052 rebuild_node_def({-4}); 1053 INFER_ERROR("not in [-3,3)", op, "[1,2,3]"); 1054 rebuild_node_def({3}); 1055 INFER_ERROR("not in [-3,3)", op, "[1,2,3]"); 1056 } 1057 1058 TEST(ArrayOpsTest, ReverseSequence_ShapeFn) { 1059 ShapeInferenceTestOp op("ReverseSequence"); 1060 auto rebuild_node_def = [&op](const int32 seq_dim, const int32 batch_dim) { 1061 TF_ASSERT_OK(NodeDefBuilder("test", "ReverseSequence") 1062 .Input("input", 0, DT_FLOAT) 1063 .Input("seq_lengths", 1, DT_INT64) 1064 .Attr("seq_dim", seq_dim) 1065 .Attr("batch_dim", batch_dim) 1066 .Finalize(&op.node_def)); 1067 }; 1068 1069 rebuild_node_def(1, 2); 1070 // No valid shape provided, so output is unknown. 1071 INFER_OK(op, "?;[10]", "?"); 1072 1073 // Bad rank for seq_lengths 1074 INFER_ERROR("Shape must be rank 1 but is rank 2", op, "?;[10,10]"); 1075 1076 // Validate seq_dim and batch_dim 1077 rebuild_node_def(1, 4); 1078 INFER_ERROR("batch_dim must be < input rank", op, "[1,2,3];[3]"); 1079 rebuild_node_def(4, 1); 1080 INFER_ERROR("seq_dim must be < input rank", op, "[1,2,3];[3]"); 1081 1082 rebuild_node_def(1, 2); 1083 INFER_OK(op, "[1,2,3];[3]", "[d0_0,d0_1,d0_2]"); 1084 // Resolves uncertainty on batch dimension by merging. 1085 INFER_OK(op, "[1,2,?];[3]", "[d0_0,d0_1,d1_0]"); 1086 INFER_OK(op, "[1,2,3];[?]", "[d0_0,d0_1,d0_2]"); 1087 } 1088 1089 TEST(ArrayOpsTest, Split_ShapeFn) { 1090 ShapeInferenceTestOp op("Split"); 1091 op.input_tensors.resize(2); 1092 1093 // No value for split_dim and no input. 1094 TF_ASSERT_OK(NodeDefBuilder("test", "Split") 1095 .Input("split_dim", 0, DT_INT32) 1096 .Input("value", 1, DT_FLOAT) 1097 .Attr("num_split", 2) 1098 .Finalize(&op.node_def)); 1099 INFER_OK(op, "?;?", "?;?"); 1100 // If the rank is known, we know the rank of each output. 1101 INFER_OK(op, "?;[?,?]", "[?,?];[?,?]"); 1102 1103 // split_dim is unknown but other inputs are known. 1104 INFER_OK(op, "?;[1,4]", "[?,?];[?,?]"); 1105 1106 // split_dim is known. 1107 Tensor split_dim = test::AsTensor<int32>({1, 2}); 1108 op.input_tensors[0] = &split_dim; 1109 INFER_ERROR("Input must be scalar but has rank 1", op, "[?];[?,?]"); 1110 split_dim = test::AsScalar<int32>(1); 1111 INFER_OK(op, "?;?", "?;?"); 1112 INFER_OK(op, "?;[?,?]", "[d1_0,?];[d1_0,?]"); 1113 INFER_OK(op, "?;[1,4]", "[d1_0,2];[d1_0,2]"); 1114 INFER_OK(op, "?;[1,?]", "[d1_0,?];[d1_0,?]"); 1115 INFER_ERROR("Dimension size must be evenly divisible by 2 but is 5", op, 1116 "?;[1,5]"); 1117 1118 // split_dim too large. 1119 split_dim = test::AsScalar<int32>(3); 1120 INFER_ERROR( 1121 "Dimension size, given by scalar input 3 must be in range [-3, 3)", op, 1122 "?;[1,4,8]"); 1123 1124 // Negative split_dim. 1125 split_dim = test::AsScalar<int32>(-1); 1126 INFER_OK(op, "?;?", "?;?"); 1127 INFER_OK(op, "?;[?,?]", "[d1_0,?];[d1_0,?]"); 1128 INFER_OK(op, "?;[1,?]", "[d1_0,?];[d1_0,?]"); 1129 INFER_OK(op, "?;[1,4]", "[d1_0,2];[d1_0,2]"); 1130 INFER_OK(op, "?;[1,4,8]", "[d1_0,d1_1,4];[d1_0,d1_1,4]"); 1131 split_dim = test::AsScalar<int32>(-2); 1132 INFER_OK(op, "?;[1,4,8]", "[d1_0,2,d1_2];[d1_0,2,d1_2]"); 1133 split_dim = test::AsScalar<int32>(-4); 1134 INFER_ERROR( 1135 "Dimension size, given by scalar input -4 must be in range [-3, 3)", op, 1136 "?;[1,4,8]"); 1137 } 1138 1139 TEST(ArrayOpsTest, Tile_ShapeFn) { 1140 ShapeInferenceTestOp op("Tile"); 1141 op.input_tensors.resize(2); 1142 1143 // No value for split_dim and no input. 1144 TF_ASSERT_OK(NodeDefBuilder("test", "Tile") 1145 .Input("input", 0, DT_FLOAT) 1146 .Input("multiples", 1, DT_INT32) 1147 .Finalize(&op.node_def)); 1148 1149 // If both are unknown, output is unknown. 1150 INFER_OK(op, "?;?", "?"); 1151 1152 // If multiples rank is unknown but input is, output rank is known. 1153 INFER_OK(op, "[2,3,1,4];?", "[?,?,?,?]"); 1154 1155 // Bad rank for 'multiples' 1156 INFER_ERROR("Shape must be rank 1 but is rank 2", op, "[2,3,1,4];[4,1]"); 1157 1158 // No multiples tensor available, but output rank is known from multiples. 1159 INFER_OK(op, "?;[4]", "[?,?,?,?]"); 1160 1161 // Test a tile of a 4D input. 1162 Tensor multiples = test::AsTensor<int32>({2, 3, 4, 5}); 1163 op.input_tensors[1] = &multiples; 1164 INFER_OK(op, "[2,3,1,4];[4]", "[4,9,4,20]"); 1165 // Test 64-bit tensor type 1166 multiples = test::AsTensor<int64>({2, 3, 4, 5}); 1167 INFER_OK(op, "[2,3,1,4];[4]", "[4,9,4,20]"); 1168 } 1169 1170 TEST(ArrayOpsTest, EditDistance_ShapeFn) { 1171 ShapeInferenceTestOp op("EditDistance"); 1172 op.input_tensors.resize(6); 1173 1174 // If the shape tensors are not available, the output shape is unknown. 1175 INFER_OK(op, "[?,?];[?];[4];[?,?];[?];[4]", "?"); 1176 1177 Tensor hypothesis_shape = test::AsTensor<int64>({2, 30, 4, 50}); 1178 op.input_tensors[2] = &hypothesis_shape; 1179 Tensor truth_shape = test::AsTensor<int64>({20, 3, 40, 5}); 1180 op.input_tensors[5] = &truth_shape; 1181 INFER_OK(op, "[?,?];[?];[4];[?,?];[?];[4]", "[20,30,40]"); 1182 1183 // Shape elements don't match 1184 hypothesis_shape = test::AsTensor<int64>({2}); 1185 op.input_tensors[2] = &hypothesis_shape; 1186 INFER_ERROR("Num elements of hypothesis_shape does not match truth_shape", op, 1187 "[?,?];[?];[1];[?,?];[?];[4]"); 1188 } 1189 1190 TEST(ArrayOpsTest, OneHot_ShapeFn) { 1191 ShapeInferenceTestOp op("OneHot"); 1192 op.input_tensors.resize(4); 1193 auto set_axis = [&op](int axis) { 1194 TF_ASSERT_OK(NodeDefBuilder("test", "OneHot") 1195 .Input("indices", 0, DT_FLOAT) 1196 .Input("depth", 1, DT_INT32) 1197 .Input("on_value", 2, DT_FLOAT) 1198 .Input("off_value", 3, DT_FLOAT) 1199 .Attr("axis", axis) 1200 .Finalize(&op.node_def)); 1201 }; 1202 1203 // Invalid axis value. 1204 set_axis(-2); 1205 INFER_ERROR("axis must be >= -1", op, "?;?;?;?"); 1206 set_axis(1); 1207 1208 // If indices shape is unknown, we return an unknown shape. 1209 INFER_OK(op, "?;[];?;?", "?"); 1210 1211 // Depth must be scalar. 1212 Tensor depth = test::AsTensor<int32>({1, 2}); 1213 op.input_tensors[1] = &depth; 1214 INFER_ERROR("Input must be scalar but has rank 1", op, "?;[2];?;?"); 1215 1216 // Full information is available. 1217 depth = test::AsScalar<int32>(2); 1218 INFER_OK(op, "[1,3,4];[];?;?", "[d0_0,2,d0_1,d0_2]"); 1219 set_axis(-1); 1220 INFER_OK(op, "[1,3,4];[];?;?", "[d0_0,d0_1,d0_2,2]"); 1221 } 1222 1223 TEST(ArrayOpsTest, ExtractImagePatchesShapeTest) { 1224 ShapeInferenceTestOp op("ExtractImagePatches"); 1225 auto set_op = [&op](const std::vector<int32>& ksizes, 1226 const std::vector<int32>& strides, 1227 const std::vector<int32>& rates, const string& padding) { 1228 TF_ASSERT_OK(NodeDefBuilder("test", "ExtractImagePatches") 1229 .Input("input", 0, DT_FLOAT) 1230 .Attr("ksizes", ksizes) 1231 .Attr("strides", strides) 1232 .Attr("rates", rates) 1233 .Attr("padding", padding) 1234 .Finalize(&op.node_def)); 1235 }; 1236 1237 // Just tests that the ksize calculation with rates works. Most of 1238 // the other code is boilerplate that is tested by a variety of 1239 // other ops. 1240 // 1241 // ksizes is 2x2. rate rows and cols is 2, so ksize_rows and 1242 // cols are changed to be 2 + (2 - 1) = 3. 7x7 input with 3x3 1243 // filter and 1x1 stride gives a 5x5 output. 1244 set_op({1, 2, 2, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID"); 1245 INFER_OK(op, "[1,7,7,2]", "[d0_0,5,5,8]"); 1246 // With ksizes as 1x1, the output depth is now exactly the last value of the 1247 // input and output spatial is reduced as well. 1248 set_op({1, 1, 1, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID"); 1249 INFER_OK(op, "[1,7,7,2]", "[d0_0,7,7,d0_3]"); 1250 1251 // Bad ksize rank 1252 set_op({1, 2, 2, 1, 1}, {1, 1, 1, 1}, {1, 2, 2, 1}, "VALID"); 1253 INFER_ERROR( 1254 "ExtractImagePatches requires the ksizes attribute to contain 4 values, " 1255 "but got: 5", 1256 op, "[1,7,7,2]"); 1257 } 1258 1259 TEST(ArrayOpsTest, QuantizeAndDequantizeV2_ShapeFn) { 1260 ShapeInferenceTestOp op("QuantizeAndDequantizeV2"); 1261 INFER_OK(op, "?;?;?", "in0"); 1262 INFER_OK(op, "[];?;?", "in0"); 1263 INFER_OK(op, "[1,2,?,4,5];?;?", "in0"); 1264 1265 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[1];[]"); 1266 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[];[1]"); 1267 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1,2,?,4,5];[1];[1]"); 1268 } 1269 1270 TEST(ArrayOpsTest, SpaceToBatch_ShapeFn) { 1271 ShapeInferenceTestOp op("SpaceToBatch"); 1272 op.input_tensors.resize(2); 1273 TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToBatch") 1274 .Input("input", 0, DT_FLOAT) 1275 .Input("paddings", 1, DT_INT32) 1276 .Attr("block_size", 2) 1277 .Finalize(&op.node_def)); 1278 1279 // Paddings not known, but batch size can be computed. 1280 INFER_OK(op, "[1,10,10,3];[2,2]", "[4,?,?,d0_3]"); 1281 1282 // Unknown paddings means width and height. 1283 INFER_OK(op, "[1,10,10,3];?", "[4,?,?,d0_3]"); 1284 1285 // Paddings not correct shape 1286 INFER_ERROR("rank", op, "[1,10,10,3];[4]"); 1287 INFER_ERROR("3 and 2", op, "[1,10,10,3];[2,3]"); 1288 1289 Tensor paddings = test::AsTensor<int32>({4, 2, 2, 4}, {{2, 2}}); 1290 op.input_tensors[1] = &paddings; 1291 INFER_OK(op, "[1,10,10,3];[2,2]", "[4,8,8,d0_3]"); 1292 paddings = test::AsTensor<int64>({4, 2, 2, 4}, {{2, 2}}); 1293 INFER_OK(op, "[1,10,10,3];[2,2]", "[4,8,8,d0_3]"); 1294 1295 // Bad paddings values 1296 paddings = test::AsTensor<int32>({1, 2, 3, 4}, {{2, 2}}); 1297 op.input_tensors[1] = &paddings; 1298 INFER_ERROR("Dimension size must be evenly divisible by 2 but is 13", op, 1299 "[1,10,10,3];[2,2]"); 1300 1301 // Negative paddsings 1302 paddings = test::AsTensor<int32>({1, -2, 3, 4}, {{2, 2}}); 1303 op.input_tensors[1] = &paddings; 1304 INFER_ERROR("cannot be negative", op, "[1,10,10,3];[2,2]"); 1305 } 1306 1307 TEST(ArrayOpsTest, SpaceToBatchND_ShapeFn) { 1308 ShapeInferenceTestOp op("SpaceToBatchND"); 1309 op.input_tensors.resize(3); 1310 TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToBatchND") 1311 .Input("input", 0, DT_FLOAT) 1312 .Input("block_shape", 1, DT_INT32) 1313 .Input("paddings", 2, DT_INT32) 1314 .Finalize(&op.node_def)); 1315 1316 // Verify that input shape and paddings shape can be unknown. 1317 INFER_OK(op, "?;[2];?", "?"); 1318 1319 // Only number of input dimensions is known. 1320 INFER_OK(op, "[?,?,?,?];[2];?", "[?,?,?,d0_3]"); 1321 1322 // Dimensions are partially known. 1323 INFER_OK(op, "[?,?,?,2];[2];?", "[?,?,?,d0_3]"); 1324 1325 { 1326 // Dimensions are partially known, block_shape known. 1327 Tensor block_shape = test::AsTensor<int32>({2, 3}); 1328 op.input_tensors[1] = &block_shape; 1329 INFER_OK(op, "[3,?,?,2];[2];?", "[18,?,?,d0_3]"); 1330 1331 // Dimensions are partially known, block_shape and paddings known. 1332 { 1333 Tensor paddings = test::AsTensor<int32>({1, 1, 0, 1}, {{2, 2}}); 1334 op.input_tensors[2] = &paddings; 1335 INFER_OK(op, "[3,?,2,2];[2];[2,2]", "[18,?,1,d0_3]"); 1336 op.input_tensors[2] = nullptr; 1337 } 1338 1339 // Dimensions are fully known, block_shape and paddings are known. 1340 { 1341 Tensor paddings = test::AsTensor<int32>({1, 1, 0, 0}, {{2, 2}}); 1342 op.input_tensors[2] = &paddings; 1343 INFER_OK(op, "[3,2,3,2];[2];[2,2]", "[18,2,1,d0_3]"); 1344 op.input_tensors[2] = nullptr; 1345 } 1346 1347 op.input_tensors[1] = nullptr; 1348 } 1349 1350 INFER_ERROR("block_shape must have rank 1", op, "?;[1,1];?"); 1351 INFER_ERROR("block_shape must have known size", op, "?;[?];?"); 1352 1353 { 1354 Tensor block_shape = test::AsTensor<int32>({0, 2}); 1355 op.input_tensors[1] = &block_shape; 1356 INFER_ERROR("block_shape must be positive", op, "[1,2,2];[2];[2,2]"); 1357 op.input_tensors[1] = nullptr; 1358 } 1359 1360 { 1361 Tensor block_shape = test::AsTensor<int32>({1, 1}); 1362 op.input_tensors[1] = &block_shape; 1363 Tensor paddings = test::AsTensor<int32>({0, -1, 0, 0}, {{2, 2}}); 1364 op.input_tensors[2] = &paddings; 1365 INFER_ERROR("paddings cannot be negative", op, "[1,2,2];[2];[2,2]"); 1366 op.input_tensors[1] = nullptr; 1367 op.input_tensors[2] = nullptr; 1368 } 1369 1370 { 1371 Tensor block_shape = test::AsTensor<int32>({3, 3}); 1372 op.input_tensors[1] = &block_shape; 1373 Tensor paddings = test::AsTensor<int32>({0, 0, 0, 0}, {{2, 2}}); 1374 op.input_tensors[2] = &paddings; 1375 INFER_ERROR("divisible", op, "[1,2,3,1];[2];[2,2]"); 1376 op.input_tensors[1] = nullptr; 1377 op.input_tensors[2] = nullptr; 1378 } 1379 1380 INFER_ERROR("rank", op, "[1,3,3,1];[2];[1]"); 1381 INFER_ERROR("shape", op, "[1,3,3,1];[2];[1,2]"); 1382 } 1383 1384 TEST(ArrayOpsTest, BatchToSpace_ShapeFn) { 1385 ShapeInferenceTestOp op("BatchToSpace"); 1386 op.input_tensors.resize(2); 1387 TF_ASSERT_OK(NodeDefBuilder("test", "BatchToSpace") 1388 .Input("input", 0, DT_FLOAT) 1389 .Input("crops", 1, DT_INT32) 1390 .Attr("block_size", 2) 1391 .Finalize(&op.node_def)); 1392 1393 // croppings not known, but batch size can be computed. 1394 INFER_OK(op, "[4,8,8,3];[2,2]", "[1,?,?,d0_3]"); 1395 1396 // block_size not compatible with batch size 1397 INFER_ERROR("Dimension size must be evenly divisible by", op, 1398 "[5,8,8,3];[2,2]"); 1399 1400 // Unknown croppings means unknown width and height. 1401 INFER_OK(op, "[4,8,8,3];?", "[1,?,?,d0_3]"); 1402 1403 // croppings not correct shape 1404 INFER_ERROR("rank", op, "[4,8,8,3];[4]"); 1405 INFER_ERROR("3 and 2", op, "[4,8,8,3];[2,3]"); 1406 1407 Tensor croppings = test::AsTensor<int64>({4, 2, 2, 4}, {{2, 2}}); 1408 op.input_tensors[1] = &croppings; 1409 INFER_OK(op, "[4,8,8,3];[2,2]", "[1,10,10,d0_3]"); 1410 1411 // Bad croppings values 1412 croppings = test::AsTensor<int32>({100, 2, 3, 4}, {{2, 2}}); 1413 op.input_tensors[1] = &croppings; 1414 INFER_ERROR("Negative dimension size caused by subtracting", op, 1415 "[4,8,8,3];[2,2]"); 1416 croppings = test::AsTensor<int32>({1, 2, 3, 400}, {{2, 2}}); 1417 op.input_tensors[1] = &croppings; 1418 INFER_ERROR("Negative dimension size caused by subtracting", op, 1419 "[4,8,8,3];[2,2]"); 1420 1421 // Negative paddsings 1422 croppings = test::AsTensor<int32>({1, -2, 3, 4}, {{2, 2}}); 1423 op.input_tensors[1] = &croppings; 1424 INFER_ERROR("cannot be negative", op, "[4,8,8,3];[2,2]"); 1425 } 1426 1427 TEST(ArrayOpsTest, BatchToSpaceND_ShapeFn) { 1428 ShapeInferenceTestOp op("BatchToSpaceND"); 1429 op.input_tensors.resize(3); 1430 TF_ASSERT_OK(NodeDefBuilder("test", "BatchToSpaceND") 1431 .Input("input", 0, DT_FLOAT) 1432 .Input("block_shape", 1, DT_INT32) 1433 .Input("crops", 2, DT_INT32) 1434 .Finalize(&op.node_def)); 1435 1436 // Verify that input shape and crops shape can be unknown. 1437 INFER_OK(op, "?;[2];?", "?"); 1438 1439 // Only number of input dimensions is known. 1440 INFER_OK(op, "[?,?,?,?];[2];?", "[?,?,?,d0_3]"); 1441 1442 { 1443 // Dimensions are partially known, block_shape known. 1444 Tensor block_shape = test::AsTensor<int32>({2, 3}); 1445 op.input_tensors[1] = &block_shape; 1446 INFER_OK(op, "[?,?,?,2];[2];?", "[?,?,?,d0_3]"); 1447 1448 INFER_OK(op, "[18,?,?,2];[2];?", "[3,?,?,d0_3]"); 1449 1450 // Dimensions are partially known, block_shape and crops known. 1451 { 1452 Tensor crops = test::AsTensor<int32>({1, 1, 0, 1}, {{2, 2}}); 1453 op.input_tensors[2] = &crops; 1454 INFER_OK(op, "[18,?,2,2];[2];[2,2]", "[3,?,5,d0_3]"); 1455 op.input_tensors[2] = nullptr; 1456 } 1457 1458 // Dimensions are fully known, block_shape and crops are known. 1459 { 1460 Tensor crops = test::AsTensor<int32>({1, 1, 0, 0}, {{2, 2}}); 1461 op.input_tensors[2] = &crops; 1462 INFER_OK(op, "[18,2,1,2];[2];[2,2]", "[3,2,3,d0_3]"); 1463 op.input_tensors[2] = nullptr; 1464 } 1465 1466 op.input_tensors[1] = nullptr; 1467 } 1468 1469 INFER_ERROR("block_shape must have rank 1", op, "?;[1,1];?"); 1470 INFER_ERROR("block_shape must have known size", op, "?;[?];?"); 1471 INFER_ERROR("rank", op, "[2,2];[2];[2,2]"); 1472 INFER_ERROR("rank", op, "[2,2,3];[3];[3,2]"); 1473 1474 { 1475 Tensor block_shape = test::AsTensor<int32>({0, 2}); 1476 op.input_tensors[1] = &block_shape; 1477 INFER_ERROR("block_shape must be positive", op, "[1,2,2];[2];[2,2]"); 1478 op.input_tensors[1] = nullptr; 1479 } 1480 1481 { 1482 Tensor block_shape = test::AsTensor<int32>({1, 1}); 1483 op.input_tensors[1] = &block_shape; 1484 Tensor paddings = test::AsTensor<int32>({0, -1, 0, 0}, {{2, 2}}); 1485 op.input_tensors[2] = &paddings; 1486 INFER_ERROR("crops cannot be negative", op, "[1,2,2];[2];[2,2]"); 1487 op.input_tensors[1] = nullptr; 1488 op.input_tensors[2] = nullptr; 1489 } 1490 1491 // The amount to crop exceeds the padded size. 1492 { 1493 Tensor block_shape = test::AsTensor<int32>({2, 2}); 1494 op.input_tensors[1] = &block_shape; 1495 Tensor crops = test::AsTensor<int32>({3, 2, 0, 0}, {{2, 2}}); 1496 op.input_tensors[2] = &crops; 1497 INFER_ERROR("Negative", op, "[4,2,3,1];[2];[2,2]"); 1498 op.input_tensors[1] = nullptr; 1499 op.input_tensors[2] = nullptr; 1500 } 1501 1502 // The batch size is not divisible by the product of the block_shape. 1503 { 1504 Tensor block_shape = test::AsTensor<int32>({2, 3}); 1505 op.input_tensors[1] = &block_shape; 1506 INFER_ERROR("divisible", op, "[3,1,1,1];[2];[2,2]"); 1507 op.input_tensors[1] = nullptr; 1508 } 1509 } 1510 1511 TEST(ArrayOpsTest, SpaceToDepth_ShapeFn) { 1512 ShapeInferenceTestOp op("SpaceToDepth"); 1513 TF_ASSERT_OK(NodeDefBuilder("test", "SpaceToDepth") 1514 .Input("input", 0, DT_FLOAT) 1515 .Attr("block_size", 2) 1516 .Finalize(&op.node_def)); 1517 1518 INFER_OK(op, "[1,2,4,4]", "[d0_0,1,2,16]"); 1519 1520 // block_size not compatible with space 1521 INFER_ERROR("Dimension size must be evenly divisible by 2 but is 3", op, 1522 "[1,3,8,4]"); 1523 INFER_ERROR("Dimension size must be evenly divisible by 2 but is 5", op, 1524 "[1,2,5,4]"); 1525 1526 // Unknown depth --> Unknown depth. 1527 INFER_OK(op, "[1,2,4,?]", "[d0_0,1,2,?]"); 1528 } 1529 1530 TEST(ArrayOpsTest, DepthToSpace_ShapeFn) { 1531 ShapeInferenceTestOp op("DepthToSpace"); 1532 TF_ASSERT_OK(NodeDefBuilder("test", "DepthToSpace") 1533 .Input("input", 0, DT_FLOAT) 1534 .Attr("block_size", 2) 1535 .Finalize(&op.node_def)); 1536 1537 INFER_OK(op, "[1,1,2,16]", "[d0_0,2,4,4]"); 1538 1539 // Bad depth 1540 INFER_ERROR("Dimension size must be evenly divisible by 4 but is 15", op, 1541 "[1,1,2,15]"); 1542 1543 // Unknown depth --> Unknown depth. 1544 INFER_OK(op, "[1,2,4,?]", "[d0_0,4,8,?]"); 1545 1546 // Check another block size. 1547 TF_ASSERT_OK(NodeDefBuilder("test", "DepthToSpace") 1548 .Input("input", 0, DT_FLOAT) 1549 .Attr("block_size", 10) 1550 .Finalize(&op.node_def)); 1551 INFER_OK(op, "[1,1,2,200]", "[d0_0,10,20,2]"); 1552 } 1553 1554 TEST(ArrayOpsTest, Slice_ShapeFn) { 1555 ShapeInferenceTestOp op("Slice"); 1556 TF_ASSERT_OK(NodeDefBuilder("test", "Slice") 1557 .Input("input", 0, DT_FLOAT) 1558 .Input("begin", 1, DT_INT64) 1559 .Input("sizes", 2, DT_INT64) 1560 .Finalize(&op.node_def)); 1561 1562 // Known rank of input and shape of begin/sizes, but unknown values. 1563 // The best we know is the rank of the output. 1564 INFER_OK(op, "[2,3,4,5];[4];[4]", "[?,?,?,?]"); 1565 1566 // Unknown shape of begin/sizes, we still know the rank. 1567 INFER_OK(op, "[2,3,4,5];[?];[?]", "[?,?,?,?]"); 1568 // Unknown all around 1569 INFER_OK(op, "?;[?];[?]", "?"); 1570 // Can infer based on begin 1571 INFER_OK(op, "?;[4];[?]", "[?,?,?,?]"); 1572 1573 // Bad rank of begin, sizes 1574 INFER_ERROR("must be rank 1", op, "[2,3,4,5];[2,3];[3]"); 1575 INFER_ERROR("must be rank 1", op, "[2,3,4,5];[2];[3,4]"); 1576 // Length of begin doesn't match input rank 1577 INFER_ERROR("must be rank 2", op, "[2,3,4,5];[2];[2]"); 1578 1579 // Tests with known values. 1580 op.input_tensors.resize(3); 1581 Tensor begin = test::AsTensor<int32>({0, 1, 2, 1}); 1582 Tensor sizes = test::AsTensor<int32>({1, 2, 1, 3}); 1583 op.input_tensors[1] = &begin; 1584 op.input_tensors[2] = &sizes; 1585 INFER_OK(op, "[2,3,4,5];[4];[4]", "[1,2,1,3]"); 1586 1587 // -1 in sizes means "get the rest" 1588 sizes = test::AsTensor<int32>({-1, -1, 1, -1}); 1589 INFER_OK(op, "[2,3,4,5];[4];[4]", "[d0_0,2,1,4]"); 1590 1591 begin = test::AsTensor<int32>({0, 1, 2, 6}); 1592 sizes = test::AsTensor<int32>({-1, -1, -1, -1}); 1593 INFER_ERROR("Negative dimension size", op, "[2,3,4,5];[4];[4]"); 1594 1595 begin = test::AsTensor<int32>({0, 1, 2, 5}); 1596 sizes = test::AsTensor<int32>({-1, -1, -1, -2}); 1597 INFER_ERROR("cannot be < -1", op, "[2,3,4,5];[4];[4]"); 1598 } 1599 1600 TEST(ArrayOpsTest, StridedSliceGrad_ShapeFn) { 1601 ShapeInferenceTestOp op("StridedSliceGrad"); 1602 op.input_tensors.resize(5); 1603 INFER_OK(op, "?;?;?;?;?", "?"); 1604 INFER_OK(op, "[?];?;?;?;?", "?"); 1605 INFER_OK(op, "[4];?;?;?;?", "[?,?,?,?]"); 1606 1607 Tensor in_t = test::AsTensor<int32>({1, 2, 3, 4}); 1608 op.input_tensors[0] = &in_t; 1609 INFER_OK(op, "[4];?;?;?;?", "[1,2,3,4]"); 1610 } 1611 1612 TEST(ArrayOpsTest, UnchangedWithQuantizationScalars_ShapeFn) { 1613 for (const char* op_name : {"Dequantize", "FakeQuantWithMinMaxVars"}) { 1614 ShapeInferenceTestOp op(op_name); 1615 1616 INFER_OK(op, "?;?;?", "in0"); 1617 INFER_OK(op, "[1,?,3];[];[]", "in0"); 1618 1619 // Rank check scalars. 1620 INFER_ERROR("be rank 0", op, "[1,?,3];[1];[]"); 1621 INFER_ERROR("be rank 0", op, "[1,?,3];[];[1]"); 1622 } 1623 } 1624 1625 TEST(ArrayOpsTest, FakeQuantWithMinMaxVarsPerChannel) { 1626 ShapeInferenceTestOp op("FakeQuantWithMinMaxVarsPerChannel"); 1627 1628 INFER_OK(op, "?;?;?", "in0"); 1629 INFER_OK(op, "[?];?;?", "in0"); 1630 INFER_OK(op, "[1,?,3];[3];[3]", "in0"); 1631 INFER_OK(op, "[3];[3];[3]", "in0"); 1632 1633 // Rank check vectors. 1634 INFER_ERROR("be rank 1", op, "[1,?,3];[1];[]"); 1635 INFER_ERROR("be rank 1", op, "[1,?,3];[];[1]"); 1636 1637 // Vectors must match each other, and match last dim of input. 1638 INFER_ERROR("must be equal", op, "[1,?,3];[2];[?]"); 1639 INFER_ERROR("must be equal", op, "[1,?,3];[?];[2]"); 1640 INFER_ERROR("must be equal", op, "[1,?,?];[1];[2]"); 1641 INFER_ERROR("must be equal", op, "[5];[4];[?]"); 1642 } 1643 1644 TEST(ArrayOpsTest, FakeQuantWithMinMaxVarsPerChannelGradient) { 1645 ShapeInferenceTestOp op("FakeQuantWithMinMaxVarsPerChannelGradient"); 1646 1647 INFER_OK(op, "?;?;?;?", "in0;[?];[?]"); 1648 INFER_OK(op, "[3];[3];[3];[3]", "in0;in3;in3"); 1649 INFER_OK(op, "[1,3];[1,3];[3];[3]", "in0;in3;in3"); 1650 INFER_OK(op, "[1,2,3,4];[1,2,3,4];[4];[4]", "in0;in3;in3"); 1651 1652 // Rank check vectors. 1653 INFER_ERROR("be equal rank", op, "[1,?,3];[1,?,3];[3];[]"); 1654 INFER_ERROR("be rank 1", op, "[1,?,3];[1,?,3];[];[3]"); 1655 INFER_ERROR("be at least rank 1", op, "[];[];[1];[1]"); 1656 INFER_ERROR("be at most rank 4", op, "[1,2,3,4,5];[1,2,3,4,5];[1];[1]"); 1657 1658 // Vectors must match each other, and match last dim of input. 1659 INFER_ERROR("must be equal", op, "[1,3];[1,3];[2];[3]"); 1660 INFER_ERROR("must be equal", op, "[1,3];[1,3];[3];[2]"); 1661 } 1662 1663 TEST(ArrayOpsTest, QuantizedConcat_ShapeFn) { 1664 ShapeInferenceTestOp op("QuantizedConcat"); 1665 auto set_n = [&op](int n) { 1666 std::vector<NodeDefBuilder::NodeOut> src_list; 1667 std::vector<NodeDefBuilder::NodeOut> limit_list; 1668 for (int i = 0; i < n; ++i) { 1669 src_list.emplace_back("a", 0, DT_QUINT8); 1670 limit_list.emplace_back("b", 0, DT_FLOAT); 1671 } 1672 TF_ASSERT_OK(NodeDefBuilder("test", "QuantizedConcat") 1673 .Input({"concat_dim", 0, DT_INT32}) 1674 .Input(src_list) 1675 .Input(limit_list) 1676 .Input(limit_list) 1677 .Attr("N", n) 1678 .Finalize(&op.node_def)); 1679 }; 1680 1681 // Confirm dimension[0] of the input (the concat_dim) is a scalar. 1682 set_n(1); 1683 INFER_ERROR("Shape must be rank 0 but is rank 1", op, "[1];?;?;?"); 1684 1685 // Last 2*<N> are all scalars. 1686 set_n(2); 1687 INFER_ERROR("must be rank 0", op, "[];?;?;?;?;?;[1]"); 1688 INFER_ERROR("must be rank 0", op, "[];?;?;?;?;[1];?"); 1689 INFER_ERROR("must be rank 0", op, "[];?;?;?;[1];?;?"); 1690 INFER_ERROR("must be rank 0", op, "[];?;?;[1];?;?;?"); 1691 1692 // First is concat dim; next N must be compatible for concat. 1693 set_n(2); 1694 INFER_ERROR("must be rank 2", op, "[];[1,2];[1,2,3];?;?;?;?"); 1695 INFER_OK(op, "[];[1,2];[1,3];?;?;?;?", "[?,?];[];[]"); 1696 1697 // Test when the concat_dim tensor is known. The concatenated dimension is 1698 // summed across all input tensors, and other dimensions are merged. 1699 Tensor concat_dim_t; 1700 op.input_tensors.push_back(&concat_dim_t); 1701 set_n(2); 1702 concat_dim_t = test::AsScalar(0); // Sum dim 0, merge the other two dims. 1703 INFER_OK(op, "[];[100,2,?];[10,?,3];?;?;?;?", "[110,d1_1,d2_2];[];[]"); 1704 INFER_ERROR("Dimension 1 in both shapes must be equal, but are 5 and 3", op, 1705 "[];[100,2,5];[10,?,3];?;?;?;?"); 1706 // Note that other cases of concat are covered in the Concat tests. 1707 } 1708 1709 TEST(StateOpsTest, _ParallelConcatStart_ShapeFn) { 1710 ShapeInferenceTestOp op("_ParallelConcatStart"); 1711 TensorShape shape({1, 2, 3}); 1712 TensorShapeProto shape_proto; 1713 shape.AsProto(&shape_proto); 1714 TF_ASSERT_OK(NodeDefBuilder("test", "_ParallelConcatStart") 1715 .Attr("shape", shape_proto) 1716 .Attr("dtype", DT_FLOAT) 1717 .Finalize(&op.node_def)); 1718 INFER_OK(op, "", "[1,2,3]"); 1719 } 1720 1721 } // end namespace tensorflow 1722