Beispiel #1
0
def _clone_and_build_model(mode,
                           keras_model,
                           custom_objects,
                           features=None,
                           labels=None):
  """Clone and build the given keras_model.

  Args:
    mode: training mode.
    keras_model: an instance of compiled keras model.
    custom_objects: Dictionary for custom objects.
    features:
    labels:

  Returns:
    The newly built model.
  """
  # Set to True during training, False for inference.
  K.set_learning_phase(mode == model_fn_lib.ModeKeys.TRAIN)

  # Clone keras model.
  input_tensors = None if features is None else _create_ordered_io(
      keras_model, features)
  if custom_objects:
    with CustomObjectScope(custom_objects):
      model = models.clone_model(keras_model, input_tensors=input_tensors)
  else:
    model = models.clone_model(keras_model, input_tensors=input_tensors)

  # Compile/Build model
  if mode is model_fn_lib.ModeKeys.PREDICT and not model.built:
    model.build()
  else:
    optimizer_config = keras_model.optimizer.get_config()
    optimizer = keras_model.optimizer.__class__.from_config(optimizer_config)
    optimizer.iterations = training_util.get_or_create_global_step()

    # Get list of outputs.
    if labels is None:
      target_tensors = None
    elif isinstance(labels, dict):
      target_tensors = _create_ordered_io(keras_model, labels, is_input=False)
    else:
      target_tensors = [
          _cast_tensor_to_floatx(
              sparse_tensor_lib.convert_to_tensor_or_sparse_tensor(labels))
      ]

    model.compile(
        optimizer,
        keras_model.loss,
        metrics=keras_model.metrics,
        loss_weights=keras_model.loss_weights,
        sample_weight_mode=keras_model.sample_weight_mode,
        weighted_metrics=keras_model.weighted_metrics,
        target_tensors=target_tensors)

  if isinstance(model, models.Sequential):
    model = model.model
  return model
Beispiel #2
0
    def _call_graph_fn(self, features, labels=None):
        """Calls graph function.

        Args:
            features: `Tensor` or `dict` of tensors
            labels: `Tensor` or `dict` of tensors
        """
        set_learning_phase(Modes.is_train(self.mode))

        kwargs = {}
        if 'labels' in get_arguments(self._graph_fn):
            kwargs['labels'] = labels
        return self._graph_fn(mode=self.mode, features=features, **kwargs)
def _process_single_batch(model,
                          inputs,
                          targets,
                          sample_weights=None,
                          training=False):
    """Calculate the loss and gradient for one input batch.

     The model weights are updated if training is set to True.

  Arguments:
      model: Model whose loss has to be calculated.
      inputs: List of input arrays.
      targets: List of target arrays.
      sample_weights: Optional list of sample weight arrays.
      training: The boolean represents if the weights of the model are updated.
              'fit' methods will set this to True while 'evaluate' methods will
              set this to False.

  Returns:
      output of the model, total loss and the loss associated with each output.

  Raises:
      ValueError: If the model has no loss to optimize.
  """
    K.set_learning_phase(training)
    with GradientTape() as tape:
        outs, loss, loss_metrics = _model_loss(model,
                                               inputs,
                                               targets,
                                               sample_weights=sample_weights,
                                               training=training)
        if loss is None:
            raise ValueError('The model cannot be run '
                             'because it has no loss to optimize.')
    if training:
        if not model._collected_trainable_weights:
            logging.warning(
                'The list of trainable weights is empty. Make sure that '
                'you are not setting model.trainable to False before '
                'compiling the model.')
        else:
            grads = tape.gradient(loss, model._collected_trainable_weights)
            model.optimizer.apply_gradients(
                zip(grads, model._collected_trainable_weights))
    return outs, loss, loss_metrics
Beispiel #4
0
    def _call_graph_fn(self, features, labels=None):
        """Calls graph function.

        Creates first one or two graph, i.e. train and target graphs.
        Return the optimal action given an exploration policy.

        If `is_dueling` is set to `True`,
        then another layer is added that represents the state value.

        Args:
            inputs: `Tensor` or `dict` of tensors
        """
        set_learning_phase(Modes.is_train(self.mode))

        graph_fn = self._build_graph_fn()
        self._graph_results = graph_fn(mode=self.mode,
                                       features=features,
                                       labels=labels)
        return self._build_actions()
Beispiel #5
0
def _process_single_batch(eager_model_inputs,
                          eager_model_outputs,
                          model,
                          training=False):
    """Calculate the loss and gradient for one input batch.

     The model weights are updated if training is set to True.

  Arguments:
      eager_model_inputs: Input batch data.
      eager_model_outputs: Output batch data.
      model: Model whose loss has to be calculated.
      training: The boolean represents if the weights of the model are updated.
              'fit' methods will set this to True while 'evaluate' methods will
              set this to False.

  Returns:
      output of the model, total loss and the loss associated with each output.

  Raises:
      ValueError: If the model loss is 0 or if the trainable weights list is
                  empty when the trainable parameter is set to True.
  """
    K.set_learning_phase(training)
    with GradientTape() as tape:
        outs, loss, loss_metrics = _model_loss(model,
                                               eager_model_inputs,
                                               eager_model_outputs,
                                               training=training)
        if loss is None:
            raise ValueError('The model cannot be run '
                             'because it has no loss to optimize.')
    if training:
        if not model._collected_trainable_weights:
            raise ValueError(
                'The list of trainable weights is empty. Make sure that '
                'you are not setting model.trainable to False before '
                'compiling the model.')
        grads = tape.gradient(loss, model._collected_trainable_weights)
        model.optimizer.apply_gradients(
            zip(grads, model._collected_trainable_weights))
    return outs, loss, loss_metrics
def _process_single_batch(eager_model_inputs, eager_model_outputs, model,
                          training=False):
  """Calculate the loss and gradient for one input batch.

     The model weights are updated if training is set to True.

  Arguments:
      eager_model_inputs: Input batch data.
      eager_model_outputs: Output batch data.
      model: Model whose loss has to be calculated.
      training: The boolean represents if the weights of the model are updated.
              'fit' methods will set this to True while 'evaluate' methods will
              set this to False.

  Returns:
      output of the model, total loss and the loss associated with each output.

  Raises:
      ValueError: If the model has no loss to optimize.
  """
  K.set_learning_phase(training)
  with GradientTape() as tape:
    outs, loss, loss_metrics = _model_loss(model, eager_model_inputs,
                                           eager_model_outputs,
                                           training=training)
    if loss is None:
      raise ValueError('The model cannot be run '
                       'because it has no loss to optimize.')
  if training:
    if not model._collected_trainable_weights:
      logging.warning('The list of trainable weights is empty. Make sure that '
                      'you are not setting model.trainable to False before '
                      'compiling the model.')
    else:
      grads = tape.gradient(loss, model._collected_trainable_weights)
      model.optimizer.apply_gradients(zip(grads,
                                          model._collected_trainable_weights))
  return outs, loss, loss_metrics
