Kaggle赛题总结:自动写作评估 2.0
https://www.kaggle.com/competitions/learning-agency-lab-automated-essay-scoring-2
论文写作是评估学生学习和表现的重要方法。但对教育者来说,手工评分非常耗时。自动写作评估(AWE)系统可以评分文章,作为教育者其他努力的补充。AWE还允许学生及时获得关于他们写作的定期反馈。 然而,由于成本较高,许多该领域的先进技术并不普及到学生和教育者手中。有必要开发开源解决方案来评估学生的写作,以便将这些重要的教育工具普及到每个社区。
先前开发的开源AWE努力受到了小型数据集的限制,这些数据集在国家范围内缺乏多样性,并且侧重于常见的文章格式。第一次自动评分竞赛评分学生的简答回答,但这种写作任务在课堂上并不经常使用。为了改进先前的努力,需要一个更广泛的数据集,其中包含高质量、现实的课堂写作样本。此外,为了扩大影响力,数据集应包含不同经济和地理背景的样本,以减少算法偏见的可能性。
比赛主办方范德堡大学是位于田纳西州纳什维尔的一所私立研究型大学。对于此次比赛,范德堡大学与The Learning Agency Lab合作,后者是一家位于亚利桑那州的独立非营利组织,致力于为社会福祉开发基于学习科学的工具和项目。
在过去的十二年里,自动化评分技术已经取得了显著的进步,特别是在处理学生写作文章评分方面。最初的自动化评分比赛标志着这一领域的开端,但在随后的岁月里,通过更新数据集、引入新的想法和技术,我们已经取得了长足的进步。
这项比赛的目标是训练一个模型来评分学生的文章。我们希望通过您的努力,减少手工评分所需的高昂费用和时间。 可靠的自动化评分技术可以使文章评分成为可能,这是目前由于评分难度而普遍避免的测试中的重要组成部分。
提交的论文将根据二次加权kappa进行评分,该指标衡量了两个结果之间的一致性。这个度量通常从0(随机一致性)到1(完全一致性)变化。如果一致性低于预期的随机一致性,那么该度量可能会低于0。二次加权kappa的计算如下。首先,构建一个N x N的直方图矩阵O,使得对应于收到预测值的论文ID (实际值)的数量。
对于测试集中的每个essay_id,您必须预测相应的分数(在数据页面上描述)。文件应包含一个标题,并具有以下格式:
essay_id,score
000d118,3
000fe60,3
001ab80,4
...
竞赛数据集包含约24000篇学生撰写的议论性文章。每篇文章的得分在1到6的范围内(链接到整体评分标准)。您的目标是根据文本预测文章的得分。
文件和字段信息:
train.csv - 作为训练数据使用的文章和得分。
test.csv - 作为测试数据使用的文章。包含与train.csv相同的字段,除了排除了score。
sample_submission.csv - 符合正确格式的提交文件。
https://www.kaggle.com/competitions/learning-agency-lab-automated-essay-scoring-2/discussion/516791
这个一等方案展示了作者如何通过仔细的数据分析、模型训练和伪标签(pseudo-labelling)技术来提高自动评分算法的性能。以下是方案的详细介绍:
数据集包含大约12年前8-12年级学生撰写的文章。竞赛使用依赖文本的文章,但大部分数据来自说服语料库,其中包括额外的独立写作任务。竞赛数据中有约13k篇说服文章(“旧”数据)和4.5k篇未见过的(“新”数据)文章。
通过比较新旧数据,发现评分标准存在明显差异。旧数据中有两个题目在新数据中没有出现,而相同题目的评分分布也有很大不同。所有文章似乎都是同时写的(12-13年前),因为即使是“新”文章也没有提到最近的事件、政治人物或亿万富翁。
为了测试这些差异,我训练了只使用旧数据或新数据的模型,并在另一组数据上评估它们。使用Deberta集成模型对文本进行排名,并计算“作弊”分数,该分数使用测试数据的确切标签分布将排名转换为预测。这有助于缩小差距,但仍然存在相当大的差异,这让我相信评分标准确实存在差异。
由于新数据显然使用了略有不同的评分标准,我设置了分阶段的训练过程:在旧数据上预训练,然后在新数据上微调。这使得公共LB的得分至少提高了0.015,并使CV-LB相关性大大改善。每个阶段我都使用了分层的5折交叉验证。
通过两阶段方法,训练Deberta相对简单:首先找到一个不错的基线,使用Deberta base,然后找到适用于Deberta large的超参数,并生成一组可以用于创建集成模型的多样化模型。所有模型都使用回归,我主要评估MSE,因为我希望它们仅用于伪标签。
最佳参数:
参数 | 值 |
---|---|
基础模型 | Deberta large, base |
损失函数 | MSE, BinaryCrossEntropy (将目标缩放到[0, 1]) |
池化 | CLS, Gem |
上下文长度 | 1024 |
批量大小 | 8 |
学习率(躯干) | 1e-5, 5e-6 (预训练 / 微调) |
学习率(头) | 2e-5, 1e-5 |
训练轮数 | 2 |
预热比例 | 15% |
衰减 | 余弦 |
梯度裁剪 | 10 |
权重衰减 | 0.01 |
随机失活 | 0 |
增加的标记 | "\n", " " (由@cdeotte分享) |
初始化 | normal_(mean=0.0, std=0.02), bias=0 |
为了创建具有多样性的集成模型,我主要改变了池化方式、损失函数、上下文长度,很少改变学习率。较短的上下文长度有时也被选择,但权重是负的… 但有时也选择了Deberta base。
微调数据集仅包含约4.5k样本。分布在五个提示下有六个可能的分数,这意味着数据非常稀缺。不同种子的模型性能差异很大,尤其是在使用阈值处理获得整数预测时。为了解决这个问题,我将所有内容进行了3种子平均。这显著提高了可预测性。训练三倍数量的模型成本很高,但我发现只重新进行微调阶段几乎没有任何性能差异,节省了大量时间。即便如此,模型文件夹大约有2TB。
由于评分标准不同,我使用了在新数据上微调的集成模型为旧数据生成更好的分数。我进行了两轮:第一轮使用mean(score, ensemble_pred)
,第二轮仅使用预测(在第一轮数据上重新训练集成模型后)。我总是使用确切的浮点预测,没有进行舍入。
这里有些混乱,第一轮显著提高了CV,但LB只略有提升。第二轮进一步提高了CV,但LB却下降了。CV似乎没有很好地相关——我担心有漏掉的地方(我没有改变微调阶段,只使用了原始标签),所以没有多用第二轮。然而,一个“坏”模型在私有LB上得分0.839(单模型,单种子),可能我应该更相信CV。
很多人发现使用自定义值(1.67而不是1.5)进行舍入可以显著提高结果。通过我的测试,它似乎做了几件事:
第1点显而易见,第2点是由于回归损失和不平衡的数据——true_label==2
的错误总是偏向多数类3而不是1,导致后者被低估。最后一点,第3点很重要,因为通过移动预测值(通常朝向少数类),Cohen's Kappa可以增加,即使它会减少准确性/MSE。参见示例。对于1/2的典型阈值是1.7,对于5/6甚至是4.9(有很少的6分,有些提示根本没有6分!)
尾部数据非常稀缺,不同模型种子的舍入阈值差异很大。我总是使用三个种子计算阈值,没有这个太像赌博了。
所有我的提交都是全数据训练的(使用所有数据训练模型),这意味着它们总是与OOF有些不同,即使使用相同的种子。平均可能有助于这一点。
为了找到阈值,我使用了scikit.optimize
中的minimize
,优化目标是1 - qwk
。结果似乎比Optuna等猜测方法更可靠、更快。找到的阈值基于优化起点有所不同,我平均了15个不同的起点。
https://www.kaggle.com/competitions/learning-agency-lab-automated-essay-scoring-2/discussion/516582
为什么需要两阶段训练? 在我看来,如果我们使用整个训练集训练,模型会更多地学习Kaggle-Persuade的分布(可能因为其数据量较大?我想),这会导致在Kaggle-Only集上表现不佳。因此,使用两阶段训练让模型先从Kaggle-Persuade中学习知识,然后在Kaggle-Only上微调以学习Kaggle-Only的分布,这更类似于我们的隐藏测试集。
我使用OptimizedRounder 此处 为每个单模型和混合模型搜索最佳阈值。经过一些实验,我发现5和6的最后一个阈值是次优的。因此,我创建了一个for循环来搜索最佳的最后一个阈值,这提升了CV、LB和PB。
一个简单的想法是仅在Kaggle-Only数据集上搜索阈值,因为这些文本更类似于测试集。尽管这给了很好的CV,但LB下降了很多,因此我假设隐藏测试集的分数分布与我们的完整训练集相似。然后我仅在整个训练集上进行阈值搜索,结果是好的LB/PB。
vhttps://www.kaggle.com/competitions/learning-agency-lab-automated-essay-scoring-2/discussion/517014
使用数据:Data B。
目标:加载阶段1的权重,仅在 Data B 上进行训练,同时在 Data A 上进行评估以防止过拟合。
结果:该策略显著提高了 CV 和私人排行榜(LB)分数,特别是对 Data B,表明该方法的有效性。
换行符的特殊标记:DeBERTa 模型忽略换行符("\n"),因此将其转换为 "[BR]" 并在 tokenizer 中设为特殊标记。这一步预处理步骤遵循了先前 FeedbackPrize 竞赛中使用的方法。
最初,方案基于提示名称使用分组 k 折交叉验证(group k-fold),这导致了高排行榜分数但存在显著的折间变异和数据不平衡。随后,策略转变为基于提示名称和分数的多标签分层 k 折交叉验证(Multilabel Stratified K-Fold),分别应用于 Data A 和 Data B。
最终集成使用 Nelder-Mead 优化方法,关注以下模型配置:
https://www.kaggle.com/competitions/learning-agency-lab-automated-essay-scoring-2/discussion/516639
竞赛的一个关键挑战在于训练和测试数据集的组成。在 train.csv
中,有 12,875 个样本来自 Persuade 数据集,而 4,432 个样本来自非 Persuade 数据集。
在 DeBERTa-v3-large 基线训练中,不同 epoch 的 QWK 结果如下:
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
,如 '[A] {full_text}'
表示非 Persuade 数据,'[B] {full_text}'
表示 Persuade 数据,结果如下:
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)
基于实验结果,我假设这两种数据源的评分方式不同,混合训练会影响模型的拟合能力。
我的最终提交是一个大型集成(平均 45 个预测):
microsoft/deberta-large
、microsoft/deberta-v3-large
、Qwen/Qwen2-1.5B-Instruct
由于文本长度不固定,为减少填充的影响,我将一个批次拆分为总 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()