返回列表

1st Place Solution

667. NeurIPS - Open Polymer Prediction 2025 | neurips-open-polymer-prediction-2025

开始: 2025-06-16 结束: 2025-09-15 化学与材料 数据算法赛
第一名解决方案 - NeurIPS Open Polymer Prediction 2025

第一名解决方案

作者: James Day (jsday96)
比赛: NeurIPS Open Polymer Prediction 2025
发布时间: 2025-09-17
排名: 第 1 名

概述

我的解决方案是 BERT、AutoGluon 和 Uni-Mol 模型的集成。我认为使我获胜的独特之处在于:

  1. 对预测的玻璃化转变温度 (Tg) 进行后处理,以解决训练集与榜单数据集之间的分布偏移。
  2. 在 PI1M 的伪标签子集上预训练 BERT 模型。

我还从训练外部标注数据集和一些表格特征工程技巧中获得了重大收益,但怀疑这些方面并不是特别独特。

下方包含了最终集成中每个模型的分数。这些是原始分数,未经过后处理技巧。最终集成中的所有模型都是特定属性的(非多任务),因此下面的每一行对应于 5 个相同类型的模型,分别为 5 个目标属性生成预测。

模型 公共榜单分数 私有榜单分数
ModernBERT-base 0.059 0.089
CodeBERT 0.058 0.090
AutoGluon 0.062 0.091
Uni-Mol 2 84M 0.062 0.091

集成模型分数:

是否使用后处理? 公共榜单分数 私有榜单分数
0.058 0.089
0.054 0.075

后处理

简而言之 - 关键技巧是 submission_df["Tg"] += (submission_df["Tg"].std() * 0.5644)

详细版本:

我不相信 LB 测试数据在最后一次更新后完全固定,所以我做了一些探测,通过将每个属性的预测值调整 +/- 0.1 * (该属性预测值的标准差) 来检查分布偏移。这 reveals 了 Tg 存在一些问题,但我没有立即尝试调查或 aggressively 利用它,因为我认为这可能是随机噪声,如果真的有问题,其他人可能会抱怨。然后,在最后一周,我开始探测以找出最佳偏移量,这 reveals 了测试数据存在严重问题。下方的图表包含了这些结果。这部分基于我在比赛结束后通过晚期提交所做的一些补充探测,用于决定后处理如何工作的结果不太完整。

后处理探测结果图表

我所应用的集成模型的原始 Tg 预测不可能偏差这么大,即使是对于标签稀疏的公共 LB 数据也是如此,因此系数 <= 0.5 的不完整探测足以让我相信测试数据出了问题。问题太严重了,我甚至不认为低行数和潜在的稀疏标签足以让随机噪声成为合理的解释;我基于一些粗略假设计算出的 p 值 < 0.01,因此我将此视为统计证据,表明测试数据集的标签系统性地错误超过 99% 的概率,随机噪声不是合理的解释。

我在想,如果标签偏离了一个常数偏差项(由于宿主数据准备管道中的错误),那么“偏差系数”(简而言之中的 0.5644 魔法常数)与 LB 分数之间的关系可能可能是某种"V"形曲线,在某最佳点两侧具有线性函数,且斜率符号相反但大小相同。基于偏差系数 <= 0.5 或 == 1.0 的公共 LB 分数,可以拟合一个几乎完美符合数据的 V 形曲线,预测的最佳系数为 0.5644,这确实在公共 LB 上比我迄今为止尝试的任何东西得分都高。我还尝试了分段函数,在某些范围内对原始预测应用更高或更低的偏移,以及依赖于 Tg 预测的线性斜率,但无法 quickly 让任何这些方法得分优于对所有预测相同的简单常数偏差,所以这是我最终提交之一所采用的方法。另一个最终提交只是生成了原始 Tg 预测,以防私有 LB 数据中问题已修复(但并没有)。

现在私有 LB 分数已经 reveal,很明显导致训练与公共 LB 分布偏移的原因在私有 LB 数据中更严重,但我直到最后才看到这一点。因此,我选择的后处理有些次优,但我并没有像大多数其他竞争者那样被完全蒙蔽。

处理脏训练标签

