def test_next_production_rule_accuracy_with_length(self):
    partial_sequence_lengths = tf.placeholder(tf.int32, shape=[None])
    value, update_op = metrics.next_production_rule_accuracy(
        next_production_rules=self.next_production_rules,
        predict_next_production_rules=self.predict_next_production_rules,
        partial_sequence_lengths=partial_sequence_lengths,
        target_length=1)

    with self.test_session() as sess:
      sess.run(tf.local_variables_initializer())
      sess.run(
          update_op,
          feed_dict={
              self.next_production_rules:
                  self.next_production_rules_values_0,
              self.predict_next_production_rules:
                  self.predict_next_production_rules_values_0,
              partial_sequence_lengths: [42, 42, 1, 42]})
      self.assertAlmostEqual(value.eval(), 1.)
      sess.run(
          update_op,
          feed_dict={
              self.next_production_rules:
                  self.next_production_rules_values_1,
              self.predict_next_production_rules:
                  self.predict_next_production_rules_values_1,
              partial_sequence_lengths: [42, 42, 42, 42, 42, 42]})
      self.assertAlmostEqual(value.eval(), 1.)
  def test_next_production_rule_accuracy(self):
    value, update_op = metrics.next_production_rule_accuracy(
        next_production_rules=self.next_production_rules,
        predict_next_production_rules=self.predict_next_production_rules)

    with self.test_session() as sess:
      sess.run(tf.local_variables_initializer())
      sess.run(
          update_op,
          feed_dict={
              self.next_production_rules:
                  self.next_production_rules_values_0,
              self.predict_next_production_rules:
                  self.predict_next_production_rules_values_0})
      self.assertAlmostEqual(value.eval(), 0.25)
      sess.run(
          update_op,
          feed_dict={
              self.next_production_rules:
                  self.next_production_rules_values_1,
              self.predict_next_production_rules:
                  self.predict_next_production_rules_values_1})
      self.assertAlmostEqual(value.eval(), 0.4)
