返回列表

2nd Place Solution for the Open Problems – Single-Cell Perturbations

584. Open Problems – Single-Cell Perturbations | open-problems-single-cell-perturbations

开始: 2023-09-12 结束: 2023-11-30 基因组学与生物信息 数据算法赛
Open Problems单细胞扰动竞赛第二名解决方案

Open Problems单细胞扰动竞赛第二名解决方案

作者:EliKal(Kaggle MASTER)
竞赛排名:第2名
发布时间:2023年12月1日

我非常激动地分享我在本次竞赛中的解决方案!

背景

本竞赛旨在预测药物扰动后细胞基因表达的变化:

方法概述

我的最优模型由四个子模型组合而成,其中三个采用归一化求和方式,第四个模型作为放大器,对符号交替变化的标签产生显著影响:

  • weight_df1: 0.5(使用标准差、均值和聚类采样,得分0.551)
  • weight_df2: 0.25(排除非常见元素,得分0.559)
  • weight_df3: 0.25(使用聚类采样,得分0.575)
  • weight_df4: 0.3(使用均值、随机采样并排除标准差,得分0.554)

最终模型是这些组件的加权和:resulted_model = weight_df1 * df1 + weight_df2 * df2 + weight_df3 * df3 + weight_df4 * df4。所有模型均采用相同的Transformer架构,但维度设置不同(最优维度为128)。

数据预处理与特征选择

为了训练深度学习模型,我对分类标签采用独热编码转换。针对高偏差和低偏差标签,我使用目标编码技术,计算每种细胞类型和SM名称的均值和标准差。实验发现,包含非常见列能显著改善编码层的训练效果,特别是对均值和标准差特征向量的编码,从而提升整体性能。

探索性数据分析

在特征探索过程中,我针对目标变量进行了截断奇异值分解(SVD)。尽管尝试了不同的SVD维度,但该方法始终无法达到全目标回归的性能水平。分析中发现某些目标变量具有显著的标准差值。

基于这一发现,我向特征集中加入了标准差作为专门特征,为每种细胞类型和SM名称创建标准差向量(std_cell_type, std_sm_name),并将其拼接到统一向量中。

数据集质量极高,不存在NaN值或重复数据,这为模型训练提供了良好基础。

采样策略

我设计了基于K-Means聚类的采样策略来划分训练集和验证集。该策略的核心思想是:同一聚类中的数据点具有相似模式,可确保更具代表性的数据分割。

对每个K-Means识别出的聚类,使用scikit-learn的train_test_split函数进行数据划分。验证集比例经实验确定:在0.1-0.2范围内测试后,最优模型采用0.1的验证比例,平衡了训练集规模和验证效果。

模型架构

以下是我的最佳模型实现:

class CustomTransformer_v3(nn.Module):  # 均值+标准差
    def __init__(self, num_features, num_labels, d_model=128, num_heads=8, num_layers=6, dropout=0.3):
        super(CustomTransformer_v3, self).__init__()
        self.num_target_encodings = 18211 * 4
        self.num_sparse_features = num_features - self.num_target_encodings

        self.sparse_feature_embedding = nn.Linear(self.num_sparse_features, d_model)
        self.target_encoding_embedding = nn.Linear(self.num_target_encodings, d_model)
        self.norm = nn.LayerNorm(d_model)

        self.concatenation_layer = nn.Linear(2 * d_model, d_model)
        self.transformer = nn.TransformerEncoder(
            nn.TransformerEncoderLayer(d_model=d_model, nhead=num_heads, dropout=dropout, activation=nn.GELU(),
                                       batch_first=True),
            num_layers=num_layers
        )
        self.fc = nn.Linear(d_model, num_labels)

    def forward(self, x):
        sparse_features = x[:, :self.num_sparse_features]
        target_encodings = x[:, self.num_sparse_features:]

        sparse_features = self.sparse_feature_embedding(sparse_features)
        target_encodings = self.target_encoding_embedding(target_encodings)

        combined_features = torch.cat((sparse_features, target_encodings), dim=1)
        combined_features = self.concatenation_layer(combined_features)
        combined_features = self.norm(combined_features)

        x = self.transformer(combined_features)
        x = self.norm(x)

        x = self.fc(x)
        return x

模型采用模块化设计,分为两个部分:

  • 稀疏特征编码: 使用线性层将稀疏特征转换为密集表示,因计算资源限制未使用nn.Embedding
  • 目标编码特征编码: 使用独立线性层处理密集的目标编码特征

两个编码结果被拼接并归一化后输入Transformer架构,采用Lion优化器进行训练。

超参数设置

训练采用以下关键超参数:

  • 初始学习率:1e-5
  • 权重衰减:1e-4(作为正则化机制)
  • ReduceLROnPlateau学习率调度器(模式为"min",衰减因子0.9999)
  • 训练轮次:20,000轮
  • 早停机制:5,000轮无改善时触发

损失函数

为平衡MAE(评估偏差)和MSE(评估方差)的优势,选用Huber损失函数。虽然使用Mrrmse作为评估指标,但最终模型选择基于验证集上的Huber损失表现。

防止过拟合

针对数据集规模有限的问题,采用以下正则化策略:

  • 在Transformer架构中加入Dropout层
  • 应用权重衰减进行L2正则化
  • 梯度裁剪(最大范数设为1)防止梯度爆炸

验证策略

采用多种子训练和k折交叉验证,各折性能如下:

  • 0.551分:结合标准差、均值和聚类采样
  • 0.559分:排除非常见元素
  • 0.575分:使用聚类采样
  • 0.554分:结合均值、随机采样并排除标准差
同比赛其他方案