训练、验证与防止过拟合
监控 val_loss,应用 Dropout,并使用回调实现提前停止
训练、验证与防止过拟合 是 CoddyKit 上的免费 R Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 R Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 R Academy 课程共包含 4 节课。
训练集、验证集和测试集划分
深度学习需要将数据划分为三部分:训练集(模型学习参数)、验证集(训练期间监控泛化能力并调整超参数)和测试集(进行最终的无偏评估)。fit() 中的 validation_split 参数可以自动创建验证集。
# validation_split = 0.2 reserves last 20% as validation
history <- model |> fit(
x_train, y_train,
epochs = 50,
batch_size = 32,
validation_split = 0.2,
verbose = 0
)
# history contains train and val metrics per epoch
names(history$metrics)训练历史对象
fit() 返回的对象包含一个 $metrics 列表,其中每个训练轮次的每个记录指标各对应一项。调用 plot(history) 可以并排可视化训练曲线和验证曲线。如果两条曲线出现分离(训练效果改善而验证效果趋于停滞),则说明可能发生了过拟合。
# Training loss and accuracy over epochs
head(history$metrics$loss)
head(history$metrics$val_loss)
# Plot training curves
plot(history)
# Or create a custom ggplot
library(ggplot2)
df <- data.frame(
epoch = seq_along(history$metrics$loss),
train = history$metrics$loss,
val = history$metrics$val_loss
)
ggplot(df, aes(epoch)) +
geom_line(aes(y = train, colour = 'Train')) +
geom_line(aes(y = val, colour = 'Validation')) +
labs(y = 'Loss', title = 'Training Curves')检测过拟合
当训练损失持续下降,但验证损失开始上升时,就发生了过拟合。模型记住了训练数据,而不是学习可泛化的模式。表现包括:训练准确率和验证准确率之间存在较大差距,验证损失先出现明显的最低点,随后又上升。
# Overfitting is visible in the history
# Example of overfitting signatures:
cat('Epoch 5 — Train loss: 0.12, Val loss: 0.18\n')
cat('Epoch 10 — Train loss: 0.06, Val loss: 0.21\n')
cat('Epoch 20 — Train loss: 0.02, Val loss: 0.31\n')
# The model should have stopped at epoch 5!
# Strategies: early stopping, dropout, regularisation, more datacallback_early_stopping()
callback_early_stopping(monitor, patience, restore_best_weights) 会在所监控的指标不再改善时停止训练。patience 表示在上一次改善后要等待的训练轮次数。将 restore_best_weights = TRUE 设置为 TRUE,即可自动恢复最佳训练轮次的权重。
early_stop <- callback_early_stopping(
monitor = 'val_loss',
patience = 10, # wait 10 epochs
restore_best_weights = TRUE # rollback to best
)
history <- model |> fit(
x_train, y_train,
epochs = 200,
batch_size = 32,
validation_split = 0.2,
callbacks = list(early_stop),
verbose = 0
)
cat('Stopped at epoch:', length(history$metrics$loss))callback_reduce_lr_on_plateau()
当训练陷入停滞时,降低学习率通常可以重新推动模型取得进展。callback_reduce_lr_on_plateau(monitor, factor, patience) 会在所监控的指标经过 patience 个训练轮次仍未改善时,将当前学习率乘以 factor。
reduce_lr <- callback_reduce_lr_on_plateau(
monitor = 'val_loss',
factor = 0.5, # halve the learning rate
patience = 5, # after 5 stagnant epochs
min_lr = 1e-6 # floor for learning rate
)
history <- model |> fit(
x_train, y_train,
epochs = 100,
batch_size = 64,
validation_split = 0.2,
callbacks = list(early_stop, reduce_lr),
verbose = 1
)callback_model_checkpoint()
callback_model_checkpoint(filepath, save_best_only) 会在每个训练轮次结束时将模型权重保存到磁盘(或者在性能改善时才保存,此时使用 save_best_only = TRUE)。这样可以防止训练崩溃导致进度丢失,即使训练超过最佳点仍在继续,也能加载最佳模型。
checkpoint <- callback_model_checkpoint(
filepath = '/tmp/best_model.h5',
monitor = 'val_accuracy',
save_best_only = TRUE,
mode = 'max', # higher accuracy = better
verbose = 1
)
history <- model |> fit(
x_train, y_train,
epochs = 100,
batch_size = 32,
validation_split = 0.2,
callbacks = list(early_stop, reduce_lr, checkpoint)
)
# Reload best model
best_model <- load_model_hdf5('/tmp/best_model.h5')validation_data 与 validation_split
validation_split 会取训练数据中最后的 N%。如果数据有顺序(例如时间序列),这样做会产生偏差。请改用 validation_data = list(x_val, y_val),从随机分层划分中提供一个预先构建好的验证集。
# Manually create a random validation split
set.seed(42)
val_idx <- sample(nrow(x_train), size = 0.2 * nrow(x_train))
x_val <- x_train[val_idx, ]
y_val <- y_train[val_idx, ]
x_tr <- x_train[-val_idx, ]
y_tr <- y_train[-val_idx, ]
history <- model |> fit(
x_tr, y_tr,
epochs = 50,
batch_size = 32,
validation_data = list(x_val, y_val), # explicit val set
callbacks = list(early_stop)
)批大小的影响
批大小是训练中的关键超参数。较小的批次会在梯度估计中引入更多噪声(起到正则化作用),有助于提高泛化能力。较大的批次速度更快,但可能收敛到更尖锐、泛化能力较差的极小值。常用值包括:32、64、128。请先尝试 32。
# Compare training with different batch sizes
for (bs in c(32, 128, 512)) {
set_weights(model, init_weights) # reset
h <- model |> fit(
x_train, y_train,
epochs = 20,
batch_size = bs,
validation_split = 0.2,
verbose = 0
)
cat('Batch:', bs, '| Val Acc:',
tail(h$metrics$val_accuracy, 1), '\n')
}学习率预热
在最初几个训练轮次中从非常小的学习率开始并逐渐增大(即预热),可以稳定训练过程,尤其适用于大型模型或小型数据集。自定义的 LearningRateScheduler 回调可以实现这种模式。
# Custom learning rate schedule with warmup
lr_schedule <- function(epoch, lr) {
if (epoch < 5) {
return(lr * (epoch + 1) / 5) # warmup
} else if (epoch < 30) {
return(lr) # constant
} else {
return(lr * 0.95) # decay
}
}
lr_callback <- callback_learning_rate_scheduler(lr_schedule)
history <- model |> fit(
x_train, y_train,
epochs = 50,
callbacks = list(lr_callback, early_stop),
validation_split = 0.2
)正则化总结
为了实现稳健的深度学习,应结合使用多种正则化技术:
- Dropout:训练期间随机将神经元置零。
- 权重衰减(L2):在损失中惩罚较大的权重。
- 提前停止:在模型过拟合之前停止训练。
- 数据增强:人为增大训练集规模。
- 批归一化:稳定激活值并减少协变量偏移。
model <- keras_model_sequential(input_shape = c(784)) |>
layer_dense(512, use_bias = FALSE,
kernel_regularizer = regularizer_l2(1e-4)) |>
layer_batch_normalization() |>
layer_activation('relu') |>
layer_dropout(0.4) |>
layer_dense(256, kernel_regularizer = regularizer_l2(1e-4)) |>
layer_batch_normalization() |>
layer_activation('relu') |>
layer_dropout(0.3) |>
layer_dense(10, activation = 'softmax')
model |> compile('adam', 'categorical_crossentropy', 'accuracy')绘制训练曲线
请始终并排可视化训练指标和验证指标。训练良好的模型应当表现为两条曲线逐渐收敛并保持接近。如果两条曲线分离,请增加正则化或降低模型容量。如果两条曲线都在较高损失处趋于平稳,则说明模型欠拟合。
# Detailed training curve plot
df <- data.frame(
epoch = seq_along(history$metrics$loss),
train_loss = history$metrics$loss,
val_loss = history$metrics$val_loss,
train_acc = history$metrics$accuracy,
val_acc = history$metrics$val_accuracy
)
par(mfrow = c(1, 2))
plot(df$epoch, df$train_loss, type = 'l', col = 'blue',
xlab = 'Epoch', ylab = 'Loss', main = 'Loss')
lines(df$epoch, df$val_loss, col = 'red')
legend('topright', c('Train', 'Val'), col = c('blue','red'), lty=1)
plot(df$epoch, df$train_acc, type = 'l', col = 'blue',
xlab = 'Epoch', ylab = 'Accuracy', main = 'Accuracy')
lines(df$epoch, df$val_acc, col = 'red')快速检查
在 callback_early_stopping() 中设置 restore_best_weights = TRUE 会执行什么操作?
训练与防止过拟合回顾
训练、验证和防止过拟合的要点:
- 使用
validation_split或validation_data在训练期间监控泛化能力。 plot(history)可视化训练曲线——曲线分离表示可能发生过拟合。callback_early_stopping(patience, restore_best_weights=TRUE)会在最佳训练轮次停止训练。callback_reduce_lr_on_plateau()会在进展停滞时降低学习率。callback_model_checkpoint(save_best_only=TRUE)会将最佳模型保存到磁盘。- 结合使用 dropout、L2 正则化、批归一化和数据增强,以实现稳健训练。
# Best practice training setup
callbacks <- list(
callback_early_stopping(
monitor = 'val_loss', patience = 15,
restore_best_weights = TRUE
),
callback_reduce_lr_on_plateau(
monitor = 'val_loss', factor = 0.5, patience = 5
),
callback_model_checkpoint(
'/tmp/best.h5', monitor = 'val_accuracy',
save_best_only = TRUE
)
)
model |> fit(
x_train, y_train,
epochs = 200, batch_size = 64,
validation_split = 0.2,
callbacks = callbacks, verbose = 0
)常见问题解答
「训练、验证与防止过拟合」课时是免费的吗?
是的 — 「训练、验证与防止过拟合」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 R Academy 课程的其余内容,请升级到 CoddyKit PRO。 R Academy 课程共包含 4 节课。
「训练、验证与防止过拟合」这节课中我会学到什么?
监控 val_loss,应用 Dropout,并使用回调实现提前停止 你通过在浏览器中直接运行的动手代码来练习 R Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。
学习 R Academy 需要有经验吗?
无需任何先前经验。CoddyKit 上的 R Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。
「训练、验证与防止过拟合」课时需要多长时间?
大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。
我能在这节 R Academy 课中编写并运行代码吗?
能。每节 R Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。
此课程中的所有课时
- 在 R 中设置 Keras 和 TensorFlow
- 构建序列模型
- 卷积神经网络基础
- 训练、验证与防止过拟合