361. TensorFlow 2.0 Question Answering | tensorflow2-question-answering
感谢 Kaggle 提供这次比赛机会,这是我第一次独自参加比赛并取得这样的成绩,对我来说是一个巨大的进步。
基于 bert4keras。我的方案基于一个用 Keras 实现的奇怪 ROBERTA 结构 (链接),它与 HuggingFace 的版本有所不同:
def build(self):
x_in = Input(shape=(512, ), name='Input-Token')
s_in = Input(shape=(512, ), name='Input-Segment')
x, s = x_in, s_in
sequence_mask = Lambda(lambda x: K.cast(K.greater(x, 0), 'float32'),
name='Sequence-Mask')(x)
# Embedding
x = Embedding(input_dim=self.vocab_size,
output_dim=self.embedding_size,
embeddings_initializer=self.initializer,
name='Embedding-Token')(x)
s = Embedding(input_dim=2, #1 or 2 , 2 finally because roberta need to train it
output_dim=self.embedding_size,
embeddings_initializer=self.initializer,
name='Embedding-Segment')(s)
x = Add(name='Embedding-Token-Segment')([x, s])
if self.max_position_embeddings == 514:
x = RobertaPositionEmbeddings(input_dim=self.max_position_embeddings,
output_dim=self.embedding_size,
merge_mode='add',
embeddings_initializer=self.initializer,
name='Embedding-Position')([x,x_in])
else:
x = PositionEmbedding(input_dim=self.max_position_embeddings,
output_dim=self.embedding_size,
merge_mode='add',
embeddings_initializer=self.initializer,
name='Embedding-Position')(x)
x = LayerNormalization(name='Embedding-Norm')(x)
if self.dropout_rate > 0:
x = Dropout(rate=self.dropout_rate, name='Embedding-Dropout')(x)
if self.embedding_size != self.hidden_size:
x = Dense(units=self.hidden_size,
kernel_initializer=self.initializer,
name='Embedding-Mapping')(x)
layers = None
for i in range(self.num_hidden_layers):
attention_name = 'Encoder-%d-MultiHeadSelfAttention' % (i + 1)
feed_forward_name = 'Encoder-%d-FeedForward' % (i + 1)
x, layers = self.transformer_block(
inputs=x,
sequence_mask=sequence_mask,
attention_mask=self.compute_attention_mask(i, s_in),
attention_name=attention_name,
feed_forward_name=feed_forward_name,
input_layers=layers)
x = self.post_processing(i, x)
if not self.block_sharing:
layers = None
outputs = [x]
我连接了最后 4 层,并为每个输出头设置了一个单独的线性输出。
非零样本(步长 256)与零样本(步长 128)的比例为 1:4。
Total_loss = loss_weights1 * sample_weights * start_loss + loss_weights2 * sample_weights * end_loss + loss_weights3 * sample_weights * answertype_loss
[start, end, answer_type] 的损失权重比例为 1:1: (1/sampleweight.mean())。
我的方案结果是:CV: 0.478,因为 10 天前我修复了指标错误后,出现了太多的假阴性样本。因此,通过我的两个开发集搜索,我最终选择了一个安全的阈值(比达到最大 CV 的阈值稍小一点,以降低风险)。如果短答案得分低于 0.5 或长答案低于 0.1,答案将为空。
因为我只上传了 1 个模型,所以推理时使用 stride=128。
我的结果:CV 0.523,Public LB 0.63,Private LB 0.65。