def test_metric_correctness(self, distribution):
    with self.cached_session():
      keras.backend.set_image_data_format('channels_last')
      num_samples = 10000

      x_train = np.random.randint(0, 2, num_samples)
      x_train = np.reshape(x_train, (num_samples, 1))
      y_train = x_train
      x_train = x_train.astype('float32')
      y_train = y_train.astype('float32')

      # Create identity model.
      model = keras.Sequential()
      model.add(
          keras.layers.Dense(1, input_shape=(1,), kernel_initializer='ones'))
      model.compile(
          loss=keras.losses.mean_squared_error,
          optimizer=gradient_descent.GradientDescentOptimizer(0.5),
          metrics=[keras.metrics.BinaryAccuracy()],
          distribute=distribution)

      batch_size = 64
      if not distributed_training_utils.global_batch_size_supported(
          distribution):
        batch_size //= distribution.num_replicas_in_sync
      train_dataset = dataset_ops.Dataset.from_tensor_slices((x_train, y_train))
      train_dataset = batch_wrapper(train_dataset, batch_size, distribution)

      history = model.fit(x=train_dataset, epochs=2, steps_per_epoch=10)
      self.assertEqual(history.history['binary_accuracy'], [1.0, 1.0])
    def test_metric_correctness(self, distribution):
        with self.cached_session():
            keras.backend.set_image_data_format('channels_last')
            num_samples = 10000

            x_train = np.random.randint(0, 2, num_samples)
            x_train = np.reshape(x_train, (num_samples, 1))
            y_train = x_train
            x_train = x_train.astype('float32')
            y_train = y_train.astype('float32')

            # Create identity model.
            model = keras.Sequential()
            model.add(
                keras.layers.Dense(1,
                                   input_shape=(1, ),
                                   kernel_initializer='ones'))
            model.compile(
                loss=keras.losses.mean_squared_error,
                optimizer=gradient_descent.GradientDescentOptimizer(0.5),
                metrics=[keras.metrics.BinaryAccuracy()],
                distribute=distribution,
                experimental_run_tf_function=False)

            batch_size = 64
            if not distributed_training_utils.global_batch_size_supported(
                    distribution):
                batch_size //= distribution.num_replicas_in_sync
            train_dataset = dataset_ops.Dataset.from_tensor_slices(
                (x_train, y_train))
            train_dataset = batch_wrapper(train_dataset, batch_size,
                                          distribution)

            history = model.fit(x=train_dataset, epochs=2, steps_per_epoch=10)
            self.assertEqual(history.history['binary_accuracy'], [1.0, 1.0])
Exemple #3
0
def get_batch_size(global_batch_size, distribution):
  batch_size = global_batch_size
  # TODO(b/118776054): Use global batch size for Keras/DS support.
  use_per_core_batch_size = (
      distribution and
      not distributed_training_utils.global_batch_size_supported(distribution))
  if use_per_core_batch_size:
    batch_size //= distribution.num_replicas_in_sync
  return batch_size
def get_batch_size(global_batch_size, distribution):
  batch_size = global_batch_size
  # TODO(b/118776054): Use global batch size for Keras/DS support.
  use_per_core_batch_size = (
      distribution and
      not distributed_training_utils.global_batch_size_supported(distribution))
  if use_per_core_batch_size:
    batch_size //= distribution.num_replicas_in_sync
  return batch_size
