def _prepare_inputs_for_rnn(sequence_features, context_features, sequence_feature_columns, num_unroll): """Prepares features batched by the SQSS for input to a state-saving RNN. Args: sequence_features: A dict of sequence feature name to `Tensor` or `SparseTensor`, with `Tensor`s of shape `[batch_size, num_unroll, ...]` or `SparseTensors` of dense shape `[batch_size, num_unroll, d]`. context_features: A dict of context feature name to `Tensor`, with tensors of shape `[batch_size, 1, ...]` and type float32. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. num_unroll: Python integer, how many time steps to unroll at a time. The input sequences of length `k` are then split into `k / num_unroll` many segments. Returns: features_by_time: A list of length `num_unroll` with `Tensor` entries of shape `[batch_size, sum(sequence_features dimensions) + sum(context_features dimensions)]` of type float32. Context features are copied into each time step. """ def _tile(feature): return array_ops.squeeze( array_ops.tile(array_ops.expand_dims(feature, 1), [1, num_unroll, 1]), axis=2) for feature in sequence_features.values(): if isinstance(feature, sparse_tensor.SparseTensor): # Explicitly set dense_shape's shape to 3 ([batch_size, num_unroll, d]) # since it can't be statically inferred. feature.dense_shape.set_shape([3]) sequence_features = layers.sequence_input_from_feature_columns( columns_to_tensors=sequence_features, feature_columns=sequence_feature_columns, weight_collections=None, scope=None) # Explicitly set shape along dimension 1 to num_unroll for the unstack op. sequence_features.set_shape([None, num_unroll, None]) if not context_features: return array_ops.unstack(sequence_features, axis=1) # TODO(jtbates): Call layers.input_from_feature_columns for context features. context_features = [ _tile(context_features[k]) for k in sorted(context_features) ] return array_ops.unstack( array_ops.concat( [sequence_features, array_ops.stack(context_features, 2)], axis=2), axis=1)
def _prepare_inputs_for_rnn(sequence_features, context_features, sequence_feature_columns, num_unroll): """Prepares features batched by the SQSS for input to a state-saving RNN. Args: sequence_features: A dict of sequence feature name to `Tensor` or `SparseTensor`, with `Tensor`s of shape `[batch_size, num_unroll, ...]` or `SparseTensors` of dense shape `[batch_size, num_unroll, d]`. context_features: A dict of context feature name to `Tensor`, with tensors of shape `[batch_size, 1, ...]` and type float32. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. num_unroll: Python integer, how many time steps to unroll at a time. The input sequences of length `k` are then split into `k / num_unroll` many segments. Returns: features_by_time: A list of length `num_unroll` with `Tensor` entries of shape `[batch_size, sum(sequence_features dimensions) + sum(context_features dimensions)]` of type float32. Context features are copied into each time step. """ def _tile(feature): return array_ops.squeeze(array_ops.tile( array_ops.expand_dims(feature, 1), [1, num_unroll, 1]), axis=2) for feature in sequence_features.values(): if isinstance(feature, sparse_tensor.SparseTensor): # Explicitly set dense_shape's shape to 3 ([batch_size, num_unroll, d]) # since it can't be statically inferred. feature.dense_shape.set_shape([3]) sequence_features = layers.sequence_input_from_feature_columns( columns_to_tensors=sequence_features, feature_columns=sequence_feature_columns, weight_collections=None, scope=None) # Explicitly set shape along dimension 1 to num_unroll for the unstack op. sequence_features.set_shape([None, num_unroll, None]) if not context_features: return array_ops.unstack(sequence_features, axis=1) # TODO(jtbates): Call layers.input_from_feature_columns for context features. context_features = [ _tile(context_features[k]) for k in sorted(context_features) ] return array_ops.unstack(array_ops.concat( [sequence_features, array_ops.stack(context_features, 2)], axis=2), axis=1)
def build_sequence_input(features, sequence_feature_columns, context_feature_columns, weight_collections=None, scope=None): """Combine sequence and context features into input for an RNN. Args: features: A `dict` containing the input and (optionally) sequence length information and initial state. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. context_feature_columns: An iterable containing all the feature columns describing context features i.e. features that apply across all time steps. All items in the set should be instances of classes derived from `FeatureColumn`. weight_collections: List of graph collections to which weights are added. scope: Optional scope, passed through to parsing ops. Returns: A `Tensor` of dtype `float32` and shape `[batch_size, padded_length, ?]`. This will be used as input to an RNN. """ features = features.copy() features.update( layers.transform_features( features, list(sequence_feature_columns) + list(context_feature_columns or []))) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=sequence_feature_columns, weight_collections=weight_collections, scope=scope) if context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return sequence_input
def _get_model_input(self, features, weight_collections=None, scope=None): # TODO(jamieas): add option to use context to construct initial state rather # than appending it to sequence input. initial_state = features.get(self._initial_state_key) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=self._sequence_feature_columns, weight_collections=weight_collections, scope=scope) if self._context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=self._context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return initial_state, sequence_input
def _get_model_input(self, features, weight_collections=None, scope=None): # TODO(jamieas): add option to use context to construct initial state rather # than appending it to sequence input. initial_state = features.get(self._initial_state_key) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=self._sequence_feature_columns, weight_collections=weight_collections, scope=scope) if self._context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=self._context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return initial_state, sequence_input
def build_sequence_input(features, sequence_feature_columns, context_feature_columns, weight_collections=None, scope=None): """Combine sequence and context features into input for an RNN. Args: features: A `dict` containing the input and (optionally) sequence length information and initial state. sequence_feature_columns: An iterable containing all the feature columns describing sequence features. All items in the set should be instances of classes derived from `FeatureColumn`. context_feature_columns: An iterable containing all the feature columns describing context features i.e. features that apply across all time steps. All items in the set should be instances of classes derived from `FeatureColumn`. weight_collections: List of graph collections to which weights are added. scope: Optional scope, passed through to parsing ops. Returns: A `Tensor` of dtype `float32` and shape `[batch_size, padded_length, ?]`. This will be used as input to an RNN. """ features = features.copy() features.update(layers.transform_features( features, list(sequence_feature_columns) + list(context_feature_columns or []))) sequence_input = layers.sequence_input_from_feature_columns( columns_to_tensors=features, feature_columns=sequence_feature_columns, weight_collections=weight_collections, scope=scope) if context_feature_columns is not None: context_input = layers.input_from_feature_columns( columns_to_tensors=features, feature_columns=context_feature_columns, weight_collections=weight_collections, scope=scope) sequence_input = _concatenate_context_input(sequence_input, context_input) return sequence_input