class_docstr: ExportArchive is used to write SavedModel artifacts (e.g. for inference).
  
  If you have a Keras model or layer that you want to export as SavedModel for
  serving (e.g. via TensorFlow-Serving), you can use `ExportArchive`
  to configure the different serving endpoints you need to make available,
  as well as their signatures. Simply instantiate an `ExportArchive`,
  use `track()` to register the layer(s) or model(s) to be used,
  then use the `add_endpoint()` method to register a new serving endpoint.
  When done, use the `write_out()` method to save the artifact.
  
  The resulting artifact is a SavedModel and can be reloaded via
  `tf.saved_model.load`.
  
  Examples:
  
  Here's how to export a model for inference.
  
  ```python
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="serve",
      fn=model.call,
      input_signature=[tf.TensorSpec(shape=(None, 3), dtype=tf.float32)],
  )
  export_archive.write_out("path/to/location")
  
  # Elsewhere, we can reload the artifact and serve it.
  # The endpoint we added is available as a method:
  serving_model = tf.saved_model.load("path/to/location")
  outputs = serving_model.serve(inputs)
  ```
  
  Here's how to export a model with one endpoint for inference and one
  endpoint for a training-mode forward pass (e.g. with dropout on).
  
  ```python
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="call_inference",
      fn=lambda x: model.call(x, training=False),
      input_signature=[tf.TensorSpec(shape=(None, 3), dtype=tf.float32)],
  )
  export_archive.add_endpoint(
      name="call_training",
      fn=lambda x: model.call(x, training=True),
      input_signature=[tf.TensorSpec(shape=(None, 3), dtype=tf.float32)],
  )
  export_archive.write_out("path/to/location")
  ```
  
  **Note on resource tracking:**
  
  `ExportArchive` is able to automatically track all `tf.Variables` used
  by its endpoints, so most of the time calling `.track(model)`
  is not strictly required. However, if your model uses lookup layers such
  as `IntegerLookup`, `StringLookup`, or `TextVectorization`,
  it will need to be tracked explicitly via `.track(model)`.
  
  Explicit tracking is also required if you need to be able to access
  the properties `variables`, `trainable_variables`, or
  `non_trainable_variables` on the revived archive.