Beispiel #7
0
    def _call_graph_fn(self, features, labels=None):
        """Calls graph function.

        Creates first one or two graph, i.e. train and target graphs.
        Return the optimal action given an exploration policy.

        If `is_dueling` is set to `True`,
        then another layer is added that represents the state value.

        Args:
            features: `Tensor` or `dict` of tensors
            labels: `Tensor` or `dict` of tensors
        """
        set_learning_phase(Modes.is_train(self.mode))

        graph_fn = self._build_graph_fn()

        if self.use_target_graph:
            # We create 2 graphs: a training graph and a target graph,
            # so that we can copy one graph to another given a frequency.
            self._train_graph = FunctionModule(mode=self.mode,
                                               build_fn=graph_fn,
                                               name='train')
            self._train_results = self._train_graph(features=features,
                                                    labels=labels)
            self._target_graph = FunctionModule(mode=self.mode,
                                                build_fn=graph_fn,
                                                name='target')
            self._target_results = self._target_graph(features=features,
                                                      labels=labels)
            return self._build_actions()
        else:
            self._train_results = graph_fn(mode=self.mode,
                                           features=features,
                                           labels=labels)
            self._target_results = self._train_results
            return self._build_actions()
Beispiel #8
0
def _clone_and_build_model(mode,
                           keras_model,
                           custom_objects,
                           features=None,
                           labels=None):
    """Clone and build the given keras_model.

  Args:
    mode: training mode.
    keras_model: an instance of compiled keras model.
    custom_objects: Dictionary for custom objects.
    features: Dict of tensors.
    labels: Dict of tensors, or single tensor instance.

  Returns:
    The newly built model.
  """
    # Set to True during training, False for inference.
    K.set_learning_phase(mode == model_fn_lib.ModeKeys.TRAIN)

    # Get list of inputs.
    if features is None:
        input_tensors = None
    else:
        input_tensors = _create_ordered_io(keras_model,
                                           estimator_io=features,
                                           is_input=True)
    # Get list of outputs.
    if labels is None:
        target_tensors = None
    elif isinstance(labels, dict):
        target_tensors = _create_ordered_io(keras_model,
                                            estimator_io=labels,
                                            is_input=False)
    else:
        target_tensors = [_convert_tensor(labels)]

    if keras_model._is_graph_network:
        if custom_objects:
            with CustomObjectScope(custom_objects):
                model = models.clone_model(keras_model,
                                           input_tensors=input_tensors)
        else:
            model = models.clone_model(keras_model,
                                       input_tensors=input_tensors)
    else:
        model = keras_model
        _in_place_subclassed_model_reset(model)
        if input_tensors is not None:
            model._set_inputs(input_tensors)

    # Compile/Build model
    if mode is model_fn_lib.ModeKeys.PREDICT:
        if isinstance(model, models.Sequential):
            model.build()
    else:
        if isinstance(keras_model.optimizer, optimizers.TFOptimizer):
            optimizer = keras_model.optimizer
        else:
            optimizer_config = keras_model.optimizer.get_config()
            optimizer = keras_model.optimizer.__class__.from_config(
                optimizer_config)
        optimizer.iterations = training_util.get_or_create_global_step()

        model.compile(optimizer,
                      keras_model.loss,
                      metrics=keras_model.metrics,
                      loss_weights=keras_model.loss_weights,
                      sample_weight_mode=keras_model.sample_weight_mode,
                      weighted_metrics=keras_model.weighted_metrics,
                      target_tensors=target_tensors)
    return model
def predict_loop(model, ins, batch_size=32, verbose=0, steps=None):
    """Abstract method to loop over some data in batches.

  Arguments:
      model:
      ins: list of tensors to be fed to `f`.
      batch_size: integer batch size.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring `_predict_loop` finished.
          Ignored with the default value of `None`.

  Returns:
      Array of predictions (if the model has a single output)
      or list of arrays of predictions
      (if the model has multiple outputs).
  """
    K.set_learning_phase(False)
    num_samples = model._check_num_samples(ins, batch_size, steps, 'steps')
    if verbose == 1:
        if steps is not None:
            progbar = Progbar(target=steps)
        else:
            progbar = Progbar(target=num_samples)

    outs = []
    batches = _make_batches(num_samples, batch_size)
    index_array = np.arange(num_samples)
    for batch_index, (batch_start, batch_end) in enumerate(batches):
        batch_ids = index_array[batch_start:batch_end]
        if ins and isinstance(ins[-1], float):
            # Do not slice the training phase flag.
            ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
        else:
            ins_batch = _slice_arrays(ins, batch_ids)

        ins_batch_converted = []
        for ib in ins_batch:
            ins_batch_converted.append(
                ops.convert_to_tensor(ib, dtype=K.floatx()))

        eager_model_inputs = []
        for i in range(len(model.inputs)):
            eager_model_inputs.append(ins_batch_converted[i])

        batch_outs = model(eager_model_inputs)

        if not isinstance(batch_outs, list):
            batch_outs = [batch_outs]
        if batch_index == 0:
            # Pre-allocate the results arrays.
            for batch_out in batch_outs:
                dims = batch_out.shape[1:].dims
                dims_list = [d.value for d in dims]
                shape = (num_samples, ) + tuple(dims_list)
                outs.append(
                    np.zeros(shape, dtype=batch_out.dtype.as_numpy_dtype))
        for i, batch_out in enumerate(batch_outs):
            outs[i][batch_start:batch_end] = batch_out
        if verbose == 1:
            progbar.update(batch_end)
    if len(outs) == 1:
        return outs[0]
    return outs
def test_loop(model, ins, batch_size=None, verbose=0, steps=None):
    """Abstract method to loop over some data in batches.

  Arguments:
      model: Model instance that is being evaluated in Eager mode.
      ins: list of tensors to be fed to `f`.
      batch_size: integer batch size or `None`.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring predictions finished.
          Ignored with the default value of `None`.

  Returns:
      Scalar loss (if the model has a single output and no metrics)
      or list of scalars (if the model has multiple outputs
      and/or metrics). The attribute `model.metrics_names` will give you
      the display labels for the scalar outputs.
  """
    K.set_learning_phase(False)
    num_samples = model._check_num_samples(ins, batch_size, steps, 'steps')
    outs = []
    if verbose == 1:
        progbar = Progbar(target=num_samples)
    batches = _make_batches(num_samples, batch_size)
    index_array = np.arange(num_samples)
    for batch_index, (batch_start, batch_end) in enumerate(batches):
        batch_ids = index_array[batch_start:batch_end]
        if isinstance(ins[-1], float):
            # Do not slice the training phase flag.
            ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
        else:
            ins_batch = _slice_arrays(ins, batch_ids)

        ins_batch_converted = []
        for ib in ins_batch:
            ins_batch_converted.append(
                ops.convert_to_tensor(ib, dtype=K.floatx()))

        eager_model_inputs = []
        eager_model_outputs = []
        for i in range(len(model.inputs)):
            eager_model_inputs.append(ins_batch_converted[i])

        for i in range(len(model.inputs), len(ins_batch_converted)):
            eager_model_outputs.append(ins_batch_converted[i])

        loss_outs, loss, loss_metrics = _model_loss(model, eager_model_inputs,
                                                    eager_model_outputs)
        _, metrics_results = _eager_metrics_fn(model, loss_outs,
                                               eager_model_outputs)
        batch_outs = []
        for _, v in zip(model.metrics_names,
                        [K.mean(loss)] + loss_metrics + metrics_results):
            batch_outs.append(tensor_util.constant_value(v))

        if isinstance(batch_outs, list):
            if batch_index == 0:
                for batch_out in enumerate(batch_outs):
                    outs.append(0.)
            for i, batch_out in enumerate(batch_outs):
                outs[i] += batch_out * len(batch_ids)
        else:
            if batch_index == 0:
                outs.append(0.)
            outs[0] += batch_outs * len(batch_ids)

        if verbose == 1:
            progbar.update(batch_end)
    for i in range(len(outs)):
        outs[i] /= num_samples
    if len(outs) == 1:
        return outs[0]
    return outs