Exemple #5
0
def get_input_params(distribution_strategy,
                     num_samples,
                     steps,
                     batch_size,
                     mode=None):
    """Calculate the number of batches and steps/steps_per_epoch.

  Args:
    distribution_strategy: The DistributionStrategy used to compile the model.
    num_samples: The number of samples from which we determine the batch size
      and steps.
    steps:  The specified number of steps.
    batch_size: The specified batch_size.
    mode: ModeKey representing whether input will be used for training,
      evaluation, or prediction. This is used to relax the constraints on
      consuming all the training samples to keep compatibility till we support
      partial batches. If none, then partial batches are not allowed.

  Returns:
    steps: The steps or steps_per_epoch argument depending on if a user is
        calling `fit`, `evaluate` or `predict`. If the is_training flag is set
        we don't require the number of samples to be used completely.
    batch_size: The batch size to be used in model iterations.

  Raises:
    ValueError: If the number of batches or steps evaluates to 0.

  """
    # TODO(b/118776054): Use global batch size for Keras/DS support.
    # Currently this is only supported in TPUStrategy and CoreMirroredStrategy.
    use_per_replica_batch = not dist_utils.global_batch_size_supported(
        distribution_strategy)

    # TODO(b/128995245): In eager mode, uneven batch sizes are allowed except for
    # `fit()` on TPUStrategy.
    # In graph mode, the zero batch case in batch norm is not handled due to
    # XLA-GPU regression. Uneven batch sizes are not allowed except
    # for `test()` and `predict()` on TPUStrategy.
    if context.executing_eagerly():
        allow_partial_batch = (
            mode != ModeKeys.TRAIN
            or not backend.is_tpu_strategy(distribution_strategy))
    else:
        allow_partial_batch = (mode == ModeKeys.TRAIN or (
            (mode == ModeKeys.PREDICT or mode == ModeKeys.TEST)
            and backend.is_tpu_strategy(distribution_strategy)))

    if steps is None:
        if batch_size is None:
            # If neither the batch size or number of steps are set. We choose the
            # global batch size as the minimum of number of samples and 32. 32 is
            # chosen to provide backward compatibility.
            global_batch_size = min(num_samples, 32)
        else:
            # If the user provided the batch size we need to handle the case
            # between different strategies that use the global/per-replica batch size
            global_batch_size = batch_size
            if use_per_replica_batch:
                global_batch_size *= distribution_strategy.num_replicas_in_sync
        if allow_partial_batch:
            steps = np.ceil(num_samples / global_batch_size).astype(int)
        else:
            if num_samples % global_batch_size:
                raise ValueError(
                    'The number of samples %s is not divisible by '
                    'batch size %s.' % (num_samples, global_batch_size))
            steps = num_samples // global_batch_size
    else:
        if batch_size is None:
            # We calculate the batch size based on the number of steps specified
            if num_samples % steps:
                raise ValueError(
                    'The number of samples %s is not divisible by '
                    'steps %s. Please change the number of steps to a '
                    'value that can consume all the samples' %
                    (num_samples, steps))
            global_batch_size = num_samples // steps
        else:
            # If the user provided the batch size we need to handle the case
            # between different strategies that use the global/per-replica batch size
            global_batch_size = batch_size
            if use_per_replica_batch:
                global_batch_size *= distribution_strategy.num_replicas_in_sync

            min_num_samples = global_batch_size * steps
            if allow_partial_batch:
                min_num_samples = global_batch_size * (
                    steps - 1) + 1 if steps > 1 else 0

            if num_samples < min_num_samples:
                raise ValueError(
                    'Number of samples %s is less than samples required '
                    'for specified batch_size %s and steps %s' %
                    (num_samples, global_batch_size, steps))

    # We need to return the per replica or global batch size based on the strategy
    if use_per_replica_batch:
        if global_batch_size % distribution_strategy.num_replicas_in_sync:
            raise ValueError(
                'The batch size (%s) could not be sharded evenly across the sync '
                'replicas (%s) in the distribution strategy.' %
                (global_batch_size,
                 distribution_strategy.num_replicas_in_sync))
        batch_size = global_batch_size // distribution_strategy.num_replicas_in_sync
    else:
        batch_size = global_batch_size

    return steps, batch_size
