1# Copyright 2016 The TensorFlow Authors. All Rights Reserved.
2#
3# Licensed under the Apache License, Version 2.0 (the "License");
4# you may not use this file except in compliance with the License.
5# You may obtain a copy of the License at
6#
7#     http://www.apache.org/licenses/LICENSE-2.0
8#
9# Unless required by applicable law or agreed to in writing, software
10# distributed under the License is distributed on an "AS IS" BASIS,
11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12# See the License for the specific language governing permissions and
13# limitations under the License.
14# ==============================================================================
15"""Deep Neural Network estimators (deprecated).
16
17This module and all its submodules are deprecated. See
18[contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md)
19for migration instructions.
20"""
21
22from __future__ import absolute_import
23from __future__ import division
24from __future__ import print_function
25
26import six
27
28from tensorflow.contrib import layers
29from tensorflow.contrib.framework import deprecated
30from tensorflow.contrib.framework import deprecated_arg_values
31from tensorflow.contrib.layers.python.layers import feature_column
32from tensorflow.contrib.layers.python.layers import optimizers
33from tensorflow.contrib.learn.python.learn import metric_spec
34from tensorflow.contrib.learn.python.learn.estimators import dnn_linear_combined
35from tensorflow.contrib.learn.python.learn.estimators import estimator
36from tensorflow.contrib.learn.python.learn.estimators import head as head_lib
37from tensorflow.contrib.learn.python.learn.estimators import model_fn
38from tensorflow.contrib.learn.python.learn.estimators import prediction_key
39from tensorflow.contrib.learn.python.learn.utils import export
40from tensorflow.python.feature_column import feature_column_lib as fc_core
41from tensorflow.python.ops import nn
42from tensorflow.python.ops import partitioned_variables
43from tensorflow.python.ops import variable_scope
44from tensorflow.python.summary import summary
45from tensorflow.python.training import training_util
46
47# The default learning rate of 0.05 is a historical artifact of the initial
48# implementation, but seems a reasonable choice.
49_LEARNING_RATE = 0.05
50
51
52def _get_feature_dict(features):
53  if isinstance(features, dict):
54    return features
55  return {"": features}
56
57
58def _get_optimizer(optimizer):
59  if callable(optimizer):
60    return optimizer()
61  else:
62    return optimizer
63
64
65_ACTIVATION_FUNCTIONS = {
66    "relu": nn.relu,
67    "tanh": nn.tanh,
68    "sigmoid": nn.sigmoid
69}
70
71
72def _get_activation_fn(activation_fn):
73  if not isinstance(activation_fn, six.string_types):
74    return activation_fn
75  if activation_fn not in _ACTIVATION_FUNCTIONS.keys():
76    raise ValueError("Activation name should be one of [%s], you provided %s." %
77                     (", ".join(_ACTIVATION_FUNCTIONS.keys()), activation_fn))
78  return _ACTIVATION_FUNCTIONS[activation_fn]
79
80
81def _add_hidden_layer_summary(value, tag):
82  summary.scalar("%s_fraction_of_zero_values" % tag, nn.zero_fraction(value))
83  summary.histogram("%s_activation" % tag, value)
84
85
86def _dnn_model_fn(features, labels, mode, params, config=None):
87  """Deep Neural Net model_fn.
88
89  Args:
90    features: `Tensor` or dict of `Tensor` (depends on data passed to `fit`).
91    labels: `Tensor` of shape [batch_size, 1] or [batch_size] labels of
92      dtype `int32` or `int64` in the range `[0, n_classes)`.
93    mode: Defines whether this is training, evaluation or prediction.
94      See `ModeKeys`.
95    params: A dict of hyperparameters.
96      The following hyperparameters are expected:
97      * head: A `_Head` instance.
98      * hidden_units: List of hidden units per layer.
99      * feature_columns: An iterable containing all the feature columns used by
100          the model.
101      * optimizer: string, `Optimizer` object, or callable that defines the
102          optimizer to use for training. If `None`, will use the Adagrad
103          optimizer with a default learning rate of 0.05.
104      * activation_fn: Activation function applied to each layer. If `None`,
105          will use `tf.nn.relu`. Note that a string containing the unqualified
106          name of the op may also be provided, e.g., "relu", "tanh", or
107          "sigmoid".
108      * dropout: When not `None`, the probability we will drop out a given
109          coordinate.
110      * gradient_clip_norm: A float > 0. If provided, gradients are
111          clipped to their global norm with this clipping ratio.
112      * embedding_lr_multipliers: Optional. A dictionary from
113          `EmbeddingColumn` to a `float` multiplier. Multiplier will be used to
114          multiply with learning rate for the embedding variables.
115      * input_layer_min_slice_size: Optional. The min slice size of input layer
116          partitions. If not provided, will use the default of 64M.
117    config: `RunConfig` object to configure the runtime settings.
118
119  Returns:
120    predictions: A dict of `Tensor` objects.
121    loss: A scalar containing the loss of the step.
122    train_op: The op for training.
123  """
124  head = params["head"]
125  hidden_units = params["hidden_units"]
126  feature_columns = params["feature_columns"]
127  optimizer = params.get("optimizer") or "Adagrad"
128  activation_fn = _get_activation_fn(params.get("activation_fn"))
129  dropout = params.get("dropout")
130  gradient_clip_norm = params.get("gradient_clip_norm")
131  input_layer_min_slice_size = (
132      params.get("input_layer_min_slice_size") or 64 << 20)
133  num_ps_replicas = config.num_ps_replicas if config else 0
134  embedding_lr_multipliers = params.get("embedding_lr_multipliers", {})
135
136  features = _get_feature_dict(features)
137  parent_scope = "dnn"
138
139  partitioner = partitioned_variables.min_max_variable_partitioner(
140      max_partitions=num_ps_replicas)
141  with variable_scope.variable_scope(
142      parent_scope,
143      values=tuple(six.itervalues(features)),
144      partitioner=partitioner):
145    input_layer_partitioner = (
146        partitioned_variables.min_max_variable_partitioner(
147            max_partitions=num_ps_replicas,
148            min_slice_size=input_layer_min_slice_size))
149    with variable_scope.variable_scope(
150        "input_from_feature_columns",
151        values=tuple(six.itervalues(features)),
152        partitioner=input_layer_partitioner) as input_layer_scope:
153      if all(
154          isinstance(fc, feature_column._FeatureColumn)  # pylint: disable=protected-access
155          for fc in feature_columns
156      ):
157        net = layers.input_from_feature_columns(
158            columns_to_tensors=features,
159            feature_columns=feature_columns,
160            weight_collections=[parent_scope],
161            scope=input_layer_scope)
162      else:
163        net = fc_core.input_layer(
164            features=features,
165            feature_columns=feature_columns,
166            weight_collections=[parent_scope])
167
168    for layer_id, num_hidden_units in enumerate(hidden_units):
169      with variable_scope.variable_scope(
170          "hiddenlayer_%d" % layer_id,
171          values=(net,)) as hidden_layer_scope:
172        net = layers.fully_connected(
173            net,
174            num_hidden_units,
175            activation_fn=activation_fn,
176            variables_collections=[parent_scope],
177            scope=hidden_layer_scope)
178        if dropout is not None and mode == model_fn.ModeKeys.TRAIN:
179          net = layers.dropout(net, keep_prob=(1.0 - dropout))
180      _add_hidden_layer_summary(net, hidden_layer_scope.name)
181
182    with variable_scope.variable_scope(
183        "logits",
184        values=(net,)) as logits_scope:
185      logits = layers.fully_connected(
186          net,
187          head.logits_dimension,
188          activation_fn=None,
189          variables_collections=[parent_scope],
190          scope=logits_scope)
191    _add_hidden_layer_summary(logits, logits_scope.name)
192
193    def _train_op_fn(loss):
194      """Returns the op to optimize the loss."""
195      return optimizers.optimize_loss(
196          loss=loss,
197          global_step=training_util.get_global_step(),
198          learning_rate=_LEARNING_RATE,
199          optimizer=_get_optimizer(optimizer),
200          gradient_multipliers=(
201              dnn_linear_combined._extract_embedding_lr_multipliers(  # pylint: disable=protected-access
202                  embedding_lr_multipliers, parent_scope,
203                  input_layer_scope.name)),
204          clip_gradients=gradient_clip_norm,
205          name=parent_scope,
206          # Empty summaries to prevent optimizers from logging training_loss.
207          summaries=[])
208
209    return head.create_model_fn_ops(
210        features=features,
211        mode=mode,
212        labels=labels,
213        train_op_fn=_train_op_fn,
214        logits=logits)
215
216
217class DNNClassifier(estimator.Estimator):
218  """A classifier for TensorFlow DNN models.
219
220  THIS CLASS IS DEPRECATED. See
221  [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md)
222  for general migration instructions.
223
224  Example:
225
226  ```python
227  sparse_feature_a = sparse_column_with_hash_bucket(...)
228  sparse_feature_b = sparse_column_with_hash_bucket(...)
229
230  sparse_feature_a_emb = embedding_column(sparse_id_column=sparse_feature_a,
231                                          ...)
232  sparse_feature_b_emb = embedding_column(sparse_id_column=sparse_feature_b,
233                                          ...)
234
235  estimator = DNNClassifier(
236      feature_columns=[sparse_feature_a_emb, sparse_feature_b_emb],
237      hidden_units=[1024, 512, 256])
238
239  # Or estimator using the ProximalAdagradOptimizer optimizer with
240  # regularization.
241  estimator = DNNClassifier(
242      feature_columns=[sparse_feature_a_emb, sparse_feature_b_emb],
243      hidden_units=[1024, 512, 256],
244      optimizer=tf.train.ProximalAdagradOptimizer(
245        learning_rate=0.1,
246        l1_regularization_strength=0.001
247      ))
248
249  # Input builders
250  def input_fn_train: # returns x, y (where y represents label's class index).
251    pass
252  estimator.fit(input_fn=input_fn_train)
253
254  def input_fn_eval: # returns x, y (where y represents label's class index).
255    pass
256  estimator.evaluate(input_fn=input_fn_eval)
257
258  def input_fn_predict: # returns x, None
259    pass
260  # predict_classes returns class indices.
261  estimator.predict_classes(input_fn=input_fn_predict)
262  ```
263
264  If the user specifies `label_keys` in constructor, labels must be strings from
265  the `label_keys` vocabulary. Example:
266
267  ```python
268  label_keys = ['label0', 'label1', 'label2']
269  estimator = DNNClassifier(
270      feature_columns=[sparse_feature_a_emb, sparse_feature_b_emb],
271      hidden_units=[1024, 512, 256],
272      label_keys=label_keys)
273
274  def input_fn_train: # returns x, y (where y is one of label_keys).
275    pass
276  estimator.fit(input_fn=input_fn_train)
277
278  def input_fn_eval: # returns x, y (where y is one of label_keys).
279    pass
280  estimator.evaluate(input_fn=input_fn_eval)
281  def input_fn_predict: # returns x, None
282  # predict_classes returns one of label_keys.
283  estimator.predict_classes(input_fn=input_fn_predict)
284  ```
285
286  Input of `fit` and `evaluate` should have following features,
287    otherwise there will be a `KeyError`:
288
289  * if `weight_column_name` is not `None`, a feature with
290     `key=weight_column_name` whose value is a `Tensor`.
291  * for each `column` in `feature_columns`:
292    - if `column` is a `SparseColumn`, a feature with `key=column.name`
293      whose `value` is a `SparseTensor`.
294    - if `column` is a `WeightedSparseColumn`, two features: the first with
295      `key` the id column name, the second with `key` the weight column name.
296      Both features' `value` must be a `SparseTensor`.
297    - if `column` is a `RealValuedColumn`, a feature with `key=column.name`
298      whose `value` is a `Tensor`.
299  """
300
301  def __init__(self,
302               hidden_units,
303               feature_columns,
304               model_dir=None,
305               n_classes=2,
306               weight_column_name=None,
307               optimizer=None,
308               activation_fn=nn.relu,
309               dropout=None,
310               gradient_clip_norm=None,
311               enable_centered_bias=False,
312               config=None,
313               feature_engineering_fn=None,
314               embedding_lr_multipliers=None,
315               input_layer_min_slice_size=None,
316               label_keys=None):
317    """Initializes a DNNClassifier instance.
318
319    Args:
320      hidden_units: List of hidden units per layer. All layers are fully
321        connected. Ex. `[64, 32]` means first layer has 64 nodes and second one
322        has 32.
323      feature_columns: An iterable containing all the feature columns used by
324        the model. All items in the set should be instances of classes derived
325        from `FeatureColumn`.
326      model_dir: Directory to save model parameters, graph and etc. This can
327        also be used to load checkpoints from the directory into a estimator to
328        continue training a previously saved model.
329      n_classes: number of label classes. Default is binary classification.
330        It must be greater than 1. Note: Class labels are integers representing
331        the class index (i.e. values from 0 to n_classes-1). For arbitrary
332        label values (e.g. string labels), convert to class indices first.
333      weight_column_name: A string defining feature column name representing
334        weights. It is used to down weight or boost examples during training. It
335        will be multiplied by the loss of the example.
336      optimizer: An instance of `tf.Optimizer` used to train the model. If
337        `None`, will use an Adagrad optimizer.
338      activation_fn: Activation function applied to each layer. If `None`, will
339        use tf.nn.relu. Note that a string containing the unqualified
340        name of the op may also be provided, e.g., "relu", "tanh", or "sigmoid".
341      dropout: When not `None`, the probability we will drop out a given
342        coordinate.
343      gradient_clip_norm: A float > 0. If provided, gradients are
344        clipped to their global norm with this clipping ratio. See
345        `tf.clip_by_global_norm` for more details.
346      enable_centered_bias: A bool. If True, estimator will learn a centered
347        bias variable for each class. Rest of the model structure learns the
348        residual after centered bias.
349      config: `RunConfig` object to configure the runtime settings.
350      feature_engineering_fn: Feature engineering function. Takes features and
351        labels which are the output of `input_fn` and returns features and
352        labels which will be fed into the model.
353      embedding_lr_multipliers: Optional. A dictionary from `EmbeddingColumn` to
354        a `float` multiplier. Multiplier will be used to multiply with learning
355        rate for the embedding variables.
356      input_layer_min_slice_size: Optional. The min slice size of input layer
357        partitions. If not provided, will use the default of 64M.
358      label_keys: Optional list of strings with size `[n_classes]` defining the
359        label vocabulary. Only supported for `n_classes` > 2.
360
361    Returns:
362      A `DNNClassifier` estimator.
363
364    Raises:
365      ValueError: If `n_classes` < 2.
366    """
367    self._feature_columns = tuple(feature_columns or [])
368    super(DNNClassifier, self).__init__(
369        model_fn=_dnn_model_fn,
370        model_dir=model_dir,
371        config=config,
372        params={
373            "head":
374                head_lib.multi_class_head(
375                    n_classes,
376                    weight_column_name=weight_column_name,
377                    enable_centered_bias=enable_centered_bias,
378                    label_keys=label_keys),
379            "hidden_units": hidden_units,
380            "feature_columns": self._feature_columns,
381            "optimizer": optimizer,
382            "activation_fn": activation_fn,
383            "dropout": dropout,
384            "gradient_clip_norm": gradient_clip_norm,
385            "embedding_lr_multipliers": embedding_lr_multipliers,
386            "input_layer_min_slice_size": input_layer_min_slice_size,
387        },
388        feature_engineering_fn=feature_engineering_fn)
389
390  @deprecated_arg_values(
391      estimator.AS_ITERABLE_DATE,
392      estimator.AS_ITERABLE_INSTRUCTIONS,
393      as_iterable=False)
394  @deprecated_arg_values(
395      "2017-03-01",
396      "Please switch to predict_classes, or set `outputs` argument.",
397      outputs=None)
398  def predict(self, x=None, input_fn=None, batch_size=None, outputs=None,
399              as_iterable=True):
400    """Returns predictions for given features.
401
402    By default, returns predicted classes. But this default will be dropped
403    soon. Users should either pass `outputs`, or call `predict_classes` method.
404
405    Args:
406      x: features.
407      input_fn: Input function. If set, x must be None.
408      batch_size: Override default batch size.
409      outputs: list of `str`, name of the output to predict.
410        If `None`, returns classes.
411      as_iterable: If True, return an iterable which keeps yielding predictions
412        for each example until inputs are exhausted. Note: The inputs must
413        terminate if you want the iterable to terminate (e.g. be sure to pass
414        num_epochs=1 if you are using something like read_batch_features).
415
416    Returns:
417      Numpy array of predicted classes with shape [batch_size] (or an iterable
418      of predicted classes if as_iterable is True). Each predicted class is
419      represented by its class index (i.e. integer from 0 to n_classes-1).
420      If `outputs` is set, returns a dict of predictions.
421    """
422    if not outputs:
423      return self.predict_classes(
424          x=x,
425          input_fn=input_fn,
426          batch_size=batch_size,
427          as_iterable=as_iterable)
428    return super(DNNClassifier, self).predict(
429        x=x,
430        input_fn=input_fn,
431        batch_size=batch_size,
432        outputs=outputs,
433        as_iterable=as_iterable)
434
435  @deprecated_arg_values(
436      estimator.AS_ITERABLE_DATE,
437      estimator.AS_ITERABLE_INSTRUCTIONS,
438      as_iterable=False)
439  def predict_classes(self, x=None, input_fn=None, batch_size=None,
440                      as_iterable=True):
441    """Returns predicted classes for given features.
442
443    Args:
444      x: features.
445      input_fn: Input function. If set, x must be None.
446      batch_size: Override default batch size.
447      as_iterable: If True, return an iterable which keeps yielding predictions
448        for each example until inputs are exhausted. Note: The inputs must
449        terminate if you want the iterable to terminate (e.g. be sure to pass
450        num_epochs=1 if you are using something like read_batch_features).
451
452    Returns:
453      Numpy array of predicted classes with shape [batch_size] (or an iterable
454      of predicted classes if as_iterable is True). Each predicted class is
455      represented by its class index (i.e. integer from 0 to n_classes-1).
456    """
457    key = prediction_key.PredictionKey.CLASSES
458    preds = super(DNNClassifier, self).predict(
459        x=x,
460        input_fn=input_fn,
461        batch_size=batch_size,
462        outputs=[key],
463        as_iterable=as_iterable)
464    if as_iterable:
465      return (pred[key] for pred in preds)
466    return preds[key].reshape(-1)
467
468  @deprecated_arg_values(
469      estimator.AS_ITERABLE_DATE,
470      estimator.AS_ITERABLE_INSTRUCTIONS,
471      as_iterable=False)
472  def predict_proba(self,
473                    x=None,
474                    input_fn=None,
475                    batch_size=None,
476                    as_iterable=True):
477    """Returns predicted probabilities for given features.
478
479    Args:
480      x: features.
481      input_fn: Input function. If set, x and y must be None.
482      batch_size: Override default batch size.
483      as_iterable: If True, return an iterable which keeps yielding predictions
484        for each example until inputs are exhausted. Note: The inputs must
485        terminate if you want the iterable to terminate (e.g. be sure to pass
486        num_epochs=1 if you are using something like read_batch_features).
487
488    Returns:
489      Numpy array of predicted probabilities with shape [batch_size, n_classes]
490      (or an iterable of predicted probabilities if as_iterable is True).
491    """
492    key = prediction_key.PredictionKey.PROBABILITIES
493    preds = super(DNNClassifier, self).predict(
494        x=x,
495        input_fn=input_fn,
496        batch_size=batch_size,
497        outputs=[key],
498        as_iterable=as_iterable)
499    if as_iterable:
500      return (pred[key] for pred in preds)
501    return preds[key]
502
503  @deprecated("2017-03-25", "Please use Estimator.export_savedmodel() instead.")
504  def export(self,
505             export_dir,
506             input_fn=None,
507             input_feature_key=None,
508             use_deprecated_input_fn=True,
509             signature_fn=None,
510             default_batch_size=1,
511             exports_to_keep=None):
512    """See BaseEstimator.export."""
513
514    def default_input_fn(unused_estimator, examples):
515      return layers.parse_feature_columns_from_examples(examples,
516                                                        self._feature_columns)
517
518    return super(DNNClassifier, self).export(
519        export_dir=export_dir,
520        input_fn=input_fn or default_input_fn,
521        input_feature_key=input_feature_key,
522        use_deprecated_input_fn=use_deprecated_input_fn,
523        signature_fn=(signature_fn or
524                      export.classification_signature_fn_with_prob),
525        prediction_key=prediction_key.PredictionKey.PROBABILITIES,
526        default_batch_size=default_batch_size,
527        exports_to_keep=exports_to_keep)
528
529
530class DNNRegressor(estimator.Estimator):
531  """A regressor for TensorFlow DNN models.
532
533  THIS CLASS IS DEPRECATED. See
534  [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md)
535  for general migration instructions.
536
537  Example:
538
539  ```python
540  sparse_feature_a = sparse_column_with_hash_bucket(...)
541  sparse_feature_b = sparse_column_with_hash_bucket(...)
542
543  sparse_feature_a_emb = embedding_column(sparse_id_column=sparse_feature_a,
544                                          ...)
545  sparse_feature_b_emb = embedding_column(sparse_id_column=sparse_feature_b,
546                                          ...)
547
548  estimator = DNNRegressor(
549      feature_columns=[sparse_feature_a, sparse_feature_b],
550      hidden_units=[1024, 512, 256])
551
552  # Or estimator using the ProximalAdagradOptimizer optimizer with
553  # regularization.
554  estimator = DNNRegressor(
555      feature_columns=[sparse_feature_a, sparse_feature_b],
556      hidden_units=[1024, 512, 256],
557      optimizer=tf.train.ProximalAdagradOptimizer(
558        learning_rate=0.1,
559        l1_regularization_strength=0.001
560      ))
561
562  # Input builders
563  def input_fn_train: # returns x, y
564    pass
565  estimator.fit(input_fn=input_fn_train)
566
567  def input_fn_eval: # returns x, y
568    pass
569  estimator.evaluate(input_fn=input_fn_eval)
570  def input_fn_predict: # returns x, None
571    pass
572  estimator.predict_scores(input_fn=input_fn_predict)
573  ```
574
575  Input of `fit` and `evaluate` should have following features,
576    otherwise there will be a `KeyError`:
577
578  * if `weight_column_name` is not `None`, a feature with
579    `key=weight_column_name` whose value is a `Tensor`.
580  * for each `column` in `feature_columns`:
581    - if `column` is a `SparseColumn`, a feature with `key=column.name`
582      whose `value` is a `SparseTensor`.
583    - if `column` is a `WeightedSparseColumn`, two features: the first with
584      `key` the id column name, the second with `key` the weight column name.
585      Both features' `value` must be a `SparseTensor`.
586    - if `column` is a `RealValuedColumn`, a feature with `key=column.name`
587      whose `value` is a `Tensor`.
588  """
589
590  def __init__(self,
591               hidden_units,
592               feature_columns,
593               model_dir=None,
594               weight_column_name=None,
595               optimizer=None,
596               activation_fn=nn.relu,
597               dropout=None,
598               gradient_clip_norm=None,
599               enable_centered_bias=False,
600               config=None,
601               feature_engineering_fn=None,
602               label_dimension=1,
603               embedding_lr_multipliers=None,
604               input_layer_min_slice_size=None):
605    """Initializes a `DNNRegressor` instance.
606
607    Args:
608      hidden_units: List of hidden units per layer. All layers are fully
609        connected. Ex. `[64, 32]` means first layer has 64 nodes and second one
610        has 32.
611      feature_columns: An iterable containing all the feature columns used by
612        the model. All items in the set should be instances of classes derived
613        from `FeatureColumn`.
614      model_dir: Directory to save model parameters, graph and etc. This can
615        also be used to load checkpoints from the directory into a estimator to
616        continue training a previously saved model.
617      weight_column_name: A string defining feature column name representing
618        weights. It is used to down weight or boost examples during training. It
619        will be multiplied by the loss of the example.
620      optimizer: An instance of `tf.Optimizer` used to train the model. If
621        `None`, will use an Adagrad optimizer.
622      activation_fn: Activation function applied to each layer. If `None`, will
623        use `tf.nn.relu`. Note that a string containing the unqualified name of
624        the op may also be provided, e.g., "relu", "tanh", or "sigmoid".
625      dropout: When not `None`, the probability we will drop out a given
626        coordinate.
627      gradient_clip_norm: A `float` > 0. If provided, gradients are clipped
628        to their global norm with this clipping ratio. See
629        `tf.clip_by_global_norm` for more details.
630      enable_centered_bias: A bool. If True, estimator will learn a centered
631        bias variable for each class. Rest of the model structure learns the
632        residual after centered bias.
633      config: `RunConfig` object to configure the runtime settings.
634      feature_engineering_fn: Feature engineering function. Takes features and
635                        labels which are the output of `input_fn` and
636                        returns features and labels which will be fed
637                        into the model.
638      label_dimension: Number of regression targets per example. This is the
639        size of the last dimension of the labels and logits `Tensor` objects
640        (typically, these have shape `[batch_size, label_dimension]`).
641      embedding_lr_multipliers: Optional. A dictionary from `EbeddingColumn` to
642          a `float` multiplier. Multiplier will be used to multiply with
643          learning rate for the embedding variables.
644      input_layer_min_slice_size: Optional. The min slice size of input layer
645          partitions. If not provided, will use the default of 64M.
646
647    Returns:
648      A `DNNRegressor` estimator.
649    """
650    self._feature_columns = tuple(feature_columns or [])
651    super(DNNRegressor, self).__init__(
652        model_fn=_dnn_model_fn,
653        model_dir=model_dir,
654        config=config,
655        params={
656            "head":
657                head_lib.regression_head(
658                    label_dimension=label_dimension,
659                    weight_column_name=weight_column_name,
660                    enable_centered_bias=enable_centered_bias),
661            "hidden_units": hidden_units,
662            "feature_columns": self._feature_columns,
663            "optimizer": optimizer,
664            "activation_fn": activation_fn,
665            "dropout": dropout,
666            "gradient_clip_norm": gradient_clip_norm,
667            "embedding_lr_multipliers": embedding_lr_multipliers,
668            "input_layer_min_slice_size": input_layer_min_slice_size,
669        },
670        feature_engineering_fn=feature_engineering_fn)
671
672  def evaluate(self,
673               x=None,
674               y=None,
675               input_fn=None,
676               feed_fn=None,
677               batch_size=None,
678               steps=None,
679               metrics=None,
680               name=None,
681               checkpoint_path=None,
682               hooks=None):
683    """See evaluable.Evaluable."""
684    # TODO(zakaria): remove once deprecation is finished (b/31229024)
685    custom_metrics = {}
686    if metrics:
687      for key, metric in six.iteritems(metrics):
688        if (not isinstance(metric, metric_spec.MetricSpec) and
689            not isinstance(key, tuple)):
690          custom_metrics[(key, prediction_key.PredictionKey.SCORES)] = metric
691        else:
692          custom_metrics[key] = metric
693
694    return super(DNNRegressor, self).evaluate(
695        x=x,
696        y=y,
697        input_fn=input_fn,
698        feed_fn=feed_fn,
699        batch_size=batch_size,
700        steps=steps,
701        metrics=custom_metrics,
702        name=name,
703        checkpoint_path=checkpoint_path,
704        hooks=hooks)
705
706  @deprecated_arg_values(
707      estimator.AS_ITERABLE_DATE,
708      estimator.AS_ITERABLE_INSTRUCTIONS,
709      as_iterable=False)
710  @deprecated_arg_values(
711      "2017-03-01",
712      "Please switch to predict_scores, or set `outputs` argument.",
713      outputs=None)
714  def predict(self, x=None, input_fn=None, batch_size=None, outputs=None,
715              as_iterable=True):
716    """Returns predictions for given features.
717
718    By default, returns predicted scores. But this default will be dropped
719    soon. Users should either pass `outputs`, or call `predict_scores` method.
720
721    Args:
722      x: features.
723      input_fn: Input function. If set, x must be None.
724      batch_size: Override default batch size.
725      outputs: list of `str`, name of the output to predict.
726        If `None`, returns scores.
727      as_iterable: If True, return an iterable which keeps yielding predictions
728        for each example until inputs are exhausted. Note: The inputs must
729        terminate if you want the iterable to terminate (e.g. be sure to pass
730        num_epochs=1 if you are using something like read_batch_features).
731
732    Returns:
733      Numpy array of predicted scores (or an iterable of predicted scores if
734      as_iterable is True). If `label_dimension == 1`, the shape of the output
735      is `[batch_size]`, otherwise the shape is `[batch_size, label_dimension]`.
736      If `outputs` is set, returns a dict of predictions.
737    """
738    if not outputs:
739      return self.predict_scores(
740          x=x,
741          input_fn=input_fn,
742          batch_size=batch_size,
743          as_iterable=as_iterable)
744    return super(DNNRegressor, self).predict(
745        x=x,
746        input_fn=input_fn,
747        batch_size=batch_size,
748        outputs=outputs,
749        as_iterable=as_iterable)
750
751  @deprecated_arg_values(
752      estimator.AS_ITERABLE_DATE,
753      estimator.AS_ITERABLE_INSTRUCTIONS,
754      as_iterable=False)
755  def predict_scores(self, x=None, input_fn=None, batch_size=None,
756                     as_iterable=True):
757    """Returns predicted scores for given features.
758
759    Args:
760      x: features.
761      input_fn: Input function. If set, x must be None.
762      batch_size: Override default batch size.
763      as_iterable: If True, return an iterable which keeps yielding predictions
764        for each example until inputs are exhausted. Note: The inputs must
765        terminate if you want the iterable to terminate (e.g. be sure to pass
766        num_epochs=1 if you are using something like read_batch_features).
767
768    Returns:
769      Numpy array of predicted scores (or an iterable of predicted scores if
770      as_iterable is True). If `label_dimension == 1`, the shape of the output
771      is `[batch_size]`, otherwise the shape is `[batch_size, label_dimension]`.
772    """
773    key = prediction_key.PredictionKey.SCORES
774    preds = super(DNNRegressor, self).predict(
775        x=x,
776        input_fn=input_fn,
777        batch_size=batch_size,
778        outputs=[key],
779        as_iterable=as_iterable)
780    if as_iterable:
781      return (pred[key] for pred in preds)
782    return preds[key]
783
784  @deprecated("2017-03-25", "Please use Estimator.export_savedmodel() instead.")
785  def export(self,
786             export_dir,
787             input_fn=None,
788             input_feature_key=None,
789             use_deprecated_input_fn=True,
790             signature_fn=None,
791             default_batch_size=1,
792             exports_to_keep=None):
793    """See BaseEstimator.export."""
794    def default_input_fn(unused_estimator, examples):
795      return layers.parse_feature_columns_from_examples(examples,
796                                                        self._feature_columns)
797
798    return super(DNNRegressor, self).export(
799        export_dir=export_dir,
800        input_fn=input_fn or default_input_fn,
801        input_feature_key=input_feature_key,
802        use_deprecated_input_fn=use_deprecated_input_fn,
803        signature_fn=signature_fn or export.regression_signature_fn,
804        prediction_key=prediction_key.PredictionKey.SCORES,
805        default_batch_size=default_batch_size,
806        exports_to_keep=exports_to_keep)
807
808
809class DNNEstimator(estimator.Estimator):
810  """A Estimator for TensorFlow DNN models with user specified _Head.
811
812  THIS CLASS IS DEPRECATED. See
813  [contrib/learn/README.md](https://www.tensorflow.org/code/tensorflow/contrib/learn/README.md)
814  for general migration instructions.
815
816  Example:
817
818  ```python
819  sparse_feature_a = sparse_column_with_hash_bucket(...)
820  sparse_feature_b = sparse_column_with_hash_bucket(...)
821
822  sparse_feature_a_emb = embedding_column(sparse_id_column=sparse_feature_a,
823                                          ...)
824  sparse_feature_b_emb = embedding_column(sparse_id_column=sparse_feature_b,
825                                          ...)
826  To create a DNNEstimator for binary classification, where
827  estimator = DNNEstimator(
828      feature_columns=[sparse_feature_a_emb, sparse_feature_b_emb],
829      head=tf.contrib.learn.multi_class_head(n_classes=2),
830      hidden_units=[1024, 512, 256])
831
832  If your label is keyed with "y" in your labels dict, and weights are keyed
833  with "w" in features dict, and you want to enable centered bias,
834  head = tf.contrib.learn.multi_class_head(
835      n_classes=2,
836      label_name="x",
837      weight_column_name="w",
838      enable_centered_bias=True)
839  estimator = DNNEstimator(
840      feature_columns=[sparse_feature_a_emb, sparse_feature_b_emb],
841      head=head,
842      hidden_units=[1024, 512, 256])
843
844  # Input builders
845  def input_fn_train: # returns x, y (where y represents label's class index).
846    pass
847  estimator.fit(input_fn=input_fn_train)
848
849  def input_fn_eval: # returns x, y (where y represents label's class index).
850    pass
851  estimator.evaluate(input_fn=input_fn_eval)
852  estimator.predict(x=x) # returns predicted labels (i.e. label's class index).
853  ```
854
855  Input of `fit` and `evaluate` should have following features,
856    otherwise there will be a `KeyError`:
857
858  * if `weight_column_name` is not `None`, a feature with
859     `key=weight_column_name` whose value is a `Tensor`.
860  * for each `column` in `feature_columns`:
861    - if `column` is a `SparseColumn`, a feature with `key=column.name`
862      whose `value` is a `SparseTensor`.
863    - if `column` is a `WeightedSparseColumn`, two features: the first with
864      `key` the id column name, the second with `key` the weight column name.
865      Both features' `value` must be a `SparseTensor`.
866    - if `column` is a `RealValuedColumn`, a feature with `key=column.name`
867      whose `value` is a `Tensor`.
868  """
869
870  def __init__(self,
871               head,
872               hidden_units,
873               feature_columns,
874               model_dir=None,
875               optimizer=None,
876               activation_fn=nn.relu,
877               dropout=None,
878               gradient_clip_norm=None,
879               config=None,
880               feature_engineering_fn=None,
881               embedding_lr_multipliers=None,
882               input_layer_min_slice_size=None):
883    """Initializes a `DNNEstimator` instance.
884
885    Args:
886      head: `Head` instance.
887      hidden_units: List of hidden units per layer. All layers are fully
888        connected. Ex. `[64, 32]` means first layer has 64 nodes and second one
889        has 32.
890      feature_columns: An iterable containing all the feature columns used by
891        the model. All items in the set should be instances of classes derived
892        from `FeatureColumn`.
893      model_dir: Directory to save model parameters, graph and etc. This can
894        also be used to load checkpoints from the directory into a estimator to
895        continue training a previously saved model.
896      optimizer: An instance of `tf.Optimizer` used to train the model. If
897        `None`, will use an Adagrad optimizer.
898      activation_fn: Activation function applied to each layer. If `None`, will
899        use `tf.nn.relu`. Note that a string containing the unqualified name of
900        the op may also be provided, e.g., "relu", "tanh", or "sigmoid".
901      dropout: When not `None`, the probability we will drop out a given
902        coordinate.
903      gradient_clip_norm: A float > 0. If provided, gradients are
904        clipped to their global norm with this clipping ratio. See
905        `tf.clip_by_global_norm` for more details.
906      config: `RunConfig` object to configure the runtime settings.
907      feature_engineering_fn: Feature engineering function. Takes features and
908                        labels which are the output of `input_fn` and
909                        returns features and labels which will be fed
910                        into the model.
911      embedding_lr_multipliers: Optional. A dictionary from `EmbeddingColumn` to
912          a `float` multiplier. Multiplier will be used to multiply with
913          learning rate for the embedding variables.
914      input_layer_min_slice_size: Optional. The min slice size of input layer
915          partitions. If not provided, will use the default of 64M.
916
917    Returns:
918      A `DNNEstimator` estimator.
919    """
920    super(DNNEstimator, self).__init__(
921        model_fn=_dnn_model_fn,
922        model_dir=model_dir,
923        config=config,
924        params={
925            "head": head,
926            "hidden_units": hidden_units,
927            "feature_columns": feature_columns,
928            "optimizer": optimizer,
929            "activation_fn": activation_fn,
930            "dropout": dropout,
931            "gradient_clip_norm": gradient_clip_norm,
932            "embedding_lr_multipliers": embedding_lr_multipliers,
933            "input_layer_min_slice_size": input_layer_min_slice_size,
934        },
935        feature_engineering_fn=feature_engineering_fn)
936