示例#1
0
    def define_loss(self, features, mode):
        """Default loss definition with state replicated across a batch.

    Time series passed to this model have a batch dimension, and each series in
    a batch can be operated on in parallel. This loss definition assumes that
    each element of the batch represents an independent sample conditioned on
    the same initial state (i.e. it is simply replicated across the batch). A
    batch size of one provides sequential operations on a single time series.

    More complex processing may operate instead on get_start_state() and
    get_batch_loss() directly.

    Args:
      features: A dictionary (such as is produced by a chunker) with at minimum
        the following key/value pairs (others corresponding to the
        `exogenous_feature_columns` argument to `__init__` may be included
        representing exogenous regressors):
        TrainEvalFeatures.TIMES: A [batch size x window size] integer Tensor
            with times for each observation. If there is no artificial chunking,
            the window size is simply the length of the time series.
        TrainEvalFeatures.VALUES: A [batch size x window size x num features]
            Tensor with values for each observation.
      mode: The tf.estimator.ModeKeys mode to use (TRAIN, EVAL). For INFER,
        see predict().
    Returns:
      A ModelOutputs object.
    """
        self._check_graph_initialized()
        start_state = math_utils.replicate_state(
            start_state=self.get_start_state(),
            batch_size=array_ops.shape(features[TrainEvalFeatures.TIMES])[0])
        return self.get_batch_loss(features=features,
                                   mode=mode,
                                   state=start_state)
 def _gap_test_template(self, times, values):
   random_model = RandomStateSpaceModel(
       state_dimension=1, state_noise_dimension=1,
       configuration=state_space_model.StateSpaceModelConfiguration(
           num_features=1))
   random_model.initialize_graph()
   input_fn = input_pipeline.WholeDatasetInputFn(
       input_pipeline.NumpyReader({
           feature_keys.TrainEvalFeatures.TIMES: times,
           feature_keys.TrainEvalFeatures.VALUES: values
       }))
   features, _ = input_fn()
   times = features[feature_keys.TrainEvalFeatures.TIMES]
   values = features[feature_keys.TrainEvalFeatures.VALUES]
   model_outputs = random_model.get_batch_loss(
       features={
           feature_keys.TrainEvalFeatures.TIMES: times,
           feature_keys.TrainEvalFeatures.VALUES: values
       },
       mode=None,
       state=math_utils.replicate_state(
           start_state=random_model.get_start_state(),
           batch_size=array_ops.shape(times)[0]))
   with self.cached_session() as session:
     variables.global_variables_initializer().run()
     coordinator = coordinator_lib.Coordinator()
     queue_runner_impl.start_queue_runners(session, coord=coordinator)
     model_outputs.loss.eval()
     coordinator.request_stop()
     coordinator.join()
示例#3
0
  def _get_cached_states(self, times):
    """Retrieve cached states for a batch of times."""
    read_chunk_numbers = self._get_chunk_number(times)
    looked_up_state = list(self._cached_states.lookup(
        math_ops.cast(read_chunk_numbers, dtypes.int64)))
    looked_up_state = tuple(looked_up_state)
    # We need to special-case the first chunk in a series to explicitly rely on
    # the model's starting state so that gradients flow back to it. Otherwise it
    # would affect only initialization, and would not be read from or updated
    # during training. Not doing this also isolates that part of the graph,
    # leading to errors on model reload if there are trainable variables
    # affecting a model's start state.
    if self._input_statistics is not None:
      start_time = self._input_statistics.start_time
    else:
      start_time = 0
    set_to_start_state = math_ops.equal(read_chunk_numbers,
                                        self._get_chunk_number(start_time))
    new_states = []
    for start_state_value, cache_variable in zip(
        nest.flatten(
            math_utils.replicate_state(self._start_state,
                                       array_ops.shape(times)[0])),
        nest.flatten(looked_up_state)):

      new_states.append(
          array_ops.where(set_to_start_state, start_state_value,
                          cache_variable))
    looked_up_state = nest.pack_sequence_as(looked_up_state, new_states)
    return looked_up_state