def fit_loop(model,
             ins,
             out_labels=None,
             batch_size=None,
             epochs=100,
             verbose=1,
             callbacks=None,
             val_ins=None,
             shuffle=True,
             callback_metrics=None,
             initial_epoch=0,
             steps_per_epoch=None,
             validation_steps=None):
    """Abstract fit function for `f(ins)`.

  Assume that f returns a list, labeled by out_labels.

  Arguments:
      model: Instance of the model that is being executed in Eager mode.
      ins: List of tensors to be fed to `f`
      out_labels: List of strings, display names of
          the outputs of `f`
      batch_size: Integer batch size or None if unknown.
      epochs: Number of times to iterate over the data
      verbose: Verbosity mode, 0, 1 or 2
      callbacks: List of callbacks to be called during training
      val_ins: List of tensors to be fed to `val_f`
      shuffle: Whether to shuffle the data at the beginning of each epoch
      callback_metrics: List of strings, the display names of the metrics
          passed to the callbacks. They should be the
          concatenation of list the display names of the outputs of
           `f` and the list of display names of the outputs of `f_val`.
      initial_epoch: Epoch at which to start training
          (useful for resuming a previous training run)
      steps_per_epoch: Total number of steps (batches of samples)
          before declaring one epoch finished and starting the
          next epoch. Ignored with the default value of `None`.
      validation_steps: Number of steps to run validation for (only if doing
        validation from data tensors). Ignored with default value of `None`.

  Returns:
      `History` object.

  Raises:
    ValueError: In case of invalid argument values.
  """
    # Required for Eager mode
    K.set_learning_phase(True)

    do_validation = False
    if val_ins:
        do_validation = True
        if (verbose and ins and hasattr(ins[0], 'shape')
                and hasattr(val_ins[0], 'shape')):
            print('Train on %d samples, validate on %d samples' %
                  (ins[0].shape[0], val_ins[0].shape[0]))
    if validation_steps:
        if steps_per_epoch is None:
            raise ValueError(
                'Can only use `validation_steps` when doing step-wise '
                'training, i.e. `steps_per_epoch` must be set.')
        do_validation = True

    num_train_samples = model._check_num_samples(ins, batch_size,
                                                 steps_per_epoch,
                                                 'steps_per_epoch')

    if num_train_samples is not None:
        index_array = np.arange(num_train_samples)

    model.history = cbks.History()
    callbacks = [cbks.BaseLogger()] + (callbacks or []) + [model.history]
    if verbose:
        if steps_per_epoch is not None:
            count_mode = 'steps'
        else:
            count_mode = 'samples'
        callbacks += [cbks.ProgbarLogger(count_mode)]
    callbacks = cbks.CallbackList(callbacks)
    out_labels = out_labels or []

    # it's possible to callback a different model than self
    # (used by Sequential models)
    if hasattr(model, 'callback_model') and model.callback_model:
        callback_model = model.callback_model
    else:
        callback_model = model

    callbacks.set_model(callback_model)

    callbacks.set_params({
        'batch_size': batch_size,
        'epochs': epochs,
        'steps': steps_per_epoch,
        'samples': num_train_samples,
        'verbose': verbose,
        'do_validation': do_validation,
        'metrics': callback_metrics or [],
    })
    callbacks.on_train_begin()
    callback_model.stop_training = False
    for cbk in callbacks:
        cbk.validation_data = val_ins

    for epoch in range(initial_epoch, epochs):
        callbacks.on_epoch_begin(epoch)
        epoch_logs = {}
        if shuffle == 'batch':
            index_array = model._batch_shuffle(index_array, batch_size)
        elif shuffle:
            np.random.shuffle(index_array)

        batches = _make_batches(num_train_samples, batch_size)

        for batch_index, (batch_start, batch_end) in enumerate(batches):
            batch_ids = index_array[batch_start:batch_end]
            try:
                if isinstance(ins[-1], float):
                    # Do not slice the training phase flag.
                    ins_batch = _slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
                else:
                    ins_batch = _slice_arrays(ins, batch_ids)
            except TypeError:
                raise TypeError('TypeError while preparing batch. '
                                'If using HDF5 input data, '
                                'pass shuffle="batch".')
            batch_logs = {}
            batch_logs['batch'] = batch_index
            batch_logs['size'] = len(batch_ids)

            callbacks.on_batch_begin(batch_index, batch_logs)

            ins_batch_converted = []
            for ib in ins_batch:
                ins_batch_converted.append(
                    ops.convert_to_tensor(ib, dtype=K.floatx()))
            eager_model_inputs = []
            eager_model_outputs = []
            for i in range(len(model.inputs)):
                eager_model_inputs.append(ins_batch_converted[i])

            for i in range(len(model.inputs), len(ins_batch_converted)):
                eager_model_outputs.append(ins_batch_converted[i])

            outs, loss, loss_metrics = _process_single_batch(
                eager_model_inputs, eager_model_outputs, model)

            if not isinstance(outs, list):
                outs = [outs]

            for l, o in zip(out_labels, outs):
                batch_logs[l] = o
            # Required for Eager mode
            metrics_names, metrics_results = _eager_metrics_fn(
                model, outs, eager_model_outputs)
            batch_logs['loss'] = tensor_util.constant_value(K.mean(loss))

            # TODO(anjalisridhar): Move this to compile to avoid duplicate code.
            # In graph mode we set the metric names in compile. However in
            # Eager mode we calculate the metrics for each batch in fit_loop.
            # We could calculate the metric names and functions in compile.
            # This would avoid setting the callback parameters separately.
            # We need to do this for the first iteration alone
            for m in metrics_names:
                if m not in callback_metrics:
                    callback_metrics.append(m)

            callbacks.set_params({
                'batch_size': batch_size,
                'epochs': epochs,
                'steps': steps_per_epoch,
                'samples': num_train_samples,
                'verbose': verbose,
                'do_validation': do_validation,
                'metrics': callback_metrics or [],
            })

            for k, v in zip(model.metrics_names,
                            [K.mean(loss)] + loss_metrics + metrics_results):
                batch_logs[k] = tensor_util.constant_value(v)

            callbacks.on_batch_end(batch_index, batch_logs)
            if callback_model.stop_training:
                break

            if batch_index == len(batches) - 1:  # Last batch.
                if do_validation:
                    val_outs = test_loop(model,
                                         val_ins,
                                         batch_size=batch_size,
                                         verbose=0)
                    if not isinstance(val_outs, list):
                        val_outs = [val_outs]
                    # Same labels assumed.
                    for l, o in zip(out_labels, val_outs):
                        epoch_logs['val_' + l] = o
        callbacks.on_epoch_end(epoch, epoch_logs)
        if callback_model.stop_training:
            break
    callbacks.on_train_end()
    return model.history
