You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义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')

关键注意事项

  1. TensorFlow 2.x中,自定义优化器必须继承tf.keras.optimizers.Optimizer,而非旧版的keras.optimizers.Optimizer。
  2. 必须重写update_step(或旧版的_resource_apply_dense/_resource_apply_sparse)方法实现参数更新逻辑。
  3. 优化器的超参数和变量建议用add_weight创建,确保能被Keras正确序列化、保存和加载。

内容的提问来源于stack exchange,提问作者Abhisek Ganguly

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 15:50:44