返回列表

5th place solution: 1.7 million training examples + domain adaptation

593. LLM - Detect AI Generated Text | llm-detect-ai-generated-text

开始: 2023-10-31 结束: 2024-01-22 AI安全与对抗 数据算法赛

第5名解决方案:170万训练样本 + 领域适应

作者: James Day
竞赛排名: 第5名
发布时间: 2024-01-23

感谢竞赛组织者创建了如此有趣的比赛!我学到了很多。也祝贺其他获奖者!

概述

在以下数据集的不同混合上微调了 deberta-v3-largemamba-790m

数据集 人类文档数 生成文档数
PERSUADE论文 25,996 327,268
无版权Pile补全 512,371 512,371
SlimPajama补全 233,146 233,146
Tricky Crawl 125,192 0

各个模型在集成中的采样比例有所不同,但一个反复出现的模式是,除了Pile数据外,其他所有数据都被欠采样。最佳模型使用了62-99%的Pile数据,这是我们最高质量的数据集。PERSUADE论文始终占数据混合的1%。

在测试时,我们的推理笔记本执行以下操作:

  1. 教师模型推理:测试数据集由1个DeBERTa模型和2个Mamba模型进行标注,上下文长度为1024个token。最终的软标签是加权平均,其中DeBERTa模型占90%的权重。使用Mamba在这里拖累了我们,如果没有它,我们本可以获得第3名(0.977分)。
  2. 学生模型训练:微调2个"短上下文学生"模型,基于测试文档的随机选取短片段来模仿教师集成的预测。一个学生模型的上下文长度为128个字符(约32个token),另一个使用256个字符。这些学生模型在来自上述数据集的100万文档上进行了预训练,主要是Pile数据,且都基于deberta-v3-large。
  3. 学生模型推理:微调后的学生模型以等于其上下文长度一半的步长对测试文档的重叠片段进行预测。每个文档的最终预测是所有这些预测的平均值,其中128字符模型的预测占60%权重,256字符模型的预测占40%权重。

我对这种领域适应策略为何有益的直觉是,短上下文学生模型学会了寻找与长上下文模型在更广文档中寻找的内容相关的特定数据集措辞怪癖。这个策略主要受到SimCLR的启发,但事后看来,我也意识到它类似于Noisy Student TrainingUDA

仅使用全上下文DeBERTa模型在私有排行榜上得分为0.970,Mamba模型得分约为0.957。最终学生模型在没有Mamba的情况下得分为0.977,有Mamba时为0.972。我们没有将最佳提交选为最终的3个提交之一,因此获得了第5名而不是第3名。此外,我们使用的DeBERTa模型并非最佳……我们有一个模型单独得分0.976,无需领域适应。

数据

所有数据集的共同点

  • 在2×RTX 3090 + 1×RTX 4090上运行vLLM来生成AI撰写文本的示例
  • 对任何参数≥13B的模型使用4-bit AWQ量化以节省GPU内存
  • 采样温度从0-2随机变化(每个vLLM API请求使用不同的随机选择温度)
  • Top-K过滤器从[禁用, 20, 40]中随机选择
  • Top-P过滤器从0.5-1随机变化
  • 频率惩罚从0-0.5随机变化

无版权Pile补全

创建此数据集的一般策略是:从The Pile随机选择文档,随机截断它们,然后提示本地托管的LLM生成文档最后25-75%的合理续写。我最初使用了一个包含版权数据且不再公开可用的旧版Pile,但过滤后仅保留基于无版权限制子集的文档补全,这些子集仍公开可用

使用以下模型生成文档补全。以下文档数量来自后处理过滤后(如果我没记错的话,大约丢弃了16%的数据)。

模型 文档数量
Airoboros-L2-13B-2.1-AWQ46,358
CodeLlama-34B-AWQ29,885
falcon-7b11,178
Llama-2-13B-AWQ61,531
Llama-2-13B-chat-AWQ43,145
Llama-2-70B-AWQ31,297
Mistral-7B-Instruct46,825
Mistral-7B-v0.161,851
mpt-7b12,232
OpenHermes-2.5-Mistral-7B21,221
StableBeluga2-70B-AWQ21,046
WizardCoder-Python-34B-V1.0-AWQ41,716
WizardLM-70B-V1.0-AWQ41,979
zephyr-7b-beta42,093

