SMOTE在多个BERT输入下的应用

4
我正在使用Keras和Bert(HuggingFace)构建一个多类文本分类模型,但是我的数据集非常不平衡。我已经使用Sklearn中的SMOTE来为低平衡类别生成额外的样本(我总共有45个类别),当我使用Bert Tokenizer的输入ID时,它可以很好地工作。
然而,我希望能够同时对输入掩码ID使用SMOTE,以便让模型确定填充值的位置。
我的问题是如何在输入ID和掩码ID上同时使用SMOTE?到目前为止,我已经做了以下工作,模型没有抱怨,但我不确定重新采样的掩码是否与重新采样的输入ID一一对应。 SMOTE需要两个输入:输入和标签,因此我使用相同的随机状态复制了过程,并返回所需的元素。
def smote(input_ids, input_masks, labels):

    smote = SMOTE("not majority", random_state=27)

    input_ids_resampled, labels_resampled = smote.fit_sample(input_ids, labels)
    input_masks_resampled, _ = smote.fit_sample(input_masks, labels)

    return input_ids_resampled, input_masks_resampled, labels_resampled

这样做可以接受吗?有更好的方法吗?

2个回答

3

我想澄清一下,这种将SMOTE应用于input_ids的方法是错误的。你需要获取到CLS对应的嵌入向量。使用BERT获取每个推文的CLS标记,然后对其应用SMOTE。然后将其从分类器(任何分类器)传递。这应该在未微调的情况下完成。


2

我认为给出的代码不是一个好的想法。

由于掩码 ID 告诉您哪些标记是真实的,哪些来自填充,如果您独立地从输入 ID 中对它们进行 smote-sample,那么您最终会得到来自真实输入 ID 的合成输入 ID,而模型会忽略相应的合成掩码 ID(从完全独立的标记生成),因为这些合成掩码 ID 表示您的合成输入 ID 是填充。

愚蠢的例子:

  • t_1:input ids = [1209、80183、290],mask ids = [1、1、0]
  • t_2:input ids = [39103、38109、2931],mask ids = [1、1、1]
  • t_3:input ids = [1242、1294、3233],mask ids = [1、0、0]

假设为了简单起见,合成是通过两个张量的平均值完成的。如果您的随机 smote-sampling 对 t_1t_2 的输入 ID 进行平均,但对 t_2t_3 的掩码 ID 进行平均,则得到的合成 t_4 没有任何意义:它不是任何真实观察的平均值。

上述问题的一个合理解决方法:只对输入 ID 进行 smote-sample,并将您的合成标记 ID 作为同一掩码 ID 的平均值。我说平均值,但我认为每个条目的掩码 ID 向量的中位数值可能更合适。可以通过将输入 ID 和掩码 ID 扁平化为 1d 张量并对其进行 smote 来安排(我认为,在假设 smote 是分量方式工作的情况下)。

然而,我认为上述修复仍然没有太多意义。我远非 BERT 专家,但我的理解是每个标记都对应于一个精确的整数(最多可能会发生哈希冲突)。如果是这种情况,仅仅平均标记就会得到完全无意义的结果。即使为每个标记选择中位数(比如在同一类别的 5 个张量中),也会得到完全无意义的句子。

因此,结论是,我不知道如何解决这个问题。也许可以在 BERT 模型的中间某个时刻进行 smote,当标记已经部分处理为浮点数时。或者甚至在标准 Bert 模型的退出和针对特定任务进行微调之前进行。

最后,我想留下这个信息给下一个遇到这个问题的人:显然有一种 SMOTE 的修改版,SMOTENC,适用于整数向量(以及其他任务)。由于上述原因,我认为它不适用于此目的,但知道这一点还是很好的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接