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

如何在Keras EarlyStopping中使用百分比delta?是否有支持百分比变化的方法?

如何在Keras EarlyStopping中使用百分比形式的delta?

确实,Keras自带的EarlyStopping回调只支持绝对数值的min_delta,没法直接设置百分比变化阈值。不过不用担心,咱们有几种靠谱的替代方法来实现基于百分比的早停逻辑,我给你详细说说:

方案一:自定义早停回调函数(最推荐)

这是最灵活的方式,完全能按照你的需求实现百分比判断逻辑。我们可以继承Keras的Callback类,自己编写监控指标的百分比变化判断逻辑。

给你写个完整的可直接用的例子:

from tensorflow.keras.callbacks import Callback

class PercentEarlyStopping(Callback):
    def __init__(self, monitor='val_loss', min_percent_delta=1.0, patience=0, mode='auto', verbose=0):
        super().__init__()
        self.monitor = monitor
        self.min_percent_delta = min_percent_delta / 100  # 把百分比转成小数方便计算
        self.patience = patience
        self.verbose = verbose
        self.wait = 0
        self.stopped_epoch = 0
        
        # 自动判断监控指标的优化方向:loss这类是越小越好,acc这类是越大越好
        if mode == 'auto':
            self.mode = 'min' if 'loss' in self.monitor else 'max'
        else:
            self.mode = mode
            
        # 初始化最佳值:min模式设为无穷大,max模式设为负无穷
        self.best = float('inf') if self.mode == 'min' else -float('inf')

    def on_epoch_end(self, epoch, logs=None):
        current = logs.get(self.monitor)
        if current is None:
            print(f"警告:监控的指标{self.monitor}未在logs中找到!")
            return
        
        # 计算百分比变化并判断是否有有效提升
        if self.mode == 'min':
            # 针对loss:计算相对最佳值的下降百分比
            percent_change = (self.best - current) / self.best * 100
            has_improved = percent_change >= self.min_percent_delta * 100
        else:
            # 针对acc:计算相对最佳值的上升百分比
            percent_change = (current - self.best) / self.best * 100
            has_improved = percent_change >= self.min_percent_delta * 100
            
        if has_improved:
            self.best = current
            self.wait = 0  # 有提升就重置等待计数器
        else:
            self.wait += 1
            if self.wait >= self.patience:
                self.stopped_epoch = epoch
                self.model.stop_training = True  # 触发早停

    def on_train_end(self, logs=None):
        if self.stopped_epoch > 0 and self.verbose > 0:
            print(f'Epoch {self.stopped_epoch + 1}: 触发早停')

怎么用这个自定义回调?

比如你想监控验证损失,要求损失相对当前最佳值下降至少2%才算有提升,且连续3个epoch没提升就停止训练:

model.fit(
    x_train, y_train,
    validation_data=(x_val, y_val),
    epochs=100,  # 设个足够大的总epoch数
    callbacks=[PercentEarlyStopping(monitor='val_loss', min_percent_delta=2.0, patience=3, verbose=1)]
)

方案二:转换监控指标为百分比变化值

另一种思路是,在训练过程中实时计算监控指标的百分比变化,把这个变化值作为新的指标,然后用原生的EarlyStopping来监控这个新指标。

举个例子,还是以验证损失为例:

from tensorflow.keras.callbacks import EarlyStopping, LambdaCallback

# 用来存储历史的验证损失值
history_val_loss = []

def calculate_percent_change(epoch, logs):
    current_loss = logs.get('val_loss')
    if len(history_val_loss) > 0:
        prev_loss = history_val_loss[-1]
        # 计算损失的相对下降百分比(值越大说明下降越多)
        percent_drop = (prev_loss - current_loss) / prev_loss * 100
        logs['val_loss_percent_drop'] = percent_drop
    history_val_loss.append(current_loss)

# 用LambdaCallback来计算并添加新指标到logs中
percent_callback = LambdaCallback(on_epoch_end=calculate_percent_change)

# 用原生EarlyStopping监控这个新的百分比下降指标
early_stop = EarlyStopping(
    monitor='val_loss_percent_drop',
    min_delta=2.0,  # 这里的delta就是我们要的百分比阈值
    patience=3,
    mode='max',  # 因为百分比下降值越大越好
    verbose=1
)

# 训练时同时传入两个回调
model.fit(
    x_train, y_train,
    validation_data=(x_val, y_val),
    epochs=100,
    callbacks=[percent_callback, early_stop]
)

不过这个方案有个小问题:第一个epoch没有前序值,没法计算百分比变化,所以前几个epoch的判断会有点特殊。如果你的patience设置得大于1,这个影响不大,但整体灵活性不如自定义回调。

最后总结

如果需要精确控制百分比早停的逻辑,自定义回调函数肯定是最优选择——你可以随时调整判断规则,比如改成基于初始值的百分比变化,或者处理除以零的极端情况。而转换指标的方式更适合快速验证想法,但细节上需要多留意。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:09:07