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