多思考模型的奇怪结果真的很重要--Kaggle第二名方案分享。


↑↑↑关注后"星标"kaggle竞赛宝典
  kaggle竞赛宝典  者:COOLZ 

Kaggle HMS 第二名方案!

简介

本次我们分享Kaggle HMS 第二名的方案,该方案能获得第二名很大原因来源于一个实验的奇怪结果。

我们向2D-CNN模型中输入bsx4xHxW的数据,最终产生了比单图像方法更差的结果。我开始思考为什么?

  • 由于标签(LPD、GPD 等)的位置敏感性,需要注意通道维度。2D-CNN 并不适合捕捉通道内的位置信息。因为通道方向没有填充。
  • 所以我们需要将频谱连接成一个图像,而不是 bsx16xHxW 图像(double banana montage)用于视觉模型的原因。

因此,我决定对频谱使用3D-CNN,对原始egg信号使用 2D-CNN 模型。

模型

01


Spectrum 模型

3d CNN, X3d-l there. 使用stft transform做预处理.

  • X3d-l cv 0.21+, publicLB 0.25 Private Lb 0.29
  • 使用2d model和 efficientnetb5,  public LB 0.26, Private Lb 0.30.
  • 将两个模型进行组合最终可以在Private LB获得0.28的分数。

对应代码

class Transform50s(nn.Module):
    def __init__(self, ):
        super().__init__()
        self.wave_transform = torchaudio.transforms.Spectrogram(n_fft=512, win_length=128, hop_length=50, power=1)

    def forward(self, x):
        image = self.wave_transform(x)
        image = torch.clip(image, min=0, max=10000) / 1000
        n, c, h, w = image.size()
        image = image[:, :, :int(20 / 100 * h + 10), :]
        return image


class Transform10s(nn.Module):
    def __init__(self, ):
        super().__init__()
        self.wave_transform = torchaudio.transforms.Spectrogram(n_fft=512, win_length=128, hop_length=10, power=1)

    def forward(self, x):
        image = self.wave_transform(x)
        image = torch.clip(image, min=0, max=10000) / 1000
        n, c, h, w = image.size()
        image = image[:, :, :int(20 / 100 * h + 10), :]
        return image


class Model(nn.Module):
    def __init__(self):
        super().__init__()

        model_name = "x3d_l"
        self.net = torch.hub.load('facebookresearch/pytorchvideo',
                                  model_name, pretrained=True)

        self.net.blocks[5].pool.pool = nn.AdaptiveAvgPool3d(1)
        # self.net.blocks[5]=nn.Identity()
        # self.net.avgpool = nn.Identity()
        self.net.blocks[5].dropout = nn.Identity()
        self.net.blocks[5].proj = nn.Identity()
        self.net.blocks[5].activation = nn.Identity()
        self.net.blocks[5].output_pool = nn.Identity()

    def forward(self, x):
        x = self.net(x)
        return x


class Net(nn.Module):
    def __init__(self, num_classes=1):
        super().__init__()

        self.preprocess50s = Transform50s()
        self.preprocess10s = Transform10s()

        self.model = Model()

        self.pool = nn.AdaptiveAvgPool3d(1)
        self.fc = nn.Linear(20486, bias=True)
        self.drop = nn.Dropout(0.5)

    def forward(self, eeg):
        # do preprocess
        bs = eeg.size(0)
        eeg_50s = eeg
        eeg_10s = eeg[:, :, 4000:6000]
        x_50 = self.preprocess50s(eeg_50s)
        x_10 = self.preprocess10s(eeg_10s)
        x = torch.cat([x_10, x_50], dim=1)
        x = torch.unsqueeze(x, dim=1)
        x = torch.cat([x, x, x], dim=1)
        x = self.model(x)
        # x = self.pool(x)
        x = x.view(bs, -1)
        x = self.drop(x)
        x = self.fc(x)
        return x

02


eeg model

将 eeg (bsx16x10000) 视为图像。展开 dim=1( bsx1x16x10000),因为时间维度太大。此处我们进行reshape。

  • egg reshape为3x16x10000,使用efficinetnetb5,我们可以得到Public LB 0.230,Private LB 0.282.