class_docstr_tok: ["ExportArchive","is","used","to","write","SavedModel","artifacts","(","e.g",".","for","inference",")",".","If","you","have","a","Keras","model","or","layer","that","you","want","to","export","as","SavedModel","for","serving","(","e.g",".","via","TensorFlow-Serving",")",",","you","can","use","`","ExportArchive","`","to","configure","the","different","serving","endpoints","you","need","to","make","available",",","as","well","as","their","signatures",".","Simply","instantiate","an","`","ExportArchive","`",",","use","`","track","(",")","`","to","register","the","layer","(","s",")","or","model","(","s",")","to","be","used",",","then","use","the","`","add_endpoint","(",")","`","method","to","register","a","new","serving","endpoint",".","When","done",",","use","the","`","write_out","(",")","`","method","to","save","the","artifact",".","The","resulting","artifact","is","a","SavedModel","and","can","be","reloaded","via","`","tf.saved_model.load","`",".","Examples",":","Here","'s","how","to","export","a","model","for","inference",".","``","`","python","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=model.call",",","input_signature=","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")","]",",",")","export_archive.write_out","(","``","path\/to\/location","''",")","#","Elsewhere",",","we","can","reload","the","artifact","and","serve","it",".","#","The","endpoint","we","added","is","available","as","a","method",":","serving_model","=","tf.saved_model.load","(","``","path\/to\/location","''",")","outputs","=","serving_model.serve","(","inputs",")","``","`","Here","'s","how","to","export","a","model","with","one","endpoint","for","inference","and","one","endpoint","for","a","training-mode","forward","pass","(","e.g",".","with","dropout","on",")",".","``","`","python","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","call_inference","''",",","fn=lambda","x",":","model.call","(","x",",","training=False",")",",","input_signature=","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")","]",",",")","export_archive.add_endpoint","(","name=","''","call_training","''",",","fn=lambda","x",":","model.call","(","x",",","training=True",")",",","input_signature=","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")","]",",",")","export_archive.write_out","(","``","path\/to\/location","''",")","``","`","*","*","Note","on","resource","tracking",":","*","*","`","ExportArchive","`","is","able","to","automatically","track","all","`","tf.Variables","`","used","by","its","endpoints",",","so","most","of","the","time","calling","`",".track","(","model",")","`","is","not","strictly","required",".","However",",","if","your","model","uses","lookup","layers","such","as","`","IntegerLookup","`",",","`","StringLookup","`",",","or","`","TextVectorization","`",",","it","will","need","to","be","tracked","explicitly","via","`",".track","(","model",")","`",".","Explicit","tracking","is","also","required","if","you","need","to","be","able","to","access","the","properties","`","variables","`",",","`","trainable_variables","`",",","or","`","non_trainable_variables","`","on","the","revived","archive","."]
docstr: Register a new serving endpoint.
  
  Arguments:
      name: Str, name of the endpoint.
      fn: A function. It should only leverage resources
          (e.g. `tf.Variable` objects or `tf.lookup.StaticHashTable`
          objects) that are available on the models/layers
          tracked by the `ExportArchive` (you can call `.track(model)`
          to track a new model).
          The shape and dtype of the inputs to the function must be
          known. For that purpose, you can either 1) make sure that
          `fn` is a `tf.function` that has been called at least once, or
          2) provide an `input_signature` argument that specifies the
          shape and dtype of the inputs (see below).
      input_signature: Used to specify the shape and dtype of the
          inputs to `fn`. List of `tf.TensorSpec` objects (one
          per positional input argument of `fn`). Nested arguments are
          allowed (see below for an example showing a Functional model
          with 2 input arguments).
  
  Example:
  
  Adding an endpoint using the `input_signature` argument when the
  model has a single input argument:
  
  ```python
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="serve",
      fn=model.call,
      input_signature=[tf.TensorSpec(shape=(None, 3), dtype=tf.float32)],
  )
  ```
  
  Adding an endpoint using the `input_signature` argument when the
  model has two positional input arguments:
  
  ```python
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="serve",
      fn=model.call,
      input_signature=[
          tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
          tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
      ],
  )
  ```
  
  Adding an endpoint using the `input_signature` argument when the
  model has one input argument that is a list of 2 tensors (e.g.
  a Functional model with 2 inputs):
  
  ```python
  model = keras.Model(inputs=[x1, x2], outputs=outputs)
  
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="serve",
      fn=model.call,
      input_signature=[
          [
              tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
              tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
          ],
      ],
  )
  ```
  
  This also works with dictionary inputs:
  
  ```python
  model = keras.Model(inputs={"x1": x1, "x2": x2}, outputs=outputs)
  
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(
      name="serve",
      fn=model.call,
      input_signature=[
          {
              "x1": tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
              "x2": tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
          },
      ],
  )
  ```
  
  Adding an endpoint that is a `tf.function`:
  
  ```python
  @tf.function()
  def serving_fn(x):
      return model(x)
  
  # The function must be traced, i.e. it must be called at least once.
  serving_fn(tf.random.normal(shape=(2, 3)))
  
  export_archive = ExportArchive()
  export_archive.track(model)
  export_archive.add_endpoint(name="serve", fn=serving_fn)
  ```
