class_docstr: Builds `_SubnetworkSpec` instances.
  
  This class manages an `adanet.subnetwork.Builder`, creates its subnetwork and
  train ops, and returns a `_SubnetworkSpec` that holds them.
  
  Args:
    head: A `tf.contrib.estimator.Head` instance.
    metric_fn: A function which should obey the following signature:
      - Args: can only have following three arguments in any order:
        * predictions: Predictions `Tensor` or dict of `Tensor` created by given
          `Head`.
        * features: Input `dict` of `Tensor` objects created by `input_fn` which
          is given to `estimator.evaluate` as an argument.
        * labels:  Labels `Tensor` or dict of `Tensor` (for multi-head) created
          by `input_fn` which is given to `estimator.evaluate` as an argument.
      - Returns: Dict of metric results keyed by name. Final metrics are a union
        of this and `Head's` existing metrics. If there is a name conflict
        between this and `estimator`s existing metrics, this will override the
        existing one. The values of the dict are the results of calling a metric
        function, namely a `(metric_tensor, update_op)` tuple.
    use_tpu: Whether AdaNet is running on TPU.
  
  Returns:
    An `_SubnetworkManager` instance.
  
  Raises:
    ValueError: If `max_steps` is <= 0.
docstr: Builds a `_SubnetworkSpec` from the given `adanet.subnetwork.Builder`.
  
  Args:
    name: String name of the subnetwork.
    subnetwork_builder: A `adanet.Builder` instance which defines how to train
      the subnetwork and ensemble mixture weights.
    summary: A `_ScopedSummary` instance for recording ensemble summaries.
    features: Input `dict` of `Tensor` objects.
    mode: Estimator's `ModeKeys`.
    labels: Labels `Tensor` or a dictionary of string label name to `Tensor`
      (for multi-head). Can be `None`.
    previous_ensemble: The previous `Ensemble` from iteration t-1. Used for
      creating the subnetwork train_op.
    config: The `tf.estimator.RunConfig` to use this iteration.
  
  Returns:
    An new `EnsembleSpec` instance with the `Subnetwork` appended.
