【发布时间】:2020-05-08 16:41:15
【问题描述】:
这个问题的本质:
我想找到一种合适的方法来计算每个 epoch 之后的验证和训练数据的 Fscore(不是批量)
对于二元分类任务,我想使用简单的keras 模型在每个时期之后计算Fscore。但如何计算Fscore 似乎颇受讨论。
我知道keras 分批工作,计算每个批次fscore 的一种方法是https://stackoverflow.com/a/45305384/10053244(Fscore-calculation:f1)。
批量计算可能会很混乱,我更喜欢在每个 epoch 之后计算 Fscore。所以只是调用history.history['f1'] 或history.history['val_f1'] 并不 做的伎俩,因为它显示了batch-wise fscores。
我想出一种方法是使用
from keras.callbacks import ModelCheckpoint 函数保存每个模型:
- 在每个 epoch 后保存每个模型的权重
- 重新加载模型并使用
model.evaluate或model.predict
编辑:
使用 tensorflow 后端,我决定跟踪 TruePositives、FalsePositives 和 FalseNegatives(按照 umbreon29 的建议)。
但现在有趣的部分来了:重新加载模型时的结果对于训练数据是不同的(TP、FP、FN 是不同的)但对于验证集却不是!
因此,存储权重以重建每个模型并重新计算 TP、FN、TP(最后是 Fscore)的简单模型如下所示:
from keras.metrics import TruePositives, TrueNegatives, FalseNegatives, FalsePositives
## simple keras model
sequence_input = Input(shape=(input_dim,), dtype='float32')
preds = Dense(1, activation='sigmoid',name='output')(sequence_input)
model = Model(sequence_input, preds)
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=[TruePositives(name='true_positives'),
TrueNegatives(name='true_negatives'),
FalseNegatives(name='false_negatives'),
FalsePositives(name='false_positives'),
f1])
# model checkpoints
filepath="weights-improvement-{epoch:02d}-{val_f1:.2f}.hdf5"
checkpoint = ModelCheckpoint(os.path.join(savemodel,filepath), monitor='val_f1', verbose=1, save_best_only=False, save_weights_only=True, mode='auto')
callbacks_list = [checkpoint]
history = model.fit(x_train, y_train, validation_data=(x_val, y_val), epochs=epoch, batch_size=batch,
callbacks=[callbacks_list])
## Saving TP, FN, FP to calculate Fscore
tp.append(history.history['true_positives'])
fp.append(history.history['false_positives'])
fn.append(history.history['false_negatives'])
arr_train = np.stack((tp, fp, fn), axis=1)
## doing the same for tp_val, fp_val, fn_val
[...]
arr_val = np.stack((tp_val, fp_val, fn_val), axis=1)
## following method just showes batch-wise fscores and shouldnt be used:
## f1_sc.append(history.history['f1'])
在每个 epoch 后重新加载模型以计算 Fscores(使用 sklearn fscore 指标from sklearn.metrics import f1_score 的 predict 方法等效于从 TP、FP、FN 计算 fscore 指标):
Fscore_val = []
fscorepredict_val_sklearn = []
Fscore_train = []
fscorepredict_train = []
## model_loads contains list of model-paths
for i in model_loads:
## rebuilding the model each time since only weights are stored
sequence_input = Input(shape=(input_dim,), dtype='float32')
preds = Dense(1, activation='sigmoid',name='output')(sequence_input)
model = Model(sequence_input, preds)
model.load_weights(i)
# Compile model (required to make predictions)
model.compile(loss='binary_crossentropy',
optimizer='adam',
metrics=[TruePositives(name='true_positives'),
TrueNegatives(name='true_negatives'),
FalseNegatives(name='false_negatives'),
FalsePositives(name='false_positives'),
f1
])
### For Validation data
## using evaluate
y_pred = model.evaluate(x_val, y_val, verbose=0)
Fscore_val.append(y_pred) ## contains (loss,tp,fp,fn, f1-batchwise)
## using predict
y_pred = model.predict(x_val)
val_preds = [1 if x > 0.5 else 0 for x in y_pred]
cm = f1_score(y_val, val_preds)
fscorepredict_val_sklearn.append(cm) ## equivalent to Fscore calculated from Fscore_vals tp,fp, fn
### For the training data
y_pred = model.evaluate(x_train, y_train, verbose=0)
Fscore_train.append(y_pred) ## also contains (loss,tp,fp,fn, f1-batchwise)
y_pred = model.predict(x_train, verbose=0) # gives probabilities
train_preds = [1 if x > 0.5 else 0 for x in y_pred]
cm = f1_score(y_train, train_preds)
fscorepredict_train.append(cm)
使用Fscore_val 的 tp,fn,fp 从 tp、fn 和 fp 计算 Fscore 并将其与fscorepredict_val_sklearn 进行比较与从 arr_val 计算它是等效且相同的。
然而,比较Fscore_train和arr_train时tp、fn和fp的数量是不同的。因此,我也得出了不同的 Fscores。 tp,fn,fp 的数量应该是相同的,但它们不是。这是一个错误吗?
我应该信任哪一个? fscorepredict_train 实际上似乎更值得信赖,因为它们从“总是猜测类 1”-Fscore 开始(当召回 = 1 时)。 (fscorepredict_train[0]=0.6784 vs f_hist[0]=0.5736 vs always-guessing-class-1-fscore = 0.6751)
[注意: Fscore_train[0] = [0.6853608025386962, 2220.0, 250.0, 111.0, 1993.0, 0.6730511784553528] (loss,tp,tn,fp,fn) 导致 fscore= 0.6784 ,所以 Fscore 来自 Fscore_train = fscorepredict_train ]
【问题讨论】:
-
我可以建议的解决方法是在每批累积测试集中的误报、真阳性和假阴性示例之后。 epoch 完成后,您可以计算整个集合中的 f1-score。我可以给你一个使用火炬的完整可重复的例子
标签: python tensorflow keras