示例#4
0
  def define_loss(self, features, mode):
    """Default loss definition with state replicated across a batch.

    Time series passed to this model have a batch dimension, and each series in
    a batch can be operated on in parallel. This loss definition assumes that
    each element of the batch represents an independent sample conditioned on
    the same initial state (i.e. it is simply replicated across the batch). A
    batch size of one provides sequential operations on a single time series.

    More complex processing may operate instead on get_start_state() and
    get_batch_loss() directly.

    Args:
      features: A dictionary (such as is produced by a chunker) with at minimum
        the following key/value pairs (others corresponding to the
        `exogenous_feature_columns` argument to `__init__` may be included
        representing exogenous regressors):
        TrainEvalFeatures.TIMES: A [batch size x window size] integer Tensor
            with times for each observation. If there is no artificial chunking,
            the window size is simply the length of the time series.
        TrainEvalFeatures.VALUES: A [batch size x window size x num features]
            Tensor with values for each observation.
      mode: The tf.estimator.ModeKeys mode to use (TRAIN, EVAL). For INFER,
        see predict().
    Returns:
      A ModelOutputs object.
    """
    self._check_graph_initialized()
    start_state = math_utils.replicate_state(
        start_state=self.get_start_state(),
        batch_size=array_ops.shape(features[TrainEvalFeatures.TIMES])[0])
    return self.get_batch_loss(features=features, mode=mode, state=start_state)
示例#5
0
    def _get_cached_states(self, times):
        """Retrieve cached states for a batch of times."""
        read_chunk_numbers = self._get_chunk_number(times)
        looked_up_state = list(
            self._cached_states.lookup(
                math_ops.cast(read_chunk_numbers, dtypes.int64)))
        looked_up_state = tuple(looked_up_state)
        # We need to special-case the first chunk in a series to explicitly rely on
        # the model's starting state so that gradients flow back to it. Otherwise it
        # would affect only initialization, and would not be read from or updated
        # during training. Not doing this also isolates that part of the graph,
        # leading to errors on model reload if there are trainable variables
        # affecting a model's start state.
        if self._input_statistics is not None:
            start_time = self._input_statistics.start_time
        else:
            start_time = 0
        set_to_start_state = math_ops.equal(read_chunk_numbers,
                                            self._get_chunk_number(start_time))
        new_states = []
        for start_state_value, cache_variable in zip(
                nest.flatten(
                    math_utils.replicate_state(self._start_state,
                                               array_ops.shape(times)[0])),
                nest.flatten(looked_up_state)):

            new_states.append(
                array_ops.where(set_to_start_state, start_state_value,
                                cache_variable))
        looked_up_state = nest.pack_sequence_as(looked_up_state, new_states)
        return looked_up_state
示例#6
0
 def _gap_test_template(self, times, values):
     random_model = RandomStateSpaceModel(
         state_dimension=1,
         state_noise_dimension=1,
         configuration=state_space_model.StateSpaceModelConfiguration(
             num_features=1))
     random_model.initialize_graph()
     input_fn = input_pipeline.WholeDatasetInputFn(
         input_pipeline.NumpyReader({
             feature_keys.TrainEvalFeatures.TIMES:
             times,
             feature_keys.TrainEvalFeatures.VALUES:
             values
         }))
     features, _ = input_fn()
     times = features[feature_keys.TrainEvalFeatures.TIMES]
     values = features[feature_keys.TrainEvalFeatures.VALUES]
     model_outputs = random_model.get_batch_loss(
         features={
             feature_keys.TrainEvalFeatures.TIMES: times,
             feature_keys.TrainEvalFeatures.VALUES: values
         },
         mode=None,
         state=math_utils.replicate_state(
             start_state=random_model.get_start_state(),
             batch_size=array_ops.shape(times)[0]))
     with self.test_session() as session:
         variables.global_variables_initializer().run()
         coordinator = coordinator_lib.Coordinator()
         queue_runner_impl.start_queue_runners(session, coord=coordinator)
         model_outputs.loss.eval()
         coordinator.request_stop()
         coordinator.join()
