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

新手求助:无model.fit()时如何用train_step保存最佳模型或适配model.fit()?

问题:自定义Transformer图像Caption训练流程中保存最佳模型权重

我是机器学习新手,正在训练Transformer图像Caption模型,想在30个epochs里只保存性能最好的模型权重,但现在的代码会保存全部30个模型:

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
    name='train_accuracy')

transformer = Transformer(num_layer, d_model, num_heads, dff, row_size, col_size, target_vocab_size,
                          max_pos_encoding=target_vocab_size, rate=dropout_rate)

@tf.function
def train_step(img_tensor, tar):
    tar_inp = tar[:, :-1]
    tar_real = tar[:, 1:]

    dec_mask = create_masks_decoder(tar_inp)

    with tf.GradientTape() as tape:
        predictions, _ = transformer(img_tensor, tar_inp,
                                     True,
                                     dec_mask)
        loss = loss_function(tar_real, predictions)

    gradients = tape.gradient(loss, transformer.trainable_variables)
    optimizer.apply_gradients(zip(gradients, transformer.trainable_variables))

    train_loss(loss)
    train_accuracy(tar_real, predictions)

for epoch in range(30):
    start = time.time()

    train_loss.reset_states()
    train_accuracy.reset_states()

    for (batch, (img_tensor, tar)) in enumerate(dataset):
        train_step(img_tensor, tar)

        if batch % 50 == 0:
            print('Epoch {} Batch {} Loss {:.4f} Accuracy {:.4f}'.format(
                epoch + 1, batch, train_loss.result(), train_accuracy.result()))

    print('Epoch {} Loss {:.4f} Accuracy {:.4f}'.format(epoch + 1,
                                                        train_loss.result(),
                                                        train_accuracy.result()))

    print('Time taken for 1 epoch: {} secs\n'.format(time.time() - start))
    model_name = 'image_caption_transformer_' + str(epoch + 1) + '.h5'
    transformer.save_weights(model_name)

想试试Keras的ModelCheckpoint,但不知道怎么在自定义train_step的流程里用,有没有办法基于现有代码保存最佳模型,或者修改代码适配model.fit()?


解决方案

方案一:在自定义训练循环中手动实现最佳模型保存

不用大改现有代码,只需要跟踪最佳性能指标(更建议加验证集用验证指标,避免过拟合,这里先以训练准确率为例),每个epoch结束后对比当前指标和历史最佳,只有当当前更好时才保存权重。

修改后的代码示例:

# 初始化最佳准确率,初始设为0
best_acc = 0.0
# 如果用损失作为判断标准,初始设为极大值:best_loss = float('inf')

train_loss = tf.keras.metrics.Mean(name='train_loss')
train_accuracy = tf.keras.metrics.SparseCategoricalAccuracy(
    name='train_accuracy')

transformer = Transformer(num_layer, d_model, num_heads, dff, row_size, col_size, target_vocab_size,
                          max_pos_encoding=target_vocab_size, rate=dropout_rate)

@tf.function
def train_step(img_tensor, tar):
    tar_inp = tar[:, :-1]
    tar_real = tar[:, 1:]

    dec_mask = create_masks_decoder(tar_inp)

    with tf.GradientTape() as tape:
        predictions, _ = transformer(img_tensor, tar_inp,
                                     True,
                                     dec_mask)
        loss = loss_function(tar_real, predictions)

    gradients = tape.gradient(loss, transformer.trainable_variables)
    optimizer.apply_gradients(zip(gradients, transformer.trainable_variables))

    train_loss(loss)
    train_accuracy(tar_real, predictions)

for epoch in range(30):
    start = time.time()

    train_loss.reset_states()
    train_accuracy.reset_states()

    for (batch, (img_tensor, tar)) in enumerate(dataset):
        train_step(img_tensor, tar)

        if batch % 50 == 0:
            print('Epoch {} Batch {} Loss {:.4f} Accuracy {:.4f}'.format(
                epoch + 1, batch, train_loss.result(), train_accuracy.result()))

    current_acc = train_accuracy.result().numpy()
    current_loss = train_loss.result().numpy()
    
    print('Epoch {} Loss {:.4f} Accuracy {:.4f}'.format(epoch + 1,
                                                        current_loss,
                                                        current_acc))

    # 对比准确率,更新并保存最佳模型
    if current_acc > best_acc:
        best_acc = current_acc
        print(f"新最佳准确率: {best_acc:.4f}, 保存模型...")
        transformer.save_weights('best_image_caption_transformer.h5')
    
    # 如果用损失判断,替换成这段:
    # if current_loss < best_loss:
    #     best_loss = current_loss
    #     print(f"新最佳损失: {best_loss:.4f}, 保存模型...")
    #     transformer.save_weights('best_image_caption_transformer.h5')

    print('单轮训练耗时: {} 秒\n'.format(time.time() - start))

方案二:修改代码适配model.fit()使用ModelCheckpoint

把Transformer包装成Keras的自定义Model类,重写train_step方法,这样就能直接用model.fit(),并搭配ModelCheckpoint回调自动保存最佳模型。

代码示例:

class ImageCaptionTransformer(tf.keras.Model):
    def __init__(self, num_layer, d_model, num_heads, dff, row_size, col_size, target_vocab_size, dropout_rate):
        super().__init__()
        self.transformer = Transformer(num_layer, d_model, num_heads, dff, row_size, col_size, target_vocab_size,
                                      max_pos_encoding=target_vocab_size, rate=dropout_rate)
    
    def train_step(self, data):
        img_tensor, tar = data
        tar_inp = tar[:, :-1]
        tar_real = tar[:, 1:]

        dec_mask = create_masks_decoder(tar_inp)

        with tf.GradientTape() as tape:
            predictions, _ = self.transformer(img_tensor, tar_inp,
                                             training=True,
                                             look_ahead_mask=dec_mask)
            loss = self.compiled_loss(tar_real, predictions)

        gradients = tape.gradient(loss, self.trainable_variables)
        self.optimizer.apply_gradients(zip(gradients, self.trainable_variables))

        self.compiled_metrics.update_state(tar_real, predictions)
        return {m.name: m.result() for m in self.metrics}

# 初始化模型
model = ImageCaptionTransformer(num_layer, d_model, num_heads, dff, row_size, col_size, target_vocab_size, dropout_rate)

# 编译模型,指定优化器、损失和指标
model.compile(
    optimizer=optimizer,
    loss=loss_function,
    metrics=[tf.keras.metrics.SparseCategoricalAccuracy()]
)

# 设置ModelCheckpoint回调,保存最佳模型
checkpoint_callback = tf.keras.callbacks.ModelCheckpoint(
    filepath='best_model.h5',
    monitor='sparse_categorical_accuracy',  # 对应你用的指标
    save_best_only=True,
    save_weights_only=True,  # 和你之前只保存权重的操作一致
    mode='max',  # 准确率越大越好,用损失的话改成'min'
    verbose=1
)

# 开始训练
model.fit(
    dataset,
    epochs=30,
    callbacks=[checkpoint_callback]
)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 10:48:19