对于基础模型,提示只是文档前缀。对于指令或聊天调优的模型,我将文档前缀随机分成两部分,第一部分用于形成"用户"指令,请求对文档进行合理续写,第二部分用作"引导词",在模型通常填充的token序列部分中(在类似"### Response:"的标记之后,具体取决于模型期望的格式)。引导词有助于确保模型生成看起来合理的文档补全,而不会出现奇怪的前缀或拒绝。

这些数据分两个阶段生成。我从早期数据训练模型观察到的结果以及为最后约15%所做的更改如下:

  • 使用初始数据训练的模型在识别采样温度接近1的生成文本方面表现最差。作为回应,我将采样温度的选择从0-2的均匀分布改为以1为中心、标准差为0.2的高斯分布,并限制在0-2范围内。这有助于将更多硬件资源集中在我的分类模型难以处理的棘手数据上。
  • 我的模型最擅长识别与Pile医学子集(PubMed Central和PubMed摘要)相关的AI生成文本。因此,我认为向训练数据集中添加更多医学相关文本是浪费硬件资源,并开始在进行LLM提示之前过滤掉这些内容(而不是像处理版权问题数据那样作为后处理步骤)。
  • 我的模型最不擅长识别AI生成的代码。这些数据似乎与竞赛不太相关,因此我开始过滤掉Pile的GitHub切片中的所有数据,类似于我对PubMed所做的处理。

SlimPajama补全

我创建此数据集的方式与最后一批Pile补全非常相似,只是使用了来自SlimPajama的源文档而不是Pile,并且模型组合略有不同。生成这些数据的目的在于,希望减轻因过滤掉Pile中有问题(版权)部分而导致的精度损失。它在公共排行榜上并没有太大帮助,但可能在私有排行榜上有所帮助——我需要更仔细地回顾分数。

我用于创建此数据集的模型组合如下:

模型 文档数量
airoboros-l2-70B-gpt4-1.4.1-AWQ23,399
deepseek-coder-33B-base-AWQ20,718
dolphin-2.6-mistral-7b24,168
Mistral-7B-Instruct-v0.224,813
Mistral-7B-v0.124,618
mixtral-8x7b-v0.1-AWQ24,609
Mixtral-8x7B-Instruct-v0.1-GPTQ24,581
Nous-Hermes-2-SOLAR-10.7B-AWQ22,833
Nous-Hermes-Llama2-AWQ18,741
SOLAR-10.7B-v1.0-AWQ24,623

我对SlimPajama的一个担忧是(这也是我最初没有使用它的原因),它包含收集于ChatGPT发布之后的互联网文本,因此可能会有一些AI生成文本被错误标记为训练时的"人类"文本。这可能就是为什么它似乎比Pile数据质量更低的原因。

PERSUADE论文

我为与PERSUADE语料库中学生论文相同的作业生成了超过30万篇论文。这些论文分为3个子集,采用不同的生成策略:

  • 基础:约13.7万篇论文,使用各种提示策略。0-shot或1-shot,使用约140种不同的指令集来改变LLM的写作风格。使用了11种不同模型的组合。
  • 学生模仿器:为了使AI生成论文更难识别,我微调了Mistral 7B和Llama 2 13B来模仿PERSUADE语料库中学生的写作风格。使用生成的模型约23.7万篇论文,其中约17.7万篇用于训练和交叉验证。其余的由于微调期间的问题导致LLM输出不连贯的文本而被丢弃。
  • 对抗:我对抗性地生成了约1.2万篇论文,这些论文会混淆17个"受害者分类器"的混合体。生成这些论文的主要策略是回溯并在论文开始听起来"太像AI生成"时重试。然而,某些LLM似乎无法生成在某些作业上能欺骗我的分类器的引言,因此许多论文以真实人类文本开头以"通过引言"。然而,即使如此,这些论文的生成成本仍然是"普通"论文的约100倍,所以数量不多。