Esempio n. 3
0
def model_fn(features, labels, mode, params, grammar):
    """Builds the model graph.

  Args:
    features: Dict of tensors.
    labels: Dict of tensors, or None if mode == INFER.
    mode: tf.estimator.ModeKeys execution mode.
    params: HParams object containing model hyperparameters.
    grammar: arithmetic_grammar.Grammar object.

  Returns:
    A ModelFnOps object defining predictions, loss, and train_op.
  """
    if mode != tf.estimator.ModeKeys.PREDICT:
        tf.summary.text('expression_string',
                        features['expression_string'][:10])
    tf.summary.text('production_rules',
                    tf.constant(grammar.grammar_to_string()))

    # Make features easier to look up.
    with tf.variable_scope('features'):
        features = {
            key: tf.identity(value, name=key)
            for key, value in six.iteritems(features)
        }

    embedding_layer = networks.partial_sequence_encoder(
        features=features,
        symbolic_properties=core.hparams_list_value(
            params.symbolic_properties),
        numerical_points=core.hparams_list_value(params.numerical_points),
        num_production_rules=grammar.num_production_rules,
        embedding_size=params.embedding_size)

    logits = networks.build_stacked_gru_model(
        embedding_layer=embedding_layer,
        partial_sequence_length=features['partial_sequence_length'],
        gru_hidden_sizes=params.gru_hidden_sizes,
        num_output_features=grammar.num_production_rules,
        bidirectional=params.bidirectional)

    predictions = {'logits': tf.identity(logits, name='predictions/logits')}
    predictions.update({
        name: tf.identity(tensor, name='predictions/%s' % name)
        for name, tensor in six.iteritems(
            mask_logits(logits, features['next_production_rule_mask']))
    })
    predictions['next_production_rule'] = tf.argmax(
        predictions['masked_probabilities'],
        axis=1,
        name='predictions/next_production_rule')

    if mode == tf.estimator.ModeKeys.PREDICT:
        return tf.estimator.EstimatorSpec(mode=mode, predictions=predictions)

    # NOTE(leeley): The mask cannot be applied directly on logits. Because 0
    # logit is still corresponding to a positive probability. Since
    # tf.losses.sparse_softmax_cross_entropy() only works for logits rather than
    # probabilities, I convert probabilities back to logits by tf.log(). Since
    # the probabilities for grammarly invalid production rules are 0, to avoid
    # numerical issue of log(0), I added a small number 1e-10.
    loss = tf.losses.sparse_softmax_cross_entropy(
        labels, tf.log(predictions['masked_probabilities'] + 1e-10))

    # Configure the training op for TRAIN mode.
    if mode == tf.estimator.ModeKeys.TRAIN:
        train_op = contrib_layers.optimize_loss(
            loss=loss,
            global_step=tf.train.get_global_step(),
            learning_rate=core.learning_rate_decay(
                initial_learning_rate=params.learning_rate,
                decay_steps=params.learning_rate_decay_steps,
                decay_rate=params.learning_rate_decay_rate),
            optimizer=params.optimizer,
            summaries=contrib_layers.OPTIMIZER_SUMMARIES)
        return tf.estimator.EstimatorSpec(mode=mode,
                                          loss=loss,
                                          train_op=train_op)

    # Add evaluation metrics for EVAL mode.
    eval_metric_ops = {
        'eval_loss':
        tf.metrics.mean(loss),
        'count':
        contrib_metrics.count(labels),
        'next_production_rule_valid_ratio':
        metrics.next_production_rule_valid_ratio(
            unmasked_probabilities_batch=predictions['unmasked_probabilities'],
            next_production_rule_masks=features['next_production_rule_mask']),
        'next_production_rule_accuracy':
        metrics.next_production_rule_accuracy(
            next_production_rules=labels,
            predict_next_production_rules=predictions['next_production_rule']),
    }

    for target_length in range(1, params.max_length + 1):
        eval_metric_ops[
            'next_production_rule_info/length_%d' %
            target_length] = metrics.next_production_rule_info_batch_text_summary(
                expression_strings=features['expression_string'],
                partial_sequences=features['partial_sequence'],
                partial_sequence_lengths=features['partial_sequence_length'],
                next_production_rules=labels,
                unmasked_probabilities_batch=predictions[
                    'unmasked_probabilities'],
                masked_probabilities_batch=predictions['masked_probabilities'],
                grammar=grammar,
                target_length=target_length)

        eval_metric_ops[
            'next_production_rule_valid_ratio/length_%d' %
            target_length] = metrics.next_production_rule_valid_ratio(
                unmasked_probabilities_batch=predictions[
                    'unmasked_probabilities'],
                next_production_rule_masks=features[
                    'next_production_rule_mask'],
                partial_sequence_lengths=features['partial_sequence_length'],
                target_length=target_length)

        eval_metric_ops[
            'next_production_rule_accuracy/length_%d' %
            target_length] = metrics.next_production_rule_accuracy(
                next_production_rules=labels,
                predict_next_production_rules=predictions[
                    'next_production_rule'],
                partial_sequence_lengths=features['partial_sequence_length'],
                target_length=target_length)

    if params.num_expressions_per_condition > 0:
        with tf.variable_scope('conditional_generation'):
            match_ratio = tf.placeholder(tf.float32,
                                         shape=[None],
                                         name='match_ratio')
            fail_ratio = tf.placeholder(tf.float32,
                                        shape=[None],
                                        name='fail_ratio')

        eval_metric_ops.update({
            'generation_match_ratio':
            tf.metrics.mean(match_ratio),
            'generation_fail_ratio':
            tf.metrics.mean(fail_ratio),
        })

    return tf.estimator.EstimatorSpec(mode=mode,
                                      loss=loss,
                                      eval_metric_ops=eval_metric_ops)