示例#7
0
 def _equivalent_to_single_model_test_template(self, model_generator):
     with self.test_session() as session:
         random_model = RandomStateSpaceModel(
             state_dimension=5,
             state_noise_dimension=4,
             configuration=state_space_model.StateSpaceModelConfiguration(
                 dtype=dtypes.float64, num_features=1))
         random_model.initialize_graph()
         series_length = 10
         model_data = random_model.generate(
             number_of_series=1,
             series_length=series_length,
             model_parameters=random_model.random_model_parameters())
         input_fn = input_pipeline.WholeDatasetInputFn(
             input_pipeline.NumpyReader(model_data))
         features, _ = input_fn()
         model_outputs = random_model.get_batch_loss(
             features=features,
             mode=None,
             state=math_utils.replicate_state(
                 start_state=random_model.get_start_state(),
                 batch_size=array_ops.shape(
                     features[feature_keys.TrainEvalFeatures.TIMES])[0]))
         variables.global_variables_initializer().run()
         compare_outputs_evaled_fn = model_generator(
             random_model, model_data)
         coordinator = coordinator_lib.Coordinator()
         queue_runner_impl.start_queue_runners(session, coord=coordinator)
         compare_outputs_evaled = compare_outputs_evaled_fn(session)
         model_outputs_evaled = session.run(
             (model_outputs.end_state, model_outputs.predictions))
         coordinator.request_stop()
         coordinator.join()
         model_posteriors, model_predictions = model_outputs_evaled
         (_, compare_posteriors,
          compare_predictions) = compare_outputs_evaled
         (model_posterior_mean, model_posterior_var,
          model_from_time) = model_posteriors
         (compare_posterior_mean, compare_posterior_var,
          compare_from_time) = compare_posteriors
         self.assertAllClose(model_posterior_mean,
                             compare_posterior_mean[0])
         self.assertAllClose(model_posterior_var, compare_posterior_var[0])
         self.assertAllClose(model_from_time, compare_from_time)
         self.assertEqual(sorted(model_predictions.keys()),
                          sorted(compare_predictions.keys()))
         for prediction_name in model_predictions:
             if prediction_name == "loss":
                 # Chunking means that losses will be different; skip testing them.
                 continue
             # Compare the last chunk to their corresponding un-chunked model
             # predictions
             last_prediction_chunk = compare_predictions[prediction_name][
                 -1]
             comparison_values = last_prediction_chunk.shape[0]
             model_prediction = (
                 model_predictions[prediction_name][0, -comparison_values:])
             self.assertAllClose(model_prediction, last_prediction_chunk)
 def _equivalent_to_single_model_test_template(self, model_generator):
   with self.cached_session() as session:
     random_model = RandomStateSpaceModel(
         state_dimension=5,
         state_noise_dimension=4,
         configuration=state_space_model.StateSpaceModelConfiguration(
             dtype=dtypes.float64, num_features=1))
     random_model.initialize_graph()
     series_length = 10
     model_data = random_model.generate(
         number_of_series=1, series_length=series_length,
         model_parameters=random_model.random_model_parameters())
     input_fn = input_pipeline.WholeDatasetInputFn(
         input_pipeline.NumpyReader(model_data))
     features, _ = input_fn()
     model_outputs = random_model.get_batch_loss(
         features=features,
         mode=None,
         state=math_utils.replicate_state(
             start_state=random_model.get_start_state(),
             batch_size=array_ops.shape(
                 features[feature_keys.TrainEvalFeatures.TIMES])[0]))
     variables.global_variables_initializer().run()
     compare_outputs_evaled_fn = model_generator(
         random_model, model_data)
     coordinator = coordinator_lib.Coordinator()
     queue_runner_impl.start_queue_runners(session, coord=coordinator)
     compare_outputs_evaled = compare_outputs_evaled_fn(session)
     model_outputs_evaled = session.run(
         (model_outputs.end_state, model_outputs.predictions))
     coordinator.request_stop()
     coordinator.join()
     model_posteriors, model_predictions = model_outputs_evaled
     (_, compare_posteriors,
      compare_predictions) = compare_outputs_evaled
     (model_posterior_mean, model_posterior_var,
      model_from_time) = model_posteriors
     (compare_posterior_mean, compare_posterior_var,
      compare_from_time) = compare_posteriors
     self.assertAllClose(model_posterior_mean, compare_posterior_mean[0])
     self.assertAllClose(model_posterior_var, compare_posterior_var[0])
     self.assertAllClose(model_from_time, compare_from_time)
     self.assertEqual(sorted(model_predictions.keys()),
                      sorted(compare_predictions.keys()))
     for prediction_name in model_predictions:
       if prediction_name == "loss":
         # Chunking means that losses will be different; skip testing them.
         continue
       # Compare the last chunk to their corresponding un-chunked model
       # predictions
       last_prediction_chunk = compare_predictions[prediction_name][-1]
       comparison_values = last_prediction_chunk.shape[0]
       model_prediction = (
           model_predictions[prediction_name][0, -comparison_values:])
       self.assertAllClose(model_prediction,
                           last_prediction_chunk)
 def test_predictions_direct(self):
   dtype = dtypes.float64
   with variable_scope.variable_scope(dtype.name):
     random_model = RandomStateSpaceModel(
         state_dimension=5, state_noise_dimension=4,
         configuration=state_space_model.StateSpaceModelConfiguration(
             dtype=dtype, num_features=1))
     random_model.initialize_graph()
     prediction_dict = random_model.predict(features={
         feature_keys.PredictionFeatures.TIMES: [[1, 3, 5, 6]],
         feature_keys.PredictionFeatures.STATE_TUPLE:
             math_utils.replicate_state(
                 start_state=random_model.get_start_state(), batch_size=1)
     })
     with self.cached_session():
       variables.global_variables_initializer().run()
       predicted_mean = prediction_dict["mean"].eval()
       predicted_covariance = prediction_dict["covariance"].eval()
     self._check_predictions(predicted_mean, predicted_covariance,
                             window_size=4)
 def test_predictions_direct(self):
   dtype = dtypes.float64
   with variable_scope.variable_scope(dtype.name):
     random_model = RandomStateSpaceModel(
         state_dimension=5, state_noise_dimension=4,
         configuration=state_space_model.StateSpaceModelConfiguration(
             dtype=dtype, num_features=1))
     random_model.initialize_graph()
     prediction_dict = random_model.predict(features={
         feature_keys.PredictionFeatures.TIMES: [[1, 3, 5, 6]],
         feature_keys.PredictionFeatures.STATE_TUPLE:
             math_utils.replicate_state(
                 start_state=random_model.get_start_state(), batch_size=1)
     })
     with self.test_session():
       variables.global_variables_initializer().run()
       predicted_mean = prediction_dict["mean"].eval()
       predicted_covariance = prediction_dict["covariance"].eval()
     self._check_predictions(predicted_mean, predicted_covariance,
                             window_size=4)
