title: tensorflow/keras "An op outside of the function building code is being passed a 'Graph' Tensor"
body: <p>I'm a newcomer to Tensorflow/Keras, and I've been following along with the book Hands-On Machine Learning with Scikit-Learn and Tensorflow. Chapter 12 deals with customizing Tensorflow, and following along with the associated notebook (<a href="https://github.com/ageron/handson-ml2/blob/master/12_custom_models_and_training_with_tensorflow.ipynb" rel="nofollow noreferrer">here</a>) I've hit the following custom model:</p>
  <pre class="lang-py prettyprint-override"><code>class ReconstructingRegressor(keras.models.Model):
      def __init__(self, output_dim, **kwargs):
          super().__init__(**kwargs)
          self.hidden = [keras.layers.Dense(30, activation=&quot;selu&quot;,
                                            kernel_initializer=&quot;lecun_normal&quot;)
                         for _ in range(5)]
          self.out = keras.layers.Dense(output_dim)
  
      def build(self, batch_input_shape):
          n_inputs = batch_input_shape[-1]
          self.reconstruct = keras.layers.Dense(n_inputs)
          super().build(batch_input_shape)
          
      def call(self, inputs, training=None):
          Z = inputs
          for layer in self.hidden:
              Z = layer(Z)
          reconstruction = self.reconstruct(Z)
  
          recon_loss = tf.reduce_mean(tf.square(reconstruction - inputs))        
          self.add_loss(0.05 * recon_loss)
  
          return self.out(Z)
  </code></pre>
  <p>When I go to train using this model, I get the following error:</p>
  <pre><code>TypeError: An op outside of the function building code is being passed
  a &quot;Graph&quot; tensor. It is possible to have Graph tensors
  leak out of the function building context by including a
  tf.init_scope in your function building code.
  For example, the following function will fail:
    @tf.function
    def has_init_scope():
      my_constant = tf.constant(1.)
      with tf.init_scope():
        added = my_constant * 2
  The graph tensor has name: mul:0
  </code></pre>
  <p>The problem is <code>self.add_loss(0.05 * recon_loss)</code>; after commenting that out everything runs fine. Presumably <code>recon_loss</code> is the <code>&quot;Graph&quot; tensor</code> and <code>self.add_loss()</code> is the <code>op outside of the function building code</code>, but -- if that applies to <code>add_loss()</code> -- I don't know how I would add to the loss from within <code>call()</code>.</p>
  <p>Full disclosure: I'm using Tensorflow 2.3 when the book was written with 2.1 in mind, so I'm not really following instructions. That said, I'm really curious how to fix this and at my current level of knowledge I feel essentially powerless. It <em>seems</em> like it should work -- how else to add to the loss function? Any help would be appreciated here.</p>
  <p>Full example:</p>
  <pre class="lang-py prettyprint-override"><code>import tensorflow as tf
  from tensorflow import keras
  
  from sklearn.datasets import fetch_california_housing
  from sklearn.model_selection import train_test_split
  from sklearn.preprocessing import StandardScaler
  
  housing = fetch_california_housing()
  X_train_full, X_test, y_train_full, y_test = train_test_split(
      housing.data, housing.target.reshape(-1, 1), random_state=42)
  X_train, X_valid, y_train, y_valid = train_test_split(
      X_train_full, y_train_full, random_state=42)
  
  scaler = StandardScaler()
  X_train_scaled = scaler.fit_transform(X_train)
  X_valid_scaled = scaler.transform(X_valid)
  X_test_scaled = scaler.transform(X_test)
  
  class ReconstructingRegressor(keras.models.Model):
      def __init__(self, output_dim, **kwargs):
          super().__init__(**kwargs)
          self.hidden = [keras.layers.Dense(30, activation=&quot;selu&quot;,
                                            kernel_initializer=&quot;lecun_normal&quot;)
                         for _ in range(5)]
          self.out = keras.layers.Dense(output_dim)
  
      def build(self, batch_input_shape):
          n_inputs = batch_input_shape[-1]
          self.reconstruct = keras.layers.Dense(n_inputs)
          super().build(batch_input_shape)
          
      def call(self, inputs, training=None):
          Z = inputs
          for layer in self.hidden:
              Z = layer(Z)
          reconstruction = self.reconstruct(Z)
          recon_loss = tf.reduce_mean(tf.square(reconstruction - inputs))
          
          self.add_loss(0.05 * recon_loss)
  
          return self.out(Z)
  
  model = ReconstructingRegressor(1, dynamic=True)
  model.compile(loss=&quot;mse&quot;, optimizer=&quot;nadam&quot;)
  history = model.fit(X_train_scaled, y_train, epochs=2)
  </code></pre>