616. NeurIPS 2024 - Predict New Medicines with BELKA | leash-BELKA
[更新]
a) 这里是数据集,包含 (i) 代码 - 模型和数据处理工具 (ii) SMILES 编码器词汇表。我也会上传处理后的训练数据(只是为了节省大家的时间)。一旦我找回训练好的权重,我也会添加它们 - 我只剩下模型的轻量版本 (tf.keras.export),所以我可能会从头重新训练它。对于那些更喜欢 Kaggle notebooks 的人 - 这里是一个(但我真的不建议在这里处理数据 - 这大概需要无限久的时间)。
b) 架构相当简单,模型非常扁平 - 只有 4 个编码器层,每层 8 个头。词汇表大小仅为 43 个 token,我最终得到的固定维度为 32。我也试过 64 和 16 - 它们表现不佳。
c) 我想我以某种不正确的方式使用了atomInSmiles,最终得到的方案中单独的 token 要么是原子(C, H, S 等),要么是数字,或者是方括号中的任何内容,如 [C@@] 都是独立的 token。我把这个混乱到底意味着什么留给化学从业者来决定 :)
d) 预训练。我分两个阶段从头预训练模型:
MLM - 标准的掩码 token 预测(15% 的 token 被掩码,其中 80% 被掩码,10% 替换为随机 token,10% 保留 - 来自 "BERT: Pre-training of Deep Bidirectional Transformers for Language Understanding" 的经典做法)。我使用了用于 CategoricalFocalCrossEntropy 的动态 mini-batch alpha 权重,但这只是为了好玩。不确定它有多大贡献。我训练了大约 100 个 epoch,每个 10K 步,每批 2028 个样本 - 模型处理数据集大约 20 次。请注意,这里我结合了所有数据 - 训练集、测试集和外部数据(参考见下文原始文本)。
SMILES 到 ECFP(size=2048, include_chirality=True)。相同的模型,只是不同的头(带有 sigmoid 激活函数的 Dense 层)和锁定的 embeddings。大约 20-50 个 epoch,如果我没记错的话。模型表现不太好(有很多论文说 SMILES 编码器通常在预测拓扑指纹方面有困难,实际情况正是如此),MAP 大约 0.4,然而,我想这正是它学习一些有用表示的地方。
我这里的动机是在某些通用任务上训练模型,而不冒重大的过拟合风险。我选择 ECFP 有 2 个原因 (a) 性能 - 它们计算足够快,特别是使用scikit-fingerprints库,(b) 预测没有预定义含义的指纹(不像 MACCS 或 PubChem)对 SMILES transformer 来说是一个具有挑战性的任务,这很好 - 俗话说 "no pain - no gain"…
而且,是的,我仍然想知道“手性”是什么 :)
e) 训练。结合 BELKA 训练集和外部数据。掩码 loss 和指标,因为外部数据仅有 sEH 蛋白的标签。
f) 验证。我从训练集中留出 3% 的构建块,所以我的验证集包含具有一个或多个非共享构建块的分子 - 大约 900 万个样本。
g) 技术 - google collab 上的 A100。
就是这样。如上所述 - 没有魔法,只是纯粹的运气和随机性…
坦率地说,最终的排行榜 (LB) 结果让我有点惊讶。获胜模型是一个非常基础的编码器:Self-Attention -> FeedForward,4 层,每层 8 个头,key/value 维度为 32。Tensorflow 教程中 Transformers 章节的经典内容 :)
我使用了atomInSmilestokenizer,但我用错了,所以我的 tokenization 方案几乎是基于字符的。我没有使用任何预训练模型,如 ChemBERTa 或类似模型。
差异可能来自于两阶段预训练计划:(a) MLM - 15% 掩码率 (b) SMILES 到 ECFP 预测。说实话,我不擅长化学,但我想第二个阶段是编码器“学会”了从 SMILES 中提取一些有意义结果的地方。
哦,最后但同样重要的是:我使用了竞赛主办方提供的数据和来自"基于构建块的 DNA 编码库结合预测"的数据集,由@hengck23引用,并在竞赛早期由@chemdatafarmer预处理。
现在,以下是未按预期工作的事情列表:
1) 复杂的 tokenization 方案:bi- 和 tri-grams, atomInSmiles
2) 任何深度超过 32 且编码器层超过 6 层的模型
3) 多输入模型(SMILES + 指纹)
4) 在更大的数据集上预训练—我花了大约一个月在 ZINC 上实验…
5) 自定义 loss 函数—BinaryFocusLoss 就很好
6) 构建块的门控融合
7) 还有更多—我会更新列表。