自定义Keras优化器报错ValueError:缺失学习率求助
解决TensorFlow自定义AdamSGD优化器的学习率缺失报错
问题根源
Keras的Optimizer基类通过**属性(property)**管理learning_rate,它的getter方法会检查self._learning_rate是否存在。你直接赋值self.learning_rate时,基类的_learning_rate尚未完成初始化,触发了报错。同时,手动用K.variable创建优化器变量的方式不符合Keras 2.x的标准规范,容易导致变量跟踪问题。
修复方案
标准实现方式(推荐)
继承tf.keras.optimizers.Optimizer,通过基类构造函数传递学习率,并使用add_weight方法创建优化器的所有变量,这是Keras官方推荐的自定义优化器写法:
import tensorflow as tf from tensorflow.keras import backend as K class AdamSGD(tf.keras.optimizers.Optimizer): def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, momentum=0.0, epsilon=None, decay=0.0, name='AdamSGD', **kwargs): # 将学习率传递给基类,由基类自动维护self._learning_rate super(AdamSGD, self).__init__(learning_rate=lr, name=name, **kwargs) self.epsilon = epsilon or K.epsilon() # 使用add_weight创建优化器变量,确保被Keras正确跟踪 self.beta_1 = self.add_weight( name='beta_1', shape=[], initializer=tf.keras.initializers.Constant(beta_1), trainable=False ) self.beta_2 = self.add_weight( name='beta_2', shape=[], initializer=tf.keras.initializers.Constant(beta_2), trainable=False ) self.momentum = self.add_weight( name='momentum', shape=[], initializer=tf.keras.initializers.Constant(momentum), trainable=False ) self.decay = self.add_weight( name='decay', shape=[], initializer=tf.keras.initializers.Constant(decay), trainable=False ) self.iterations = self.add_weight( name='iterations', shape=[], dtype='int64', initializer=tf.keras.initializers.Constant(0), trainable=False ) # 必须重写update_step方法(TF 2.4+),实现参数更新逻辑 def update_step(self, gradient, variable): # 此处添加你的AdamSGD核心更新逻辑 iteration = tf.cast(self.iterations, tf.float32) lr = self.learning_rate * (1.0 / (1.0 + self.decay * iteration)) # 获取/初始化一阶矩、二阶矩变量 m = self.get_slot(variable, 'm') v = self.get_slot(variable, 'v') # 示例更新逻辑(根据你的算法调整) m.assign(self.beta_1 * m + (1. - self.beta_1) * gradient) v.assign(self.beta_2 * v + (1. - self.beta_2) * tf.square(gradient)) m_hat = m / (1. - tf.pow(self.beta_1, iteration + 1)) v_hat = v / (1. - tf.pow(self.beta_2, iteration + 1)) # 结合动量更新变量 var_update = variable - lr * (m_hat / (tf.sqrt(v_hat) + self.epsilon) + self.momentum * m) variable.assign(var_update) # 更新迭代次数 self.iterations.assign_add(1) # 重写get_config方法,保存优化器配置 def get_config(self): config = super(AdamSGD, self).get_config() config.update({ 'lr': self._serialize_hyperparameter('learning_rate'), 'beta_1': self._serialize_hyperparameter('beta_1'), 'beta_2': self._serialize_hyperparameter('beta_2'), 'momentum': self._serialize_hyperparameter('momentum'), 'epsilon': self.epsilon, 'decay': self._serialize_hyperparameter('decay'), }) return config # 初始化参数的slot(如Adam的m、v变量) def build(self, var_list): super(AdamSGD, self).build(var_list) for var in var_list: self.add_slot(var, 'm') self.add_slot(var, 'v')
临时修复方案(不推荐)
如果不想修改整体实现逻辑,可直接赋值self._learning_rate而非self.learning_rate,绕过基类的属性检查:
def __init__(self, lr=0.001, beta_1=0.9, beta_2=0.999, momentum=0.0, epsilon=None, decay=0.0, name='AdamSGD', **kwargs): super(AdamSGD, self).__init__(name=name, **kwargs) self.iterations = K.variable(0, dtype='int64', name='iterations') # 直接赋值_learning_rate,避免触发property检查 self._learning_rate = K.variable(lr, name='lr') self.beta_1 = K.variable(beta_1, name='beta_1') self.beta_2 = K.variable(beta_2, name='beta_2') self.momentum = K.variable(momentum, name='momentum') self.epsilon = epsilon or K.epsilon() self.decay = K.variable(decay, name='decay')
关键注意事项
- TensorFlow 2.x中,自定义优化器必须继承
tf.keras.optimizers.Optimizer,而非旧版的keras.optimizers.Optimizer。 - 必须重写
update_step(或旧版的_resource_apply_dense/_resource_apply_sparse)方法实现参数更新逻辑。 - 优化器的超参数和变量建议用
add_weight创建,确保能被Keras正确序列化、保存和加载。
内容的提问来源于stack exchange,提问作者Abhisek Ganguly
相关产品推荐
相关产品推荐

