尝试加载我训练有素的Keras模型以进行进一步推断时
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,
})
我收到以下错误。这三个函数与我用来训练模型的函数相同,权重URL正确。错误消息什么都没告诉我。
file "/home/long/Desktop/bachelor-thesis/unet/pipeline.py", line 344, in <module>
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'
以下是我的代码如何构建模型:
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 > 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 > 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()
以下是我的损失函数的编码方式:
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
在我训练了二进制模型,将其保存并再次加载以进行推断之后,发生了错误。如您所见,为推理而导入的损失函数在训练阶段是相同的。所以我不太明白为什么会出现错误。而且我也不明白该错误意味着什么。
答案 0 :(得分:3)
您可以在load_model调用中尝试使用compile = False
参数。这将删除与优化器和损失函数有关的所有元数据,并且由于您具有重新初始化的函数,并且如果您不需要从上次停止的地方对其进行训练,那么我猜这将不是问题。
正如您所说的,它可以与compile = False一起使用,我认为问题可能出在您的自定义函数(用于损耗/优化器等)中,我无法指出问题的确切原因,可以尝试tf。而不是tf.keras.backend。如果需要的话。