返回列表

9th Place Solution

574. CommonLit - Evaluate Student Summaries | commonlit-evaluate-student-summaries

开始: 2023-07-12 结束: 2023-10-11 智能评测 数据算法赛
作者:Takoi (Kaggle Grandmaster)
排名:第9名
发布时间:2023-10-12

第9名解决方案

首先,我要向主办方表示感谢,也祝贺所有获奖者!我很高兴向大家介绍我获得第九名的解决方案。

交叉验证

prompt_id 814d6b 的表述与其他 prompt_id 明显不同。在使用 prompt_id 进行 groupkfold 交叉验证时,预测该特定 prompt_id 与其他 prompt_id 的分数没有相关性。假设测试集中有任何 id 的分布与 814d6b 相似,那么在训练数据中包含 814d6b 可能会产生不错的准确率。然而,无法验证这一点。在本次比赛中,我使用了两种交叉验证方法,并分别提交了结果:
交叉验证1:groupkfold(group = prompt_id),在评估中排除 814d6b。
交叉验证2:groupkfold(group = prompt_id),在评估中包含 814d6b。
最终,使用交叉验证2的模型在 private 分数上表现更好,因此我将详细介绍该模型。
由于仅改变种子就导致 CV 分数变化,我使用了三个不同的种子进行交叉验证,并基于它们的集成结果来评估模型。最终提交是基于使用三个不同种子训练的所有数据的模型预测。

训练

我对文本进行了如下标记:
text1: summary_text
text2: prompt_question + [SEP] + prompt_text

inputs = self.tokenizer.encode_plus(text1,
                                  text2,
                                  add_special_tokens=True,
                                  max_length=self.max_len,
                                  padding='max_length',
                                  truncation=True,
                                  return_token_type_ids=True)

模型:由两个 deberta-v3-large 和一个 LSTM 组成,如下所述:

  • 第一个 deberta-v3-large 使用整个输入文本进行训练。
  • 第二个 deberta-v3-large 和 LSTM 仅使用 summary_text 进行训练。
model_path = "microsoft/deberta-v3-large"
class CustomModel(nn.Module):
    def __init__(self):
        super(CustomModel, self).__init__()
        self.model = AutoModel.from_pretrained(model_path)
        config = AutoConfig.from_pretrained(
            model_path, output_hidden_states=True)
        config.num_hidden_layers = 6
        self.model2 = DebertaV2Encoder(config)
        self.lstm = nn.LSTM(input_size=1024, hidden_size=1024,
                            num_layers=1, batch_first=True,
                            bidirectional=True)
        self.linear1 = nn.Sequential(
            nn.Linear(1024*2, 512),
            nn.LayerNorm(512),
            nn.ReLU(),
            nn.Dropout(0.2),
            nn.Linear(512, 2))

        self.pool = MeanPooling()

    def forward(self, ids, mask, token_type_ids,
                s_mask):
        out = self.model(ids, attention_mask=mask,
                         token_type_ids=token_type_ids)[
            'last_hidden_state']
        s_mask_len = s_mask.shape[1]
        out = out[:, :s_mask_len, :]
        out = out.contiguous()
        out = self.model2(out, s_mask)[
            'last_hidden_state']
        out_list = []
        for s in range(len(s_mask)):
            s_mask_ = s_mask[s]
            s_mask_len = torch.sum(s_mask_)
            emb = out[[s], :s_mask_len, :]
            s_mask_ = s_mask_[:s_mask_len].unsqueeze(0)
            emb, _ = self.lstm(emb)
            emb = self.pool(emb, s_mask_)
            out_list.append(emb)
        out_concat = torch.cat(out_list,
                               axis=0)
        out_concat = self.linear1(out_concat)
        return out_concat

训练设置:

  • token_len: 1680
  • epochs: 3
  • Loss: SmoothL1Loss
  • lr: 8e-6
  • optimizer: AdamW
    • weight_decay: 0.01
    • beta: (0.9, 0.98)
  • scheduler: get_linear_schedule_with_warmup
    • num_warmup_steps: 总训练步数的10%
  • EMA (指数移动平均)
    • ema_decay: 0.995
    • 使用 EMA 有助于稳定训练。

推理

token_len: 4200

分数

  • CV: 0.495(3个种子的集成)
    • 814d6b: 0.604982
    • ebad26: 0.431438
    • 3b9047: 0.49692
    • 39c16e: 0.483208
  • 公开分数: 0.456
  • 私有分数: 0.457
同比赛其他方案