返回列表

3rd Place Solution

674. Jigsaw - Agile Community Rules Classification | jigsaw-agile-community-rules

开始: 2025-07-23 结束: 2025-10-23 内容安全 数据算法赛
第三名解决方案
作者: Sergio Manuel Papadakis (Grandmaster)
发布日期: 2025-10-26
竞赛排名: 第 3 名

第三名解决方案

首先,我要感谢 Kaggle 和 Jigsaw ACRC 组织并主办了这场精彩的比赛。

我公开了我的最佳提交方案:notebook

该解决方案基于以下思路

  • 由于许多规则是隐藏的,我依赖测试时训练(Test-Time Training, TTT)在推理期间拟合模型。
  • 我构建了一个强大的模型集成,其表现优于任何单个模型,并且能够抵御公共排行榜和私有排行榜之间的分数波动。
  • 所有模型和最终集成都在公共排行榜(Public LB)上进行了验证。
  • 我在 12 小时的推理窗口期内尽可能多地拟合了模型。
  • 最终集成由 2 个子集成组成:
    1. 慢速集成 (slow ensemble):由 LLMs 组成:2xQwen2.5-instruct-14b, 2xQwen2.5-instruct-7b, 2xQwen3-instruct-14b 和 2xQwen3-instruct-8b
    2. 快速集成 (fast ensemble):由更快的模型组成:2xbge-base-v1.5, Qwen3-embedding-0.6bDeBERTa-v3-small

训练方法

  • 为了进行预训练和 TTT,使用所有规则、正文/示例及其对应的已知目标构建了一个新数据集。
  • 丢弃了 subreddit 列。事实证明它在预训练和 TTT 阶段都无用。
  • 预训练阶段使用此 notebook 进行。

慢速集成 (Slow ensemble)

  • LLMs 使用公共数据集进行了 1 个 epoch 的预训练。
  • LLMs 预训练以零样本 (zero-shot) 方式完成,使用以下提示词:
    • 系统提示词 (System prompt): "You are given a comment on reddit. Your task is to classify if it violates the given rule. Only respond Yes or No.\nRule: {rule_str}"
    • 用户提示词 (User prompt): "1. ```{example_body_str}```\nViolation:{answer_str}"
  • 预训练阶段的输出是 LoRA 权重。这些权重随后用于设置 TTT 阶段的起点。这种方法有助于模型在 TTT 期间获得更好的性能,因为所有 LoRA 已经了解了竞赛任务和使用的提示词。
  • 我使用 Unsloth 库在预训练和 TTT 期间训练 LLMs。Unsloth 使我能够将一个模型放置在一个 GPU (T4) 上并并行执行训练。
  • 推理使用 vLLM 执行,输出由最后一个 token 的嵌入 (embeddings) 组成。
  • 为了在 12 小时的推理窗口期内容纳所有模型,我合并了两个 Qwen2.5-instruct-7b 的 LoRA 权重,并作为单个模型运行推理。同样的方法也应用于两个 Qwen3-instruct-7b 模型。
  • 在 TTT 期间,我使用最终的 LoRA 对训练集和测试集进行推理。输出是最终 "Violation:" token 的嵌入。
  • 这些嵌入用于拟合一批交叉验证的经典机器学习 (ML) 模型 (LightGBM, XGBoostSVC)。这背后的想法是利用训练数据集(在 TTT 期间使用)来训练这些 ML 模型,以输出可以与其他模型的相应概率进行集成的概率。

快速集成 (Fast ensemble)

  • 快速集成中的所有模型都没有预训练阶段,它们仅在 TTT 期间进行训练。

bge-base-en-v1.5:

  • bge-base-en-v1.5 模型使用三元组损失 (Triplet Loss) 进行训练,如公共 notebook 中建议的那样。
  • 我训练了两个版本的此模型:一个使用给定的规则 (NormalRules),另一个使用翻转的规则 (FlippedRules)(例如,不说“不要提供法律建议”,而是否定规则为“提供法律建议”)。
    • NormalRules 版本:三元组损失中的正样本是没有违规的示例,负样本是有违规的示例,锚点 (anchor) 是规则。
    • FlippedRules 版本:示例被反转:三元组损失中的正样本是有违规的示例,负样本是没有违规的示例,锚点是反转的规则。
  • 训练后,最终模型用于为数据集中的所有示例和正文生成嵌入。我计算了正负中心嵌入 (centroid embeddings),并将最终嵌入组合为: final_embedding = concat([body_embeddings - positive_examples_centroid_embedding, body_embeddings - negative_examples_centroid_embedding])
  • 使用这些嵌入拟合了一组新的 ML 模型来预测规则违规。最终预测用于输入快速集成。

Qwen3 embedding 0.6b

  • 我训练了一个 LoRA 来使用 ArcFace 损失预测规则违规,输出类别只有两个:rule_violation, no_rule_violation(我也尝试过其他配置,例如每个规则一个类别,但在我的测试中效果不佳)。
  • 作为此模型的输入,我只使用了正文(我也训练过使用 '{rule}: {body}' 作为输入,但分数没有提高)。
  • 我使用平均池化 (mean pooling) 从训练集和测试集中的所有正文和示例中提取嵌入。
  • 使用这些嵌入,训练了一组新的 ML 模型来预测每个规则的违规情况。生成的预测随后用作快速集成的输入。

DeBERTa v3 small

  • 为了训练 DeBERTa v3 small 模型,我使用了交叉熵损失 (cross entropy loss),并从第一个 token ([CLS] token) 提取嵌入。
  • 作为此模型的输入,我使用了 '{rule}[SEP]{body}'
  • 使用这些嵌入拟合了一组新的 ML 模型来预测规则违规。
  • 从 ML 模型获得的概率与 DeBERTa 模型的输出概率取平均。最终预测用于输入快速集成。

部分集成分数

模型 公共分数 (Public Score) 私有分数 (Private Score)
2xQwen2.5-instruct-14b 0.90828 0.90248
2xQwen3-instruct-14b 0.92571 0.92049
2xQwen2.5-instruct-7b 0.91024 0.90637
2xQwen3-instruct-8b 0.89598 0.88969
2xbge-base-v1.5 0.90952 0.89714
Qwen3-embedding-0.6b 0.88856 0.88021
DeBERTa-v3-small 0.89546 0.88946
同比赛其他方案