title: Keras import model AttributeError: 'NoneType' object has no attribute 'op'
body: <p>While trying to loading my trained Keras model for further inference with</p>
  
  <pre><code>self.model = tf.keras.models.load_model(filepath=weight_url, custom_objects={
                  'dice_coef': dice_coef,
                  'iou_coef': iou_coef,
                  'bce_dice_coef': bce_dice_coef,
              })
  </code></pre>
  
  <p>I get the following error. Those three functions are the same I used to train my model, the weight URL is correct. The error message doesn't tell me anything.</p>
  
  <pre><code>file "/home/long/Desktop/bachelor-thesis/unet/pipeline.py", line 344, in &lt;module&gt;
      binary.inference_blood_cell_unet()
    File "/home/long/Desktop/bachelor-thesis/unet/pipeline.py", line 305, in inference_blood_cell_unet
      self.blood_cell_unet = UNet(weight_url=self.blood_cell_final_name, class_weights=self.blut_koerperchen_classweights, num_classes=2)
    File "/home/long/Desktop/bachelor-thesis/unet/model.py", line 39, in __init__
      'bce_dice_coef': bce_dice_coef,
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/save.py", line 146, in load_model
      return hdf5_format.load_model_from_hdf5(filepath, custom_objects, compile)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/keras/saving/hdf5_format.py", line 193, in load_model_from_hdf5
      model._make_train_function()
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/keras/engine/training.py", line 2116, in _make_train_function
      params=self._collected_trainable_weights, loss=self.total_loss)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/keras/optimizer_v2/optimizer_v2.py", line 500, in get_updates
      grads = self.get_gradients(loss, params)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/keras/optimizer_v2/optimizer_v2.py", line 391, in get_gradients
      grads = gradients.gradients(loss, params)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/ops/gradients_impl.py", line 158, in gradients
      unconnected_gradients)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/ops/gradients_util.py", line 550, in _GradientsHelper
      gradient_uid)
    File "/home/long/Desktop/bachelor-thesis/venv/lib/python3.7/site-packages/tensorflow_core/python/ops/gradients_util.py", line 166, in _DefaultGradYs
      with _maybe_colocate_with(y.op, gradient_uid, colocate_gradients_with_ops):
  AttributeError: 'NoneType' object has no attribute 'op'
  </code></pre>
  
  <p>Following is my code how the model is built:</p>
  
  <pre><code>import tensorflow as tf
  from tensorflow.keras.callbacks import ModelCheckpoint
  from tensorflow.keras.layers import Input, Conv2D, BatchNormalization, LeakyReLU, Dropout, MaxPooling2D, Conv2DTranspose
  from tensorflow.keras.layers import concatenate
  from tensorflow.keras.optimizers import Adam
  
  from unet.metrics import dice_coef, iou_coef, cce_dice_coef, weighted_loss, bce_dice_coef
  
  fil_coef = 4
  
  class UNet(UNetBase, DataHandlingBase):
      def __init__(self,
                   class_weights,
                   weight_url=None,
                   width=256,
                   height=256,
                   channel=3,
                   learning_rate=0.0005,
                   num_classes=2,
                   alpha=0.01,
                   dropout_rate=0.25):
          super().__init__(weight_url, width, height, channel, learning_rate, num_classes, alpha, dropout_rate)
          self.class_weights = class_weights
  
          if self.num_classes &gt; 2:
              self.loss_function = weighted_loss(cce_dice_coef, weights_list=self.class_weights)
          elif self.num_classes == 2:
              self.loss_function = bce_dice_coef
          else:
              raise Exception("Invalid num class: ", self.num_classes)
  
          if weight_url:
              self.model = tf.keras.models.load_model(filepath=weight_url, custom_objects={
                  'dice_coef': dice_coef,
                  'iou_coef': iou_coef,
                  'bce_dice_coef': bce_dice_coef,
                  'loss_function': self.loss_function
              })
          else:
              model_input = Input((self.height, self.width, self.channel))
              c1 = Conv2D(filters=16 * fil_coef, kernel_size=(3, 3), padding='same')(model_input)
              c1 = BatchNormalization()(c1)
              c1 = LeakyReLU(self.alpha)(c1)
              c1 = Dropout(self.dropout_rate)(c1)
              c1 = Conv2D(filters=16 * fil_coef, kernel_size=(3, 3), padding='same')(c1)
  
              ...
  
              c9 = BatchNormalization()(c9)
              c9 = LeakyReLU(self.alpha)(c9)
              c9 = Dropout(self.dropout_rate)(c9)
  
              if self.num_classes == 2:
                  output = Conv2D(1, kernel_size=(1, 1), activation='sigmoid')(c9)
              else:
                  output = Conv2D(self.num_classes, kernel_size=(1, 1), activation='softmax')(c9)
              self.model = tf.keras.Model(inputs=[model_input], outputs=[output])
  
              self.reinitialize()
  
      def reinitialize(self):
          if self.num_classes &gt; 2:
              self.model.compile(optimizer=Adam(lr=self.learning_rate),
                                 loss=self.loss_function,
                                 metrics=[dice_coef, iou_coef])
          else:
              self.model.compile(optimizer=Adam(lr=self.learning_rate),
                                 loss=self.loss_function,
                                 metrics=[dice_coef, iou_coef],
                                 class_weight=self.class_weights)
  
      def fit(self, X, Y, x=None, y=None,
              batch_size=params["batch_size"],
              epochs=params["epochs"],
              validation_split=params["validation_split"],
              checkpoint_path="temp/models/model-{epoch:02d}-{val_loss:.2f}.h5",
              patience=params["patience"],
              min_delta=params["min_delta"]):
          checkpoint = ModelCheckpoint(checkpoint_path,
                                       verbose=0,
                                       save_best_only=False,
                                       monitor='val_loss',
                                       mode='auto')
          if x is None and y is None:
              history = self.model.fit(X, Y,
                                       validation_split=validation_split,
                                       batch_size=batch_size,
                                       epochs=epochs,
                                       shuffle=True,
                                       callbacks=[checkpoint])
              return history
          elif x is not None and y is not None:
              history = self.model.fit(X, Y,
                                       verbose=0,
                                       steps_per_epoch=X.shape[0] // batch_size,
                                       validation_data=[x, y],
                                       validation_steps=x.shape[0] // batch_size,
                                       batch_size=batch_size,
                                       epochs=epochs,
                                       shuffle=True)
              return history
  
      def save_weights(self, url):
          self.model.save(url)
  
      def predict(self, X):
          return self.model.predict(X)
  
      def summary(self):
          log.info(f"Learning rate {self.learning_rate} Alpha {self.alpha} Dropout Rate {self.dropout_rate}")
          self.model.summary()
  </code></pre>
  
  <p>And here are how my loss functions coded:</p>
  
  <pre><code>import tensorflow as tf
  import tensorflow.keras.backend as K
  
  
  def weighted_loss(original_loss_function, weights_list):
      """
      Author: https://stackoverflow.com/questions/51793737/custom-loss-function-for-u-net-in-keras-using-class-weights-class-weight-not
      """
  
      def loss_function(true, pred):
          axis = -1  # if channels last
          # axis=  1 #if channels first
  
          # argmax returns the index of the element with the greatest value
          # done in the class axis, it returns the class index
          class_selectors = tf.cast(K.argmax(true, axis=axis), tf.int32)
          # if your loss is sparse, use only true as classSelectors
  
          # considering weights are ordered by class, for each class
          # true(1) if the class index is equal to the weight index
          class_selectors = [K.equal(i, class_selectors) for i in range(len(weights_list))]
  
          # casting boolean to float for calculations
          # each tensor in the list contains 1 where ground true class is equal to its index
          # if you sum all these, you will get a tensor full of ones.
          class_selectors = [K.cast(x, K.floatx()) for x in class_selectors]
  
          # for each of the selections above, multiply their respective weight
          weights = [sel * w for sel, w in zip(class_selectors, weights_list)]
  
          # sums all the selections
          # result is a tensor with the respective weight for each element in predictions
          weight_multiplier = weights[0]
          for i in range(1, len(weights)):
              weight_multiplier = weight_multiplier + weights[i]
  
          # make sure your originalLossFunc only collapses the class axis
          # you need the other axes intact to multiply the weights tensor
          loss = original_loss_function(true, pred)
          loss = loss * weight_multiplier
          return loss
  
      return loss_function
  
  
  @tf.function
  def cce_iou_coef(y_true, y_pred, smooth=1, cat_weight=1, iou_weight=1):
      return cat_weight * K.categorical_crossentropy(y_true, y_pred) + iou_weight * log_iou_coef(y_true, y_pred, smooth)
  
  
  @tf.function
  def cce_dice_coef(y_true, y_pred, smooth=1, cat_weight=1, dice_weight=1):
      return cat_weight * K.categorical_crossentropy(y_true, y_pred) + dice_weight * log_dice_coef(y_true, y_pred, smooth)
  
  
  @tf.function
  def bce_iou_coef(y_true, y_pred, smooth=1, cat_weight=1, iou_weight=1):
      return cat_weight * K.binary_crossentropy(y_true, y_pred) + iou_weight * log_iou_coef(y_true, y_pred, smooth)
  
  
  @tf.function
  def bce_dice_coef(y_true, y_pred, smooth=1, cat_weight=1, dice_weight=1):
      return cat_weight * K.binary_crossentropy(y_true, y_pred) + dice_weight * log_dice_coef(y_true, y_pred, smooth)
  
  
  @tf.function
  def log_iou_coef(y_true, y_pred, smooth=1):
      return - K.log(iou_coef(y_true, y_pred, smooth))
  
  
  @tf.function
  def log_dice_coef(y_true, y_pred, smooth=1):
      return -K.log(dice_coef(y_true, y_pred, smooth))
  
  
  @tf.function
  def iou_coef(y_true, y_pred, smooth=1):
      intersection = K.sum(K.abs(y_true * y_pred), axis=-1)
      union = K.sum(y_true, axis=-1) + K.sum(y_pred, axis=-1) - intersection
      iou = K.mean((intersection + smooth) / (union + smooth), axis=0)
      return iou
  
  
  @tf.function
  def dice_coef(y_true, y_pred, smooth=1):
      intersection = K.sum(y_true * y_pred, axis=-1)
      union = K.sum(y_true, axis=-1) + K.sum(y_pred, axis=-1)
      dice = K.mean((2. * intersection + smooth) / (union + smooth), axis=0)
      return dice
  </code></pre>
  
  <p>The error happens after I trained a binary model, saved it and loads it again for inference. As you can see the loss functions imported for inference are the same for the training phase. So I don't really understand why I get the error. And I don't understand what the error means, either.</p>