【问题标题】:How can I create a Keras Learning Rate Schedule that updates based upon batches rather than epochs如何创建基于批次而不是时期更新的 Keras 学习率计划
【发布时间】:2026-02-12 01:40:02
【问题描述】:

我正在使用 Keras,并尝试创建一个学习率调度程序,该调度程序根据处理的批次数而不是 epoch 数进行调度。为此,我将调度代码插入到我的“优化器”的get_updates 方法中。在大多数情况下,我尝试将常规 Python 变量用于在给定训练运行期间保持不变的值,并将计算图节点仅用于实际变化的参数。

我的 2 个问题是:

  1. 如果将下面的代码放在 Keras Optimizerget_updates 方法中,它是否看起来应该像学习率调度程序一样正常运行。

  2. 如何将此代码嵌入到类似于 LearningRateScheduler 的类中,但根据批次数而不是 epoch 数进行调度?


    #Copying graph node that stores original value of learning rate
    lr = self.lr 

    # Checking whether learning rate schedule is to be used
    if self.initial_lr_decay > 0:
        # this decay mimics exponential decay from 
        # tensorflow/python/keras/optimizer_v2/exponential_decay 

        # Get value of current number of processed batches from graph node
        # and convert to numeric value for use in K.pow()
        curr_batch = float(K.get_value(self.iterations))

        # Create graph node containing lr decay factor
        # Note: self.lr_decay_steps is a number, not a node
        #       self.lr_decay is a node, not a number
        decay_factor =  K.pow(self.lr_decay, (curr_batch / self.lr_decay_steps)) 

        # Reassign lr to graph node formed by
        # product of graph node containing decay factor
        # and graph node containing original learning rate.
        lr = lr * decay_factor

        # Get product of two numbers to calculate number of batches processed
        # in warmup period
        num_warmup_batches = self.steps_per_epoch_num * self.warmup_epochs

        # Make comparisons between numbers to determine if we're in warmup period
        if (self.warmup_epochs > 0) and (curr_batch < num_warmup_batches):

            # Create node with value of learning rate by multiplying a number
            # by a node, and then dividing by a number
            lr = (self.initial_lr  *
                  K.cast(self.iterations, K.floatx()) / curr_batch)

【问题讨论】:

    标签: keras keras-2


    【解决方案1】:

    比弄乱 Keras 源代码更容易(这是可能的,但它既复杂又合理),您可以使用回调。

    from keras.callbacks import LambdaCallback
    
    total_batches = 0
    def what_to_do_when_batch_ends(batch, logs):
       total_batches += 1 #or use the "batch" variable,
                          #which is the batch index of the last finished batch
    
       #change learning rate at will
       if your_condition == True:
           keras.backend.set_value(model.optimizer.lr, newLrValueAsPythonFloat)
    

    训练时,使用回调:

    lrUpdater = LambdaCallback(on_batch_end = what_to_do_when_batch_ends)
    model.fit(........, callbacks = [lrUpdater, ...other callbacks...])
    

    【讨论】:

    • - 谢谢,我会阅读 LambdaCallback。但是我不能只使用 model.optimizer.iterations 来跟踪我的批次吗?
    • 训练的时候不是很容易,它是一个符号张量,你不能评估它,那么你需要使用基于张量函数而不是ifs的条件,以及一个更新函数。这很复杂。可能,但很复杂。
    • 嗨丹尼尔,我在这里遇到了同样的问题(想让学习率基于批次而不是时代衰减)。您的答案中的解决方案很清楚。但是我还有一个关于你用来在“keras.backend.set_value(model.optimizer.lr, newLrValueAsPythonFloat)”中获取学习率的“模型”变量的问题。在函数而不是回调中调用模型是否可行。我意思是在回调中,我可以从self.model中调用模型,但是在我可以直接建模的函数中,会出现关于未解析的“模型”的错误。期待您的回复。提前谢谢。
    • 对不起,错误不是未解析的模型而是未定义名称'model'。
    • 如果您没有定义model,请使用您定义的模型。如您所见,lambda 回调不采用“self”。因此,您可以选择创建自己的回调,然后从您创建的自定义回调中获取self.model,或者您可以使用定义模型的变量。运气好的话,您可以使用 lrUpdater.model 从回调中获取模型,从未测试过,可能有怪癖。