返回列表

4th place solution

615. Learning Agency Lab - Automated Essay Scoring 2.0 | learning-agency-lab-automated-essay-scoring-2

开始: 2024-04-03 结束: 2024-07-02 智能评测 数据算法赛
第四名解决方案 - Learning Agency Lab: Automated Essay Scoring 2

第四名解决方案

Author Avatar
作者: tascj (Grandmaster)
发布时间: 2024-07-03
竞赛: Learning Agency Lab: Automated Essay Scoring 2

首先,我要感谢 Kaggle 和竞赛主办方组织这次挑战。
我也要感谢所有的参与者。我通过讨论帖发现了很多关键信息。

关键点

Persuade 和 Non-Persuade 数据之间的不兼容性

本次竞赛的关键挑战在于训练集和测试集的数据构成。在 train.csv 中,我们有 12,875 个来自 persuade 数据集的样本和 4,432 个来自 non-persuade 数据集的样本。

我的 DeBERTa-v3-large 基线训练结果如下:QWK: all (non-persuade, persuade)

Epoch 1: QWK: 0.8289 (0.7896, 0.8403)
Epoch 2: QWK: 0.8370 (0.7946, 0.8491)
Epoch 3: QWK: 0.8347 (0.7838, 0.8493)
Epoch 4: QWK: 0.8260 (0.7742, 0.8409)
Epoch 5: QWK: 0.8229 (0.7703, 0.8381)

如果我在 full_text 中添加数据源标签,non-persuade 为 '[A] {full_text}',persuade 为 '[B] {full_text}',结果如下:

Epoch 1: QWK: 0.8282 (0.7953, 0.8371)
Epoch 2: QWK: 0.8401 (0.8082, 0.8487)
Epoch 3: QWK: 0.8446 (0.8093, 0.8541)
Epoch 4: QWK: 0.8424 (0.8033, 0.8528)
Epoch 5: QWK: 0.8395 (0.8022, 0.8496)

基于实验结果,我假设这两个数据源的分数收集方式不同,因此“不兼容”。将它们混合在一起训练影响了模型的拟合能力。

假设:所有测试样本均为 Non-Persuade

在讨论帖 Adversarial Validation Probe (Train vs Test) 中,AUC 介于 0.65 和 0.675 之间。
我进行了本地测试,比例为 51% persuade 样本 + 18% non-persuade 样本作为训练集,31% non-persuade 样本作为验证集, resulting 一个 0.66x 的 AUC。

此外,一个 探测性讨论 表明测试集几乎只包含五个 prompt,这与 train.csv 中的 non-persuade 样本一致。

基于这些讨论,我相信所有测试样本都是 non-persuade。

建模

知道了这些关键点,建模过程就直截了当了。

在训练期间:

  1. 在输入中添加标签以区分数据源。
  2. 添加一个数据源分类头,以确保模型的输出特征能够区分数据源。
  3. 在某些模型中,为不同的数据源使用不同的分类头。
  4. 基于 non-persuade 样本的分数使用早停(early stopping)。

在提交期间:
假设所有样本都是 non-persuade。

此外,我尝试了交换标签用于伪标签(pseudo-labeling)和蒸馏(distillation),这似乎提供了一些轻微的改进。希望这对效率挑战有用,尽管我没来得及提交。

最终提交

我的最终提交是一个大型集成(45 个预测的平均值):

  1. 3 个模型:microsoft/deberta-large, microsoft/deberta-v3-large, Qwen/Qwen2-1.5B-Instruct
  2. 5 折交叉验证
  3. 3 次运行(不同的随机种子)

阈值是在折外(out-of-fold)预测上搜索的。

non-persuade 样本的 OOF 分数为 0.818,阈值搜索后为 0.827。

一些有用的技巧

我使用了一些技巧来加速训练和推理,你可以在我的 笔记本 中找到。

动态微批次 Collation (Dynamic Micro Batch Collation)

由于文本长度是可变的,为了减少填充(padding)的影响,我将一个批次 split 为微批次,限制 token 的总数。这使得训练更快且内存使用稳定。
梯度累积训练循环如下所示:

for batch in dataloader:
    optimizer.zero_grad()
    total_batch_size = sum(micro_batch["batch_size"] for micro_batch in batch)
    for micro_batch in batch:
        micro_batch = to_gpu(micro_batch)
        loss = model(micro_batch)
        scale = micro_batch["batch_size"] / total_batch_size
        (loss * scale).backward()
    optimizer.step()

更快的 DeBERTa 实现

我对 transformers 中的 DeBERTa 实现做了一些修改,在我的环境中实现了 15%+ 更快的训练和 30%+ 更快的推理。并且内存使用量更低。

同比赛其他方案