docstr_tok: ["Register","a","new","serving","endpoint",".","Arguments",":","name",":","Str",",","name","of","the","endpoint",".","fn",":","A","function",".","It","should","only","leverage","resources","(","e.g",".","`","tf.Variable","`","objects","or","`","tf.lookup.StaticHashTable","`","objects",")","that","are","available","on","the","models\/layers","tracked","by","the","`","ExportArchive","`","(","you","can","call","`",".track","(","model",")","`","to","track","a","new","model",")",".","The","shape","and","dtype","of","the","inputs","to","the","function","must","be","known",".","For","that","purpose",",","you","can","either","1",")","make","sure","that","`","fn","`","is","a","`","tf.function","`","that","has","been","called","at","least","once",",","or","2",")","provide","an","`","input_signature","`","argument","that","specifies","the","shape","and","dtype","of","the","inputs","(","see","below",")",".","input_signature",":","Used","to","specify","the","shape","and","dtype","of","the","inputs","to","`","fn","`",".","List","of","`","tf.TensorSpec","`","objects","(","one","per","positional","input","argument","of","`","fn","`",")",".","Nested","arguments","are","allowed","(","see","below","for","an","example","showing","a","Functional","model","with","2","input","arguments",")",".","Example",":","Adding","an","endpoint","using","the","`","input_signature","`","argument","when","the","model","has","a","single","input","argument",":","``","`","python","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=model.call",",","input_signature=","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")","]",",",")","``","`","Adding","an","endpoint","using","the","`","input_signature","`","argument","when","the","model","has","two","positional","input","arguments",":","``","`","python","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=model.call",",","input_signature=","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")",",","tf.TensorSpec","(","shape=","(","None",",","4",")",",","dtype=tf.float32",")",",","]",",",")","``","`","Adding","an","endpoint","using","the","`","input_signature","`","argument","when","the","model","has","one","input","argument","that","is","a","list","of","2","tensors","(","e.g",".","a","Functional","model","with","2","inputs",")",":","``","`","python","model","=","keras.Model","(","inputs=","[","x1",",","x2","]",",","outputs=outputs",")","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=model.call",",","input_signature=","[","[","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")",",","tf.TensorSpec","(","shape=","(","None",",","4",")",",","dtype=tf.float32",")",",","]",",","]",",",")","``","`","This","also","works","with","dictionary","inputs",":","``","`","python","model","=","keras.Model","(","inputs=","{","``","x1","''",":","x1",",","``","x2","''",":","x2","}",",","outputs=outputs",")","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=model.call",",","input_signature=","[","{","``","x1","''",":","tf.TensorSpec","(","shape=","(","None",",","3",")",",","dtype=tf.float32",")",",","``","x2","''",":","tf.TensorSpec","(","shape=","(","None",",","4",")",",","dtype=tf.float32",")",",","}",",","]",",",")","``","`","Adding","an","endpoint","that","is","a","`","tf.function","`",":","``","`","python","@","tf.function","(",")","def","serving_fn","(","x",")",":","return","model","(","x",")","#","The","function","must","be","traced",",","i.e",".","it","must","be","called","at","least","once",".","serving_fn","(","tf.random.normal","(","shape=","(","2",",","3",")",")",")","export_archive","=","ExportArchive","(",")","export_archive.track","(","model",")","export_archive.add_endpoint","(","name=","''","serve","''",",","fn=serving_fn",")","``","`"]
code: def add_endpoint(self, name, fn, input_signature=None):
      """Register a new serving endpoint.
  
      Arguments:
          name: Str, name of the endpoint.
          fn: A function. It should only leverage resources
              (e.g. `tf.Variable` objects or `tf.lookup.StaticHashTable`
              objects) that are available on the models/layers
              tracked by the `ExportArchive` (you can call `.track(model)`
              to track a new model).
              The shape and dtype of the inputs to the function must be
              known. For that purpose, you can either 1) make sure that
              `fn` is a `tf.function` that has been called at least once, or
              2) provide an `input_signature` argument that specifies the
              shape and dtype of the inputs (see below).
          input_signature: Used to specify the shape and dtype of the
              inputs to `fn`. List of `tf.TensorSpec` objects (one
              per positional input argument of `fn`). Nested arguments are
              allowed (see below for an example showing a Functional model
              with 2 input arguments).
  
      Example:
  
      Adding an endpoint using the `input_signature` argument when the
      model has a single input argument:
  
      ```python
      export_archive = ExportArchive()
      export_archive.track(model)
      export_archive.add_endpoint(
          name="serve",
          fn=model.call,
          input_signature=[tf.TensorSpec(shape=(None, 3), dtype=tf.float32)],
      )
      ```
  
      Adding an endpoint using the `input_signature` argument when the
      model has two positional input arguments:
  
      ```python
      export_archive = ExportArchive()
      export_archive.track(model)
      export_archive.add_endpoint(
          name="serve",
          fn=model.call,
          input_signature=[
              tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
              tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
          ],
      )
      ```
  
      Adding an endpoint using the `input_signature` argument when the
      model has one input argument that is a list of 2 tensors (e.g.
      a Functional model with 2 inputs):
  
      ```python
      model = keras.Model(inputs=[x1, x2], outputs=outputs)
  
      export_archive = ExportArchive()
      export_archive.track(model)
      export_archive.add_endpoint(
          name="serve",
          fn=model.call,
          input_signature=[
              [
                  tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
                  tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
              ],
          ],
      )
      ```
  
      This also works with dictionary inputs:
  
      ```python
      model = keras.Model(inputs={"x1": x1, "x2": x2}, outputs=outputs)
  
      export_archive = ExportArchive()
      export_archive.track(model)
      export_archive.add_endpoint(
          name="serve",
          fn=model.call,
          input_signature=[
              {
                  "x1": tf.TensorSpec(shape=(None, 3), dtype=tf.float32),
                  "x2": tf.TensorSpec(shape=(None, 4), dtype=tf.float32),
              },
          ],
      )
      ```
  
      Adding an endpoint that is a `tf.function`:
  
      ```python
      @tf.function()
      def serving_fn(x):
          return model(x)
  
      # The function must be traced, i.e. it must be called at least once.
      serving_fn(tf.random.normal(shape=(2, 3)))
  
      export_archive = ExportArchive()
      export_archive.track(model)
      export_archive.add_endpoint(name="serve", fn=serving_fn)
      ```
      """
      if name in self._endpoint_names:
          raise ValueError(f"Endpoint name '{name}' is already taken.")
  
      if input_signature:
          if backend.backend() == "tensorflow":
              decorated_fn = tf.function(
                  fn, input_signature=input_signature
              )
          else:  # JAX backend
              fn = self._convert_jax2tf_function(fn, input_signature)
              decorated_fn = tf.function(
                  fn, input_signature=input_signature, autograph=False
              )
          self._endpoint_signatures[name] = input_signature
      else:
          if isinstance(fn, tf.types.experimental.GenericFunction):
              if not fn._list_all_concrete_functions():
                  raise ValueError(
                      f"The provided tf.function '{fn}' "
                      "has never been called. "
                      "To specify the expected shape and dtype "
                      "of the function's arguments, "
                      "you must either provide a function that "
                      "has been called at least once, or alternatively pass "
                      "an `input_signature` argument in `add_endpoint()`."
                  )
              decorated_fn = fn
          else:
              raise ValueError(
                  "If the `fn` argument provided is not a `tf.function`, "
                  "you must provide an `input_signature` argument to "
                  "specify the shape and dtype of the function arguments. "
                  "Example:\n\n"
                  "export_archive.add_endpoint(\n"
                  "    name='call',\n"
                  "    fn=model.call,\n"
                  "    input_signature=[\n"
                  "        tf.TensorSpec(\n"
                  "            shape=(None, 224, 224, 3),\n"
                  "            dtype=tf.float32,\n"
                  "        )\n"
                  "    ],\n"
                  ")"
              )
      setattr(self._tf_trackable, name, decorated_fn)
      self._endpoint_names.append(name)
  
imports: from absl import logging
  from keras import backend
  from keras.api_export import keras_export
  from keras.layers import Layer
  from keras.models import Functional
  from keras.models import Sequential
  from keras.utils import io_utils
  from keras.utils.module_utils import tensorflow
label_desc: Use image node_id 6 for calling the ExportArchive obj's underlying member method code with example usage: obj.add_endpoint(name, fn, input_signature) without return types