示例#11
0
    def test_exact_posterior_recovery_no_transition_noise(self):
        with self.test_session() as session:
            stub_model, data, true_params = self._get_single_model()
            input_fn = input_pipeline.WholeDatasetInputFn(
                input_pipeline.NumpyReader(data))
            features, _ = input_fn()
            model_outputs = stub_model.get_batch_loss(
                features=features,
                mode=None,
                state=math_utils.replicate_state(
                    start_state=stub_model.get_start_state(),
                    batch_size=array_ops.shape(
                        features[feature_keys.TrainEvalFeatures.TIMES])[0]))
            variables.global_variables_initializer().run()
            coordinator = coordinator_lib.Coordinator()
            queue_runner_impl.start_queue_runners(session, coord=coordinator)
            posterior_mean, posterior_var, posterior_times = session.run(
                # Feed the true model parameters so that this test doesn't depend on
                # the generated parameters being close to the variable initializations
                # (an alternative would be training steps to fit the noise values,
                # which would be slow).
                model_outputs.end_state,
                feed_dict=true_params)
            coordinator.request_stop()
            coordinator.join()

            self.assertAllClose(numpy.zeros([1, 4, 4]),
                                posterior_var,
                                atol=1e-2)
            self.assertAllClose(numpy.dot(
                numpy.linalg.matrix_power(
                    stub_model.transition,
                    data[feature_keys.TrainEvalFeatures.TIMES].shape[1]),
                true_params[stub_model.prior_state_mean]),
                                posterior_mean[0],
                                rtol=1e-1)
            self.assertAllClose(
                math_utils.batch_end_time(
                    features[feature_keys.TrainEvalFeatures.TIMES]).eval(),
                posterior_times)
  def test_exact_posterior_recovery_no_transition_noise(self):
    with self.cached_session() as session:
      stub_model, data, true_params = self._get_single_model()
      input_fn = input_pipeline.WholeDatasetInputFn(
          input_pipeline.NumpyReader(data))
      features, _ = input_fn()
      model_outputs = stub_model.get_batch_loss(
          features=features,
          mode=None,
          state=math_utils.replicate_state(
              start_state=stub_model.get_start_state(),
              batch_size=array_ops.shape(
                  features[feature_keys.TrainEvalFeatures.TIMES])[0]))
      variables.global_variables_initializer().run()
      coordinator = coordinator_lib.Coordinator()
      queue_runner_impl.start_queue_runners(session, coord=coordinator)
      posterior_mean, posterior_var, posterior_times = session.run(
          # Feed the true model parameters so that this test doesn't depend on
          # the generated parameters being close to the variable initializations
          # (an alternative would be training steps to fit the noise values,
          # which would be slow).
          model_outputs.end_state, feed_dict=true_params)
      coordinator.request_stop()
      coordinator.join()

      self.assertAllClose(numpy.zeros([1, 4, 4]), posterior_var,
                          atol=1e-2)
      self.assertAllClose(
          numpy.dot(
              numpy.linalg.matrix_power(
                  stub_model.transition,
                  data[feature_keys.TrainEvalFeatures.TIMES].shape[1]),
              true_params[stub_model.prior_state_mean]),
          posterior_mean[0],
          rtol=1e-1)
      self.assertAllClose(
          math_utils.batch_end_time(
              features[feature_keys.TrainEvalFeatures.TIMES]).eval(),
          posterior_times)