带加权损失的TensorFlow二分类器:训练准确率与历史记录不符
神经网络训练疑问解答
训练代码
model = tf.keras.Sequential([ tf.keras.layers.InputLayer(input_shape=(input_length,)), tf.keras.layers.Dropout(0.8, seed=42), tf.keras.layers.Dense(units=200, activation='relu'), tf.keras.layers.Dropout(0.65, seed=42), tf.keras.layers.Dense(units=400, activation='relu'), tf.keras.layers.Dropout(0.65, seed=42), tf.keras.layers.Dense(units=300, activation='relu'), tf.keras.layers.Dropout(0.65, seed=42), tf.keras.layers.Dense(units=200, activation='relu'), #tf.keras.layers.Dense(units=2, activation='softmax') tf.keras.layers.Dense(units=1, activation='sigmoid') ]) #create weights for classes weights = sklearn.utils.class_weight.compute_class_weight(class_weight='balanced',classes=np.unique(y_train),y=[x[0] for x in y_train]) my_weight={0:weights[0],1:weights[1]} model.compile(optimizer='adam', #loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=False), loss='binary_crossentropy', metrics=['accuracy']) early_stop=tf.keras.callbacks.EarlyStopping( monitor='val_loss', patience=100, restore_best_weights=True ) model_checkpoint_callback=tf.keras.callbacks.ModelCheckpoint( filepath='./../../../data/models/', monitor='val_accuracy', mode='max', save_best_only=True ) callbacks=[ early_stop, #model_checkpoint_callback ] history=model.fit(x_train, y_train, batch_size= 16, epochs=500, validation_data=(x_val,y_val), callbacks=callbacks, class_weight=my_weight )
训练曲线
损失曲线

准确率曲线

绘图代码
def plot_acc(history,eval_ret): plt.plot(history.history['accuracy'],label='train_acc', color='red') plt.plot(history.history['val_accuracy'],label='val_acc',color='blue') plt.axhline(eval_ret[1],label='test_acc',color='green') plt.title('Accuracy of the model over training epochs') plt.ylabel('Accuracy') plt.xlabel('Training epochs') plt.legend() plt.show() def plot_loss(history,eval_ret): plt.plot(history.history['loss'],label='train_loss', color='red') plt.plot(history.history['val_loss'],label='val_loss',color='blue') plt.axhline(eval_ret[0],label='test_loss',color='green') plt.title('Loss of the model over training epochs') plt.ylabel('Loss') plt.xlabel('Training epochs') plt.legend() plt.show() eval_ret=model.evaluate(x_test, y_test) plot_loss(history,eval_ret) plot_acc(history,eval_ret)
评估代码与结果
评估代码
print('train:',model.evaluate(x_train, y_train,verbose=None)) print('test:',model.evaluate(x_test, y_test,verbose=None)) print('validate:',model.evaluate(x_val, y_val,verbose=None))
评估结果

疑问解答
1. 为何训练集的损失和准确率反而比测试/验证集更差?
有两个核心原因:
- Dropout的开关差异:训练过程中Dropout层会随机丢弃部分神经元,刻意降低模型拟合能力防止过拟合;而
model.evaluate()(验证、测试、最终训练集评估)时,Dropout层自动关闭,模型使用全部神经元计算,性能更强,因此准确率更高、损失更低。 - 类权重的影响:训练时使用了
class_weight=my_weight(平衡类别权重),计算的损失是加权后的值,会比不使用权重的验证/测试损失更高;评估阶段默认不应用类权重,损失是原始未加权值,进一步拉大了差距。
2. 最终模型的实测训练准确率为96%,但训练历史记录中的训练准确率始终低于60%,这是为什么?
- 训练历史
history.history['accuracy']记录的是每轮训练时启用Dropout状态下的准确率,此时模型因Dropout丢弃神经元,预测能力被限制,所以准确率较低。 - 最终
model.evaluate(x_train)是在关闭Dropout的状态下评估训练集,模型用全部神经元运行,加上EarlyStopping的restore_best_weights=True恢复了验证集表现最优的权重,因此能在训练集上达到远高于训练过程的准确率。
内容的提问来源于stack exchange,提问作者mat.tho
相关产品推荐
相关产品推荐

