多工况提前停车

2024-04-18 14:21:37 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在为推荐系统(项目推荐)进行多类分类,目前我正在使用sparse_categorical_crossentropyloss训练我的网络。因此,通过监视我的验证丢失来执行EarlyStopping是合理的,val_loss

tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=10)

这和预期的一样。然而,网络(推荐系统)的性能是通过平均精度-at-10来衡量的,并且在训练期间作为一项指标进行跟踪,如average_precision_at_k10。因此,我还可以使用以下指标执行提前停止:

tf.keras.callbacks.EarlyStopping(monitor='average_precision_at_k10', patience=10)

这也和预期的一样有效

我的问题: 有时验证损失增加,而at-10的平均精度正在提高,反之亦然。因此,当且仅当两种情况都恶化时,我需要监控它们,并提前停止。我想做的是:

tf.keras.callbacks.EarlyStopping(monitor=['val_loss', 'average_precision_at_k10'], patience=10)

这显然不起作用。你知道怎么做吗


Tags: 网络tf系统精度valatprecisionmonitor
3条回答

您可以通过创建自定义回调来实现这一点。下面的here.中提供了有关如何执行此操作的信息。下面是一些代码,说明了在自定义回调中可以执行的操作。我引用的文档显示了许多其他选项

class LRA(keras.callbacks.Callback): # subclass the callback class
# create class variables as below. These can be accessed in your code outside the class definition as LRA.my_class_variable, LRA.best_weights
    my_class_variable=something  # a class variable
    best_weights=model.get_weights() # another  class variable
# define an initialization function with parameters you want to feed to the callback
    def __init__(self, param1, param2, etc):
        super(LRA, self).__init__()
        self.param1=param1
        self.param2=param2
        etc for all parameters
        # write any initialization code you need here

    def on_epoch_end(self, epoch, logs=None):  # method runs on the end of each epoch
        v_loss=logs.get('val_loss')  # example of getting log data at end of epoch the validation loss for this epoch
        acc=logs.get('accuracy') # another example of getting log data 
        LRA.best_weights=model.get_weights() # example of setting class variable value
        print(f'Hello epoch {epoch} has just ended') # print a message at the end of every epoch
        lr=float(tf.keras.backend.get_value(self.model.optimizer.lr)) # get the current learning rate
        if v_loss > self.param1:
           new_lr=lr * self.param2
           tf.keras.backend.set_value(model.optimizer.lr, new_lr) # set the learning rate in the optimizer
        # write whatever code you need

我建议您创建自己的回调。 在接下来的部分中,我添加了一个解决方案,该解决方案可以监控精度和损失。您可以使用自己的度量值替换acc:

class CustomCallback(keras.callbacks.Callback):
    acc = {}
    loss = {}
    best_weights = None
    
    def __init__(self, patience=None):
        super(CustomCallback, self).__init__()
        self.patience = patience
    
    def on_epoch_end(self, epoch, logs=None):
        epoch += 1
        self.loss[epoch] = logs['loss']
        self.acc[epoch] = logs['accuracy']
    
        if self.patience and epoch > self.patience:
            # best weight if the current loss is less than epoch-patience loss. Simiarly for acc but when larger
            if self.loss[epoch] < self.loss[epoch-self.patience] and self.acc[epoch] > self.acc[epoch-self.patience]:
                self.best_weights = self.model.get_weights()
            else:
                # to stop training
                self.model.stop_training = True
                # Load the best weights
                self.model.set_weights(self.best_weights)
        else:
            # best weight are the current weights
            self.best_weights = self.model.get_weights()

请记住,如果您想要控制监控数量的最小变化(又名.min_delta),您必须将其集成到代码中

以下是有关如何构建custome回调的文档:custom_callback

在上面Gerry P的指导下,我成功地创建了自己的自定义EarlyStopping回调,并认为我可以在这里发布它,以防其他人希望实现类似的功能

如果两个验证损失在10时的平均精度没有改善patience个历元数,则执行提前停止

class CustomEarlyStopping(keras.callbacks.Callback):
    def __init__(self, patience=0):
        super(CustomEarlyStopping, self).__init__()
        self.patience = patience
        self.best_weights = None
        
    def on_train_begin(self, logs=None):
        # The number of epoch it has waited when loss is no longer minimum.
        self.wait = 0
        # The epoch the training stops at.
        self.stopped_epoch = 0
        # Initialize the best as infinity.
        self.best_v_loss = np.Inf
        self.best_map10 = 0

    def on_epoch_end(self, epoch, logs=None): 
        v_loss=logs.get('val_loss')
        map10=logs.get('val_average_precision_at_k10')

        # If BOTH the validation loss AND map10 does not improve for 'patience' epochs, stop training early.
        if np.less(v_loss, self.best_v_loss) and np.greater(map10, self.best_map10):
            self.best_v_loss = v_loss
            self.best_map10 = map10
            self.wait = 0
            # Record the best weights if current results is better (less).
            self.best_weights = self.model.get_weights()
        else:
            self.wait += 1
            if self.wait >= self.patience:
                self.stopped_epoch = epoch
                self.model.stop_training = True
                print("Restoring model weights from the end of the best epoch.")
                self.model.set_weights(self.best_weights)
                
    def on_train_end(self, logs=None):
        if self.stopped_epoch > 0:
            print("Epoch %05d: early stopping" % (self.stopped_epoch + 1))

然后将其用作:

model.fit(
    x_train,
    y_train,
    batch_size=64,
    steps_per_epoch=5,
    epochs=30,
    verbose=0,
    callbacks=[CustomEarlyStopping(patience=10)],
)

相关问题 更多 >