Exemple #6
0
    def __init__(self,
                 input_shape=None,
                 batch_size=None,
                 dtype=None,
                 input_tensor=None,
                 sparse=False,
                 name=None,
                 ragged=False,
                 **kwargs):
        strategy = distribution_strategy_context.get_strategy()
        if strategy and batch_size is not None and \
            distributed_training_utils.global_batch_size_supported(strategy):
            if batch_size % strategy.num_replicas_in_sync != 0:
                raise ValueError(
                    'The `batch_size` argument value {} cannot be '
                    'divisible by number of replicas {}'.format(
                        batch_size, strategy.num_replicas_in_sync))
            batch_size = batch_size // strategy.num_replicas_in_sync

        if 'batch_input_shape' in kwargs:
            batch_input_shape = kwargs.pop('batch_input_shape')
            if input_shape and batch_input_shape:
                raise ValueError('Only provide the input_shape OR '
                                 'batch_input_shape argument to '
                                 'InputLayer, not both at the same time.')
            batch_size = batch_input_shape[0]
            input_shape = batch_input_shape[1:]
        if kwargs:
            raise ValueError('Unrecognized keyword arguments:', kwargs.keys())

        if not name:
            prefix = 'input'
            name = prefix + '_' + str(backend.get_uid(prefix))

        if not dtype:
            if input_tensor is None:
                dtype = backend.floatx()
            else:
                dtype = backend.dtype(input_tensor)
        elif input_tensor is not None and input_tensor.dtype != dtype:
            raise ValueError(
                '`input_tensor.dtype` differs from `dtype`: %s vs. %s' %
                (input_tensor.dtype, dtype))
        super(InputLayer, self).__init__(dtype=dtype, name=name)
        self.built = True
        self.sparse = sparse
        self.batch_size = batch_size
        self.supports_masking = True

        if isinstance(input_shape, tensor_shape.TensorShape):
            input_shape = tuple(input_shape.as_list())
        elif isinstance(input_shape, int):
            input_shape = (input_shape, )

        if input_tensor is None:
            if input_shape is not None:
                batch_input_shape = (batch_size, ) + tuple(input_shape)
            else:
                batch_input_shape = None
            graph = backend.get_graph()
            with graph.as_default():
                input_tensor = backend.placeholder(shape=batch_input_shape,
                                                   dtype=dtype,
                                                   name=self.name,
                                                   sparse=sparse,
                                                   ragged=ragged)

            self.is_placeholder = True
            self._batch_input_shape = batch_input_shape
        else:
            if not tf_utils.is_symbolic_tensor(input_tensor):
                raise ValueError(
                    'You should not pass an EagerTensor to `Input`. '
                    'For example, instead of creating an '
                    'InputLayer, you should instantiate your model and '
                    'directly call it on your input.')
            self.is_placeholder = False
            self._batch_input_shape = tuple(input_tensor.shape.as_list())

        # Create an input node to add to self.outbound_node
        # and set output_tensors' _keras_history.
        input_tensor._keras_history = base_layer.KerasHistory(self, 0, 0)
        input_tensor._keras_mask = None
        node_module.Node(self,
                         inbound_layers=[],
                         node_indices=[],
                         tensor_indices=[],
                         input_tensors=[input_tensor],
                         output_tensors=[input_tensor])
