我在Keras中有一个用于处理高度不平衡数据的LSTM序列标记器。因此,我想使用(多类别)F1分数作为模型的主要指标。我有两个问题:
1) 我在数据中使用了零填充(因此在我的嵌入层中设置了mask_zero=True
),并且所有损失都是自动计算在掩码数据上的。然而,我猜测对于自定义指标的计算,需要手动进行掩码操作吗?有没有高效的向量化解决方案?
2) 是否可以将sklearn的f1_score实现传递到模型的compile
中(可能需要以某种方式包装它)?直接尝试时不起作用,因为显然传递给它的是一个占位符而不是numpy数组(我使用的是tensorflow后端..)
[更新] 鉴于我的实现,现在有一个问题:我不确定是否有可能对模型的输出也进行掩码。因为如果我们不关心模型对’pad’输入位置的输出(它们无论如何都不影响损失),那么输出中可能会有一些随机垃圾,这将影响F1指标。理想情况下,这些位置也应该只有零值。
回答:
根据这个代码,我切换到了以下方法:
import numpy as npfrom keras.callbacks import Callbackfrom sklearn.metrics import f1_scoreclass ZeroPaddedF1Score(Callback): def on_train_begin(self, logs={}): self.val_f1s = [] def on_epoch_end(self, epoch, logs={}): y_true = np.argmax(self.validation_data[1], axis=-1) y_pred = np.argmax(self.model.predict(self.validation_data[0]), axis=-1) val_f1 = zero_padded_f1(y_true, y_pred) self.val_f1s.append(val_f1) print ' - val_f1: %f' % (val_f1)def zero_padded_f1(y_true, y_pred): y_pred_flat, y_true_flat = [], [] for y_pred_i, y_true_i in zip(y_pred.flatten(), y_true.flatten()): if y_true_i != 0: y_pred_flat.append(y_pred_i) y_true_flat.append(y_true_i) result = f1_score(y_true_flat, y_pred_flat, average='macro') return result
它可能无法与model.compile
一起使用(因为它操作的是numpy数组,因此需要一个已经编译的模型),但作为回调函数,它确实完成了任务。