docstr_tok: ["Builds","a","`","_SubnetworkSpec","`","from","the","given","`","adanet.subnetwork.Builder","`",".","Args",":","name",":","String","name","of","the","subnetwork",".","subnetwork_builder",":","A","`","adanet.Builder","`","instance","which","defines","how","to","train","the","subnetwork","and","ensemble","mixture","weights",".","summary",":","A","`","_ScopedSummary","`","instance","for","recording","ensemble","summaries",".","features",":","Input","`","dict","`","of","`","Tensor","`","objects",".","mode",":","Estimator","'s","`","ModeKeys","`",".","labels",":","Labels","`","Tensor","`","or","a","dictionary","of","string","label","name","to","`","Tensor","`","(","for","multi-head",")",".","Can","be","`","None","`",".","previous_ensemble",":","The","previous","`","Ensemble","`","from","iteration","t-1",".","Used","for","creating","the","subnetwork","train_op",".","config",":","The","`","tf.estimator.RunConfig","`","to","use","this","iteration",".","Returns",":","An","new","`","EnsembleSpec","`","instance","with","the","`","Subnetwork","`","appended","."]
code: def build_subnetwork_spec(
      self,
      name,
      subnetwork_builder,
      summary,
      features,
      mode,
      labels=None,
      previous_ensemble=None,
      config=None,
  ):
      """Builds a `_SubnetworkSpec` from the given `adanet.subnetwork.Builder`.
  
      Args:
        name: String name of the subnetwork.
        subnetwork_builder: A `adanet.Builder` instance which defines how to train
          the subnetwork and ensemble mixture weights.
        summary: A `_ScopedSummary` instance for recording ensemble summaries.
        features: Input `dict` of `Tensor` objects.
        mode: Estimator's `ModeKeys`.
        labels: Labels `Tensor` or a dictionary of string label name to `Tensor`
          (for multi-head). Can be `None`.
        previous_ensemble: The previous `Ensemble` from iteration t-1. Used for
          creating the subnetwork train_op.
        config: The `tf.estimator.RunConfig` to use this iteration.
  
      Returns:
        An new `EnsembleSpec` instance with the `Subnetwork` appended.
      """
  
      old_vars = _get_current_vars()
  
      with tf_compat.v1.variable_scope("subnetwork_{}".format(name)):
          step = tf_compat.v1.get_variable(
              "step",
              shape=[],
              initializer=tf_compat.v1.zeros_initializer(),
              trainable=False,
              dtype=tf.int64,
          )
  
          # Convert to tensor so that users cannot mutate it.
          step_tensor = tf.convert_to_tensor(value=step)
          with summary.current_scope():
              summary.scalar(
                  "iteration_step/adanet/iteration_step", step_tensor
              )
          if config:
              subnetwork_config = config.replace(
                  model_dir=os.path.join(
                      config.model_dir, "assets", name
                  )
              )
          else:
              subnetwork_config = tf.estimator.RunConfig(
                  session_config=tf.compat.v1.ConfigProto(
                      gpu_options=tf.compat.v1.GPUOptions(
                          allow_growth=True
                      )
                  )
              )
  
          build_subnetwork = functools.partial(
              subnetwork_builder.build_subnetwork,
              features=features,
              logits_dimension=self._head.logits_dimension,
              training=mode == tf.estimator.ModeKeys.TRAIN,
              iteration_step=step_tensor,
              summary=summary,
              previous_ensemble=previous_ensemble,
          )
          # Check which args are in the implemented build_subnetwork method
          # signature for backwards compatibility.
          # Calling low level getargs for py_2_and_3 compatibility.
          defined_args = inspect.getargs(
              subnetwork_builder.build_subnetwork.__code__
          ).args
          if "labels" in defined_args:
              build_subnetwork = functools.partial(
                  build_subnetwork, labels=labels
              )
          if "config" in defined_args:
              build_subnetwork = functools.partial(
                  build_subnetwork, config=subnetwork_config
              )
          subnetwork_scope = tf_compat.v1.get_variable_scope()
          with summary.current_scope(), _monkey_patch_context(
              iteration_step_scope=subnetwork_scope,
              scoped_summary=summary,
              trainable_vars=[],
          ):
              subnetwork = build_subnetwork()
  
          subnetwork_var_list = _get_current_vars(diffbase=old_vars)[
              "trainable"
          ]
  
          estimator_spec = _create_estimator_spec(
              self._head,
              features,
              labels,
              mode,
              subnetwork.logits,
              self._use_tpu,
          )
  
          subnetwork_metrics = _SubnetworkMetrics(self._use_tpu)
          if mode == tf.estimator.ModeKeys.EVAL:
              subnetwork_metrics.create_eval_metrics(
                  features=features,
                  labels=labels,
                  estimator_spec=estimator_spec,
                  metric_fn=self._metric_fn,
              )
  
          if mode == tf.estimator.ModeKeys.TRAIN:
              with summary.current_scope():
                  summary.scalar("loss", estimator_spec.loss)
  
          # Create train ops for training subnetworks and ensembles.
          train_op = None
          if mode == tf.estimator.ModeKeys.TRAIN and subnetwork_builder:
              with summary.current_scope(), _monkey_patch_context(
                  iteration_step_scope=subnetwork_scope,
                  scoped_summary=summary,
                  trainable_vars=subnetwork_var_list,
              ):
                  train_op = _to_train_op_spec(
                      subnetwork_builder.build_subnetwork_train_op(
                          subnetwork=subnetwork,
                          loss=estimator_spec.loss,
                          var_list=subnetwork_var_list,
                          labels=labels,
                          iteration_step=step_tensor,
                          summary=summary,
                          previous_ensemble=previous_ensemble,
                      )
                  )
  
          new_vars = _get_current_vars(diffbase=old_vars)
          # Sort our dictionary by key to remove non-determinism of variable order.
          new_vars = collections.OrderedDict(sorted(new_vars.items()))
          # Combine all trainable, global and savable variables into a single list.
          subnetwork_variables = sum(new_vars.values(), []) + [step]
  
      return _SubnetworkSpec(
          name=name,
          subnetwork=subnetwork,
          builder=subnetwork_builder,
          predictions=estimator_spec.predictions,
          variables=subnetwork_variables,
          loss=estimator_spec.loss,
          step=step,
          train_op=train_op,
          eval_metrics=subnetwork_metrics,
          asset_dir=subnetwork_config.model_dir,
      )
  
imports: from __future__ import absolute_import
  from __future__ import division
  from __future__ import print_function
  import collections
  import contextlib
  import copy
  import functools
  import inspect
  import os
  from absl import logging
  from adanet import ensemble
  from adanet import subnetwork
  from adanet import tf_compat
  from adanet.core.architecture import _Architecture
  from adanet.core.eval_metrics import _EnsembleMetrics
  from adanet.core.eval_metrics import _SubnetworkMetrics
  from adanet.core.summary import monkey_patched_summaries
  import tensorflow.compat.v1
  import tensorflow.compat.v2
label_desc: Use image node_id 2 for calling the _SubnetworkManager obj's underlying member method code with example usage: obj.build_subnetwork_spec(name, subnetwork_builder, summary, features, mode, labels, previous_ensemble, config) and returns: _SubnetworkSpec