Beispiel #12
0
def _clone_and_build_model(mode,
                           keras_model,
                           custom_objects,
                           features=None,
                           labels=None):
  """Clone and build the given keras_model.

  Args:
    mode: training mode.
    keras_model: an instance of compiled keras model.
    custom_objects: Dictionary for custom objects.
    features: Dict of tensors.
    labels: Dict of tensors, or single tensor instance.

  Returns:
    The newly built model.
  """
  # Set to True during training, False for inference.
  K.set_learning_phase(mode == model_fn_lib.ModeKeys.TRAIN)

  # Get list of inputs.
  if features is None:
    input_tensors = None
  else:
    input_tensors = _create_ordered_io(keras_model,
                                       estimator_io=features,
                                       is_input=True)
  # Get list of outputs.
  if labels is None:
    target_tensors = None
  elif isinstance(labels, dict):
    target_tensors = _create_ordered_io(keras_model,
                                        estimator_io=labels,
                                        is_input=False)
  else:
    target_tensors = [
        _convert_tensor(labels)
    ]

  if keras_model._is_graph_network:
    if custom_objects:
      with CustomObjectScope(custom_objects):
        model = models.clone_model(keras_model, input_tensors=input_tensors)
    else:
      model = models.clone_model(keras_model, input_tensors=input_tensors)
  else:
    model = keras_model
    _in_place_subclassed_model_reset(model)
    if input_tensors is not None:
      model._set_inputs(input_tensors)

  # Compile/Build model
  if mode is model_fn_lib.ModeKeys.PREDICT:
    if isinstance(model, models.Sequential):
      model.build()
  else:
    if isinstance(keras_model.optimizer, optimizers.TFOptimizer):
      optimizer = keras_model.optimizer
    else:
      optimizer_config = keras_model.optimizer.get_config()
      optimizer = keras_model.optimizer.__class__.from_config(optimizer_config)
    optimizer.iterations = training_util.get_or_create_global_step()

    model.compile(
        optimizer,
        keras_model.loss,
        metrics=keras_model.metrics,
        loss_weights=keras_model.loss_weights,
        sample_weight_mode=keras_model.sample_weight_mode,
        weighted_metrics=keras_model.weighted_metrics,
        target_tensors=target_tensors)
  return model
Beispiel #13
0
  def _specialize_model(self, input_specs):
    """Specialize `self.model` (a Keras model) for the given input shapes."""
    # Re-create our input and output layers inside our subgraph.  They will be
    # attached to the true computation when we clone our model in `tpu_fn`.
    K.set_learning_phase(
        self.execution_mode == model_fn_lib.ModeKeys.TRAIN
    )

    # functools.partial and callable objects are not supported by tpu.rewrite
    def _model_fn():
      """Compute fit/eval/predict for the TPU."""
      is_training = self.execution_mode == model_fn_lib.ModeKeys.TRAIN
      is_test = self.execution_mode == model_fn_lib.ModeKeys.EVAL
      is_predict = self.execution_mode == model_fn_lib.ModeKeys.PREDICT

      # During train/eval, we infeed our features as well as labels.
      if is_training or is_test:
        infeed_layers = self.model._input_layers + self.model._output_layers
      else:
        infeed_layers = self.model._input_layers

      # Generate our infeed operation to read features & labels.
      infeed_tensors = tpu_ops.infeed_dequeue_tuple(
          dtypes=[spec.dtype for spec in input_specs],
          shapes=[spec.shape for spec in input_specs],
          name='infeed-%s' % self.execution_mode)

      assert len(infeed_tensors) == len(infeed_layers), (
          'Infeed inputs did not match model: %s vs %s', (infeed_layers,
                                                          infeed_tensors))

      tpu_targets = []
      tpu_inputs = []

      # Sort infeed outputs into inputs and labels for calling our Keras model.
      for tensor, layer in zip(infeed_tensors, infeed_layers):
        if layer in self.model._input_layers:
          tpu_inputs.append(layers.Input(name=layer.name, tensor=tensor))
        if layer in self.model._output_layers:
          tpu_targets.append(tensor)

      # Call our model with our infeed inputs (re-using the weights).
      model_outputs = self.model(tpu_inputs)
      child_model = models.Model(inputs=tpu_inputs, outputs=model_outputs)
      if is_training or is_test:
        child_model.compile(
            optimizer=self.model.optimizer,
            loss=self.model.loss,
            loss_weights=self.model.loss_weights,
            metrics=self.model.metrics,
            weighted_metrics=self.model.weighted_metrics,
            target_tensors=tpu_targets,
        )

      # Compute our outfeed depending on the execution mode
      if is_training:
        child_model._make_train_function()
        self._outfeed_spec = [
            tensor_spec.TensorSpec(tensor.shape, tensor.dtype, tensor.name)
            for tensor in child_model.train_function.outputs
        ]
        return [
            child_model.train_function.updates_op,
            tpu_ops.outfeed_enqueue_tuple(
                child_model.train_function.outputs, name='oufeed-enqueue-train')
        ]
      elif is_test:
        child_model._make_test_function()
        self._outfeed_spec = [
            tensor_spec.TensorSpec(tensor.shape, tensor.dtype, tensor.name)
            for tensor in child_model.test_function.outputs
        ]
        return [
            tpu_ops.outfeed_enqueue_tuple(
                child_model.test_function.outputs, name='outfeed-enqueue-test')
        ]
      elif is_predict:
        child_model._make_predict_function()
        self._outfeed_spec = [
            tensor_spec.TensorSpec(tensor.shape, tensor.dtype, tensor.name)
            for tensor in child_model.predict_function.outputs
        ]
        return [
            tpu_ops.outfeed_enqueue_tuple(
                child_model.predict_function.outputs,
                name='outfeed-enqueue-predict',
            )
        ]
      else:
        assert False, 'Unexpected execution mode: %s' % self.execution_mode

    # Capture outfeed metadata computed during the rewrite.
    self._outfeed_spec = None

    tpu_execute_op = tpu.rewrite(_model_fn)

    # Generate CPU side operations to enqueue features/labels and dequeue
    # outputs from the model call.
    with ops.device('/device:TPU:0'):
      infeed_tensors = []
      for spec in input_specs:
        infeed_tensors.append(
            array_ops.placeholder(
                dtype=spec.dtype,
                shape=spec.shape,
                name='infeed-enqueue-%s' % spec.name))

      infeed_op = tpu_ops.infeed_enqueue_tuple(
          infeed_tensors, [spec.shape for spec in input_specs],
          name='infeed-enqueue-%s' % self.execution_mode)

      outfeed_op = tpu_ops.outfeed_dequeue_tuple(
          dtypes=[spec.dtype for spec in self._outfeed_spec],
          shapes=[spec.shape for spec in self._outfeed_spec],
          name='outfeed-dequeue-%s' % self.execution_mode)

    return CompiledTPUOp(tpu_execute_op, infeed_tensors, infeed_op, outfeed_op)
