code: def _convert_training_info(model, builder, output_features):
      """
      Convert the training information from the given Keras 'model' into the Core
      ML in 'builder'.
  
      :param model: keras.model.Sequential
          The source Keras model.
      :param builder: NeutralNetworkBuilder
          The target model that will gain the loss and optimizer.
      :param output_features: list of tuples, (str, datatype)
          The set of tensor names that are output from the layers in the Keras
          model.
      """
      # Keras does not have a number of epochs compiled into the model, so we
      # invent one here for ease of use.  1 makes the most sense, as the user
      # can just invoke training repeatedly if they'd like to do more.
      builder.set_epochs(1)
      import keras
  
      try:
          if (
              model.loss == keras.losses.categorical_crossentropy
              or model.loss == "categorical_crossentropy"
          ):
              builder.set_categorical_cross_entropy_loss(
                  name="loss_layer", input=output_features[0][0]
              )
          elif (
              model.loss == keras.losses.mean_squared_error
              or model.loss == "mean_squared_error"
          ):
              builder.set_mean_squared_error_loss(
                  name="loss_layer", input_feature=output_features[0]
              )
          else:
              print(
                  "Models loss: "
                  + str(model.loss)
                  + ", vs Keras loss: "
                  + str(keras.losses.mean_squared_error)
              )
              logging.warning(
                  "Loss " + str(model.loss) + " is not yet "
                  "supported by Core ML. The loss layer will "
                  "not be carried over. To train this model, "
                  "you will need to manually add a supported "
                  "loss layer."
              )
      except AttributeError:
          logging.warning(
              "Core ML conversion was asked to respect trainable "
              "parameters from the Keras model, but the input "
              "model does not include a loss layer."
          )
      try:
          opt = model.optimizer
      except AttributeError:
          logging.warning(
              "Core ML conversion was asked to respect trainable "
              "parameters from the Keras model, but could not read "
              "the optimizer from Keras."
          )
          return
  
      if model.optimizer:
          # a dict of the parameters we need.
          cfg = model.optimizer.get_config()
          if "decay" in cfg and cfg["decay"] != 0.0:
              logging.warning(
                  "Keras optimizer has 'decay' set, which is "
                  "not supported in Core ML. This parameter "
                  "of the optimizer will be ignored. Clients "
                  "can change the learning rate from within an "
                  "MLUpdateTask callback to achieve the same "
                  "effect."
              )
          if isinstance(model.optimizer, keras.optimizers.SGD):
              params = SgdParams(lr=cfg["lr"], momentum=cfg["momentum"])
              if "nesterov" in cfg and cfg["nesterov"] == True:
                  logging.warning(
                      "Keras SGD optimizer has 'nesterov' set, "
                      "but this is not supported by Core ML. "
                      "The parameter will be ignored."
                  )
              # Keras does not require a user to specify batch size up front,
              # as Core ML does.  We need to choose something, let's be a bit
              # wide to minimize the chance of user "surprise" when running.
              params.set_batch(16, [1, 16, 32])
              builder.set_sgd_optimizer(params)
          elif isinstance(model.optimizer, keras.optimizers.Adam):
              params = AdamParams(
                  lr=cfg["lr"],
                  beta1=cfg["beta_1"],
                  beta2=cfg["beta_2"],
                  eps=cfg["epsilon"],
              )
              if "amsgrad" in cfg and cfg["amsgrad"] == True:
                  logging.warning(
                      "Keras Adam optimizer has 'amsgrad' set, "
                      "but this is not supported by Core ML. "
                      "The parameter will be ignored."
                  )
              # Keras does not require a user to specify batch size up front,
              # as Core ML does.  We need to choose something, let's be a bit
              # wide to minimize the chance of user "surprise" when running.
              params.set_batch(16, [1, 16, 32])
              builder.set_adam_optimizer(params)
          else:
              logging.warning(
                  "Optimizer " + str(model.optimizer) + " is "
                  "not yet supported by Core ML. The optimizer "
                  "will not be carried over. To train this "
                  "model, you will need to manually add a "
                  "supported optimizer."
              )
      else:
          logging.warning(
              "Core ML conversion was asked to respect "
              "trainable parameters from the Keras model, but "
              "the input model does not include an optimizer."
          )
  
file_path: turicreate/src/external/coremltools_wrap/coremltools/coremltools/converters/keras/_keras2_converter.py
imports: import logging
  from six import string_types
  from ...models.neural_network import NeuralNetworkBuilder
  from ...models.neural_network.update_optimizer_utils import AdamParams
  from ...models.neural_network.update_optimizer_utils import SgdParams
  from ...proto import FeatureTypes_pb2
  from collections import OrderedDict
  from ...proto import Model_pb2
  from ...models import datatypes
  from ...models import MLModel
  from ...models.utils import save_spec
  from ..._deps import _HAS_KERAS2_TF
label_desc: Use image node_id 6 for calling a global function with example usage: _convert_training_info(model, builder, output_features) without return types