榜单的测试数据集并不是唯一拥有脏标签的,我训练的所有外部数据集也有自己独特的不良怪癖。通常是随机标签噪声、与真实值具有奇怪非线性关系的标签、偏离某些常数偏差因子的标签和/或分布外的异常样本的混合。我使用了以下概述的 5 种策略混合来处理。前 3 种策略的组合足以从大多数数据集中提取有用的东西,最后 2 种仅在少数情况下使用。

  1. 标签重缩放: 我使用了一个相当强的集成模型(其预测在交叉验证测试期间与“真实值”具有非常好的线性关系)来预测每个聚合物的属性,该集成模型仅 trained 于宿主的原始训练数据,然后训练了一个保序回归模型来基于原始数据集标签预测该集成模型的预测,然后使用该保序回归模型的预测作为重缩放标签。想法是,如果数据集的原始标签偏离了某个常数偏差因子或与真实值具有奇怪的非线性关系,保序回归模型将学习调整这一点并产生更干净的标签。为了减少过拟合,用于训练我最终模型的标签通常是原始标签和重缩放标签的加权平均,权重由 Optuna 按数据集基础调整。
  2. 基于误差的数据过滤: 在上述重缩放步骤之后,我的代码计算每个标签与集成预测之间的绝对差,然后丢弃所有误差超过某个阈值的样本。这些阈值通常表示为样本误差与集成在针对原始宿主数据集测试时观察到的平均绝对误差的比率,因此所有属性的阈值都在相似范围内,这使得更容易定义搜索空间供 Optuna 在寻找最佳配置时探索。
  3. 样本加权: 即使经过上述清理步骤,某些数据集的质量仍然低于其他数据集。因此,我让 Optuna 按数据集基础调整样本权重,以便模型可以较少关注来自低质量数据集的训练示例。
  4. 半手动过滤规则: RadonPy GitHub repo 中的"data.csv"文件有一些我认为可疑地高的热导率值(基于集成预测与数据集标签的散点图)。因此,我创建了一个变体,丢弃所有 Tc 值高于 0.402 的行。Optuna 在调整外部数据使用配置时通常倾向于这个版本而不是原始版本,所以我认为这种过滤对大多数模型都是有益的。
  5. 模型堆叠: 我没有对上述基于我自己运行的 MD 模拟的属性或分子描述符使用清理方法。部分是因为我生成的数据有我想要利用的补充指标,部分是因为我直觉觉得我的一些标签可能太脏了,没有任何过滤、重缩放和重新加权能够从中提取有用的东西。因此,我转而训练了 41 个 XGBoost 模型的集成来预测模拟结果,然后使用这些模型的预测作为补充特征输入到 AutoGluon 作为我解决方案表格部分的输入。想法是第二级模型可以学习基于数据中可能存在的任何奇怪非线性关系进行预测。对于表格模型,与完全不使用模拟结果相比,这给了我 CV wMAE 分数约 0.0005 的改进,所以我认为这是有用的。

为了在调整外部数据配置时保持交叉验证结果一致,并防止不现实的测试样本影响我的 CV 分数,交叉验证分数仅使用来自原始宿主数据的样本进行计算。 broadly speaking,CV 策略是在 100% 选定的外部数据 + 80% 宿主数据上训练,然后在 20% 宿主数据上测试,然后重复该过程 5 次,每次保留不同的宿主数据。

我没有仔细跟踪上述第 1-4 项有多大帮助,但 Optuna 非常喜欢它们,足以以一些相当积极的配置启用它们,所以我认为它们在本地交叉验证测试中至少是有益的。

去重

许多数据集包含彼此重复或近乎重复的聚合物。我使用了两种策略的混合来处理这个问题,为了避免训练集和测试集之间的泄露,比训练数据内的重复更积极地去重。

  • 消除训练数据内的重复: 我在检查重复 SMILES 之前将所有 SMILES 字符串转换为其规范格式。如果两个训练示例具有相同的规范 SMILES,则丢弃具有较低样本权重(由 Optuna 根据其来源的数据集选择)的那个。这会导致在标签冲突的情况下丢弃来自低质量数据集的重复项。并且因为所有 SMILES 在去重之前都转换为其规范格式,轻微的符号差异不足以欺骗此去重逻辑。
  • 避免训练与测试泄露: 对于每个测试 fold,计算所有可能的训练和测试单体对之间的 Tanimoto 相似度分数,并丢弃与测试数据集中任何单体相似度分数高于 0.99 的任何训练示例,以消除近乎重复项。回想起来,虽然存在具有不同规范形式的近乎重复项,但如果我让它们通过,它们对交叉验证分数影响不大,所以我认为只检查 exact-duplicate 规范 SMILES 可能就足够了。这种过滤主要源于一个 bug,该 bug 导致我看到不现实地“好”的 CV 分数,并且在消除数据泄露方面变得比平时更加偏执;即使在 bug 修复后,我也保留了它。

