如何在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
相关产品推荐
相关产品推荐