def predict_loop(model, ins, batch_size=32, verbose=0, steps=None):
  """Abstract method to loop over some data in batches.

  Arguments:
      model:
      ins: list of tensors to be fed to `f`.
      batch_size: integer batch size.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring `_predict_loop` finished.
          Ignored with the default value of `None`.

  Returns:
      Array of predictions (if the model has a single output)
      or list of arrays of predictions
      (if the model has multiple outputs).
  """
  K.set_learning_phase(False)
  num_samples = model._check_num_samples(ins, batch_size, steps, 'steps')
  if verbose == 1:
    if steps is not None:
      progbar = Progbar(target=steps)
    else:
      progbar = Progbar(target=num_samples)

  outs = []
  batches = make_batches(num_samples, batch_size)
  index_array = np.arange(num_samples)
  for batch_index, (batch_start, batch_end) in enumerate(batches):
    batch_ids = index_array[batch_start:batch_end]
    if ins and isinstance(ins[-1], float):
      # Do not slice the training phase flag.
      ins_batch = slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
    else:
      ins_batch = slice_arrays(ins, batch_ids)

    ins_batch_converted = []
    for ib in ins_batch:
      ins_batch_converted.append(ops.convert_to_tensor(ib, dtype=K.floatx()))

    eager_model_inputs = []
    for i in range(len(model.inputs)):
      eager_model_inputs.append(ins_batch_converted[i])

    if len(eager_model_inputs) == 1:
      batch_outs = model.call(eager_model_inputs[0])
    else:
      batch_outs = model.call(eager_model_inputs)

    if not isinstance(batch_outs, list):
      batch_outs = [batch_outs]
    if batch_index == 0:
      # Pre-allocate the results arrays.
      for batch_out in batch_outs:
        dims = batch_out.shape[1:].dims
        dims_list = [d.value for d in dims]
        shape = (num_samples,) + tuple(dims_list)
        outs.append(np.zeros(shape, dtype=batch_out.dtype.as_numpy_dtype))
    for i, batch_out in enumerate(batch_outs):
      outs[i][batch_start:batch_end] = batch_out
    if verbose == 1:
      progbar.update(batch_end)
  if len(outs) == 1:
    return outs[0]
  return outs
def test_loop(model,
              inputs,
              targets,
              sample_weights=None,
              batch_size=None,
              verbose=0,
              steps=None):
    """Abstract method to loop over some data in batches.

  Arguments:
      model: Model instance that is being evaluated in Eager mode.
      inputs: List of input arrays.
      targets: List of target arrays.
      sample_weights: Optional list of sample weight arrays.
      batch_size: integer batch size or `None`.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring predictions finished.
          Ignored with the default value of `None`.

  Returns:
      Scalar loss (if the model has a single output and no metrics)
      or list of scalars (if the model has multiple outputs
      and/or metrics). The attribute `model.metrics_names` will give you
      the display labels for the scalar outputs.
  """
    K.set_learning_phase(False)
    feed_data = inputs + targets
    if sample_weights:
        feed_data += sample_weights
    num_samples = training_utils.check_num_samples(feed_data,
                                                   batch_size=batch_size,
                                                   steps=steps,
                                                   steps_name='steps')
    outs = []
    if verbose == 1:
        progbar = Progbar(target=num_samples)
    batches = make_batches(num_samples, batch_size)
    index_array = np.arange(num_samples)
    for batch_index, (batch_start, batch_end) in enumerate(batches):
        batch_ids = index_array[batch_start:batch_end]
        inputs_batch = slice_arrays(inputs, batch_ids)
        targets_batch = slice_arrays(targets, batch_ids)
        if sample_weights:
            sample_weights_batch = slice_arrays(sample_weights, batch_ids)
        else:
            sample_weights_batch = None

        inputs_batch = [
            ops.convert_to_tensor(val, dtype=K.floatx())
            for val in inputs_batch
        ]
        targets_batch = [
            ops.convert_to_tensor(val, dtype=K.floatx())
            for val in targets_batch
        ]
        if sample_weights:
            sample_weights_batch = [
                ops.convert_to_tensor(val, dtype=K.floatx())
                if val is not None else None for val in sample_weights_batch
            ]

        loss_outs, loss, loss_metrics = _model_loss(
            model,
            inputs_batch,
            targets_batch,
            sample_weights=sample_weights_batch,
            training=False)
        _, metrics_results = _eager_metrics_fn(model, loss_outs, targets_batch)
        batch_outs = []
        for _, v in zip(model.metrics_names,
                        [K.mean(loss)] + loss_metrics + metrics_results):
            batch_outs.append(tensor_util.constant_value(v))

        if isinstance(batch_outs, list):
            if batch_index == 0:
                for batch_out in enumerate(batch_outs):
                    outs.append(0.)
            for i, batch_out in enumerate(batch_outs):
                outs[i] += batch_out * len(batch_ids)
        else:
            if batch_index == 0:
                outs.append(0.)
            outs[0] += batch_outs * len(batch_ids)

        if verbose == 1:
            progbar.update(batch_end)
    for i in range(len(outs)):
        outs[i] /= num_samples
    if len(outs) == 1:
        return outs[0]
    return outs