BERT

我的 BERT 模型分 2 个阶段训练,这是在 HuggingFace hub 上计算预训练权重 whatever 预训练之后。

  1. 在 PI1M 上预训练: 我使用了 BERT、Uni-Mol、AutoGluon 和 D-MPNN 模型的集成来预测 PI1M 中 50,000 个假设聚合物的属性,然后在分类任务上预训练其他 BERT 模型,以预测哪些聚合物对具有更高或更低的属性值。对于具有相似属性值的对,忽略损失值,这减少了模型暴露于与原始集成预测不准确相关的标签噪声的程度。为了效率,这是一个多任务分类目标;模型被预训练为一次计算所有 5 个属性的分类结果,所以我不必为每个属性训练单独的基础模型。这 inspired by 论文"RankUp: Boosting Semi-Supervised Regression with an Auxiliary Ranking Classifier",但我发现使用预计算的伪标签进行预训练比原论文中描述的在线版本效果更好。与仅使用来自 HuggingFace 的预训练模型权重相比,它将我的 BERT 模型分数提高了约 0.004 LB,约 0.01 CV(尝试了 5 个不同的第三方基础模型,添加这个额外的预训练阶段提高了它们所有的分数)。一些在此预训练后微调的模型比用于计算伪标签的原始教师集成更准确,所以我认为它比标准知识蒸馏更有效。
  2. 微调: 这方面的大部分内容对于 BERT 微调脚本来说非常标准 - AdamW 优化器,没有层冻结,带有线性衰减的一个周期学习率计划,自动混合精度,使用 optuna 调整学习率 + 批量大小 + epoch count,梯度范数裁剪为 1 等。唯一感觉有点不寻常或特定于领域的是数据增强策略以及对回归头和骨干网络使用单独的学习率计划(具有不同的 max_lr 值)。数据增强在后面自己的部分讨论更多。至于双重 max_lr 技巧(将头的学习率设置为高于骨干网络使用的值),我以前听说过人们这样做,并且听说它通常对小数据集有益,但我自己从未用过。对于此竞争中的大多数基础模型和目标属性,我发现将头学习率设置为骨干网络学习率的一个数量级高一点略有beneficial。训练数据集相对较小,所以这并不太令人惊讶。

数据增强:

  • 训练时增强: 在预训练和微调期间,我使用了 Chem.MolToSmiles(..., canonical=False, doRandom=True, isomericSmiles=True) 为每个输入 SMILES 创建 10 个非规范 SMILES,以增加训练数据量约 10 倍。我还尝试了随机使用 Kukulized SMILES,去除立体化学,并使氢和键更明确,但这些增强没有beneficial。
  • 测试时增强: 我的推理代码使用与训练期间使用的相同数据增强策略为每个 SMILE 生成 50 个预测,只是随机变化量增加了 5 倍。每个 BERT 模型的最终预测是这 50 个预测的中位数。

仅测试时增强就在一个早期实验中提供了约 0.01 的 LB 改进。我的笔记太碎片化了,无法在没有额外消融测试的情况下准确说明训练数据增强有多大帮助,但我印象非常深刻,并且 10 倍的训练数据增强因子在 +/- 30% 的范围内是最佳的(与测试时增强不同,越多越好)。