不幸的是,与Pile数据相比,这些论文并不是很有用。我的分类器似乎很快就会过拟合,需要更多样化的数据才能很好地泛化。

Tricky Crawl

这是通过过滤The Pile的Common Crawl子集(Pile-CC)创建的,目的是提取出被2个中等强度的通用AI内容检测模型误分类为AI生成的人类撰写文本。其中一个分类器基于deberta-v3-base,另一个基于deberta-v3-xsmall。

用于最终提交模型训练的此数据集版本是通过过滤150万文档创建的,提取出对受害者分类器来说最混乱的约12.5万篇文档。

此数据集背后的总体思路是通过增加训练数据集中棘手人类文本的数量来减少假阳性。以5%的采样比例(即5%的训练示例来自此数据集)将其混合到训练数据集中,似乎对短上下文模型有益,但对全上下文模型没有太大差异。

数据增强

竞赛组织者的数据似乎有些损坏,因此我们解决方案中的模型经过以下数据增强步骤以提高鲁棒性:

  • buggy拼写检查类似于@deltawi此讨论帖中描述的实现。然而,我使用了一个正则表达式,似乎能更一致地处理竞赛数据中的'字符,并使用了jamspell而不是pyspellchecker,因为jamspell更快。对于PERSUADE文档以70%的概率执行,对于所有其他数据集以20%的概率执行。
  • 黑名单字符移除使用@nbroad此讨论帖中建议的相同黑名单。对于PERSUADE文档以70%的概率执行,对于所有其他数据集以20%的概率执行。
  • 添加拼写错误。更具体地说...
    • typo库支持的所有拼写错误都有2次机会以每次10%的概率添加到所有训练示例中。
    • 随机字符的大小写被翻转。2次机会将大写字母转为小写,1次机会将小写字母转为大写。所有这些拼写错误的"机会"对每个文档都有10%的发生概率。

Mamba vs. DeBERTa

效率

mamba-790m的速度大致与deberta-v3-large相当,尽管参数超过2倍,但在训练期间消耗的GPU内存更少。由于它是结构化状态空间模型而非Transformer,因此似乎具有一些重大效率优势。

准确率(和稳定性问题)

mamba-790m在Pile数据的本地CV上做得几乎和DeBERTa一样好(低0.001-0.002),在公共排行榜上也几乎一样好(比"不幸"的DeBERTa运行低约0.003,比"良好"的DeBERTa运行低约0.006)。主要差异出现在私有排行榜上。Mamba的得分从公共到私有基本保持不变,而大多数DeBERTa模型跃升了约0.01。结果,Mamba在公共排行榜上似乎略有作用,以低权重集成时,但在私有排行榜上却拖累了我们。

我认为Mamba在这里的弱点并非真正由于架构缺陷或结构化状态空间模型天生劣于Transformer,而是因为这是我第一次使用Mamba,我在竞赛最后3-4天匆忙训练它。此外,mamba-ssm库似乎主要用于文本生成,而非分类,因此用于此类工作负载并不太直接。

详细说明我训练时的错误,我通常像这样初始化Mamba模型:

model = MambaLMHeadModel.from_pretrained("state-spaces/mamba-790m")
model.lm_head = nn.Linear(model.config.d_model, 2)

这导致其输出形状为(batch size, token count, 2)的预测。在早期训练中,我使用如下操作从每个序列的最后一个token获取类别标签预测:

raw_predictions = output.logits[:, -1, :]

这种方法的问题在于token序列是填充的,填充影响了预测。通过使用如下操作从填充开始前最后一个token获取预测:

last_token_indices = torch.clamp(attention_masks.sum(dim = 1) - 1, min = 0)
raw_predictions = torch.gather(
    logits, 
    dim=1, 
    index=last_token_indices.unsqueeze(1).unsqueeze(2).expand(-1, -1, logits.shape[2])
).squeeze(1)

