Keras自定义三参数损失报错及TF2.2.0更新后新问题求助
先解决第二个报错:AttributeError: module 'tensorflow' has no attribute 'get_default_graph'
这个问题的核心是你混合导入了原生Keras和TensorFlow Keras模块,这在TensorFlow 2.x版本里会导致严重的兼容性问题。
看你的导入代码:
import tensorflow as tf from tensorflow import keras from tensorflow.keras import Input, optimizers from tensorflow.keras.models import Sequential, load_model # 这里用了原生keras的导入,和tf.keras冲突了! from keras.layers.convolutional import Conv3D, Conv3DTranspose from keras.layers.normalization import BatchNormalization from keras.layers import Cropping3D, UpSampling3D, AveragePooling3D
TensorFlow 2.x已经将Keras整合到自身框架里,所有Keras相关的导入都应该统一使用tensorflow.keras的路径,修改后的导入代码应该是:
import tensorflow as tf from tensorflow import keras from tensorflow.keras import Input, optimizers from tensorflow.keras.models import Sequential, load_model # 全部改为tf.keras的导入 from tensorflow.keras.layers import Conv3D, Conv3DTranspose from tensorflow.keras.layers import BatchNormalization from tensorflow.keras.layers import Cropping3D, UpSampling3D, AveragePooling3D
原生Keras(即单独安装的keras包)和tensorflow.keras是两个独立的实现,混用会导致后端上下文混乱,比如原生Keras试图调用TensorFlow的旧版API(tf.get_default_graph在TF 2.x默认eager模式下的使用逻辑和原生Keras不兼容)。
解决第一个报错:AttributeError: 'Model' object has no attribute '_callable_losses'
这个错误源于你构建模型和添加损失函数的方式有问题,主要有以下几个问题需要修正:
1. 重复创建Model对象
在get_loss方法里,你先后两次创建了Model并赋值给self._model,这是完全多余的,而且会导致模型状态混乱:
# 第一次创建(无用) self._model = Model(inputs=[inputs], outputs=[outputs]) # 第二次创建 y_true = Input(self._input_shape, name = 'y_true') is_weight = Input(self._input_shape, name = 'is_weight') self._model = Model(inputs=[inputs, y_true, is_weight], outputs=[outputs])
你只需要保留第二次的Model创建即可,因为你的模型需要接收三个输入:原始输入、真实标签、权重。
2. add_loss的正确用法
在Keras中使用add_loss时,损失函数的参数必须是模型输入张量或者由模型输入张量推导而来的张量。你的weighted_dice_loss需要接收y_true、outputs(模型输出)、is_weight,这三个都是模型的输入或输出,所以需要确保损失函数是一个基于这些张量的计算表达式。
另外,在TensorFlow 2.x的Keras中,add_loss可以直接接收损失张量,但需要确保模型在编译时loss=None(你已经这么做了)。
3. 修正后的get_loss方法示例
def get_loss(self, inputs, outputs): # 定义额外的输入张量 y_true = Input(shape=self._input_shape, name='y_true') is_weight = Input(shape=self._input_shape, name='is_weight') # 只创建一次Model,包含所有输入 self._model = Model(inputs=[inputs, y_true, is_weight], outputs=[outputs]) # 确保weighted_dice_loss是一个返回张量的函数,基于传入的三个张量计算损失 loss = weighted_dice_loss(y_true, outputs, is_weight) self._model.add_loss(loss) # 编译模型,loss设为None,metrics正常设置 self._model.compile(optimizer=self._optimiser, loss=None, metrics=[dice_coef]) return self._model
4. 额外注意点
- 确保你的
weighted_dice_loss函数是用TensorFlow/Keras的张量操作实现的,不能使用NumPy操作,否则会导致张量和数组不兼容的问题。 - 在训练模型时,你需要传入三个输入:原始输入数据、真实标签数据、权重数据,比如:
model.fit([x_train, y_train, weight_train], epochs=10, batch_size=32)
内容的提问来源于stack exchange,提问作者Daniel

