def _discount_reward_py_1d(reward, sequence_length, discount=1., dtype=None): if sequence_length is None: raise ValueError('sequence_length must not be `None` for 1D reward.') reward = np.array(reward) sequence_length = np.array(sequence_length) batch_size = reward.shape[0] max_seq_length = np.max(sequence_length) dtype = dtype or reward.dtype if discount == 1.: dmat = np.ones([batch_size, max_seq_length], dtype=dtype) else: steps = np.tile(np.arange(max_seq_length), [batch_size, 1]) mask = np.asarray(steps < (sequence_length-1)[:, None], dtype=dtype) # Make each row = [discount, ..., discount, 1, ..., 1] dmat = mask * discount + (1 - mask) dmat = np.cumprod(dmat[:, ::-1], axis=1)[:, ::-1] disc_reward = dmat * reward[:, None] disc_reward = mask_sequences(disc_reward, sequence_length, dtype=dtype) #mask = np.asarray(steps < sequence_length[:, None], dtype=dtype) #disc_reward = mask * disc_reward return disc_reward
def _build( self, # pylint: disable=arguments-differ inputs, sequence_length=None, dtype=None, mode=None): """Feeds forward inputs through the network layers and returns outputs. Args: inputs: The inputs to the network, which is a 3D tensor. sequence_length (optional): An int tensor of shape `[batch_size]` containing the length of each element in :attr:`inputs`. If given, time steps beyond the length will first be masked out before feeding to the layers. dtype (optional): Type of the inputs. If not provided, infers from inputs automatically. mode (optional): A tensor taking value in :tf_main:`tf.estimator.ModeKeys <estimator/ModeKeys>`, including `TRAIN`, `EVAL`, and `PREDICT`. If `None`, :func:`texar.tf.global_mode` is used. Returns: The output of the final layer. """ if sequence_length is not None: inputs = mask_sequences(inputs, sequence_length, dtype=dtype, time_major=False, tensor_rank=3) return super(Conv1DNetwork, self)._build(inputs, mode=mode)
def _discount_reward_tensor_1d(reward, sequence_length, discount=1., dtype=None): if sequence_length is None: raise ValueError('sequence_length must not be `None` for 1D reward.') batch_size = tf.shape(reward)[0] max_seq_length = tf.reduce_max(sequence_length) dtype = dtype or reward.dtype if discount == 1.: dmat = tf.ones(tf.concat([[batch_size], [max_seq_length]], 0), dtype=dtype) else: mask = tf.sequence_mask(sequence_length, dtype=dtype) mask = tf.concat([mask[:, 1:], tf.zeros_like(mask[:, -1:])], axis=1) # Make each row = [discount, ..., discount, 1, ..., 1] dmat = mask * discount + (1 - mask) dmat = tf.cumprod(dmat, axis=1, reverse=True) disc_reward = dmat * tf.expand_dims(reward, -1) disc_reward = mask_sequences(disc_reward, sequence_length, dtype=dtype, tensor_rank=2) return disc_reward
def _forward_output_layers(inputs, input_size, output_layer, time_major, hparams, mode, sequence_length=None): """Forwards inputs through the output layers. Args: inputs: A Tensor of shape `[batch_size, max_time] + input_size` if :attr:`time_major=False`, or shape `[max_time, batch_size] + input_size` if :attr:`time_major=True`. Returns: A pair :attr:`(outputs, outputs_size), where - :attr:`outputs`: A Tensor of shape \ `[batch_size, max_time] + outputs_size`. - :attr:`outputs_size`: An `int` or 1D `int` array representing the \ output size. """ if output_layer is None: return inputs, input_size if hparams is None: # output_layer was passed in from the constructor if isinstance(output_layer, (list, tuple)): raise ValueError('output_layer must not be a list or tuple.') output, output_size = _forward_single_output_layer( inputs, input_size, output_layer) else: # output_layer was built based on hparams output_layer = _to_list(output_layer) dropout_layer_ids = _to_list(hparams.dropout_layer_ids) if len(dropout_layer_ids) > 0: training = is_train_mode(mode) output = inputs output_size = input_size for i, layer in enumerate(output_layer): if i in dropout_layer_ids: output = _apply_dropout(output, time_major, hparams, training) output, output_size = _forward_single_output_layer( output, output_size, layer) if len(output_layer) in dropout_layer_ids: output = _apply_dropout(output, time_major, hparams, training) if sequence_length is not None: output = mask_sequences(output, sequence_length, time_major=time_major, tensor_rank=3) return output, output_size
def test_mask_sequences(self): """Tests :func:`texar.tf.utils.shapes.mask_sequences`. """ seq = np.ones([3, 4, 3], dtype=np.int32) seq_length = np.array([3, 2, 1], dtype=np.int32) masked_seq = shapes.mask_sequences(seq, seq_length) self.assertEqual(masked_seq.shape, seq.shape) seq_sum = np.sum(masked_seq, axis=(1, 2)) np.testing.assert_array_equal(seq_sum, seq_length * 3)
def _discount_reward_py_2d(reward, sequence_length=None, discount=1., dtype=None): if sequence_length is not None: reward = mask_sequences(reward, sequence_length, dtype=dtype) dtype = dtype or reward.dtype if discount == 1.: disc_reward = np.cumsum( reward[:, ::-1], axis=1, dtype=dtype)[:, ::-1] else: disc_reward = np.copy(reward) for i in range(reward.shape[1]-2, -1, -1): disc_reward[:, i] += disc_reward[:, i+1] * discount return disc_reward
def _discount_reward_tensor_2d(reward, sequence_length=None, discount=1., dtype=None): if sequence_length is not None: reward = mask_sequences( reward, sequence_length, dtype=dtype, tensor_rank=2) if discount == 1.: disc_reward = tf.cumsum(reward, axis=1, reverse=True) else: # [max_time, batch_size] rev_reward_T = tf.transpose(tf.reverse(reward, [1]), [1, 0]) rev_reward_T_cum = tf.scan( fn=lambda acc, cur: cur + discount * acc, elems=rev_reward_T, initializer=tf.zeros_like(reward[:, 1]), back_prop=False) disc_reward = tf.reverse( tf.transpose(rev_reward_T_cum, [1, 0]), [1]) return disc_reward
def mask_and_reduce(sequence, sequence_length, rank=2, average_across_batch=True, average_across_timesteps=False, average_across_remaining=False, sum_over_batch=False, sum_over_timesteps=True, sum_over_remaining=True, dtype=None, time_major=False): """Masks out sequence entries that are beyond the respective sequence lengths, and reduces (average or sum) away dimensions. This is a combination of :func:`~texar.tf.utils.shapes.mask_sequences` and :func:`~texar.tf.losses.losses_utils.reduce_batch_time`. Args: sequence: A Tensor of sequence values. If `time_major=False` (default), this must be a Tensor of shape `[batch_size, max_time, d_2, ..., d_rank]`, where the rank of the Tensor is specified with :attr:`rank`. The batch and time dimensions are exchanged if `time_major` is True. sequence_length: A Tensor of shape `[batch_size]`. Time steps beyond the respective sequence lengths will be made zero. If `None`, not masking is performed. rank (int): The rank of :attr:`sequence`. Must be >= 2. Default is 2, i.e., `sequence` is a 2D Tensor consisting of batch and time dimensions. average_across_timesteps (bool): If set, average the sequence across the time dimension. Must not set `average_across_timesteps` and `sum_over_timesteps` at the same time. average_across_batch (bool): If set, average the sequence across the batch dimension. Must not set `average_across_batch`' and `sum_over_batch` at the same time. average_across_remaining (bool): If set, average the sequence across the remaining dimensions. Must not set `average_across_remaining`' and `sum_over_remaining` at the same time. sum_over_timesteps (bool): If set, sum the loss across the time dimension. Must not set `average_across_timesteps` and `sum_over_timesteps` at the same time. sum_over_batch (bool): If set, sum the loss across the batch dimension. Must not set `average_across_batch` and `sum_over_batch` at the same time. sum_over_remaining (bool): If set, sum the loss across the remaining dimension. Must not set `average_across_remaining` and `sum_over_remaining` at the same time. time_major (bool): The shape format of the inputs. If `True`, :attr:`sequence` must have shape `[max_time, batch_size, ...]`. If `False` (default), `sequence` must have shape `[batch_size, max_time, ...]`. dtype (dtype): Type of :attr:`sequence`. If `None`, infer from :attr:`sequence` automatically. Returns A Tensor containing the masked and reduced sequence. """ if rank < 2: raise ValueError('`rank` must be >= 2.') if time_major: sequence = rnn._transpose_batch_time(sequence) if sequence_length is not None: sequence = mask_sequences(sequence, sequence_length, dtype=dtype, time_major=False, tensor_rank=rank) if rank > 2: if average_across_remaining and sum_over_remaining: raise ValueError("Only one of `average_across_remaining` and " "`sum_over_remaining` can be set.") if average_across_remaining: sequence = tf.reduce_mean(sequence, axis=np.arange(2, rank)) elif sum_over_remaining: sequence = tf.reduce_sum(sequence, axis=np.arange(2, rank)) sequence = reduce_batch_time(sequence, sequence_length, average_across_batch, average_across_timesteps, sum_over_batch, sum_over_timesteps) reduce_time = average_across_timesteps or sum_over_timesteps reduce_batch = average_across_batch or sum_over_batch if not reduce_time and not reduce_batch and time_major: sequence = rnn._transpose_batch_time(sequence) return sequence
def _build(self, positions=None, sequence_length=None, mode=None, **kwargs): r"""Embeds the positions. Either :attr:`positions` or :attr:`sequence_length` is required: - If both are given, :attr:`sequence_length` is used to mask out embeddings of those time steps beyond the respective sequence lengths. - If only :attr:`sequence_length` is given, then positions from 0 to ``sequence_length-1`` are embedded. Args: positions (optional): An integer tensor containing the position ids to embed. sequence_length (optional): An integer tensor of shape ``[batch_size]``. Time steps beyond the respective sequence lengths will have zero-valued embeddings. mode (optional): A tensor taking value in :tf_main:`tf.estimator.ModeKeys <estimator/ModeKeys>`, including `TRAIN`, `EVAL`, and `PREDICT`. If `None`, dropout will be controlled by :func:`texar.tf.global_mode`. kwargs: Additional keyword arguments for :tf_main:`tf.nn.embedding_lookup <nn/embedding_lookup>` besides :attr:`params` and :attr:`ids`. Returns: A `Tensor` of shape `shape(inputs) + embedding dimension`. """ # Gets embedder inputs # pylint:disable=too-many-locals inputs = positions if positions is None: if sequence_length is None: raise ValueError( "Either `positions` or `sequence_length` is required.") max_length = tf.reduce_max(sequence_length) single_inputs = tf.range(start=0, limit=max_length, dtype=tf.int32) # Expands `single_inputs` to have shape [batch_size, max_length] expander = tf.expand_dims(tf.ones_like(sequence_length), -1) inputs = expander * tf.expand_dims(single_inputs, 0) ids_rank = len(inputs.shape.dims) embedding = self._embedding is_training = is_train_mode(mode) # Gets dropout strategy st = self._hparams.dropout_strategy if positions is None and st == "item": # If `inputs` is based on `sequence_length`, then dropout # strategies 'item' and 'item_type' have the same effect, we # use 'item_type' to avoid unknown noise_shape in the 'item' # strategy st = "item_type" # Dropouts as 'item_type' before embedding if st == "item_type": dropout_layer = self._get_dropout_layer(self._hparams, dropout_strategy=st) if dropout_layer: embedding = dropout_layer.apply(inputs=embedding, training=is_training) # Embeds outputs = tf.nn.embedding_lookup(embedding, inputs, **kwargs) # Dropouts as 'item' or 'elements' after embedding if st != "item_type": dropout_layer = self._get_dropout_layer( self._hparams, ids_rank=ids_rank, dropout_input=outputs, dropout_strategy=st, ) if dropout_layer: outputs = dropout_layer.apply(inputs=outputs, training=is_training) # Optionally masks if sequence_length is not None: outputs = mask_sequences( outputs, sequence_length, tensor_rank=len(inputs.shape.dims) + self._dim_rank, ) return outputs