交叉验证下模型训练准确率与损失可视化的代码实现方法
交叉验证下可视化训练准确率与损失变化的解决方案
这个问题在Keras交叉验证训练中很常见——你猜的没错,核心问题就是没有在fit()中传入验证数据集,导致history里没有val_acc和val_loss这些关键指标。下面是具体的调整方案和代码示例:
步骤1:修改训练代码,传入验证数据并收集历史记录
首先,我们需要在每一轮K折交叉验证的训练中,把当前fold的测试集作为验证数据传入fit(),同时把每一轮的训练历史保存下来:
import numpy as np import matplotlib.pyplot as plt from sklearn.model_selection import StratifiedKFold from tensorflow.keras.models import Sequential from tensorflow.keras import layers seed = 42 kfold = StratifiedKFold(n_splits=5, shuffle=True, random_state=seed) cvscores = [] all_histories = [] # 用来保存每一轮fold的训练历史 for train, test in kfold.split(x_train, y_train): model = Sequential() model.add(layers.Conv2D(32,(4,4), activation = 'relu', input_shape = (224,224,3))) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Conv2D(64, (4,4), activation = 'relu')) model.add(layers.MaxPooling2D((2, 2))) model.add(layers.Flatten()) model.add(layers.Dense(64, activation = 'relu')) model.add(layers.Dropout(0.5)) model.add(layers.Dense(1, activation = 'sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy']) # 关键修改:传入validation_data,使用当前fold的测试集作为验证集 history = model.fit(x_train[train], y_train[train], epochs=15, batch_size=64, validation_data=(x_train[test], y_train[test])) all_histories.append(history) scores = model.evaluate(x_train[test], y_train[test], verbose=0) print("%s: %.2f%%" % (model.metrics_names[1], scores[1]*100)) cvscores.append(scores[1] * 100) print("%.2f%% (+/- %.2f%%)" % (np.mean(cvscores), np.std(cvscores)))
步骤2:可视化训练过程
现在我们有了每一轮fold的训练历史,可以用两种方式可视化:
方式一:绘制每折的单独曲线
这种方式能直观看到不同fold之间的训练差异:
# 绘制准确率曲线 plt.figure(figsize=(12, 6)) for i, history in enumerate(all_histories): plt.plot(history.history['accuracy'], label=f'Train Fold {i+1}') plt.plot(history.history['val_accuracy'], label=f'Val Fold {i+1}') plt.title('Model Accuracy Across Folds') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.grid(True) plt.show() # 绘制损失曲线 plt.figure(figsize=(12, 6)) for i, history in enumerate(all_histories): plt.plot(history.history['loss'], label=f'Train Fold {i+1}') plt.plot(history.history['val_loss'], label=f'Val Fold {i+1}') plt.title('Model Loss Across Folds') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(bbox_to_anchor=(1.05, 1), loc='upper left') plt.grid(True) plt.show()
方式二:绘制平均后的趋势曲线
如果想看到整体的训练趋势,可以计算所有fold在每个epoch的指标平均值:
# 提取所有fold的指标数据 num_epochs = 15 avg_acc = np.zeros(num_epochs) avg_val_acc = np.zeros(num_epochs) avg_loss = np.zeros(num_epochs) avg_val_loss = np.zeros(num_epochs) for history in all_histories: avg_acc += np.array(history.history['accuracy']) avg_val_acc += np.array(history.history['val_accuracy']) avg_loss += np.array(history.history['loss']) avg_val_loss += np.array(history.history['val_loss']) # 计算平均值 avg_acc /= len(all_histories) avg_val_acc /= len(all_histories) avg_loss /= len(all_histories) avg_val_loss /= len(all_histories) # 绘制平均准确率曲线 plt.figure(figsize=(10, 5)) plt.plot(avg_acc, label='Train Accuracy (Avg)') plt.plot(avg_val_acc, label='Val Accuracy (Avg)') plt.title('Average Model Accuracy') plt.ylabel('Accuracy') plt.xlabel('Epoch') plt.legend(loc='upper left') plt.grid(True) plt.show() # 绘制平均损失曲线 plt.figure(figsize=(10, 5)) plt.plot(avg_loss, label='Train Loss (Avg)') plt.plot(avg_val_loss, label='Val Loss (Avg)') plt.title('Average Model Loss') plt.ylabel('Loss') plt.xlabel('Epoch') plt.legend(loc='upper left') plt.grid(True) plt.show()
补充说明
- 这里用当前fold的测试集作为验证数据,完全符合交叉验证的逻辑——每一轮训练时,我们用未见过的当前fold测试集来评估泛化能力。
- 如果你的数据集很大,也可以考虑在训练集内部再划分一个小验证集,但这样会减少训练数据量;用fold的测试集作为验证是更标准的交叉验证做法。
内容的提问来源于stack exchange,提问作者Janne
相关产品推荐
相关产品推荐