def fit_loop(
    model,
    ins,
    out_labels=None,
    batch_size=None,
    epochs=100,
    verbose=1,
    callbacks=None,
    val_ins=None,
    shuffle=True,
    callback_metrics=None,
    initial_epoch=0,
    steps_per_epoch=None,
    validation_steps=None):
  """Abstract fit function for `f(ins)`.

  Assume that f returns a list, labeled by out_labels.

  Arguments:
      model: Instance of the model that is being executed in Eager mode.
      ins: List of tensors to be fed to `f`
      out_labels: List of strings, display names of
          the outputs of `f`
      batch_size: Integer batch size or None if unknown.
      epochs: Number of times to iterate over the data
      verbose: Verbosity mode, 0, 1 or 2
      callbacks: List of callbacks to be called during training
      val_ins: List of tensors to be fed to `val_f`
      shuffle: Whether to shuffle the data at the beginning of each epoch
      callback_metrics: List of strings, the display names of the metrics
          passed to the callbacks. They should be the
          concatenation of list the display names of the outputs of
           `f` and the list of display names of the outputs of `f_val`.
      initial_epoch: Epoch at which to start training
          (useful for resuming a previous training run)
      steps_per_epoch: Total number of steps (batches of samples)
          before declaring one epoch finished and starting the
          next epoch. Ignored with the default value of `None`.
      validation_steps: Number of steps to run validation for (only if doing
        validation from data tensors). Ignored with default value of `None`.

  Returns:
      `History` object.

  Raises:
    ValueError: In case of invalid argument values.
  """
  # Required for Eager mode
  K.set_learning_phase(True)

  do_validation = False
  if val_ins:
    do_validation = True
    if (verbose and ins and hasattr(ins[0], 'shape') and
        hasattr(val_ins[0], 'shape')):
      print('Train on %d samples, validate on %d samples' %
            (ins[0].shape[0], val_ins[0].shape[0]))
  if validation_steps:
    if steps_per_epoch is None:
      raise ValueError('Can only use `validation_steps` when doing step-wise '
                       'training, i.e. `steps_per_epoch` must be set.')
    do_validation = True

  num_train_samples = model._check_num_samples(
      ins, batch_size, steps_per_epoch, 'steps_per_epoch')

  if num_train_samples is not None:
    index_array = np.arange(num_train_samples)

  model.history = cbks.History()
  callbacks = [cbks.BaseLogger()] + (callbacks or []) + [model.history]
  if verbose:
    if steps_per_epoch is not None:
      count_mode = 'steps'
    else:
      count_mode = 'samples'
    callbacks += [cbks.ProgbarLogger(count_mode)]
  callbacks = cbks.CallbackList(callbacks)
  out_labels = out_labels or []

  # it's possible to callback a different model than self
  # (used by Sequential models)
  if hasattr(model, 'callback_model') and model.callback_model:
    callback_model = model.callback_model
  else:
    callback_model = model

  callbacks.set_model(callback_model)

  callbacks.set_params({
      'batch_size': batch_size,
      'epochs': epochs,
      'steps': steps_per_epoch,
      'samples': num_train_samples,
      'verbose': verbose,
      'do_validation': do_validation,
      'metrics': callback_metrics or [],
  })
  callbacks.on_train_begin()
  callback_model.stop_training = False
  for cbk in callbacks:
    cbk.validation_data = val_ins

  for epoch in range(initial_epoch, epochs):
    callbacks.on_epoch_begin(epoch)
    epoch_logs = {}
    if shuffle == 'batch':
      index_array = model._batch_shuffle(index_array, batch_size)
    elif shuffle:
      np.random.shuffle(index_array)

    batches = make_batches(num_train_samples, batch_size)

    for batch_index, (batch_start, batch_end) in enumerate(batches):
      batch_ids = index_array[batch_start:batch_end]
      try:
        if isinstance(ins[-1], float):
          # Do not slice the training phase flag.
          ins_batch = slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
        else:
          ins_batch = slice_arrays(ins, batch_ids)
      except TypeError:
        raise TypeError('TypeError while preparing batch. '
                        'If using HDF5 input data, '
                        'pass shuffle="batch".')
      batch_logs = {}
      batch_logs['batch'] = batch_index
      batch_logs['size'] = len(batch_ids)

      callbacks.on_batch_begin(batch_index, batch_logs)

      ins_batch_converted = []
      for ib in ins_batch:
        ins_batch_converted.append(ops.convert_to_tensor(ib, dtype=K.floatx()))
      eager_model_inputs = []
      eager_model_outputs = []
      for i in range(len(model.inputs)):
        eager_model_inputs.append(ins_batch_converted[i])

      for i in range(len(model.inputs), len(ins_batch_converted)):
        eager_model_outputs.append(ins_batch_converted[i])

      outs, loss, loss_metrics = _process_single_batch(eager_model_inputs,
                                                       eager_model_outputs,
                                                       model)

      if not isinstance(outs, list):
        outs = [outs]

      for l, o in zip(out_labels, outs):
        batch_logs[l] = o
      # Required for Eager mode
      metrics_names, metrics_results = _eager_metrics_fn(model, outs,
                                                         eager_model_outputs)
      batch_logs['loss'] = tensor_util.constant_value(K.mean(loss))

      # TODO(anjalisridhar): Move this to compile to avoid duplicate code.
      # In graph mode we set the metric names in compile. However in
      # Eager mode we calculate the metrics for each batch in fit_loop.
      # We could calculate the metric names and functions in compile.
      # This would avoid setting the callback parameters separately.
      # We need to do this for the first iteration alone
      for m in metrics_names:
        if m not in callback_metrics:
          callback_metrics.append(m)

      callbacks.set_params({
          'batch_size': batch_size,
          'epochs': epochs,
          'steps': steps_per_epoch,
          'samples': num_train_samples,
          'verbose': verbose,
          'do_validation': do_validation,
          'metrics': callback_metrics or [],
      })

      for k, v in zip(model.metrics_names,
                      [K.mean(loss)] + loss_metrics + metrics_results):
        batch_logs[k] = tensor_util.constant_value(v)

      callbacks.on_batch_end(batch_index, batch_logs)
      if callback_model.stop_training:
        break

      if batch_index == len(batches) - 1:  # Last batch.
        if do_validation:
          val_outs = test_loop(
              model, val_ins, batch_size=batch_size, verbose=0)
          if not isinstance(val_outs, list):
            val_outs = [val_outs]
          # Same labels assumed.
          for l, o in zip(out_labels, val_outs):
            epoch_logs['val_' + l] = o
    callbacks.on_epoch_end(epoch, epoch_logs)
    if callback_model.stop_training:
      break
  callbacks.on_train_end()
  return model.history