rclass Net(nn.Module):
    def __init__(self,):
        super(Net, self).__init__()
        self.model = timm.create_model('efficientnet_b5', pretrained=True, in_chans=3)
        self.pool = nn.AdaptiveAvgPool2d(1)
        self.fc = nn.Linear(2048, out_features=6, bias=True)
        self.dropout = nn.Dropout(p=0.5)

    def extract_features(self, x):
        feature1 = self.model.forward_features(x)
        return feature1

    def forward(self, x):
        bs = x.size(0)
        reshaped_tensor = x.view(bs, 16100010)
        reshaped_and_permuted_tensor = reshaped_tensor.permute(0132)
        reshaped_and_permuted_tensor = reshaped_and_permuted_tensor.reshape(bs, 16 * 101000)
        x = torch.unsqueeze(reshaped_and_permuted_tensor, dim=1)

        x = torch.cat([x, x, x], dim=1)
        bs = x.size(0)

        x = self.extract_features(x)
        x = self.pool(x)
        x = x.view(bs, -1)
        x = self.dropout(x)
        x = self.fc(x)
        return x

03


eeg+spectrum

使用x3d-l抽取spectrum的特征(此处仅仅使用Transform50s),使用efficientnetb5抽取原始egg特征。

预处理

  • Double banana montage, eeg as 16x10000
  • Filter with 0.5-20hz
  • Clip by +-1024

训练

  • 步骤1: 训练15 个 epoch,损失权重 votes_num/20,Adamw lr=0.001,cos scheduel
  • 步骤2: 5 个 epoch,损失权重=1,votes_num>=6,Adamw lr=0.0001,cos scheduel
  • 使用 eeg_label_offset_seconds。为每个eegid随机选择一个偏移量,最终目标是根据每个训练迭代的 eegid 进行平均;
  • 增强,mirror eeg,在左脑数据和右脑数据之间翻转。
  • 10折,将1000个样本从val转移到train,使用709个样本进行验证,使用vote_num >=6进行验证。

集成

通过合并这些模型,可以获得我的当前分数。最后分数是6个模型集成,(0.28->0.27 private lb)。

最终集成包括:

  • 2 个频谱模型(x3d、efficientnetb5),两者都使用 mne-filter;
  • 3 个原始脑egg模型(带有 mne.filter的 efficientnetb5、efficientnetb5 -butter filter、1 个 hgnetb5 mne.filter);
  • 1 个egg频谱混合模型,butter filter。

权重 [0.1,0.1,0.2,0.2,0.2,0.2]。

参考文献

  1. https://www.kaggle.com/competitions/hms-harmful-brain-activity-classification/discussion/492254

相关推荐

  • [开源]一款开源的图片在线设计工具,开箱即用,可免费商用
  • 十年前的微信消息收发架构长啥样?
  • 开源8K+高星的一键式AI视频生成工具
  • AI检测丁丁技术引争议!官方号召用户上传照片:急需各种丁照,越多越好!
  • “计算机视觉女神”被IEEE期刊封杀
  • Eric Evans 鼓励 DDD 实践者尝试 LLM
  • C++ 会变成像 Rust 一样的安全语言吗?
  • 火速报名!探索未来数据库的无限可能 ,腾讯云 HTAP 技术与自研力量的深度揭秘 | Q推荐
  • QCon 北京2024 盛大开幕,韦青、王皓、程操红、郭东白、章文嵩、蒋晓伟、李飞飞、张凯等行业领袖呈现精彩分享
  • 用 100 年前的 IT 架构和淘汰的软盘技术,美国列车系统升不了级:要花费十年、上百亿美元,“风险太大!”
  • 每日prompt:红发辫子女孩
  • 音乐创作工具suno的劲敌Udio上线了~Midjourney 新版本v 6.1即将到来
  • 看不懂来打我,vue3如何将template编译成render函数
  • 前端代码规范 - 图片相关
  • 如何写出“高颜值”的Python代码
  • 写给职场新人|从迷茫到屡获殊荣的技术人成长之路
  • 推荐一个开源的MES系统
  • 58.5K Star火火火!开源的企业级BI工具
  • AI员工「红衣」入职360;字节跳动否认“2023年利润狂飙60%”;Mixtral 8x22B开源模型登场 | 极客头条
  • 斩获 3.4k+ Star 的 C++ Insights:用编译器的视角看源码!