Exemple #7
0
  def __init__(self,
               input_shape=None,
               batch_size=None,
               dtype=None,
               input_tensor=None,
               sparse=False,
               name=None,
               **kwargs):
    strategy = distribution_strategy_context.get_strategy()
    if strategy and batch_size is not None and \
        distributed_training_utils.global_batch_size_supported(strategy):
      if batch_size % strategy.num_replicas_in_sync != 0:
        raise ValueError('The `batch_size` argument value {} cannot be '
                         'divisible by number of replicas {}'.format(
                             batch_size, strategy.num_replicas_in_sync))
      batch_size = batch_size // strategy.num_replicas_in_sync

    if 'batch_input_shape' in kwargs:
      batch_input_shape = kwargs.pop('batch_input_shape')
      if input_shape and batch_input_shape:
        raise ValueError('Only provide the input_shape OR '
                         'batch_input_shape argument to '
                         'InputLayer, not both at the same time.')
      batch_size = batch_input_shape[0]
      input_shape = batch_input_shape[1:]
    if kwargs:
      raise ValueError('Unrecognized keyword arguments:', kwargs.keys())

    if not name:
      prefix = 'input'
      name = prefix + '_' + str(backend.get_uid(prefix))

    if not dtype:
      if input_tensor is None:
        dtype = backend.floatx()
      else:
        dtype = backend.dtype(input_tensor)
    elif input_tensor is not None and input_tensor.dtype != dtype:
      raise ValueError('`input_tensor.dtype` differs from `dtype`: %s vs. %s' %
                       (input_tensor.dtype, dtype))
    super(InputLayer, self).__init__(dtype=dtype, name=name)
    self.built = True
    self.sparse = sparse
    self.batch_size = batch_size
    self.supports_masking = True

    if isinstance(input_shape, tensor_shape.TensorShape):
      input_shape = tuple(input_shape.as_list())
    elif isinstance(input_shape, int):
      input_shape = (input_shape,)

    if input_tensor is None:
      if input_shape is not None:
        batch_input_shape = (batch_size,) + tuple(input_shape)
      else:
        batch_input_shape = None
      graph = backend.get_graph()
      with graph.as_default():
        # In graph mode, create a graph placeholder to call the layer on.
        if sparse:
          input_tensor = backend.placeholder(
              shape=batch_input_shape,
              dtype=dtype,
              name=self.name,
              sparse=True)
        else:
          input_tensor = backend.placeholder(
              shape=batch_input_shape,
              dtype=dtype,
              name=self.name)

      self.is_placeholder = True
      self._batch_input_shape = batch_input_shape
    else:
      if not tf_utils.is_symbolic_tensor(input_tensor):
        raise ValueError('You should not pass an EagerTensor to `Input`. '
                         'For example, instead of creating an '
                         'InputLayer, you should instantiate your model and '
                         'directly call it on your input.')
      self.is_placeholder = False
      self._batch_input_shape = tuple(input_tensor.shape.as_list())

    # Create an input node to add to self.outbound_node
    # and set output_tensors' _keras_history.
    input_tensor._keras_history = (self, 0, 0)  # pylint: disable=protected-access
    input_tensor._keras_mask = None
    base_layer.Node(
        self,
        inbound_layers=[],
        node_indices=[],
        tensor_indices=[],
        input_tensors=[input_tensor],
        output_tensors=[input_tensor])
