我正在尝试使用基于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)