如何在Keras中获得稳定的验证准确率与验证损失值?
MLP文本分类训练不稳定问题的修复方案
你的问题主要来自代码里的几个关键逻辑错误和训练参数设置不当,以下是具体排查和修复方案:
1. 修正clear_session()调用时机
当前代码在创建模型后才调用clear_session(),这会直接销毁已构建的模型,后续训练的是Keras自动重建的临时模型,逻辑完全错误。正确做法是在创建模型前调用,确保彻底清空之前的会话和模型残留:
# 先清空会话,再创建模型 clear_session() model = Sequential() # ... 后续模型构建代码
2. 统一标签编码逻辑
测试集标签不能重新执行fit_transform,必须复用训练集的编码器映射,否则会出现标签编码不一致(比如正负类映射颠倒):
Encoder = LabelEncoder() # 仅在训练集上拟合编码器 Train_Y2 = Encoder.fit_transform(Train_Y2) # 测试集直接用训练集的编码器转换 Test_Y2 = Encoder.transform(Test_Y2)
3. 固定随机种子消除结果随机性
神经网络权重初始化、优化器内部运算都带有随机性,固定全局种子才能让每次训练结果一致:
import random import numpy as np import tensorflow as tf # 固定所有随机源的种子 random.seed(42) np.random.seed(42) tf.random.set_seed(42)
4. 移除硬编码的输入维度
手动写input_dim=1148极易导致输入维度不匹配,直接从TF-IDF特征矩阵获取真实维度:
# 从训练集特征矩阵获取输入维度 input_dim = arr_Train_X2_Tfidf.shape[1] model.add(Dense(100, input_dim=input_dim, activation='relu'))
5. 降低学习率稳定训练
你设置的Adam学习率0.01是默认值的10倍,过大的学习率会导致训练过程剧烈震荡,验证指标波动甚至持续恶化。调整为默认的0.001:
opt = Adam(learning_rate=0.001)
6. 解决验证集参数冲突
model.fit()中同时设置validation_split=0.2和validation_data会触发冲突,Keras会优先使用validation_data。建议仅用训练集的20%做验证,测试集留到训练完成后再评估(避免过拟合到测试集):
# 仅保留validation_split,用训练集的20%做验证 history = model.fit(arr_Train_X2_Tfidf, Train_Y2, epochs=100,verbose=1, validation_split=0.2, batch_size=32, callbacks=[es]) # 训练完成后单独评估测试集 test_loss, test_acc = model.evaluate(arr_Test_X2_Tfidf, Test_Y2)
7. 替换激活函数缓解梯度消失
隐藏层用sigmoid容易出现梯度消失问题,换成relu能提升训练稳定性和收敛速度:
model.add(Dense(100, input_dim=input_dim, activation='relu'))
完整修正代码
import random import numpy as np import tensorflow as tf from sklearn import model_selection from sklearn.preprocessing import LabelEncoder from sklearn.feature_extraction.text import TfidfVectorizer from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense from tensorflow.keras.optimizers import Adam from tensorflow.keras.callbacks import EarlyStopping from keras.backend import clear_session # 固定全局随机种子 random.seed(42) np.random.seed(42) tf.random.set_seed(42) # 分割训练/测试集(80:20) Train_X2, Test_X2, Train_Y2, Test_Y2 = model_selection.train_test_split( dataset['review'], dataset['sentiment'], test_size=0.2, random_state=1 ) # 标签编码:训练集拟合,测试集复用 Encoder = LabelEncoder() Train_Y2 = Encoder.fit_transform(Train_Y2) Test_Y2 = Encoder.transform(Test_Y2) # TF-IDF特征提取 Tfidf_vect2 = TfidfVectorizer(max_features=None) Tfidf_vect2.fit(dataset['review']) Train_X2_Tfidf = Tfidf_vect2.transform(Train_X2) Test_X2_Tfidf = Tfidf_vect2.transform(Test_X2) # 转换为稠密数组适配Keras输入 arr_Train_X2_Tfidf = Train_X2_Tfidf.toarray() arr_Test_X2_Tfidf = Test_X2_Tfidf.toarray() # 清空会话后构建模型 clear_session() input_dim = arr_Train_X2_Tfidf.shape[1] model = Sequential() model.add(Dense(100, input_dim=input_dim, activation='relu')) model.add(Dense(1, activation='sigmoid')) # 编译模型:使用默认学习率 opt = Adam(learning_rate=0.001) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) model.summary() # 早停策略:保留最优权重 es = EarlyStopping(monitor="val_loss", mode='min', patience=10, restore_best_weights=True) # 训练模型 history = model.fit( arr_Train_X2_Tfidf, Train_Y2, epochs=100, verbose=1, validation_split=0.2, batch_size=32, callbacks=[es] ) # 评估测试集 test_loss, test_acc = model.evaluate(arr_Test_X2_Tfidf, Test_Y2, verbose=0) print(f"\n测试集结果:准确率={test_acc:.4f},损失={test_loss:.4f}")
额外优化建议
- 隐藏层后添加
Dropout(0.2)层,缓解过拟合:model.add(tf.keras.layers.Dropout(0.2)) - 设置
TfidfVectorizer(max_features=5000)减少特征维度,提升训练效率 - 绘制训练曲线观察收敛情况:
import matplotlib.pyplot as plt plt.plot(history.history['accuracy'], label='训练准确率') plt.plot(history.history['val_accuracy'], label='验证准确率') plt.xlabel('Epoch') plt.ylabel('Accuracy') plt.legend() plt.show() plt.plot(history.history['loss'], label='训练损失') plt.plot(history.history['val_loss'], label='验证损失') plt.xlabel('Epoch') plt.ylabel('Loss') plt.legend() plt.show()
内容的提问来源于stack exchange,提问作者andryan86
相关产品推荐
相关产品推荐

