docstr: Create a TFOptimizer from a tensorflow.keras model. The model must be compiled.
  :param keras_model: the tensorflow.keras model, which must be compiled.
  :param dataset: a TFDataset
  :return:
docstr_tok: ["Create","a","TFOptimizer","from","a","tensorflow.keras","model",".","The","model","must","be","compiled",".",":","param","keras_model",":","the","tensorflow.keras","model",",","which","must","be","compiled",".",":","param","dataset",":","a","TFDataset",":","return",":"]
code: def from_keras(
      cls,
      keras_model,
      dataset,
      session_config=None,
      model_dir=None,
      metrics=None,
      optimizer=None,
  ):
      """
      Create a TFOptimizer from a tensorflow.keras model. The model must be compiled.
      :param keras_model: the tensorflow.keras model, which must be compiled.
      :param dataset: a TFDataset
      :return:
      """
      import tensorflow.keras.backend as K
  
      model_inputs = keras_model.inputs
  
      if hasattr(keras_model, "targets"):
          model_targets = keras_model.targets
      else:
          model_targets = keras_model._targets
  
      # target can be None if loss is None
      model_targets = list(
          filter(lambda x: x is not None, model_targets)
      )
  
      check_data_compatible(dataset, keras_model, mode="train")
      # standarize feature, labels to support keras model
      if isinstance(dataset, TFNdarrayDataset):
          dataset = _standarize_feature_label_dataset(
              dataset, keras_model
          )
  
      flatten_inputs = nest.flatten(dataset.feature_tensors)
      assert len(model_inputs) == len(flatten_inputs), (
          "the keras model and TFDataset should have the same number of tensors"
          + " keras model has {} inputs "
          + "while TFDataset has {} inputs"
      ).format(len(model_inputs), len(flatten_inputs))
      for i in range(len(flatten_inputs)):
          if not TFOptimizer._shape_match(
              model_inputs[i].shape, flatten_inputs[i].shape
          ):
              raise ValueError(
                  (
                      "The {}th input in keras model {}"
                      " does not match the TFDataset"
                      "input {}"
                  ).format(i, model_inputs[i], flatten_inputs[i])
              )
  
      flatten_targets = nest.flatten(dataset.label_tensors)
      assert len(model_targets) == len(flatten_targets), (
          "the keras model and TFDataset should have the same number of tensors"
          + " keras model has {} targets "
          + "while TFDataset has {} labels"
      ).format(len(model_targets), len(flatten_inputs))
      # todo check targets shape, currently checking target shape will
      # cause too much false alarm.
  
      loss = keras_model.total_loss
      variables = keras_model._collected_trainable_weights
      variables.sort(key=lambda variable: variable.name)
      keras_optimizer = keras_model.optimizer
  
      from zoo.tfpark.zoo_optimizer import get_gradients_for_keras
  
      grads = get_gradients_for_keras(keras_optimizer, loss, variables)
      grads_and_vars = list(zip(grads, variables))
      import tensorflow.python.keras.optimizers as koptimizers
  
      if isinstance(keras_optimizer, koptimizers.TFOptimizer):
          # work around keras TFOptimzier bug
          train_op = keras_optimizer.optimizer.apply_gradients(
              grads_and_vars
          )
      else:
          train_op = keras_optimizer.apply_gradients(grads_and_vars)
  
      sess = K.get_session()
  
      if keras_model.metrics and (
          dataset.get_validation_data() is not None
      ):
          if isinstance(keras_model.metrics, dict):
              raise ValueError(
                  "different metrics for different outputs are not supported right now"
              )
  
          if len(keras_model.outputs) > 1:
              if not all(
                  [
                      name.endswith("loss")
                      for name in keras_model.metrics_names
                  ]
              ):
                  raise ValueError(
                      "metrics (except loss) for multi-head model is not supported"
                  )
              else:
                  bigdl_val_methods = [Loss()]
                  val_outputs = keras_model.outputs
                  val_labels = model_targets
          else:
              bigdl_val_methods = [
                  to_bigdl_metric(m, keras_model.loss)
                  for m in keras_model.metrics_names
              ]
              val_outputs = keras_model.outputs
              val_labels = model_targets
      else:
          val_outputs = None
          val_labels = None
          bigdl_val_methods = None
  
      tensor_with_value = {K.learning_phase(): [True, False]}
  
      updates = []
  
      updates += keras_model.get_updates_for(None)
      # Conditional updates relevant to this model
      updates += keras_model.get_updates_for(keras_model.inputs)
  
      if bigdl_val_methods is not None:
          val_methods = to_list(bigdl_val_methods)
          bigdl_metrics = {}
          for i, method in enumerate(val_methods):
              bigdl_metrics["bigdl_metric_" + str(i)] = BigDLMetric(
                  method, val_outputs, val_labels
              )
          if metrics is None:
              metrics = bigdl_metrics
          else:
              metrics.update(bigdl_metrics)
  
      if optimizer is not None:
          clip_norm = None
          clip_value = None
          if hasattr(keras_optimizer, "clipnorm"):
              clip_norm = keras_optimizer.clipnorm
          if hasattr(keras_optimizer, "clipvalue"):
              clip_value = (
                  -keras_optimizer.clipvalue,
                  keras_optimizer.clipvalue,
              )
          tf_model = TFModel.create(
              loss,
              sess,
              model_inputs,
              model_targets,
              keras_model.outputs,
              grads,
              variables,
              loss.graph,
              tensor_with_value,
              session_config,
              metrics,
              updates,
              model_dir=None,
          )
  
          return cls(
              tf_model,
              optimizer,
              sess=sess,
              dataset=dataset,
              clip_norm=clip_norm,
              clip_value=clip_value,
              model_dir=model_dir,
          )
  
      return cls.from_train_op(
          train_op,
          loss,
          inputs=model_inputs,
          labels=model_targets,
          metrics=metrics,
          updates=updates,
          sess=sess,
          dataset=dataset,
          tensor_with_value=tensor_with_value,
          session_config=session_config,
          model_dir=model_dir,
      )
  
imports: import json
  import logging
  import os
  import sys
  import tempfile
  from bigdl.nn.criterion import Criterion
  from bigdl.nn.layer import Layer
  from bigdl.optim.optimizer import MaxEpoch, EveryEpoch
  from bigdl.util.common import to_list, JavaValue
  from zoo.common.utils import callZooFunc
  from zoo.feature.common import FeatureSet
  from zoo.pipeline.api.keras.engine.topology import to_bigdl_metric, Loss, OptimMethod
  from zoo.pipeline.api.net.utils import find_placeholders, to_bigdl_optim_method, find_tensors
  from zoo.pipeline.estimator import Estimator
  from zoo.util import nest
  from zoo.util.triggers import EveryEpoch
  from zoo.util.triggers import ZooTrigger
  from zoo.tfpark.tf_dataset import TFNdarrayDataset, check_data_compatible
  from zoo.tfpark.tf_dataset import _standarize_feature_label_dataset
label_desc: Use image node_id 12 for calling the TFOptimizer obj's underlying member method code with example usage: obj.from_keras(cls, keras_model, dataset, session_config, model_dir, metrics, optimizer) and returns: cls, cls