Beispiel #1
0
    def export(self, estimator, export_path, checkpoint_path, eval_result,
               is_the_final_export):
        del is_the_final_export

        export_result = export.export_eval_savedmodel(
            estimator=estimator,
            export_dir_base=export_path,
            eval_input_receiver_fn=self._eval_input_receiver_fn,
            serving_input_receiver_fn=self._serving_input_receiver_fn,
            assets_extra=self._assets_extra,
            checkpoint_path=checkpoint_path,
        )

        return export_result
Beispiel #2
0
  def export(self, estimator: tf.estimator.Estimator, export_path: Text,
             checkpoint_path: Optional[Text], eval_result: Optional[bytes],
             is_the_final_export: bool) -> bytes:
    del is_the_final_export

    export_result = export.export_eval_savedmodel(
        estimator=estimator,
        export_dir_base=export_path,
        eval_input_receiver_fn=self._eval_input_receiver_fn,
        serving_input_receiver_fn=self._serving_input_receiver_fn,
        assets_extra=self._assets_extra,
        checkpoint_path=checkpoint_path,
    )

    return export_result
Beispiel #3
0
def export_model_and_eval_model(estimator,
                                serving_input_receiver_fn=None,
                                eval_input_receiver_fn=None,
                                export_path=None,
                                eval_export_path=None):
  """Export SavedModel and EvalSavedModel.

  Args:
    estimator: Estimator to export.
    serving_input_receiver_fn: Serving input receiver function.
    eval_input_receiver_fn: Eval input receiver function.
    export_path: Export path. If None, inference model is not exported.
    eval_export_path: Eval export path. If None, EvalSavedModel is not exported.

  Returns:
    Tuple of (path to the export directory, path to eval export directory).
  """
  export_path_result = None
  eval_export_path_result = None

  if export_path and serving_input_receiver_fn:
    args = dict(export_dir_base=export_path)
    if isinstance(estimator, tf.contrib.learn.Estimator):
      args['serving_input_fn'] = serving_input_receiver_fn
      export_fn = estimator.export_savedmodel
    else:
      args['serving_input_receiver_fn'] = serving_input_receiver_fn
      export_fn = estimator.export_saved_model
    export_path_result = export_fn(**args)
  if eval_export_path and eval_input_receiver_fn:
    eval_export_path_result = export.export_eval_savedmodel(
        estimator=estimator,
        export_dir_base=eval_export_path,
        eval_input_receiver_fn=eval_input_receiver_fn,
        serving_input_receiver_fn=serving_input_receiver_fn)

  return export_path_result, eval_export_path_result
