Kaggle Multimodal Single-Cell Integration 振り返り

Posted on
Updated on
この記事は、最終更新日から 1 年以上経過しています。 情報が古い可能性があります。

コンペで取り組んだことを中心に振り返りです。

このコンペは、Private テストデータが、学習データには存在しない将来の日付のもので、 いわゆるドメイン汎化性能が問われるコンペでした。 一方で、日付による変化の要素もあり、完全に日付の特徴を無視するのも望ましくないことが、 予想されていました。

はじめに、Adversarial training (学習データとテストデータを分類するタスク) を行ったところ、 Citeseq は 99% 分類が可能な状況で、この特徴量で学習をすると、学習データへの過学習が 懸念されると考えられました。 しかし、Adversarial training の精度を下げるために、特徴量を減らすと、著しく、Public LBのスコアも 下がる状況で、基本的には、特徴量を減らすアプローチでは厳しいのではないかと考えました。

そこで、なにか生物学的な特徴量の工夫を行うことや、モデルのバリエーションによる 汎化性能の向上を目指す方針で臨みました。


Table of Contents generated with DocToc


✨ Result

🖼️ Solution

🌱 Preprocess

🤸 Pre Training

🏃 Training

🎨 Base Models

Citeseq はさまざまなモデルのアンサンブルでスコアがのびました。 一方、 Multiome は 1D CNN が強く、他のモデルをアンサンブルしてもスコアが伸びず、1D CNN のみ使用しました。

🚀 Postprocess

💡 Tips

Pearson Loss for XGBoost

XGBoost は Pearson Loss Function が提供されていないので、以下のように実装しました。 ただし、この実装は学習が遅く、もう少し、改善をしたい印象を持っています。。

from functools import partial
from typing import Any, Callable

import numpy as np
import torch
import torch.nn.functional as F
import xgboost as xgb


def pearson_cc_loss(inputs, targets):
    try:
        assert inputs.shape == targets.shape
    except AssertionError:
        inputs = inputs.view(targets.shape)

    pcc = F.cosine_similarity(inputs, targets)
    return 1.0 - pcc


# https://towardsdatascience.com/jax-vs-pytorch-automatic-differentiation-for-xgboost-10222e1404ec
def torch_autodiff_grad_hess(
    loss_function: Callable[[torch.Tensor, torch.Tensor], torch.Tensor], y_true: np.ndarray, y_pred: np.ndarray
):
    """
    Perform automatic differentiation to get the
    Gradient and the Hessian of `loss_function`.
    """
    y_true = torch.tensor(y_true, dtype=torch.float, requires_grad=False)
    y_pred = torch.tensor(y_pred, dtype=torch.float, requires_grad=True)
    loss_function_sum = lambda y_pred: loss_function(y_true, y_pred).sum()

    loss_function_sum(y_pred).backward()
    grad = y_pred.grad.reshape(-1)

    # hess_matrix = torch.autograd.functional.hessian(loss_function_sum, y_pred, vectorize=True)
    # hess = torch.diagonal(hess_matrix)
    hess = np.ones(grad.shape)

    return grad, hess


custom_objective = partial(torch_autodiff_grad_hess, pearson_cc_loss)


xgb_params = dict(
    n_estimators=10000,
    early_stopping_rounds=20,
    # learning_rate=0.05,
    objective=custom_objective,  # "binary:logistic", "reg:squarederror",
    eval_metric=pearson_cc_xgb_score,  # "logloss", "rmse",
    random_state=440,
    tree_method="gpu_hist",
)  # type: dict[str, Any]

clf = xgb.XGBRegressor(**xgb_params)