我在尝试训练Keras模型。训练和验证时有很高的准确率(我使用的是f1分数,但准确率也很高)。但当我尝试预测某些数据集时,得到的准确率较低。即使我预测的是训练集。所以我认为这不是过拟合的问题。那么问题出在哪里呢?
import matplotlib.pyplot as pltskf = StratifiedKFold(n_splits=5)for train_index, test_index in skf.split(X, y): X_train, X_test = X[train_index], X[test_index] y_train, y_test = y[train_index], y[test_index] X_train,x_val,y_train,y_val = train_test_split(X_train, y_train, test_size=0.5,stratify = y_train) y_train = encode(y_train) y_val = encode(y_val) model = Sequential() model.add(Dense(50,input_dim=X_train.shape[1],activation='tanh')) model.add(Dropout(0.5)) model.add(Dense(25,activation='tanh')) model.add(Dropout(0.5)) model.add(Dense(10,activation='tanh')) model.add(Dropout(0.5)) model.add(Dense(2, activation='softmax')) opt = Adam(learning_rate=0.001) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['acc', ta.utils.metrics.f1score]) history = model.fit(X_train, y_train, validation_data=(x_val, y_val), epochs=5000, verbose=0) plt.plot(history.history['f1score']) plt.plot(history.history['val_f1score']) plt.title('model accuracy') plt.ylabel('f1score') plt.xlabel('epoch') plt.legend(['train', 'test'], loc='upper left') plt.show() break
结果在这里这里。如你所见,训练和验证集的结果都很高。
预测的代码如下:
from sklearn.metrics import f1_scorey_pred = model.predict(x_train)y_pred = decode(y_pred)y_train_t = decode(y_train)print(f1_score(y_train_t, y_pred))
结果是0.64,低于预期的0.9。
我的解码和编码函数如下:
def encode(y): Y=np.zeros((y.shape[0],2)) for i in range(len(y)): if y[i]==1: Y[i][1]=1 else : Y[i][0]=1 return Ydef decode(y): Y=np.zeros((y.shape[0])) for i in range(len(y)): if np.argmax(y[i])==1: Y[i]=1 else : Y[i]=0 return Y
回答:
由于你使用了最后一层
model.add(Dense(2, activation='softmax')
你不应该在model.compile()
中使用loss='binary_crossentropy'
,而应该使用loss='categorical_crossentropy'
。
由于这个错误,模型拟合期间显示的结果可能是错误的——sklearn的f1_score
返回的结果才是真实的。
与你的问题无关(因为我猜接下来的问题会是如何改进?),我们几乎从不使用activation='tanh'
作为隐藏层的激活函数(尝试使用relu
)。此外,Dropout不应该默认使用(特别是如此高的0.5值);请注释掉所有Dropout层,只有在你的模型过拟合时才重新添加(在不需要时使用Dropout已知会损害性能)。