Beispiel #4
0
def simple_csv_linear_classifier(export_path, eval_export_path):
    """Trains and exports a simple linear classifier."""
    def parse_csv(rows_string_tensor):
        """Takes the string input tensor and returns a dict of rank-2 tensors."""

        csv_columns = ['age', 'language', 'label']
        csv_column_defaults = [[0.0], ['unknown'], [0.0]]

        # Takes a rank-1 tensor and converts it into rank-2 tensor
        # Example if the data is ['csv,line,1', 'csv,line,2', ..] to
        # [['csv,line,1'], ['csv,line,2']] which after parsing will result in a
        # tuple of tensors: [['csv'], ['csv']], [['line'], ['line']], [[1], [2]]
        row_columns = tf.expand_dims(rows_string_tensor, -1)
        columns = tf.decode_csv(row_columns,
                                record_defaults=csv_column_defaults)
        features = dict(zip(csv_columns, columns))
        return features

    def eval_input_receiver_fn():
        """Eval input receiver function."""
        csv_row = tf.placeholder(dtype=tf.string,
                                 shape=[None],
                                 name='input_csv_row')
        features = parse_csv(csv_row)
        receiver_tensors = {'examples': csv_row}

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=features['label'])

    def input_fn():
        """Train input function."""
        return {
            'age':
            tf.constant([[1], [2], [3], [4]]),
            'language':
            tf.SparseTensor(
                values=['english', 'english', 'chinese', 'chinese'],
                indices=[[0, 0], [1, 0], [2, 0], [3, 0]],
                dense_shape=[4, 1])
        }, tf.constant([[1], [1], [0], [0]])

    language = tf.contrib.layers.sparse_column_with_keys(
        'language', ['english', 'chinese'])
    age = tf.contrib.layers.real_valued_column('age')
    all_features = [age, language]
    feature_spec = tf.contrib.layers.create_feature_spec_for_parsing(
        all_features)

    classifier = tf.estimator.LinearClassifier(feature_columns=all_features)
    classifier.train(input_fn=input_fn, steps=1000)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = classifier.export_savedmodel(
            export_dir_base=export_path,
            serving_input_receiver_fn=tf.estimator.export.
            build_parsing_serving_input_receiver_fn(feature_spec))

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=classifier,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir
Beispiel #5
0
def simple_linear_classifier(export_path, eval_export_path):
    """Trains and exports a simple linear classifier."""
    def eval_input_receiver_fn():
        """Eval input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')

        language = tf.contrib.layers.sparse_column_with_keys(
            'language', ['english', 'chinese'])
        slice_key = tf.contrib.layers.sparse_column_with_hash_bucket(
            'slice_key', 100)
        age = tf.contrib.layers.real_valued_column('age')
        label = tf.contrib.layers.real_valued_column('label')
        all_features = [age, language, label, slice_key]
        feature_spec = tf.contrib.layers.create_feature_spec_for_parsing(
            all_features)
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=features['label'])

    def input_fn():
        """Train input function."""
        return {
            'age':
            tf.constant([[1], [2], [3], [4]]),
            'language':
            tf.SparseTensor(
                values=['english', 'english', 'chinese', 'chinese'],
                indices=[[0, 0], [1, 0], [2, 0], [3, 0]],
                dense_shape=[4, 1])
        }, tf.constant([[1], [1], [0], [0]])

    language = tf.contrib.layers.sparse_column_with_keys(
        'language', ['english', 'chinese'])
    age = tf.contrib.layers.real_valued_column('age')
    all_features = [age, language]  # slice_key not used in training.
    feature_spec = tf.contrib.layers.create_feature_spec_for_parsing(
        all_features)

    def my_metrics(features, labels, predictions):
        return {
            'my_mean_prediction': tf.metrics.mean(predictions['logistic']),
            'my_mean_age': tf.metrics.mean(features['age']),
            'my_mean_label': tf.metrics.mean(labels),
            'my_mean_age_times_label':
            tf.metrics.mean(labels * features['age']),
        }

    classifier = tf.estimator.LinearClassifier(feature_columns=all_features)
    classifier = tf.contrib.estimator.add_metrics(classifier, my_metrics)
    classifier.train(input_fn=input_fn, steps=1000)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = classifier.export_savedmodel(
            export_dir_base=export_path,
            serving_input_receiver_fn=tf.estimator.export.
            build_parsing_serving_input_receiver_fn(feature_spec))

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=classifier,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir
def simple_fixed_prediction_estimator_extra_fields(export_path,
                                                   eval_export_path):
    """Exports a simple fixed prediction estimator that parses extra fields."""
    def model_fn(features, labels, mode, params):
        """Model function for custom estimator."""
        del params
        predictions = features['prediction']

        if mode == tf.estimator.ModeKeys.PREDICT:
            return tf.estimator.EstimatorSpec(
                mode=mode,
                predictions={'score': predictions},
                export_outputs={
                    'score': tf.estimator.export.RegressionOutput(predictions)
                })

        loss = tf.losses.mean_squared_error(predictions, labels)
        train_op = tf.assign_add(tf.train.get_global_step(), 1)

        return tf.estimator.EstimatorSpec(mode=mode,
                                          loss=loss,
                                          train_op=train_op,
                                          predictions=predictions)

    def train_input_fn():
        """Train input function."""
        return {
            'prediction': tf.constant([[1.0], [2.0], [3.0], [4.0]]),
        }, tf.constant([[1.0], [2.0], [3.0], [4.0]]),

    def serving_input_receiver_fn():
        """Serving input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        feature_spec = {
            'prediction': tf.FixedLenFeature([1], dtype=tf.float32)
        }
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)
        return tf.estimator.export.ServingInputReceiver(
            features, receiver_tensors)

    def eval_input_receiver_fn():
        """Eval input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        feature_spec = {
            'prediction': tf.FixedLenFeature([1], dtype=tf.float32),
            'label': tf.FixedLenFeature([1], dtype=tf.float32),
            'fixed_float': tf.FixedLenFeature([1], dtype=tf.float32),
            'fixed_string': tf.FixedLenFeature([1], dtype=tf.string),
            'var_float': tf.VarLenFeature(dtype=tf.float32),
            'var_string': tf.VarLenFeature(dtype=tf.string)
        }
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=features['label'])

    estimator = tf.estimator.Estimator(model_fn=model_fn)
    estimator.train(input_fn=train_input_fn, steps=1)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = estimator.export_savedmodel(
            export_dir_base=export_path,
            serving_input_receiver_fn=serving_input_receiver_fn)

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=estimator,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir
def simple_fake_sequence_to_prediction(export_path, eval_export_path):
    """Trains and exports a fake_sequence_to_prediction model."""

    input_feature_spec = {
        'values_t1': tf.VarLenFeature(dtype=tf.float32),
        'values_t2': tf.VarLenFeature(dtype=tf.float32),
        'values_t3': tf.VarLenFeature(dtype=tf.float32)
    }
    label_feature_spec = dict(input_feature_spec)
    label_feature_spec['label'] = tf.FixedLenFeature([1], dtype=tf.float32)

    def _make_embedding_and_sparse_values(features):
        """Make "embedding" and "sparse_values" features."""
        embedding_dim = 3
        sparse_dims = 3
        sparse_timesteps = 3

        # Create a three-dimensional "embedding" based on the value of the feature
        # The embedding is simply [1, 1, 1] * feature_value
        # (or [0, 0, 0] if the feature is missing).
        batch_size = tf.cast(tf.shape(features['values_t1'])[0],
                             dtype=tf.int64)

        ones = tf.ones(shape=[embedding_dim])
        dense_t1 = tf.sparse_tensor_to_dense(features['values_t1'])
        dense_t2 = tf.sparse_tensor_to_dense(features['values_t2'])
        dense_t3 = tf.sparse_tensor_to_dense(features['values_t3'])
        embedding_t1 = ones * dense_t1
        embedding_t2 = ones * dense_t2
        embedding_t3 = ones * dense_t3
        embeddings = tf.stack([embedding_t1, embedding_t2, embedding_t3],
                              axis=1)
        features['embedding'] = embeddings
        del features['values_t1']
        del features['values_t2']
        del features['values_t3']

        # Make the "sparse_values" feature.
        sparse_values = tf.squeeze(
            tf.concat([
                dense_t1, dense_t1**2, dense_t1**3, dense_t2, dense_t2**2,
                dense_t2**3, dense_t3, dense_t3**2, dense_t3**3
            ],
                      axis=0))
        sparse_total_elems = batch_size * sparse_dims * sparse_timesteps
        seq = tf.range(0, sparse_total_elems, dtype=tf.int64)
        batch_num = seq % batch_size
        timestep = tf.div(seq, batch_size * sparse_dims)
        offset = tf.div(seq, batch_size) % sparse_dims
        sparse_indices = tf.stack([batch_num, timestep, offset], axis=1)
        features['sparse_values'] = tf.SparseTensor(
            indices=sparse_indices,
            values=sparse_values,
            dense_shape=[batch_size, sparse_timesteps, sparse_dims])

    def model_fn(features, labels, mode, params):
        """Model function for custom estimator."""
        del params
        dense_values = tf.sparse_tensor_to_dense(features['sparse_values'],
                                                 validate_indices=False)
        a = tf.Variable(1.0, dtype=tf.float32, name='a')
        b = tf.Variable(2.0, dtype=tf.float32, name='b')
        c = tf.Variable(3.0, dtype=tf.float32, name='c')
        d = tf.Variable(4.0, dtype=tf.float32, name='d')
        e = tf.Variable(5.0, dtype=tf.float32, name='e')
        f = tf.Variable(6.0, dtype=tf.float32, name='f')
        predictions = (
            a * tf.reduce_sum(features['embedding'][:, 0, :], axis=1) +
            b * tf.reduce_sum(features['embedding'][:, 1, :], axis=1) +
            c * tf.reduce_sum(features['embedding'][:, 2, :], axis=1) +
            d * tf.reduce_sum(dense_values[:, 0, :], axis=1) +
            e * tf.reduce_sum(dense_values[:, 1, :], axis=1) +
            f * tf.reduce_sum(dense_values[:, 2, :], axis=1))

        if mode == tf.estimator.ModeKeys.PREDICT:
            return tf.estimator.EstimatorSpec(
                mode=mode,
                predictions={'score': predictions},
                export_outputs={
                    'score': tf.estimator.export.RegressionOutput(predictions)
                })

        loss = tf.losses.mean_squared_error(
            labels, tf.expand_dims(predictions, axis=-1))

        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.0001)
        train_op = optimizer.minimize(loss=loss,
                                      global_step=tf.train.get_global_step())

        return tf.estimator.EstimatorSpec(mode=mode,
                                          loss=loss,
                                          train_op=train_op,
                                          eval_metric_ops={
                                              'mean_squared_error':
                                              tf.metrics.mean_squared_error(
                                                  labels,
                                                  tf.expand_dims(predictions,
                                                                 axis=-1)),
                                              'mean_prediction':
                                              tf.metrics.mean(predictions),
                                          },
                                          predictions=predictions)

    def train_input_fn():
        """Train input function."""
        def make_example_with_label(values_t1=None,
                                    values_t2=None,
                                    values_t3=None):
            """Make example with label."""
            effective_t1 = 0.0
            effective_t2 = 0.0
            effective_t3 = 0.0
            args = {}
            if values_t1 is not None:
                args['values_t1'] = float(values_t1)
                effective_t1 = values_t1
            if values_t2 is not None:
                args['values_t2'] = float(values_t2)
                effective_t2 = values_t2
            if values_t3 is not None:
                args['values_t3'] = float(values_t3)
                effective_t3 = values_t3
            label = (3 * effective_t1 + 6 * effective_t2 + 9 * effective_t3 +
                     4 * (effective_t1 + effective_t1**2 + effective_t1**3) +
                     5 * (effective_t2 + effective_t2**2 + effective_t2**3) +
                     6 * (effective_t3 + effective_t3**2 + effective_t3**3))
            args['label'] = float(label)
            return util.make_example(**args)

        examples = [
            make_example_with_label(values_t1=1.0),
            make_example_with_label(values_t2=1.0),
            make_example_with_label(values_t3=1.0),
            make_example_with_label(values_t1=2.0, values_t2=3.0),
            make_example_with_label(values_t1=5.0, values_t3=7.0),
            make_example_with_label(values_t2=11.0, values_t3=13.0),
            make_example_with_label(values_t1=2.0,
                                    values_t2=3.0,
                                    values_t3=5.0),
        ]
        serialized_examples = [x.SerializeToString() for x in examples]
        features = tf.parse_example(serialized_examples, label_feature_spec)
        _make_embedding_and_sparse_values(features)
        label = features.pop('label')
        return features, label

    def serving_input_receiver_fn():
        """Serving input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, input_feature_spec)
        _make_embedding_and_sparse_values(features)
        return tf.estimator.export.ServingInputReceiver(
            features, receiver_tensors)

    def eval_input_receiver_fn():
        """Eval input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, label_feature_spec)
        _make_embedding_and_sparse_values(features)

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=features['label'])

    estimator = tf.estimator.Estimator(model_fn=model_fn)
    estimator.train(input_fn=train_input_fn, steps=10)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = estimator.export_saved_model(
            export_dir_base=export_path,
            serving_input_receiver_fn=serving_input_receiver_fn)

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=estimator,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir
Beispiel #8
0
def simple_custom_estimator(export_path, eval_export_path):
    """Trains and exports a simple custom estimator."""
    def model_fn(features, labels, mode, params):
        """Model function for custom estimator."""
        del params
        m = tf.Variable(0.0, dtype=tf.float32, name='m')
        c = tf.Variable(0.0, dtype=tf.float32, name='c')
        predictions = m * features['age'] + c

        if mode == tf.estimator.ModeKeys.PREDICT:
            return tf.estimator.EstimatorSpec(
                mode=mode,
                predictions={'score': predictions},
                export_outputs={
                    'score': tf.estimator.export.RegressionOutput(predictions)
                })

        loss = tf.losses.mean_squared_error(labels, predictions)
        eval_metric_ops = {
            'mean_absolute_error':
            tf.metrics.mean_absolute_error(tf.cast(labels, tf.float64),
                                           tf.cast(predictions, tf.float64)),
            'mean_prediction':
            tf.metrics.mean(predictions),
            'mean_label':
            tf.metrics.mean(labels),
        }

        optimizer = tf.train.GradientDescentOptimizer(learning_rate=0.001)
        train_op = optimizer.minimize(loss=loss,
                                      global_step=tf.train.get_global_step())

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

    def train_input_fn():
        """Train input function."""
        return {
            'age': tf.constant([[1.0], [2.0], [3.0], [4.0]]),
        }, tf.constant([[4.0], [7.0], [10.0], [13.0]]),

    def serving_input_receiver_fn():
        """Serving input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        feature_spec = {'age': tf.FixedLenFeature([1], dtype=tf.float32)}
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)
        return tf.estimator.export.ServingInputReceiver(
            features, receiver_tensors)

    def eval_input_receiver_fn():
        """Eval input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')
        feature_spec = {
            'age': tf.FixedLenFeature([1], dtype=tf.float32),
            'label': tf.FixedLenFeature([1], dtype=tf.float32)
        }
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=features['label'])

    estimator = tf.estimator.Estimator(model_fn=model_fn)
    estimator.train(input_fn=train_input_fn, steps=1000)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = estimator.export_savedmodel(
            export_dir_base=export_path,
            serving_input_receiver_fn=serving_input_receiver_fn)

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=estimator,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir
Beispiel #9
0
def simple_multi_head(export_path, eval_export_path):
    """Trains and exports a simple multi-headed model."""
    def eval_input_receiver_fn():
        """Eval input receiver function."""
        serialized_tf_example = tf.placeholder(dtype=tf.string,
                                               shape=[None],
                                               name='input_example_tensor')

        language = tf.contrib.layers.sparse_column_with_keys(
            'language', ['english', 'chinese', 'other'])
        age = tf.contrib.layers.real_valued_column('age')
        english_label = tf.contrib.layers.real_valued_column('english_label')
        chinese_label = tf.contrib.layers.real_valued_column('chinese_label')
        other_label = tf.contrib.layers.real_valued_column('other_label')
        all_features = [
            age, language, english_label, chinese_label, other_label
        ]
        feature_spec = tf.contrib.layers.create_feature_spec_for_parsing(
            all_features)
        receiver_tensors = {'examples': serialized_tf_example}
        features = tf.parse_example(serialized_tf_example, feature_spec)

        labels = {
            'english_head': features['english_label'],
            'chinese_head': features['chinese_label'],
            'other_head': features['other_label'],
        }

        return export.EvalInputReceiver(features=features,
                                        receiver_tensors=receiver_tensors,
                                        labels=labels)

    def input_fn():
        """Train input function."""
        labels = {
            'english_head': tf.constant([[1], [1], [0], [0], [0], [0]]),
            'chinese_head': tf.constant([[0], [0], [1], [1], [0], [0]]),
            'other_head': tf.constant([[0], [0], [0], [0], [1], [1]])
        }
        features = {
            'age':
            tf.constant([[1], [2], [3], [4], [5], [6]]),
            'language':
            tf.SparseTensor(values=[
                'english', 'english', 'chinese', 'chinese', 'other', 'other'
            ],
                            indices=[[0, 0], [1, 0], [2, 0], [3, 0], [4, 0],
                                     [5, 0]],
                            dense_shape=[6, 1]),
        }
        return features, labels

    language = tf.contrib.layers.sparse_column_with_keys(
        'language', ['english', 'chinese', 'other'])
    age = tf.contrib.layers.real_valued_column('age')
    all_features = [age, language]
    feature_spec = tf.contrib.layers.create_feature_spec_for_parsing(
        all_features)

    english_head = tf.contrib.learn.multi_class_head(n_classes=2,
                                                     label_name='english_head',
                                                     head_name='english_head')
    chinese_head = tf.contrib.learn.multi_class_head(n_classes=2,
                                                     label_name='chinese_head',
                                                     head_name='chinese_head')
    other_head = tf.contrib.learn.multi_class_head(n_classes=2,
                                                   label_name='other_head',
                                                   head_name='other_head')
    estimator = tf.contrib.learn.DNNLinearCombinedEstimator(
        head=tf.contrib.learn.multi_head(
            heads=[english_head, chinese_head, other_head]),
        dnn_feature_columns=[],
        dnn_optimizer=tf.train.AdagradOptimizer(learning_rate=0.01),
        dnn_hidden_units=[],
        linear_feature_columns=[language, age],
        linear_optimizer=tf.train.FtrlOptimizer(learning_rate=0.05))
    estimator.fit(input_fn=input_fn, steps=1000)

    export_dir = None
    eval_export_dir = None
    if export_path:
        export_dir = estimator.export_savedmodel(
            export_dir_base=export_path,
            serving_input_fn=tf.contrib.learn.build_parsing_serving_input_fn(
                feature_spec),
            default_output_alternative_key='english_head')

    if eval_export_path:
        eval_export_dir = export.export_eval_savedmodel(
            estimator=estimator,
            export_dir_base=eval_export_path,
            eval_input_receiver_fn=eval_input_receiver_fn)

    return export_dir, eval_export_dir