返回列表

27th solution with luck and some questions from me

361. TensorFlow 2.0 Question Answering | tensorflow2-question-answering

开始: 2019-10-28 结束: 2020-01-22 自然语言处理 数据算法赛
第27名方案:运气与一些疑问

第27名方案:运气与一些疑问

作者: SchenbergZ | 比赛排名: 第27名

感谢 Kaggle 提供这次比赛机会,这是我第一次独自参加比赛并取得这样的成绩,对我来说是一个巨大的进步。

1. 奇怪的 ROBERTA 架构

基于 bert4keras。我的方案基于一个用 Keras 实现的奇怪 ROBERTA 结构 (链接),它与 HuggingFace 的版本有所不同:

  1. 2*1024 token_type_id_embedding 层(0 放入预训练权重,1 设置为 np.zeros((1,1024)))。
  2. 没有填充掩码。
  3. 注意力掩码中奇怪的零掩码:
    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 层,并为每个输出头设置了一个单独的线性输出。

2. 数据分布

非零样本(步长 256)与零样本(步长 128)的比例为 1:4。

3. 训练

  1. 使用 Radam 优化器,warmup 设为 0.05,训练 1 个 epoch。
  2. 设置不同的权重以匹配开发集的分布(我使用了两个开发集:第 135000 到 140000 条和第 302373 到最后部分)。因此我的损失函数如下:

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())。

4. 阈值消除假阳性

我的方案结果是:CV: 0.478,因为 10 天前我修复了指标错误后,出现了太多的假阴性样本。因此,通过我的两个开发集搜索,我最终选择了一个安全的阈值(比达到最大 CV 的阈值稍小一点,以降低风险)。如果短答案得分低于 0.5 或长答案低于 0.1,答案将为空。

因为我只上传了 1 个模型,所以推理时使用 stride=128。
我的结果:CV 0.523,Public LB 0.63,Private LB 0.65。

5. 我的疑问

  1. 如何进行填充掩码:
    我尝试在 embedding 层之前添加填充掩
同比赛其他方案