Exemple #8
0
    def __init__(self,
                 input_shape=None,
                 batch_size=None,
                 dtype=None,
                 input_tensor=None,
                 sparse=None,
                 name=None,
                 ragged=None,
                 type_spec=None,
                 **kwargs):
        self._init_input_shape = input_shape
        self._init_batch_size = batch_size
        self._init_dtype = dtype
        self._init_sparse = sparse
        self._init_ragged = ragged
        self._init_type_spec = type_spec

        strategy = distribution_strategy_context.get_strategy()
        if strategy and batch_size is not None and \
            distributed_training_utils.global_batch_size_supported(strategy):
            if batch_size % strategy.num_replicas_in_sync != 0:
                raise ValueError(
                    'The `batch_size` argument ({}) must be divisible by '
                    'the number of replicas ({})'.format(
                        batch_size, strategy.num_replicas_in_sync))
            batch_size = batch_size // strategy.num_replicas_in_sync

        if 'batch_input_shape' in kwargs:
            batch_input_shape = kwargs.pop('batch_input_shape')
            if input_shape and batch_input_shape:
                raise ValueError('Only provide the input_shape OR '
                                 'batch_input_shape argument to '
                                 'InputLayer, not both at the same time.')
            batch_size = batch_input_shape[0]
            input_shape = batch_input_shape[1:]
        if kwargs:
            raise ValueError('Unrecognized keyword arguments:', kwargs.keys())

        if sparse and ragged:
            raise ValueError(
                'Cannot set both sparse and ragged to True in a Keras input.')

        if not name:
            prefix = 'input'
            name = prefix + '_' + str(backend.get_uid(prefix))

        if not dtype:
            if input_tensor is None:
                dtype = backend.floatx()
            else:
                dtype = backend.dtype(input_tensor)
        elif input_tensor is not None and input_tensor.dtype != dtype:
            raise ValueError(
                '`input_tensor.dtype` differs from `dtype`: %s vs. %s' %
                (input_tensor.dtype, dtype))
        super(InputLayer, self).__init__(dtype=dtype, name=name)
        self.built = True
        self.sparse = True if sparse else False
        self.ragged = True if ragged else False
        self.batch_size = batch_size
        self.supports_masking = True

        if isinstance(input_shape, tensor_shape.TensorShape):
            input_shape = tuple(input_shape.as_list())
        elif isinstance(input_shape, int):
            input_shape = (input_shape, )

        if type_spec is not None:
            args_that_must_be_none = [
                ('(input_)shape', self._init_input_shape),
                ('batch_size', self._init_batch_size),
                ('dtype', self._init_dtype),
                ('input_tensor', input_tensor),
                ('sparse', self._init_sparse),
                ('ragged', self._init_ragged),
            ]
            for arg_name, arg in args_that_must_be_none:
                _assert_other_arg_none(arg_name, arg)
            if not keras_tensor.keras_tensors_enabled():
                raise ValueError(
                    'Creating Keras inputs from a type_spec is only '
                    'supported when eager execution is enabled.')
            input_tensor = keras_tensor.keras_tensor_from_type_spec(type_spec)
            if isinstance(input_tensor, keras_tensor.SparseKerasTensor):
                self.sparse = True
            if isinstance(input_tensor, keras_tensor.RaggedKerasTensor):
                self.ragged = True
            self.is_placeholder = True
            try:
                self._batch_input_shape = tuple(input_tensor.shape.as_list())
            except ValueError:
                # If the shape cannot be represented as a tuple (e.g. unknown rank)
                self._batch_input_shape = None
        elif input_tensor is None:
            if input_shape is not None:
                batch_input_shape = (batch_size, ) + tuple(input_shape)
            else:
                batch_input_shape = None
            graph = backend.get_graph()
            with graph.as_default():
                input_tensor = backend.placeholder(shape=batch_input_shape,
                                                   dtype=dtype,
                                                   name=self.name,
                                                   sparse=sparse,
                                                   ragged=ragged)

            self.is_placeholder = True
            self._batch_input_shape = batch_input_shape
        else:
            if keras_tensor.keras_tensors_enabled():
                if not isinstance(input_tensor, keras_tensor.KerasTensor):
                    input_tensor = keras_tensor.keras_tensor_from_tensor(
                        input_tensor)
            else:
                if not tf_utils.is_symbolic_tensor(input_tensor):
                    raise ValueError(
                        'You should not pass an EagerTensor to `Input`. '
                        'For example, instead of creating an '
                        'InputLayer, you should instantiate your model and '
                        'directly call it on your input.')
            self.is_placeholder = False
            try:
                self._batch_input_shape = tuple(input_tensor.shape.as_list())
            except ValueError:
                # If the shape cannot be represented as a tuple (e.g. unknown rank)
                self._batch_input_shape = None
        # Create an input node.
        input_tensor._keras_mask = None
        node_module.Node(layer=self, outputs=input_tensor)

        # Store type spec
        if isinstance(input_tensor, keras_tensor.KerasTensor) or (
                tf_utils.is_extension_type(input_tensor)):
            self._type_spec = input_tensor._type_spec  # pylint: disable=protected-access
        else:
            self._type_spec = tensor_spec.TensorSpec(shape=input_tensor.shape,
                                                     dtype=input_tensor.dtype,
                                                     name=self.name)
