title: Model cannot be saved because the forward pass of the model is not defined
body: <p>I am trying to save a model after training. The code trains the model and then I am trying to save the model.</p>
  <p>But at the time of saving the model, I get the following error from the model.save API call:</p>
  <pre><code>class SiameseModel(Model):
      &quot;&quot;&quot;The Siamese Network model with a custom training and testing loops.
      Computes the triplet loss using the three embeddings produced by the
      Siamese Network.
      The triplet loss is defined as:
         L(A, P, N) = max(‖f(A) - f(P)‖² - ‖f(A) - f(N)‖² + margin, 0)
      &quot;&quot;&quot;
  
      def __init__(self, siamese_network, margin=0.5):
          super(SiameseModel, self).__init__()
          self.siamese_network = siamese_network
          self.margin = margin
          self.loss_tracker = metrics.Mean(name=&quot;loss&quot;)
  
      def call(self, inputs):
          return self.siamese_network(inputs)
  
      def train_step(self, data):
          # GradientTape is a context manager that records every operation that
          # you do inside. We are using it here to compute the loss so we can get
          # the gradients and apply them using the optimizer specified in
          # `compile()`.
          with tf.GradientTape() as tape:
              loss = self._compute_loss(data)
  
          # Storing the gradients of the loss function with respect to the
          # weights/parameters.
          gradients = tape.gradient(loss, self.siamese_network.trainable_weights)
  
          # Applying the gradients on the model using the specified optimizer
          self.optimizer.apply_gradients(
              zip(gradients, self.siamese_network.trainable_weights)
          )
  
          # Let's update and return the training loss metric.
          self.loss_tracker.update_state(loss)
          return {&quot;loss&quot;: self.loss_tracker.result()}
  
      def test_step(self, data):
          loss = self._compute_loss(data)
  
          # Let's update and return the loss metric.
          self.loss_tracker.update_state(loss)
          return {&quot;loss&quot;: self.loss_tracker.result()}
  
      def _compute_loss(self, data):
          # The output of the network is a tuple containing the distances
          # between the anchor and the positive example, and the anchor and
          # the negative example.
          ap_distance, an_distance = self.siamese_network(data)
  
          # Computing the Triplet Loss by subtracting both distances and
          # making sure we don't get a negative value.
          loss = ap_distance - an_distance
          loss = tf.maximum(loss + self.margin, 0.0)
          return loss
  
      @property
      def metrics(self):
          # We need to list our metrics here so the `reset_states()` can be
          # called automatically.
          return [self.loss_tracker]
  
  
  &quot;&quot;&quot;
  ## Training
  We are now ready to train our model.
  &quot;&quot;&quot;
  
  siamese_model = SiameseModel(siamese_network)
  siamese_model.compile(optimizer=optimizers.Adam(0.0001))
  siamese_model.fit(train_dataset, epochs=10, validation_data=val_dataset)
  
  siamese_model.save(&quot;./siamese_model.pt&quot;)
  </code></pre>
  <p>Complete code could be found here: <a href="https://github.com/keras-team/keras-io/blob/master/examples/vision/siamese_network.py#L272" rel="nofollow noreferrer">https://github.com/keras-team/keras-io/blob/master/examples/vision/siamese_network.py#L272</a></p>
  <p>Error details is shown below:</p>
  <pre><code>ValueError: Model &lt;siamese_model.SiameseModel object at 0x17e0c7b50&gt; cannot be saved either because the input shape is not available or because the forward pass of the model is not defined.To define a forward pass, please override `Model.call()`. To specify an input shape, either call `build(input_shape)` directly, or call the model on actual data using `Model()`, `Model.fit()`, or `Model.predict()`. If you have a custom training step, please make sure to invoke the forward pass in train step through `Model.__call__`, i.e. `model(inputs)`, as opposed to `model.call()`.
  </code></pre>