def testInitialValueOfMaskedTimeSeries(self): if not self.use_static_shape: return # Dynamic rank is not currently supported. series = tf.random.stateless_normal( [2, 1, 3, 4], seed=test_util.test_seed(sampler_type='stateless')) mask = np.array([ [False, True, False, True], [True, False, True, False], # Ensure no error if a batch element is fully masked. [True, True, True, True] ]) expected_initial_values = distribution_util.move_dimension( tf.convert_to_tensor( [series[..., 0, 0], series[..., 1, 1], series[..., 2, 3]]), source_idx=0, dest_idx=-1) initial_values = missing_values_util.initial_value_of_masked_time_series( self._build_tensor(self.evaluate(series)), broadcast_mask=self._build_tensor(self.evaluate( tf.broadcast_to(mask, series.shape)), dtype=np.bool_)) self.assertAllClose(self.evaluate(initial_values), expected_initial_values)
def empirical_statistics(observed_time_series): """Compute statistics of a provided time series, as heuristic initialization. Args: observed_time_series: `Tensor` representing a time series, or batch of time series, of shape either `batch_shape + [num_timesteps, 1]` or `batch_shape + [num_timesteps]` (allowed if `num_timesteps > 1`). Returns: observed_mean: `Tensor` of shape `batch_shape`, giving the empirical mean of each time series in the batch. observed_stddev: `Tensor` of shape `batch_shape`, giving the empirical standard deviation of each time series in the batch. observed_initial_centered: `Tensor of shape `batch_shape`, giving the initial value of each time series in the batch after centering (subtracting the mean). """ with tf.name_scope('empirical_statistics'): [ observed_time_series, mask ] = canonicalize_observed_time_series_with_mask(observed_time_series) squeezed_series = observed_time_series[..., 0] if mask is None: observed_mean, observed_variance = tf.nn.moments( x=squeezed_series, axes=-1) observed_initial = squeezed_series[..., 0] else: broadcast_mask = tf.broadcast_to(tf.cast(mask, tf.bool), tf.shape(input=squeezed_series)) observed_mean, observed_variance = ( missing_values_util.moments_of_masked_time_series( squeezed_series, broadcast_mask=broadcast_mask)) try: observed_initial = ( missing_values_util.initial_value_of_masked_time_series( squeezed_series, broadcast_mask=broadcast_mask)) except NotImplementedError: tf1.logging.warn( 'Cannot compute initial values for a masked time series' 'with dynamic shape; using the mean instead. This will' 'affect heuristic priors and may change the results of' 'inference.') observed_initial = observed_mean observed_stddev = tf.sqrt(observed_variance) observed_initial_centered = observed_initial - observed_mean return observed_mean, observed_stddev, observed_initial_centered
def testInitialValueOfMaskedTimeSeries(self): if not self.use_static_shape: return # Dynamic rank is not currently supported. series = np.random.randn(2, 4) mask = np.array([[False, True, False, True], [True, False, True, False]]) expected_initial_values = [series[0, 0], series[1, 1]] initial_values = missing_values_util.initial_value_of_masked_time_series( self._build_tensor(series), broadcast_mask=self._build_tensor(mask, dtype=np.bool)) self.assertAllClose(self.evaluate(initial_values), expected_initial_values)
def empirical_statistics(observed_time_series): """Compute statistics of a provided time series, as heuristic initialization. If a series is entirely unobserved (all values are masked), default statistics `mean == 0.`, `stddev == 1.`, and `initial_centered == 0.` are returned. To avoid degenerate models, a value of `1.` is returned for `stddev` whenever the input series is entirely constant (when the true `stddev` is `0.`). Args: observed_time_series: `Tensor` representing a time series, or batch of time series, of shape either `batch_shape + [num_timesteps, 1]` or `batch_shape + [num_timesteps]` (allowed if `num_timesteps > 1`). Returns: observed_mean: `Tensor` of shape `batch_shape`, giving the empirical mean of each time series in the batch. observed_stddev: `Tensor` of shape `batch_shape`, giving the empirical standard deviation of each time series in the batch. observed_initial_centered: `Tensor of shape `batch_shape`, giving the initial value of each time series in the batch after centering (subtracting the mean). """ with tf.name_scope('empirical_statistics'): [observed_time_series, mask ] = canonicalize_observed_time_series_with_mask(observed_time_series) squeezed_series = observed_time_series[..., 0] if mask is None: observed_mean, observed_variance = tf.nn.moments(x=squeezed_series, axes=-1) observed_initial = squeezed_series[..., 0] else: broadcast_mask = tf.broadcast_to(tf.cast(mask, tf.bool), ps.shape(squeezed_series)) observed_mean, observed_variance = ( missing_values_util.moments_of_masked_time_series( squeezed_series, broadcast_mask=broadcast_mask)) try: observed_initial = ( missing_values_util.initial_value_of_masked_time_series( squeezed_series, broadcast_mask=broadcast_mask)) except NotImplementedError: tf1.logging.warn( 'Cannot compute initial values for a masked time series' 'with dynamic shape; using the mean instead. This will' 'affect heuristic priors and may change the results of' 'inference.') observed_initial = observed_mean observed_stddev = tf.sqrt(observed_variance) observed_initial_centered = observed_initial - observed_mean # Dividing by zero will estimate `inf` or `nan` for the mean and stddev # (and thus initial_centered) if a series is entirely masked. Replace these # with default values. replace_nans = (lambda x, v: tf.where(tf.math.is_finite(x), x, tf.cast(v, x.dtype))) # Avoid stddev of zero from a constant series. replace_zeros = ( lambda x, v: tf.where(tf.equal(x, 0.), tf.cast(v, x.dtype), x)) return (replace_nans(observed_mean, 0.), replace_zeros(replace_nans(observed_stddev, 1.), 1.), replace_nans(observed_initial_centered, 0.))