使用BERT的词件标记器时如何处理标签

时间:2019-05-14 11:16:50

标签: python tensorflow machine-learning keras nlp

我正在尝试使用基于BERT无大小写的模型和tensorflow / keras进行多类序列分类。但是,在使用BERT词片标记器标记数据时,我遇到了一个问题。我不确定如何按照标记化程序修改标签。

我已经阅读了Github上有关该问题的一些公开和未解决的问题,并且还阅读了Google发布的BERT论文。具体来说,在本文的第4.3节中,说明了如何调整标签,但在将其转换为案例时遇到了麻烦。我还阅读了官方的BERT存储库README,其中有关于标记化的部分,并提到了如何创建将原始标记映射到新标记的字典类型,并且可以将其用作投影标签的方式。

我使用了自述文件中提供的代码,并设法按照我认为的方式创建了标签。但是,我不确定这是否是正确的方法。下面是一个标记化句子的示例,它是在使用BERT标记化工具之前和之后的标签。只是一个旁注。我已经调整了分词器中的某些代码,以使它不会根据标点符号对某些单词进行分词,因为我希望它们保持完整。

这是创建映射的代码:

bert_tokens = []
label_to_token_mapping = []

bert_tokens.append("[CLS]")

for token in original_tokens:
   label_to_token_mapping.append(len(bert_tokens))
   bert_tokens.extend(tokenizer.tokenize(token, ignore_set=ignore_set))

bert_tokens.append("[SEP]")

original_tokens = ['The', <start>', 'eng-30-01258617-a', '<end>', 'frailty']
tokens = ['[CLS]', 'the', '<start>', 'eng-30-01258617-a', '<end>', 'frail', '##ty', '[SEP]']
labels = [0,2, 3, 4, 1]
label_to_token_mapping = [1, 2, 3, 4, 5]

使用映射,我调整了标签数组,结果如下:

labels = [0, 2, 3, 4, 1, 1]

在此之后,我添加了填充标签(假设最大序列长度为10),因此最终我的标签数组如下所示:

labels = [0, 2, 3, 4, 1, 1, 5, 5, 5, 5, 5]

您可以看到,由于最后一个标记(标记为1)被分成两部分,所以我现在将两个单词标记为“ 1”。

我不确定这是否正确。在本文的第4.3节中,它们被标记为“ X”,但是我不确定这是否也是我应该做的。因此,在论文(https://arxiv.org/abs/1810.04805)中给出了以下示例:

Jim    Hen    ##son  was  a puppet  ##eer
I-PER  I-PER    X     O   O   O       X

我的最终目标是在模型中输入一个句子,然后返回一个看起来像[0,0,1,1,2,2,3,4,5,5,5]的数组。因此,每个单词一个标签。然后,我可以重新组合单词以得到句子的原始长度,从而得到预测值的实际显示方式。

此外,在训练了几个时期的模型之后,我尝试进行预测并获得怪异的值。例如,单词用标签“ 5”标记,填充值和填充值用标签“ 1”标记。这使我认为创建标签的方式有问题。最初,我没有调整标签,因此即使将原始句子标记化之后,也可以保留标签的原始状态。这并没有给我很好的结果。

任何帮助都将不胜感激,因为我一直在努力寻找应该在网上进行的工作,但我还无法弄清楚。预先谢谢你!

此外,以下是我用来创建模型的代码:

from tensorflow.python.keras.layers import Input, Dense
from tensorflow.python.keras.models import Model
from tensorflow.python.keras import backend as K
import tensorflow_hub as hub
import tensorflow as tf


class BertLayer(tf.layers.Layer):
    def __init__(self, bert_path, max_seq_length, n_fine_tune_layers=10, **kwargs):
        self.n_fine_tune_layers = n_fine_tune_layers
        self.trainable = True
        self.output_size = 768
        self.bert_path = bert_path
        self.max_seq_length = max_seq_length

        super(BertLayer, self).__init__(**kwargs)

    def build(self, input_shape):
        self.bert = hub.Module(
            self.bert_path,
            trainable=self.trainable,
            name="{}_module".format(self.name)
        )
        trainable_vars = self.bert.variables

        # Remove unused layers
        # trainable_vars = [var for var in trainable_vars if not "/cls/" in var.name]
        trainable_vars = [var for var in trainable_vars
                          if not ("/cls/" in var.name) and not ("/pooler/" in var.name)]

        # Select how many layers to fine tune
        trainable_vars = trainable_vars[-self.n_fine_tune_layers:]

        # Add to trainable weights
        for var in trainable_vars:
            self._trainable_weights.append(var)

        for var in self.bert.variables:
            if var not in self._trainable_weights:
                self._non_trainable_weights.append(var)

        super(BertLayer, self).build(input_shape)

    def call(self, inputs):
        inputs = [K.cast(x, dtype="int32") for x in inputs]
        input_ids, input_mask, segment_ids = inputs
        bert_inputs = dict(
            input_ids=input_ids, input_mask=input_mask, segment_ids=segment_ids
        )
        result = self.bert(inputs=bert_inputs, signature="tokens", as_dict=True)[
            "sequence_output"
        ]
        return result

    def compute_output_shape(self, input_shape):
        return input_shape[0], self.output_size

    def get_config(self):
        config = {'bert_path': self.bert_path, 'max_seq_length': self.max_seq_length}
        base_config = super(BertLayer, self).get_config()
        return dict(list(base_config.items()) + list(config.items()))


# Build model
def build_model(bert_path, max_seq_length):
    in_id = Input(shape=(None,), name="input_ids")
    in_mask = Input(shape=(None,), name="input_masks")
    in_segment = Input(shape=(None,), name="segment_ids")
    bert_inputs = [in_id, in_mask, in_segment]

    bert_output = BertLayer(bert_path=bert_path, n_fine_tune_layers=3, max_seq_length=max_seq_length)(bert_inputs)
    dense = Dense(128, activation='relu')(bert_output)
    pred = Dense(8, activation='softmax',)(dense)

    model = Model(inputs=bert_inputs, outputs=pred)
    model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['categorical_accuracy'])
    model.summary()

    return model


def initialize_vars(sess):
    sess.run(tf.local_variables_initializer())
    sess.run(tf.global_variables_initializer())
    sess.run(tf.tables_initializer())
    K.set_session(sess)

0 个答案:

没有答案