Beispiel #17
0
    def _specialize_model(self, input_specs):
        """Specialize `self.model` (a Keras model) for the given input shapes."""
        # Re-create our input and output layers inside our subgraph.  They will be
        # attached to the true computation when we clone our model in `tpu_fn`.
        K.set_learning_phase(
            self.execution_mode == model_fn_lib.ModeKeys.TRAIN)

        # functools.partial and callable objects are not supported by tpu.rewrite
        def _model_fn():
            """Compute fit/eval/predict for the TPU."""
            is_training = self.execution_mode == model_fn_lib.ModeKeys.TRAIN
            is_test = self.execution_mode == model_fn_lib.ModeKeys.EVAL
            is_predict = self.execution_mode == model_fn_lib.ModeKeys.PREDICT

            # During train/eval, we infeed our features as well as labels.
            if is_training or is_test:
                infeed_layers = self.model._input_layers + self.model._output_layers
            else:
                infeed_layers = self.model._input_layers

            # Generate our infeed operation to read features & labels.
            infeed_tensors = tpu_ops.infeed_dequeue_tuple(
                dtypes=[spec.dtype for spec in input_specs],
                shapes=[spec.shape for spec in input_specs],
                name='infeed-%s' % self.execution_mode)

            assert len(infeed_tensors) == len(infeed_layers), (
                'Infeed inputs did not match model: %s vs %s',
                (infeed_layers, infeed_tensors))

            tpu_targets = []
            tpu_inputs = []

            # Sort infeed outputs into inputs and labels for calling our Keras model.
            for tensor, layer in zip(infeed_tensors, infeed_layers):
                if layer in self.model._input_layers:
                    tpu_inputs.append(
                        layers.Input(name=layer.name, tensor=tensor))
                if layer in self.model._output_layers:
                    tpu_targets.append(tensor)

            # Call our model with our infeed inputs (re-using the weights).
            model_outputs = self.model(tpu_inputs)
            child_model = models.Model(inputs=tpu_inputs,
                                       outputs=model_outputs)

            if is_training or is_test:
                child_model.compile(
                    optimizer=_replicated_optimizer(self.model.optimizer,
                                                    self.num_replicas),
                    loss=self.model.loss,
                    loss_weights=self.model.loss_weights,
                    metrics=self.model.metrics,
                    weighted_metrics=self.model.weighted_metrics,
                    target_tensors=tpu_targets,
                )

            # Compute our outfeed depending on the execution mode
            if is_training:
                child_model._make_train_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.train_function.outputs
                ]
                return [
                    child_model.train_function.updates_op,
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.train_function.outputs,
                        name='outfeed-enqueue-train')
                ]
            elif is_test:
                child_model._make_test_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.test_function.outputs
                ]
                return [
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.test_function.outputs,
                        name='outfeed-enqueue-test')
                ]
            elif is_predict:
                child_model._make_predict_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.predict_function.outputs
                ]
                return [
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.predict_function.outputs,
                        name='outfeed-enqueue-predict',
                    )
                ]
            else:
                assert False, 'Unexpected execution mode: %s' % self.execution_mode

        # Capture outfeed metadata computed during the rewrite.
        self._outfeed_spec = None

        # Generate out TPU operations using `tpu.split_compile_and_replicate`.
        # `compile_op` can be used to test the TPU model compiles before execution.
        # `execute op` replicates `_model_fn` `num_replicas` times, with each shard
        # running on a different logical core.
        compile_op, execute_op = tpu.split_compile_and_replicate(
            _model_fn, inputs=[[]] * self.num_replicas)

        # Generate CPU side operations to enqueue features/labels and dequeue
        # outputs from the model call.
        infeed_op = []
        outfeed_op = []
        shard_infeed_tensors = []

        for shard_id in range(self.num_replicas):
            with ops.device('/device:TPU:%d' % shard_id):
                infeed_tensors = []
                for spec in input_specs:
                    infeed_tensors.append(
                        array_ops.placeholder(dtype=spec.dtype,
                                              shape=spec.shape,
                                              name='infeed-enqueue-%s-%d' %
                                              (spec.name, shard_id)))
                shard_infeed_tensors.append(infeed_tensors)

                infeed_op.append(
                    tpu_ops.infeed_enqueue_tuple(
                        infeed_tensors, [spec.shape for spec in input_specs],
                        name='infeed-enqueue-%s-%d' %
                        (self.execution_mode, shard_id)))

                outfeed_op.extend(
                    tpu_ops.outfeed_dequeue_tuple(
                        dtypes=[spec.dtype for spec in self._outfeed_spec],
                        shapes=[spec.shape for spec in self._outfeed_spec],
                        name='outfeed-dequeue-%s-%d' %
                        (self.execution_mode, shard_id)))

        return TPUModelOp(compile_op,
                          execute_op,
                          infeed_tensors=shard_infeed_tensors,
                          infeed_op=infeed_op,
                          outfeed_op=outfeed_op)
    def _specialize_model(self, input_specs):
        """Specialize `self.model` (a Keras model) for the given input shapes."""
        # Re-create our input and output layers inside our subgraph.  They will be
        # attached to the true computation when we clone our model in `tpu_fn`.
        K.set_learning_phase(
            self.execution_mode == model_fn_lib.ModeKeys.TRAIN)

        # functools.partial and callable objects are not supported by tpu.rewrite
        def _model_fn():
            """Compute fit/eval/predict for the TPU."""
            is_training = self.execution_mode == model_fn_lib.ModeKeys.TRAIN
            is_test = self.execution_mode == model_fn_lib.ModeKeys.EVAL
            is_predict = self.execution_mode == model_fn_lib.ModeKeys.PREDICT

            # During train/eval, we infeed our features as well as labels.
            if is_training or is_test:
                infeed_layers = self.model._input_layers + self.model._output_layers
            else:
                infeed_layers = self.model._input_layers

            # Generate our infeed operation to read features & labels.
            infeed_tensors = tpu_ops.infeed_dequeue_tuple(
                dtypes=[spec.dtype for spec in input_specs],
                shapes=[spec.shape for spec in input_specs],
                name='infeed-%s' % self.execution_mode)

            assert len(infeed_tensors) == len(infeed_layers), (
                'Infeed inputs did not match model: %s vs %s',
                (infeed_layers, infeed_tensors))

            tpu_targets = []
            tpu_inputs = []

            # Sort infeed outputs into inputs and labels for calling our Keras model.
            for tensor, layer in zip(infeed_tensors, infeed_layers):
                if layer in self.model._input_layers:
                    tpu_inputs.append(
                        layers.Input(name=layer.name, tensor=tensor))
                if layer in self.model._output_layers:
                    tpu_targets.append(tensor)

            optimizer = self.model.optimizer
            optimizer.iterations = training_util.get_or_create_global_step()

            # Call our model with our infeed inputs (re-using the weights).
            model_outputs = self.model(tpu_inputs)
            child_model = models.Model(inputs=tpu_inputs,
                                       outputs=model_outputs)
            if is_training or is_test:
                child_model.compile(
                    optimizer=self.model.optimizer,
                    loss=self.model.loss,
                    loss_weights=self.model.loss_weights,
                    metrics=self.model.metrics,
                    weighted_metrics=self.model.weighted_metrics,
                    target_tensors=tpu_targets,
                )

            # Compute our outfeed depending on the execution mode
            if is_training:
                child_model._make_train_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.train_function.outputs
                ]
                return [
                    child_model.train_function.updates_op,
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.train_function.outputs,
                        name='oufeed-enqueue-train')
                ]
            elif is_test:
                child_model._make_test_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.test_function.outputs
                ]
                return [
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.test_function.outputs,
                        name='outfeed-enqueue-test')
                ]
            elif is_predict:
                child_model._make_predict_function()
                self._outfeed_spec = [
                    tensor_spec.TensorSpec(tensor.shape, tensor.dtype,
                                           tensor.name)
                    for tensor in child_model.predict_function.outputs
                ]
                return [
                    tpu_ops.outfeed_enqueue_tuple(
                        child_model.predict_function.outputs,
                        name='outfeed-enqueue-predict',
                    )
                ]
            else:
                assert False, 'Unexpected execution mode: %s' % self.execution_mode

        # Capture outfeed metadata computed during the rewrite.
        self._outfeed_spec = None

        tpu_execute_op = tpu.rewrite(_model_fn)

        K._initialize_variables(
            K.get_session())  # pylint-disable: protected-access

        # Generate CPU side operations to enqueue features/labels and dequeue
        # outputs from the model call.
        with ops.device('/device:TPU:0'):
            infeed_tensors = []
            for spec in input_specs:
                infeed_tensors.append(
                    array_ops.placeholder(dtype=spec.dtype,
                                          shape=spec.shape,
                                          name='infeed-enqueue-%s' %
                                          spec.name))

            infeed_op = tpu_ops.infeed_enqueue_tuple(
                infeed_tensors, [spec.shape for spec in input_specs],
                name='infeed-enqueue-%s' % self.execution_mode)

            outfeed_op = tpu_ops.outfeed_dequeue_tuple(
                dtypes=[spec.dtype for spec in self._outfeed_spec],
                shapes=[spec.shape for spec in self._outfeed_spec],
                name='outfeed-dequeue-%s' % self.execution_mode)

        return CompiledTPUOp(tpu_execute_op, infeed_tensors, infeed_op,
                             outfeed_op)
def predict_loop(model, inputs, batch_size=32, verbose=0, steps=None):
    """Abstract method to loop over some data in batches.

  Arguments:
      model:
      inputs: List of input arrays.
      batch_size: integer batch size.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring `_predict_loop` finished.
          Ignored with the default value of `None`.

  Returns:
      Array of predictions (if the model has a single output)
      or list of arrays of predictions
      (if the model has multiple outputs).
  """
    K.set_learning_phase(False)
    num_samples = training_utils.check_num_samples(inputs, batch_size, steps,
                                                   'steps')
    if verbose == 1:
        if steps is not None:
            progbar = Progbar(target=steps)
        else:
            progbar = Progbar(target=num_samples)

    outs = []
    batches = make_batches(num_samples, batch_size)
    index_array = np.arange(num_samples)
    for batch_index, (batch_start, batch_end) in enumerate(batches):
        batch_ids = index_array[batch_start:batch_end]
        inputs_batch = slice_arrays(inputs, batch_ids)

        inputs_batch = [
            ops.convert_to_tensor(val, dtype=K.floatx())
            for val in inputs_batch
        ]

        if len(inputs_batch) == 1:
            if model._expects_training_arg:
                batch_outs = model.call(inputs_batch[0], training=False)
            else:
                batch_outs = model.call(inputs_batch[0])
        else:
            if model._expects_training_arg:
                batch_outs = model.call(inputs_batch, training=False)
            else:
                batch_outs = model.call(inputs_batch)

        if not isinstance(batch_outs, list):
            batch_outs = [batch_outs]
        if batch_index == 0:
            # Pre-allocate the results arrays.
            for batch_out in batch_outs:
                dims = batch_out.shape[1:].dims
                dims_list = [d.value for d in dims]
                shape = (num_samples, ) + tuple(dims_list)
                outs.append(
                    np.zeros(shape, dtype=batch_out.dtype.as_numpy_dtype))
        for i, batch_out in enumerate(batch_outs):
            outs[i][batch_start:batch_end] = batch_out
        if verbose == 1:
            progbar.update(batch_end)
    if len(outs) == 1:
        return outs[0]
    return outs