基础模型选择:

  1. 特定化学的基础模型不是很好: 在一轮没有伪标签训练数据的实验中,使用 ChemBERTa 达到的最佳 CV wMAE 分数为 0.0634,使用 polyBERT 达到的最佳分数为 0.592,使用 ModernBERT-base 达到的最佳分数为 0.0584。所以,通用模型击败了任何特定化学或聚合物的模型。
  2. 更大的模型并不更好: 使用与上面 #1 相同的调整和测试方法,ModernBERT-large 得分为 0.0587,而 -base 得分为 0.0584。所以扩大规模使分数变差。DeBERTa-v3-large 的分数也很差,所以我不认为这种行为孤立于 ModernBERT 家族。
  3. 在代码上预训练比自然语言更好: DeBERTa 交叉验证结果太差了,我没有 bother 记录它们或提交任何 DeBERTa 模型,但我模糊记得 DeBERTa-v3-large 大约和 ChemBERTa 一样差, substantially worse than ModernBERT-baseModernBERT-large。在思考为什么会这样时,我回忆起 ModernBERT 家族在编程相关基准上也得分不成比例地好,并且在其预训练数据集中有相对大量的代码,所以这导致我想知道如果在代码与自然语言的比率上训练更高的模型是否会得分甚至更好,这导致我尝试了 CodeBERTCodeBERT 最终成为我最佳单一模型的并列者。在交叉验证测试和公共榜单上略优于 ModernBERT-base,在私有榜单上略差,但通常足够接近误差范围,并且 substantially better than 任何纯粹 trained on 化学或英语数据的模型。

表格模型

特征工程: 特征从以下 broad categories 中选择。我使用 Optuna 调整了我尝试的每个属性和类型的表格模型使用的特征。它能够丢弃整个特征类别,调整指纹维度计数,并对分子描述符执行基于重要性的特征选择。特征重要性分数是为 XGBoost 和 LightGBM 模型的集成预计算的,跨目标属性平均,并在后续运行中共享。Optuna 能够调整保留每种类型的前 N 个特征的数量。

  • RDKit 支持的所有 2D 和基于图的分子描述符。
  • Morgan 指纹。
  • 原子对指纹。
  • 拓扑扭转指纹。
  • MACCS keys。
  • 我在许多公共 notebooks 中看到的基于 networkx 的图特征。
  • 我在本公共 notebook中看到的骨干与侧链特征的扩展版本。我让 ChatGPT 和 Gemini 头脑风暴了可以使用相同的一般数据准备策略计算的额外 107 个特征。
  • 来自我训练的 41 个 XGBoost 模型集成的预测,我训练这些模型来预测我自己运行的 MD 模拟的结果(FFV、密度、Rg 预测 + 一堆 3D 结构相关描述符)。
  • 来自在 PI1M 上预训练的 polyBERT 模型的嵌入(与我的最佳 BERT 模型相同的预训练策略,但没有最终微调阶段)- 这是在最后 bolted on 的,所以没有像我使用其他特征类型那样仔细调整。
  • ~17 个其他由 Gemini 建议的杂项特征:一些拓扑和形状基于描述符,Gasteiger 电荷统计,以及元素组成和键类型比率。

数据生成: 如上所述,我为 PI1M 中的 1,000 多个假设聚合物运行了分子动力学模拟,并使用它来训练模型,其预测用作其他表格模型的补充特征,这略微提高了我的 CV 分数(~0.0005 wMAE)。我采取了很多捷径来节省 CPU 时间,这设置起来非常复杂,而且我没有 prior MD 经验,所以结果有用简直是个小奇迹。我的数据生成管道中的主要步骤概述如下。

  1. 选择构象搜索配置:我有一个快速不稳定的配置,对于约一半的聚合物会崩溃或挂起,还有一个慢速配置,需要约 5 倍长的时间(即每个聚合物约 5 小时而不是约 1 小时)。我训练了一个 LightGBM 分类模型来基于 RDKit 分子描述符、一些更高重要性的骨干与侧链特征,以及基于 ETKDGv3 的构象生成和 MMFFOptimization 的结果(这 quickly 产生不准确的构象 - 此步骤中的随机误差和势能统计是预测下游代码会遇到问题的有用线索)来预测哪些聚合物会导致崩溃。这允许我的数据生成代码对困难聚合物进行下采样,并直接对简单的聚合物使用快速不稳定配置。“快速不稳定”配置基于 psi4 的 Hartree-Fock 几何优化方法,“慢速稳定”配置基于"b97-3c"。可能有一个适合所有情况的配置可以获得两全其美,但这是作为一个完整的化学/分子动力学新手,我在一周内能想到的最好的。
  2. 构象搜索:RadonPy 使这变得简单,除了上面的配置选择步骤。
  3. 聚合:聚合度自动调整为每条链约 600 个原子,无论单体大小如何。RadonPy 使这相当简单。
  4. 电荷分配:RadonPy 使这变得简单。
  5. 非晶胞生成:我每个单元格使用 10 条链,起始密度为 0.15。RadonPy 使这变得简单。
  6. 平衡模拟:这通过作为子进程运行 LAMMPS 来工作。我从源代码构建 LAMMPS,因为我找不到带有 GPU 支持的好预编译可执行文件。@hengck23LAMMPS starter 在弄清楚如何运行它时非常有用,虽然我确实 tinkered 设置以获得更真实的密度结果(更接近宿主数据),提高吞吐量,并修复一些杂项错误。不再记得所有差异 - 问题不如 figuring out 可行的构象搜索配置那么‘有趣’,所以它们在记忆中几乎没有注册。
  7. 属性和分子描述符估计:这是一堆 LLM-slop,它 ingests 原始模拟结果并使用 MDAnalsysis、RdKit 和几百行自定义逻辑来估计 FFV、密度、Rg、RDKit 中所有可用的 3D 描述符(对于单体和完整聚合物链),以及 ChatGPT 认为有用但我从未花时间完全理解的一堆统计信息。我的 general philosophy 是计算我能得到的所有特征,然后计算特征重要性值,让 Optuna 整理出哪些值得保留。最重要的前 5 个(根据 XGBoost 和 LightGBM)是 FFV、密度、NPR1、NPR2 和偏心率值,但 Optuna 发现保留远比这更多的值是有益的。这有点是全有或全无;对于 5 个目标中的 3 个,它选择保留所有 41 个,对于其他 2 个(密度和 Rg),它决定全部丢弃。当与 AutoGluon 结合使用时,基于重要性的特征选择不是特别有用,可能是因为顶级特征在某种程度上是有毒的(也许它们导致某些目标过拟合?),但我观察到当与 GBDT 模型结合使用时有一些增益。