def get_correctness_test_inputs(use_numpy, use_validation_data,
                                with_distribution,
                                x_train, y_train, x_predict):
  """Generates the inputs for correctness check when enable Keras with DS."""
  training_epochs = 2
  global_batch_size = 64
  batch_size = global_batch_size
  # TODO(b/118776054): Use global batch size for Keras/DS support.
  use_per_core_batch_size = (
      with_distribution and
      not distributed_training_utils.global_batch_size_supported(
          with_distribution))
  if use_per_core_batch_size:
    batch_size //= with_distribution.num_replicas_in_sync

  if use_numpy:
    training_inputs = {
        'batch_size': batch_size,
        'x': x_train,
        'y': y_train,
        'epochs': training_epochs,
        'shuffle': False,
    }

    if use_validation_data:
      eval_inputs = None
      training_inputs['validation_data'] = (x_train, y_train)
    else:
      eval_inputs = {
          'batch_size': batch_size,
          'x': x_train,
          'y': y_train,
      }
    predict_inputs = {
        'x': np.array(x_predict, dtype=np.float32),
    }
  else:
    # For dataset inputs, we do not pass batch_size to
    # keras.fit/evaluate/predict. The batch size is part of the dataset.
    train_dataset = dataset_ops.Dataset.from_tensor_slices(
        (x_train, y_train))
    x = batch_wrapper(
        train_dataset, batch_size, with_distribution, repeat=training_epochs)

    training_inputs = {
        'batch_size': None,
        'x': x,
        'y': None,
        'epochs': training_epochs,
        'shuffle': False,
        'steps_per_epoch': len(x_train) // global_batch_size,
    }
    if use_validation_data:
      eval_inputs = None  # Remove the eval_inputs
      eval_dataset = dataset_ops.Dataset.from_tensor_slices(
          (x_train, y_train))
      x = batch_wrapper(eval_dataset, batch_size, with_distribution)
      training_inputs['validation_data'] = x
      training_inputs['validation_steps'] = 5
    else:
      eval_inputs = {
          'batch_size': None,
          'x': x,
          'y': None,
          'steps': 20,
      }

    predict_batch_size = len(x_predict)
    if use_per_core_batch_size:
      predict_batch_size //= with_distribution.num_replicas_in_sync
    predict_dataset = dataset_ops.Dataset.from_tensor_slices(x_predict)
    predict_dataset = batch_wrapper(predict_dataset,
                                    predict_batch_size, with_distribution)
    predict_inputs = {
        'steps': 1,
        'x': predict_dataset,
    }

  return training_inputs, eval_inputs, predict_inputs
Exemple #10
0
def get_correctness_test_inputs(use_numpy, use_validation_data,
                                with_distribution,
                                x_train, y_train, x_predict):
  """Generates the inputs for correctness check when enable Keras with DS."""
  training_epochs = 2
  global_batch_size = 64
  batch_size = global_batch_size
  # TODO(b/118776054): Use global batch size for Keras/DS support.
  use_per_core_batch_size = (
      with_distribution and
      not distributed_training_utils.global_batch_size_supported(
          with_distribution))
  if use_per_core_batch_size:
    batch_size //= with_distribution.num_replicas_in_sync

  if use_numpy:
    training_inputs = {
        'batch_size': batch_size,
        'x': x_train,
        'y': y_train,
        'epochs': training_epochs,
        'shuffle': False,
    }

    if use_validation_data:
      eval_inputs = None
      training_inputs['validation_data'] = (x_train, y_train)
    else:
      eval_inputs = {
          'batch_size': batch_size,
          'x': x_train,
          'y': y_train,
      }
    predict_inputs = {
        'x': np.array(x_predict, dtype=np.float32),
    }
  else:
    # For dataset inputs, we do not pass batch_size to
    # keras.fit/evaluate/predict. The batch size is part of the dataset.
    train_dataset = dataset_ops.Dataset.from_tensor_slices(
        (x_train, y_train))
    x = batch_wrapper(
        train_dataset, batch_size, with_distribution, repeat=training_epochs)

    training_inputs = {
        'batch_size': None,
        'x': x,
        'y': None,
        'epochs': training_epochs,
        'shuffle': False,
        'steps_per_epoch': len(x_train) // global_batch_size,
    }
    if use_validation_data:
      eval_inputs = None  # Remove the eval_inputs
      eval_dataset = dataset_ops.Dataset.from_tensor_slices(
          (x_train, y_train))
      x = batch_wrapper(eval_dataset, batch_size, with_distribution)
      training_inputs['validation_data'] = x
      training_inputs['validation_steps'] = 5
    else:
      eval_inputs = {
          'batch_size': None,
          'x': x,
          'y': None,
          'steps': 20,
      }

    predict_batch_size = len(x_predict)
    if use_per_core_batch_size:
      predict_batch_size //= with_distribution.num_replicas_in_sync
    predict_dataset = dataset_ops.Dataset.from_tensor_slices(x_predict)
    predict_dataset = batch_wrapper(predict_dataset,
                                    predict_batch_size, with_distribution)
    predict_inputs = {
        'steps': 1,
        'x': predict_dataset,
    }

  return training_inputs, eval_inputs, predict_inputs