似乎使最佳学习率提高了约8倍,并允许在相对小规模的训练运行中(仅对10万个示例文档进行一个epoch)更快地收敛到更准确的模型。然而,当我尝试以更高的学习率扩展到更多数据时,它变得不稳定。弄清楚这一点后,我并没有太多时间正确地训练它。因此,第5名解决方案使用的2个Mamba模型是通过以下非理想设置训练的:

  • 125万训练文档,使用原始的logit选择方法([:, -1, :])和相对较低的学习率(batch size为4时2e-6)。此训练在后台执行,而我使用其他GPU来弄清楚如何"正确"训练Mamba。
  • 35万训练文档,前70%训练的最大学习率设置得过高(1.6e-5),随后反复出现问题:损失变为nan,模型开始输出垃圾,因此需要从学习率低得多的旧检查点反复重启。我最终在最后30%的训练中手动将学习率一路降至5e-7,并且没有时间像大多数其他模型那样在更多数据上训练它。我怀疑如果我从头开始使用配置良好的学习率调度并开始运行,并使用更多的数据,我会得到更好的结果。

额外训练细节

  • Dropout:所有模型完全禁用。
    • 遇到奇怪行为:如果用Huggingface transformers库的默认dropout率训练DeBERTa模型,它们在推理时如果保持dropout启用(即保持"train"模式而非切换到"eval"模式)会更准确。我怀疑这是因为DeBERTa使用非标准的StableDropout层,似乎进行某种内部归一化,模型学会了依赖这一点,从而迫使我保持dropout启用以获得最佳结果。不用说,在测试时随机丢弃模型中的连接对准确率不好。在训练和测试时都禁用dropout,即使与通过启用dropout的模型进行多次前向传递的平均值相比,我也获得了更好的结果。
    • mamba-ssm库不支持dropout。
  • 学习率调度:线性预热后接线性衰减。通常在本地训练运行中预热前5%的训练,在测试时的领域适应中预热30%。领域适应期间更长的预热似乎使其更稳定,结果更一致,但我没有对此进行太多实验。
  • 批量大小:对于1024 token上下文长度的模型,DeBERTa使用批量大小2,Mamba使用4,主要是因为Mamba更节省内存。对于领域适应中使用的短上下文模型(32-96 token),我通常使用批量大小16。
  • 数据混合:
    • 1024 token上下文的DeBERTa模型:99% Pile,1% Persuade
      • 其他数据集在公共排行榜上对长上下文模型似乎没有帮助,但我们在私有排行榜上最好的单个模型(得分0.976)使用的是用于最终提交的短上下文DeBERTa模型的数据混合。
    • 短上下文"学生"DeBERTa模型:62% Pile,32% Pajama,5% Tricky Crawl,1% Persuade
    • Mamba:77% Pile,20% Pajama,2% Tricky Crawl,1% Persuade
  • 数据量:通常只对可用数据的某些子集进行一个epoch的训练,并对部分数据进行欠采样。
    • 全上下文DeBERTa:140万训练文档(不耐烦等待超过2天来训练更多数据,且怀疑如果没有增加数据多样性会帮助不大)
    • 短上下文DeBERTa:100万训练文档(这些模型在测试时进行微调,因此我不认为预训练更长时间有任何好处)
    • Mamba:35万-125万训练文档(如果有时间我本可以训练更多——关于DeBERTa与Mamba的部分有关于此事的抱怨,称这是匆忙且非理想的)

我们尝试过的替代方案

  • 1D卷积ResNets(在排行榜上得分≤0.87,但极其快速,无需GPU加速约10分钟即可在排行榜上评估——如果扩展可能会得分更好,但DeBERTa从一开始就给出了更好的结果)
  • 仅使用PERSUADE相关数据训练基于深度学习的解决方案(它们不能很好地泛化到排行榜数据——扩展到更大的Transformer对此没有帮助)
  • 将DeBERTa模型与tf-idf集成(在公共排行榜上得分很好,但在shakeup期间表现糟糕)
  • 更小的DeBERTa模型(它们得分不高)
  • 仅使用更小上下文窗口的模型(它们得分不高)
  • 尝试了类似于@asalhi第21名解决方案中使用的迭代伪标签策略(https://www.kaggle.com/competitions/llm-detect-ai-generated-text/discussion/470148)。由于似乎取决于训练/测试数据如何打乱的大随机分数变化而丢弃了此方法。我们第5名解决方案中使用的领域适应策略得分更稳定。
同比赛其他方案