1# Copyright 2018 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"""Tests for Keras composite tensor support.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21from absl.testing import parameterized 22 23import numpy as np 24import scipy.sparse 25 26from tensorflow.python import keras 27 28from tensorflow.python.data.ops import dataset_ops 29from tensorflow.python.eager import context 30from tensorflow.python.framework import dtypes 31from tensorflow.python.framework import ops 32from tensorflow.python.framework import sparse_tensor 33from tensorflow.python.framework import test_util 34from tensorflow.python.keras import keras_parameterized 35from tensorflow.python.keras import testing_utils 36from tensorflow.python.keras.engine import input_layer 37from tensorflow.python.keras.layers import core 38from tensorflow.python.keras.layers import Dense 39from tensorflow.python.keras.layers import Embedding 40from tensorflow.python.keras.layers import Layer 41from tensorflow.python.ops import array_ops 42from tensorflow.python.ops import math_ops 43from tensorflow.python.ops import sparse_ops 44from tensorflow.python.ops.ragged import ragged_factory_ops 45from tensorflow.python.ops.ragged import ragged_tensor 46from tensorflow.python.platform import test 47from tensorflow.python.util import nest 48 49 50# Define test-only Layer classes to validate passing Sparse and Ragged tensors 51# between layers. 52class ToDense(Layer): 53 """Create a dense (standard) tensor from the given input tensor.""" 54 55 def __init__(self, default_value, **kwargs): 56 super(ToDense, self).__init__(**kwargs) 57 self._default_value = default_value 58 59 def call(self, inputs): 60 if isinstance(inputs, dict): # Dicts are no longer flattened. 61 # Always a single element in these tests. 62 inputs = nest.flatten(inputs)[0] 63 64 if isinstance(inputs, ragged_tensor.RaggedTensor): 65 output = inputs.to_tensor(default_value=self._default_value) 66 elif isinstance(inputs, sparse_tensor.SparseTensor): 67 output = sparse_ops.sparse_tensor_to_dense( 68 inputs, default_value=self._default_value) 69 elif isinstance(inputs, ops.Tensor): 70 output = inputs 71 else: 72 raise TypeError("Unexpected tensor type %s" % type(inputs).__name__) 73 74 # Return a float so that we can compile models with this as the final layer. 75 return math_ops.cast(output, dtypes.float32) 76 77 78class ToRagged(Layer): 79 """Create a ragged tensor based on a given dense tensor.""" 80 81 def __init__(self, padding, ragged_rank=1, **kwargs): 82 super(ToRagged, self).__init__(**kwargs) 83 self._padding = padding 84 self._ragged_rank = ragged_rank 85 86 def call(self, inputs): 87 return ragged_tensor.RaggedTensor.from_tensor( 88 inputs, padding=self._padding, ragged_rank=self._ragged_rank) 89 90 91class ToSparse(Layer): 92 """Create a sparse tensor based on a given dense tensor.""" 93 94 def call(self, inputs): 95 indices = array_ops.where_v2(math_ops.not_equal(inputs, 0)) 96 values = array_ops.gather_nd(inputs, indices) 97 shape = array_ops.shape(inputs, out_type=dtypes.int64) 98 return sparse_tensor.SparseTensor(indices, values, dense_shape=shape) 99 100 101class _SubclassModel(keras.Model): 102 """A Keras subclass model.""" 103 104 def __init__(self, layers, i_layer=None): 105 super(_SubclassModel, self).__init__() 106 # Note that clone and build doesn't support lists of layers in subclassed 107 # models. Adding each layer directly here. 108 for i, layer in enumerate(layers): 109 setattr(self, self._layer_name_for_i(i), layer) 110 self.num_layers = len(layers) 111 if i_layer is not None: 112 self._set_inputs(i_layer) 113 114 def _layer_name_for_i(self, i): 115 return "layer{}".format(i) 116 117 def call(self, inputs, **kwargs): 118 x = inputs 119 for i in range(self.num_layers): 120 layer = getattr(self, self._layer_name_for_i(i)) 121 x = layer(x) 122 return x 123 124 125def get_model_from_layers_with_input(layers, 126 input_shape=None, 127 input_dtype=None, 128 model_input=None): 129 """Builds a model from a sequence of layers.""" 130 if model_input is not None and input_shape is not None: 131 raise ValueError("Cannot specify a model_input and an input shape.") 132 133 model_type = testing_utils.get_model_type() 134 if model_type == "subclass": 135 return _SubclassModel(layers, model_input) 136 137 if model_type == "sequential": 138 model = keras.models.Sequential() 139 if model_input is not None: 140 model.add(model_input) 141 elif input_shape is not None: 142 model.add(keras.Input(shape=input_shape, dtype=input_dtype)) 143 for layer in layers: 144 model.add(layer) 145 return model 146 147 if model_type == "functional": 148 if model_input is not None: 149 inputs = model_input 150 else: 151 if not input_shape: 152 raise ValueError("Cannot create a functional model from layers with no " 153 "input shape.") 154 inputs = keras.Input(shape=input_shape, dtype=input_dtype) 155 outputs = inputs 156 for layer in layers: 157 outputs = layer(outputs) 158 return keras.Model(inputs, outputs) 159 160 raise ValueError("Unknown model type {}".format(model_type)) 161 162 163def get_test_mode_kwargs(): 164 run_eagerly = testing_utils.should_run_eagerly() 165 return { 166 "run_eagerly": run_eagerly, 167 } 168 169 170@keras_parameterized.run_with_all_model_types 171@keras_parameterized.run_all_keras_modes 172class CompositeTensorInternalTest(keras_parameterized.TestCase): 173 174 def test_internal_ragged_tensors(self): 175 # Create a model that accepts an input, converts it to Ragged, and 176 # converts the ragged tensor back to a dense tensor. 177 layers = [ToRagged(padding=0), ToDense(default_value=-1)] 178 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 179 180 # Define some input data with additional padding. 181 input_data = np.array([[1, 0, 0], [2, 3, 0]]) 182 expected_output = np.array([[1, -1], [2, 3]]) 183 output = model.predict(input_data) 184 self.assertAllEqual(expected_output, output) 185 186 def test_internal_sparse_tensors(self): 187 # Create a model that accepts an input, converts it to Sparse, and 188 # converts the sparse tensor back to a dense tensor. 189 layers = [ToSparse(), ToDense(default_value=-1)] 190 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 191 192 # Define some input data with additional padding. 193 input_data = np.array([[1, 0, 0], [2, 3, 0]]) 194 expected_output = np.array([[1, -1, -1], [2, 3, -1]]) 195 output = model.predict(input_data) 196 self.assertAllEqual(expected_output, output) 197 198 def test_training_internal_ragged_tensors(self): 199 # Create a model that implements y=Mx. This is easy to learn and will 200 # demonstrate appropriate gradient passing. (We have to use RaggedTensors 201 # for this test, as ToSparse() doesn't support gradient propagation through 202 # the layer.) TODO(b/124796939): Investigate this. 203 layers = [core.Dense(2), ToRagged(padding=0), ToDense(default_value=-1)] 204 model = testing_utils.get_model_from_layers(layers, input_shape=(1,)) 205 206 input_data = np.random.rand(1024, 1) 207 expected_data = np.concatenate((input_data * 3, input_data * .5), axis=-1) 208 209 model.compile(loss="mse", optimizer="adam", **get_test_mode_kwargs()) 210 history = model.fit(input_data, expected_data, epochs=10, verbose=0) 211 212 # If the model trained, the loss stored at history[0] should be different 213 # than the one stored at history[-1]. 214 self.assertNotEqual(history.history["loss"][-1], history.history["loss"][0]) 215 216 217@keras_parameterized.run_with_all_model_types 218@keras_parameterized.run_all_keras_modes 219class CompositeTensorOutputTest(keras_parameterized.TestCase): 220 221 def test_ragged_tensor_outputs(self): 222 # Create a model that accepts an input, converts it to Ragged, and 223 # converts the ragged tensor back to a dense tensor. 224 layers = [ToRagged(padding=0)] 225 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 226 model._run_eagerly = testing_utils.should_run_eagerly() 227 228 # Define some input data with additional padding. 229 input_data = np.array([[1, 0, 0], [2, 3, 0]]) 230 output = model.predict(input_data) 231 232 expected_values = [[1], [2, 3]] 233 self.assertAllEqual(expected_values, output) 234 235 def test_ragged_tensor_rebatched_outputs(self): 236 # Create a model that accepts an input, converts it to Ragged, and 237 # converts the ragged tensor back to a dense tensor. 238 layers = [ToRagged(padding=0)] 239 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 240 model._run_eagerly = testing_utils.should_run_eagerly() 241 242 # Define some input data with additional padding. 243 input_data = np.array([[1, 0, 0], [2, 3, 0], [4, 0, 0], [5, 6, 0]]) 244 output = model.predict(input_data, batch_size=2) 245 246 expected_values = [[1], [2, 3], [4], [5, 6]] 247 self.assertAllEqual(expected_values, output) 248 249 def test_sparse_tensor_outputs(self): 250 # Create a model that accepts an input, converts it to Ragged, and 251 # converts the ragged tensor back to a dense tensor. 252 layers = [ToSparse()] 253 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 254 model._run_eagerly = testing_utils.should_run_eagerly() 255 256 # Define some input data with additional padding. 257 input_data = np.array([[1, 0, 0], [2, 3, 0]]) 258 output = model.predict(input_data) 259 260 expected_indices = np.array([[0, 0], [1, 0], [1, 1]]) 261 expected_values = np.array([1, 2, 3]) 262 expected_dense_shape = np.array([2, 3]) 263 264 self.assertAllEqual(output.indices, expected_indices) 265 self.assertAllEqual(output.values, expected_values) 266 self.assertAllEqual(output.dense_shape, expected_dense_shape) 267 268 def test_sparse_tensor_rebatched_outputs(self): 269 # Create a model that accepts an input, converts it to Ragged, and 270 # converts the ragged tensor back to a dense tensor. 271 layers = [ToSparse()] 272 model = testing_utils.get_model_from_layers(layers, input_shape=(None,)) 273 model._run_eagerly = testing_utils.should_run_eagerly() 274 275 # Define some input data with additional padding. 276 input_data = np.array([[1, 0, 0], [2, 3, 0], [4, 0, 0], [5, 6, 0]]) 277 output = model.predict(input_data, batch_size=2) 278 279 expected_indices = np.array([[0, 0], [1, 0], [1, 1], [2, 0], [3, 0], [3, 280 1]]) 281 expected_values = np.array([1, 2, 3, 4, 5, 6]) 282 expected_dense_shape = np.array([4, 3]) 283 284 self.assertAllEqual(output.indices, expected_indices) 285 self.assertAllEqual(output.values, expected_values) 286 self.assertAllEqual(output.dense_shape, expected_dense_shape) 287 288 289def get_input_name(use_dict): 290 # Define the input name. 291 if not use_dict: 292 return None # This is the same as not setting 'name'. 293 elif testing_utils.get_model_type() == "subclass": 294 return "input_1" # Subclass models don"t support input names. 295 else: 296 return "test_input_name" 297 298 299def get_kwargs(use_dataset, action="predict"): 300 if use_dataset or not context.executing_eagerly(): 301 if action == "fit": 302 return {"steps_per_epoch": 1} 303 return {"steps": 1} 304 else: 305 return {"batch_size": 2} 306 307 308def prepare_inputs(data, use_dict, use_dataset, action, input_name): 309 input_data, expected_output = data 310 batch_size = input_data.shape[0] 311 # Prepare the input data. 312 if use_dict: 313 input_data = {input_name: input_data} 314 if use_dataset: 315 if action == "predict": 316 input_data = dataset_ops.DatasetV2.from_tensor_slices(input_data).batch( 317 batch_size) 318 else: 319 input_data = dataset_ops.DatasetV2.from_tensor_slices( 320 (input_data, expected_output)).batch(batch_size) 321 expected_output = None 322 return (input_data, expected_output) 323 324 325@keras_parameterized.run_with_all_model_types 326@keras_parameterized.run_all_keras_modes 327@parameterized.named_parameters( 328 *testing_utils.generate_combinations_with_testcase_name( 329 use_dict=[True, False], 330 use_dataset=[True, False], 331 action=["predict", "evaluate", "fit"])) 332class SparseTensorInputTest(keras_parameterized.TestCase): 333 334 def test_sparse_tensors(self, use_dict, use_dataset, action): 335 data = [(sparse_tensor.SparseTensor([[0, 0, 0], [1, 0, 0], [1, 0, 1]], 336 [1, 2, 3], [2, 1, 3]), 337 np.array([[[1, -1, -1]], [[2, 3, -1]]])), 338 (sparse_tensor.SparseTensor( 339 [[0, 0, 0], [1, 0, 0], [1, 0, 1], [2, 0, 1]], [5, 6, 7, 8], 340 [3, 1, 4]), 341 np.array([[[5, -1, -1, -1]], [[6, 7, -1, -1]], [[-1, 8, -1, 342 -1]]]))] 343 # Prepare the model to test. 344 input_name = get_input_name(use_dict) 345 model_input = input_layer.Input( 346 shape=(1, None), sparse=True, name=input_name, dtype=dtypes.int32) 347 layers = [ToDense(default_value=-1)] 348 model = get_model_from_layers_with_input(layers, model_input=model_input) 349 model.compile( 350 optimizer="sgd", 351 loss="mse", 352 metrics=["accuracy"], 353 **get_test_mode_kwargs()) 354 kwargs = get_kwargs(use_dataset, action) 355 356 # Prepare the input data 357 for data_element in data: 358 input_data, expected_output = prepare_inputs(data_element, use_dict, 359 use_dataset, action, 360 input_name) 361 # Perform the action. 362 if action == "predict": 363 result = model.predict(input_data, **kwargs) 364 self.assertAllEqual(expected_output, result) 365 if action == "evaluate": 366 result = model.evaluate(input_data, expected_output, **kwargs) 367 self.assertAllEqual(1.0, result[-1]) 368 if action == "fit": 369 # TODO(momernick): What's the best way of validating that fit happened? 370 _ = model.fit(input_data, expected_output, shuffle=False, **kwargs) 371 372 373@keras_parameterized.run_with_all_model_types 374@keras_parameterized.run_all_keras_modes 375class ScipySparseTensorInputTest(keras_parameterized.TestCase, 376 test_util.TensorFlowTestCase): 377 378 def test_sparse_scipy_predict_inputs_via_input_layer_args(self): 379 # Create a model that accepts a sparse input and converts the sparse tensor 380 # back to a dense tensor. Scipy sparse matrices are limited to 2D, so use 381 # a one-dimensional shape; note also that scipy's default dtype is int64. 382 model_input = input_layer.Input(shape=(3,), sparse=True, dtype=dtypes.int64) 383 layers = [ToDense(default_value=-1)] 384 model = get_model_from_layers_with_input(layers, model_input=model_input) 385 386 input_data = scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), 387 shape=[2, 3]) 388 expected_output = np.array([[1, -1, -1], [2, 3, -1]]) 389 output = model.predict(input_data, steps=1) 390 self.assertAllEqual(expected_output, output) 391 392 input_data_2 = scipy.sparse.coo_matrix( 393 ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) 394 expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) 395 output_2 = model.predict(input_data_2, steps=1) 396 self.assertAllEqual(expected_output_2, output_2) 397 398 def test_sparse_scipy_eval_inputs(self): 399 # Create a model that accepts a sparse input and converts the sparse tensor 400 # back to a dense tensor. Scipy sparse matrices are limited to 2D, so use 401 # a one-dimensional shape; note also that scipy's default dtype is int64. 402 model_input = input_layer.Input(shape=(3,), sparse=True, dtype=dtypes.int64) 403 layers = [ToDense(default_value=-1)] 404 model = get_model_from_layers_with_input(layers, model_input=model_input) 405 model.compile( 406 optimizer="sgd", 407 loss="mse", 408 metrics=["accuracy"]) 409 410 input_data = scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), 411 shape=[2, 3]) 412 expected_output = np.array([[1, -1, -1], [2, 3, -1]]) 413 414 output = model.evaluate(input_data, expected_output, steps=1) 415 self.assertAllEqual(1.0, output[-1]) 416 417 input_data_2 = scipy.sparse.coo_matrix( 418 ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) 419 expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) 420 output_2 = model.evaluate(input_data_2, expected_output_2, steps=1) 421 self.assertAllEqual(1.0, output_2[-1]) 422 423 def test_sparse_scipy_predict_input_dicts_via_input_layer_args(self): 424 # Create a model that accepts a sparse input and converts the sparse tensor 425 # back to a dense tensor. Scipy sparse matrices are limited to 2D, so use 426 # a one-dimensional shape; note also that scipy's default dtype is int64. 427 if testing_utils.get_model_type() == "subclass": 428 input_name = "input_1" # Subclass models don"t support input names. 429 else: 430 input_name = "test_input_name" 431 model_input = input_layer.Input( 432 shape=(3,), sparse=True, name=input_name, dtype=dtypes.int64) 433 layers = [ToDense(default_value=-1)] 434 model = get_model_from_layers_with_input(layers, model_input=model_input) 435 436 input_data = { 437 input_name: 438 scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), 439 shape=[2, 3]) 440 } 441 expected_output = np.array([[1, -1, -1], [2, 3, -1]]) 442 output = model.predict(input_data, steps=1) 443 self.assertAllEqual(expected_output, output) 444 445 input_data_2 = { 446 input_name: 447 scipy.sparse.coo_matrix( 448 ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) 449 } 450 expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) 451 output_2 = model.predict(input_data_2, steps=1) 452 self.assertAllEqual(expected_output_2, output_2) 453 454 def test_sparse_scipy_eval_input_dicts(self): 455 # Create a model that accepts a sparse input and converts the sparse tensor 456 # back to a dense tensor. Scipy sparse matrices are limited to 2D, so use 457 # a one-dimensional shape; note also that scipy's default dtype is int64. 458 if testing_utils.get_model_type() == "subclass": 459 input_name = "input_1" # Subclass models don"t support input names. 460 else: 461 input_name = "test_input_name" 462 model_input = input_layer.Input( 463 shape=(3,), sparse=True, name=input_name, dtype=dtypes.int64) 464 layers = [ToDense(default_value=-1)] 465 model = get_model_from_layers_with_input(layers, model_input=model_input) 466 model.compile( 467 optimizer="sgd", 468 loss="mse", 469 metrics=["accuracy"]) 470 471 input_data = { 472 input_name: 473 scipy.sparse.coo_matrix(([1, 2, 3], ([0, 1, 1], [0, 0, 1])), 474 shape=[2, 3]) 475 } 476 expected_output = np.array([[1, -1, -1], [2, 3, -1]]) 477 output = model.evaluate(input_data, expected_output, steps=1) 478 self.assertAllEqual(1.0, output[-1]) 479 480 input_data_2 = { 481 input_name: 482 scipy.sparse.coo_matrix( 483 ([5, 6, 7, 8], ([0, 1, 1, 2], [0, 0, 1, 1])), shape=[3, 3]) 484 } 485 expected_output_2 = np.array([[5, -1, -1], [6, 7, -1], [-1, 8, -1]]) 486 output_2 = model.evaluate(input_data_2, expected_output_2, steps=1) 487 self.assertAllEqual(1.0, output_2[-1]) 488 489 490@keras_parameterized.run_with_all_model_types 491@keras_parameterized.run_all_keras_modes 492@parameterized.named_parameters( 493 *testing_utils.generate_combinations_with_testcase_name( 494 use_dict=[True, False], 495 use_dataset=[True, False], 496 action=["predict", "evaluate", "fit"])) 497class RaggedTensorInputTest(keras_parameterized.TestCase, 498 test_util.TensorFlowTestCase): 499 500 def test_ragged_input(self, use_dict, use_dataset, action): 501 data = [(ragged_factory_ops.constant([[[1]], [[2, 3]]]), 502 np.array([[[1, -1]], [[2, 3]]]))] 503 504 # Prepare the model to test. 505 input_name = get_input_name(use_dict) 506 model_input = input_layer.Input( 507 shape=(None, None), ragged=True, name=input_name, dtype=dtypes.int32, 508 batch_size=2) 509 self.assertIsInstance(model_input._type_spec, 510 ragged_tensor.RaggedTensorSpec) 511 self.assertEqual(model_input.shape.as_list(), [2, None, None]) 512 layers = [ToDense(default_value=-1)] 513 model = get_model_from_layers_with_input(layers, model_input=model_input) 514 model.compile( 515 optimizer="sgd", 516 loss="mse", 517 metrics=["accuracy"], 518 **get_test_mode_kwargs()) 519 520 # Prepare the input data 521 for data_element in data: 522 input_data, expected_output = prepare_inputs(data_element, use_dict, 523 use_dataset, action, 524 input_name) 525 # Perform the action. 526 if action == "predict": 527 result = model.predict(input_data) 528 self.assertAllEqual(expected_output, result) 529 if action == "evaluate": 530 result = model.evaluate(input_data, expected_output) 531 self.assertAllEqual(1.0, result[-1]) 532 if action == "fit": 533 # TODO(momernick): What's the best way of validating that fit happened? 534 _ = model.fit(input_data, expected_output, shuffle=False) 535 536 537@keras_parameterized.run_with_all_model_types 538@keras_parameterized.run_all_keras_modes 539@parameterized.named_parameters( 540 *testing_utils.generate_combinations_with_testcase_name( 541 use_dict=[True, False], use_dataset=[True, False])) 542class RaggedTensorInputValidationTest(keras_parameterized.TestCase, 543 test_util.TensorFlowTestCase): 544 545 def test_ragged_tensor_input_with_one_none_dimension(self, use_dict, 546 use_dataset): 547 # Define some input data. 548 data = [(ragged_factory_ops.constant([[[1, 0]], [[2, 3]]], ragged_rank=1), 549 np.array([[[1, 0]], [[2, 3]]]))] 550 551 # Prepare the model to test. 552 input_shape = (None, 2) # RaggedTensorInputTest uses (None, None). 553 input_name = get_input_name(use_dict) 554 model_input = input_layer.Input( 555 shape=input_shape, ragged=True, name=input_name, dtype=dtypes.int32) 556 layers = [ToDense(default_value=-1)] 557 model = get_model_from_layers_with_input(layers, model_input=model_input) 558 model.compile( 559 optimizer="sgd", 560 loss="mse", 561 metrics=["accuracy"], 562 **get_test_mode_kwargs()) 563 564 for data_element in data: 565 input_data, expected_output = prepare_inputs( 566 data_element, 567 use_dict, 568 use_dataset, 569 action="predict", 570 input_name=input_name) 571 result = model.predict(input_data) 572 self.assertAllEqual(expected_output, result) 573 574 def test_ragged_tensor_input_with_no_none_dimension(self, use_dict, 575 use_dataset): 576 # Define some input data. 577 data = [(ragged_factory_ops.constant([[[1, 0]], [[2, 3]]], ragged_rank=0), 578 np.array([[[1, 0]], [[2, 3]]]))] 579 580 # Prepare the model to test. 581 input_shape = (1, 2) # RaggedTensorInputTest uses (None, None). 582 input_name = get_input_name(use_dict) 583 model_input = input_layer.Input( 584 shape=input_shape, ragged=True, name=input_name, dtype=dtypes.int32) 585 layers = [ToDense(default_value=-1)] 586 model = get_model_from_layers_with_input(layers, model_input=model_input) 587 model.compile( 588 optimizer="sgd", 589 loss="mse", 590 metrics=["accuracy"], 591 **get_test_mode_kwargs()) 592 kwargs = get_kwargs(use_dataset) 593 594 for data_element in data: 595 input_data, expected_output = prepare_inputs( 596 data_element, 597 use_dict, 598 use_dataset, 599 action="predict", 600 input_name=input_name) 601 result = model.predict(input_data, **kwargs) 602 self.assertAllEqual(expected_output, result) 603 604 605@keras_parameterized.run_with_all_model_types() 606@keras_parameterized.run_all_keras_modes(always_skip_v1=True) 607class CompositeTensorModelPredictTest(keras_parameterized.TestCase): 608 609 def _normalize_shape(self, shape): 610 if not isinstance(shape, tuple): 611 shape = tuple(shape.as_list()) 612 return shape 613 614 def test_sparse_tensor_model_predict(self): 615 # Create a model that accepts a sparse input and runs a "Dense" layer on it. 616 model_input = input_layer.Input( 617 shape=(3,), sparse=True, dtype=dtypes.float32) 618 619 self.assertEqual([None, 3], model_input.shape.as_list()) 620 621 layers = [Dense(2)] 622 model = get_model_from_layers_with_input(layers, model_input=model_input) 623 624 sparse_input = sparse_tensor.SparseTensor( 625 # A two-row matrix 626 indices=[(0, 0), (0, 1), (0, 2), (5, 0), (5, 1), (5, 2)], 627 values=[1., 1., 1., 1., 1., 1.], 628 dense_shape=(6, 3)) 629 630 shape = model(sparse_input).shape 631 self.assertEqual((6, 2), self._normalize_shape(shape)) 632 633 shape = model.predict(sparse_input, steps=1).shape 634 self.assertEqual((6, 2), self._normalize_shape(shape)) 635 636 def test_ragged_tensor_model_predict(self): 637 # Create a model that accepts a sparse input and runs a "Dense" layer on it. 638 model_input = input_layer.Input(shape=(None,), ragged=True) 639 self.assertEqual([None, None], model_input.shape.as_list()) 640 641 layers = [Embedding(input_dim=7, output_dim=5)] 642 model = get_model_from_layers_with_input(layers, model_input=model_input) 643 644 ragged_input = ragged_factory_ops.constant([ 645 [1, 2, 3, 4, 5], 646 [2, 4], 647 ]) 648 649 shape = model(ragged_input).shape 650 self.assertEqual((2, None, 5), self._normalize_shape(shape)) 651 652 shape = model.predict(ragged_input, steps=1).shape 653 self.assertEqual((2, None, 5), self._normalize_shape(shape)) 654 655 656if __name__ == "__main__": 657 test.main() 658