AutoGluon 与“传统方法”: AutoGluon 的"best"质量预设,每个属性 2 小时限制,能够击败我用 Optuna 调整和约 20 倍计算量调整的 XGBoost、LightGBM 和 TabM 模型的集成(不包括数据预处理调整,每个下游预测库我 paired it with 大约是 ~1 天,或者我在 settling on XGB + LGBM + TabM 用于相对手动集成之前尝试的所有其他模型)。它的 wMAE 分数比相对手动集成好约 2%,足够好,以至于制作 AutoGluon + 我更手动构建的集成的集成没有用。"best"质量 AutoGluon 运行非常慢,所以为了让数据调整在合理的时间框架内运行并具有 decent trial count,我将其与 5 分钟时间限制的"good"质量 AG 运行 paired。这是我第一次使用 AutoGluon,我发现它非常令人印象深刻。投入手动集成的努力水平可能只有我用来赢得 UM MCTS 比赛的三分之一,所以如果我真的全力以赴并且没有被非表格实验分心,我有可能击败它,但我绝对被 AutoGluon 的效率惊呆了。AG 1.4.0 中引入的"extreme"质量预设据说甚至更准确和高效,但当我尝试切换过去时没有观察到任何好处(可能是因为特征计数太高,无法使用其所有模型 - 我看到了一些关于此的错误),所以我最终集成中的表格预测器是使用"best"质量预设创建的。

3D 模型 (Uni-Mol 2 84M)

这是所有准确到足以进入我最终集成的模型中最简单的。只不过是将合并、清理的数据集对于每个目标属性 toss into unimol_tools.MolTrain 并使用 Optuna 调整学习率、epoch count 和批量大小。它不需要任何特征工程或自定义训练循环。我甚至没有调整我的数据准备代码的设置;它们大致是我为各种类型的表格模型调整的一些配置的中位数。唯一的真正问题是 (1) 这比我尝试的任何其他模型都更 memory intensive,以至于如果训练数据包含任何具有超过 ~130 个原子的单体,24 GB GPU 上会发生 OOM 错误,(2) FFV 结果不是很好。OOM 问题对于 FFV 比任何其他目标更是一个问题(因为 FFV 训练数据集的单体比任何其他属性的单体更大),但即使在升级到可以运行训练且限制较少的 RTX 5090 并让 Optuna 花费几天时间进行超参数调整后,我仍然无法获得准确到足以有用的 FFV 结果。所以 Uni-Mol 2 只进入了 5 个目标中的 4 个的最终集成,AutoGluon 和 BERT 用于所有 5 个。

效果不佳的事情

  • GNNs (D-MPNN)
  • 我在公共 notebooks 中看到的基于 GMM 的数据增强策略。
同比赛其他方案