def test_loop(model, ins, batch_size=None, verbose=0, steps=None):
  """Abstract method to loop over some data in batches.

  Arguments:
      model: Model instance that is being evaluated in Eager mode.
      ins: list of tensors to be fed to `f`.
      batch_size: integer batch size or `None`.
      verbose: verbosity mode.
      steps: Total number of steps (batches of samples)
          before declaring predictions finished.
          Ignored with the default value of `None`.

  Returns:
      Scalar loss (if the model has a single output and no metrics)
      or list of scalars (if the model has multiple outputs
      and/or metrics). The attribute `model.metrics_names` will give you
      the display labels for the scalar outputs.
  """
  K.set_learning_phase(False)
  num_samples = model._check_num_samples(ins, batch_size, steps, 'steps')
  outs = []
  if verbose == 1:
    progbar = Progbar(target=num_samples)
  batches = make_batches(num_samples, batch_size)
  index_array = np.arange(num_samples)
  for batch_index, (batch_start, batch_end) in enumerate(batches):
    batch_ids = index_array[batch_start:batch_end]
    if isinstance(ins[-1], float):
      # Do not slice the training phase flag.
      ins_batch = slice_arrays(ins[:-1], batch_ids) + [ins[-1]]
    else:
      ins_batch = slice_arrays(ins, batch_ids)

    ins_batch_converted = []
    for ib in ins_batch:
      ins_batch_converted.append(ops.convert_to_tensor(ib, dtype=K.floatx()))

    eager_model_inputs = []
    eager_model_outputs = []
    for i in range(len(model.inputs)):
      eager_model_inputs.append(ins_batch_converted[i])

    for i in range(len(model.inputs), len(ins_batch_converted)):
      eager_model_outputs.append(ins_batch_converted[i])

    loss_outs, loss, loss_metrics = _model_loss(model, eager_model_inputs,
                                                eager_model_outputs)
    _, metrics_results = _eager_metrics_fn(model, loss_outs,
                                           eager_model_outputs)
    batch_outs = []
    for _, v in zip(model.metrics_names,
                    [K.mean(loss)] + loss_metrics + metrics_results):
      batch_outs.append(tensor_util.constant_value(v))

    if isinstance(batch_outs, list):
      if batch_index == 0:
        for batch_out in enumerate(batch_outs):
          outs.append(0.)
      for i, batch_out in enumerate(batch_outs):
        outs[i] += batch_out * len(batch_ids)
    else:
      if batch_index == 0:
        outs.append(0.)
      outs[0] += batch_outs * len(batch_ids)

    if verbose == 1:
      progbar.update(batch_end)
  for i in range(len(outs)):
    outs[i] /= num_samples
  if len(outs) == 1:
    return outs[0]
  return outs
Beispiel #21
0
    def from_config(cls, mode, features, labels, config):  # pylint: disable=arguments-differ
        """Instantiates a Graph container from its config (output of `get_config()`).

        Arguments:
            mode:
            features:
            labels:
            config: Model config dictionary.

        Returns:
            A model instance.

        Raises:
            ValueError: In case of improperly formatted config dict.
        """
        # set the training mode
        set_learning_phase(Modes.is_train(mode))

        if not isinstance(config, GraphConfig):
            config = GraphConfig.from_dict(config)

        # layer instances created during
        # the graph reconstruction process
        created_layers = {}

        # Create an input layer based on the defined inputs and features
        for layer in config.input_layers:
            layer_name, node_index, tensor_index = cls.get_node_data(layer)
            if layer_name in features:
                created_layers[layer_name] = InputLayer(
                    input_tensor=features[layer_name], name=layer_name)
            elif isinstance(labels, Mapping) and layer_name in labels:
                created_layers[layer_name] = InputLayer(
                    input_tensor=labels[layer_name], name=layer_name)
            else:
                raise ConfigurationError("Input `{}`is not found".format(layer_name))

        def process_layer(layer):
            """Deserialize a layer, then call it on appropriate inputs.

            Arguments:
                layer_data: layer config dict.

            Raises:
                ValueError: In case of improperly formatted `layer_data` dict.
            """
            layer_class = layer.IDENTIFIER
            layer_name = layer.name

            # Instantiate layer.
            if layer_class in LAYERS:
                created_layer = LAYERS[layer_class].from_config(layer)
            elif layer_class in IMAGE_PROCESSORS:
                created_layer = IMAGE_PROCESSORS[layer_class].from_config(layer)
            else:
                raise ValueError("The layer `{}` is not supported.".format(layer_class))
            created_layers[layer_name] = created_layer

            # Gather layer inputs.
            inbound_nodes_data = layer.inbound_nodes
            input_tensors = []
            for input_data in inbound_nodes_data:
                in_layer_name, in_node_index, in_tensor_index = cls.get_node_data(input_data)
                if len(input_data) == 3:
                    kwargs = {}
                elif len(input_data) == 4:
                    kwargs = input_data[3]
                else:
                    raise ValueError('Improperly formatted model config.')
                if in_layer_name not in created_layers:
                    raise ValueError('Missing layer: ' + in_layer_name)
                inbound_layer = created_layers[in_layer_name]
                inbound_node = inbound_layer.inbound_nodes[in_node_index]
                input_tensors.append(inbound_node.output_tensors[in_tensor_index])
            # Call layer on its inputs, thus creating the node
            # and building the layer if needed.
            if input_tensors:
                if len(input_tensors) == 1:
                    created_layer(input_tensors[0], **kwargs)
                else:
                    created_layer(input_tensors, **kwargs)

        for layer in config.layers:
            process_layer(layer)

        name = config.name
        input_tensors = []
        output_tensors = []
        for layer_data in config.input_layers:
            layer_name, node_index, tensor_index = cls.get_node_data(layer_data)
            assert layer_name in created_layers, "Layer `{}` not found".format(layer_name)
            layer = created_layers[layer_name]
            layer_output_tensors = layer.inbound_nodes[node_index].output_tensors
            input_tensors.append(layer_output_tensors[tensor_index])
        for layer_data in config.output_layers:
            layer_name, node_index, tensor_index = cls.get_node_data(layer_data)
            assert layer_name in created_layers
            layer = created_layers[layer_name]
            layer_output_tensors = layer.inbound_nodes[node_index].output_tensors
            output_tensors.append(layer_output_tensors[tensor_index])
        return cls(inputs=input_tensors, outputs=output_tensors, name=name)