自定义tf.keras模型定义get_grad仍报No gradients错误原因问询
核心原因
你自定义的get_grad方法不属于TensorFlow Keras Model类的官方公开接口,Keras的fit训练流程完全不会主动调用这个方法,你按照自己的习惯命名的梯度计算方法对Keras来说是无效的。
具体错误点
- 你调用
model.compile()时没有传入任何损失函数,Keras不知道你要优化的目标是什么,自然不会自动计算梯度,这是报错的直接原因。 - 你写的
get_grad方法第一行就执行了return self.auto_encoder.get_grad(X,Y),后面的梯度计算逻辑永远不会执行,属于语法逻辑错误。 - 你在
get_loss中直接使用λ变量,但你在__init__中定义的是类属性self.λ,直接写λ会抛出变量未定义的错误。 - 你尝试自己计算梯度时,
tape.gradient(L,tf.ones(self.input.shape))的第二个参数传入的是全1张量,没有指向模型的可训练权重,就算执行了也得不到网络参数的梯度。 - 你的
call方法返回两个值(自编码器输出、z变量),但fit时传入的y只有一组输入,Keras默认的损失计算逻辑无法匹配输出和标签的结构,也会导致梯度计算失败。
修复建议
如果要接入自定义损失逻辑,不需要自己实现梯度计算方法,按Keras的规范修改即可:
- 把自定义损失逻辑放到
train_step方法中,这是Keras开放的自定义训练流程接口,fit会自动调用这个方法:
class probablistic_model(tf.keras.Model): def __init__(self,dimension,sigma): super().__init__() self.z=probablistic_feature(dimension,sigma) self.auto_encoder=keras_auto_encoder(dimension[0], 30) self.λ=2e-1 def call(self,inputs): return self.auto_encoder(inputs),self.z def train_step(self, data): X = data with tf.GradientTape() as tape: Y, z = self(X, training=True) diff = (X - Y) diff = tf.norm(diff, ord=2, axis=1) diff *= 2 diff *= z loss = diff - self.λ * tf.norm(diff, ord=1) # 计算模型可训练参数的梯度 grads = tape.gradient(loss, self.trainable_variables) # 优化器更新参数 self.optimizer.apply_gradients(zip(grads, self.trainable_variables)) # 返回损失值用于日志打印 return {"loss": loss}
- 编译时传入优化器即可,不需要额外传入损失:
model.compile(optimizer="adam") model.fit(dataset, epochs=10)
内容的提问来源于stack exchange,提问作者material bug
相关产品推荐
相关产品推荐

