667. NeurIPS - Open Polymer Prediction 2025 | neurips-open-polymer-prediction-2025
副标题:一个用于学习分子嵌入的 GNN,并在这些嵌入及其他手工特征之上堆叠多个梯度提升模型
GINEConv 是一个 PyTorch Geometric 层。GINEConv 很好,因为它允许使用丰富的边特征,而 vanilla GCNConv 只允许节点特征。
class GINENet(torch.nn.Module):
def __init__(self, node_dim=NODE_DIM, edge_dim=EDGE_DIM, first_conv_dim=107, second_conv_dim=107):
super().__init__()
self.conv1 = GINEConv(
nn.Sequential(
nn.Linear(node_dim, first_conv_dim),
nn.ReLU(),
nn.Linear(first_conv_dim, first_conv_dim)
),
edge_dim=edge_dim,
train_eps=True
)
self.ln1 = nn.LayerNorm(first_conv_dim)
self.conv2 = GINEConv(
nn.Sequential(
nn.Linear(first_conv_dim, second_conv_dim),
nn.ReLU(),
nn.Linear(second_conv_dim, second_conv_dim)
),
edge_dim=edge_dim,
train_eps=True
)
self.ln2 = nn.LayerNorm(second_conv_dim)
self.lin1 = nn.Linear(second_conv_dim, first_conv_dim)
self.lin2 = nn.Linear(first_conv_dim, 5)
self.dropout = nn.Dropout(0.5)
def forward(self, data):
x, edge_index, edge_attr, batch = data.x, data.edge_index, data.edge_attr, data.batch
x1 = self.conv1(x, edge_index, edge_attr)
x1 = self.ln1(x1)
x1 = F.relu(x1)
x2 = self.conv2(x1, edge_index, edge_attr)
x2 = self.ln2(x2)
x2 = F.leaky_relu(x2, negative_slope=0.005)
x = global_mean_pool(x2, batch)
x = self.lin1(x)
x = F.relu(x)
x = self.dropout(x)
x = self.lin2(x)
return x
我在最后一个卷积层后使用了 LeakyReLU 而不是 ReLU,这样 stacking 模型就不会得到全零嵌入。
我使用 Huber loss 训练了这个模型,根据竞争数据中 3500 个样本的验证 MAE 选择了最佳检查点。我调整了这个架构的超参数,并最终确定了在公共榜单上得分最好的那个 (0.069)。
现在除了描述符和指纹数据外,我们还有丰富的 GNN 嵌入和 GNN 预测值可以使用 😋
我丢弃了低方差和高 NaN 的列
| 特征组 | 维度 |
|---|---|
| 描述符 (Descriptors) | 220 |
| 指纹 (Fingerprints) | 162 (从 1024 位截断 SVD) |
| GNN 嵌入 | 107 |
| 图特征 | 10 |
| GNN 预测 | 5 |
| 总计 | ~500 |
对于每个目标,我训练了 5 折模型,使用 optuna 进行优化。
最后我使用随机森林作为元模型。
| 目标 | 描述符 | 指纹 | GNN | GNN_预测 | 图 |
|---|---|---|---|---|---|
| Tg | 23.49 | 22.09 | 51.20 | 0.63 | 2.58 |
| FFV | 27.55 | 5.15 | 66.45 | 0.12 | 0.73 |
| Tc | 23.68 | 27.09 | 46.38 | 0.60 | 2.24 |
| Density | 19.15 | 4.42 | 75.78 | 0.07 | 0.57 |
| Rg | 29.23 | 19.42 | 50.33 | 0.41 | 0.61 |
| 目标 | 描述符 | 指纹 | GNN | GNN_预测 | 图 |
|---|---|---|---|---|---|
| Tg | 14.77 | 24.75 | 57.74 | 1.22 | 1.51 |
| FFV | 12.77 | 18.79 | 66.74 | 1.36 | 0.34 |
| Tc | 12.73 | 26.12 | 56.92 | 2.44 | 1.78 |
| Density | 20.28 | 13.78 | 63.95 | 1.69 | 0.30 |
| Rg | 16.42 | 32.41 | 46.49 | 3.91 | 0.78 |
| 目标 | GNN | 描述符 | 指纹 | 图 | GNN_预测 |
|---|---|---|---|---|---|
| Tg | 86.91 | 5.59 | 5.49 | 1.97 | 0.06 |
| FFV | 93.97 | 3.73 | 2.09 | 0.15 | 0.07 |
| Tc | 82.56 | 10.11 | 6.02 | 1.27 | 0.03 |
| Density | 90.23 | 6.46 | 3.13 | 0.14 | 0.05 |
| Rg | 85.11 | 9.07 | 5.45 | 0.26 | 0.11 |
Tc 的前 30 个特征重要性
MAE 和 MSE 作为 GNN 损失,两者效果都不错,我无法决定,所以选择了 Huber。所有 boosting 模型也使用了 Huber。我刚刚在讨论区发现了 TabPFN,相信它可以进一步帮助我的 stacking,但没能及时完成 😐