返回列表

5th Place Training and Inference

555. Parkinsons Freezing of Gait Prediction | tlvmc-parkinsons-freezing-gait-prediction

开始: 2023-03-09 结束: 2023-06-08 临床决策支持 数据算法赛
第5名训练与推理方案

第5名训练与推理方案

比赛排名: 第5名
作者: InnerVoice (Kaggle Master)
发布时间: 2023年6月19日

整体流程

整体流程图

训练方法

数据集

  • 预训练阶段:将每个无标签序列分割成长度为100,000的片段
  • 训练阶段:
    • 使用窗口大小为2000个观测值进行分割,重叠500个观测值
    • 对于defog数据,从上述集合中随机选择4个窗口
    • 对于tdcsfog数据,从上述集合中选择1个窗口。使用librosa(v0.9.2)将tdcsfog数据重采样至100Hz。当我在Kaggle代码上移植训练时,发现使用librosa(v0.10.0)重采样时训练收敛速度不够快,可能是由于默认重采样技术不同导致的。
    • 设置数据加载器长度为每个fold中时间序列数量的8倍

交叉验证折

  • 使用GroupKFold以Subject为组创建5折交叉验证
  • 可以通过仔细选择受试者来改进,使每个目标类型在每折中都有相似的分布

网络架构
所有模型使用以下架构:

class Wave_Block(nn.Module):
    def __init__(self, in_channels, out_channels, dilation_rates, kernel_size):
        super(Wave_Block, self).__init__()
        self.num_rates = dilation_rates
        self.convs = nn.ModuleList()
        self.filter_convs = nn.ModuleList()
        self.gate_convs = nn.ModuleList()

        self.convs.append(nn.Conv1d(in_channels, out_channels, kernel_size=1))
        dilation_rates = [2 ** i for i in range(dilation_rates)]
        for dilation_rate in dilation_rates:
            self.filter_convs.append(
                nn.Conv1d(out_channels, out_channels, kernel_size=kernel_size, 
                         padding=int((dilation_rate*(kernel_size-1))/2), dilation=dilation_rate))
            self.gate_convs.append(
                nn.Conv1d(out_channels, out_channels, kernel_size=kernel_size, 
                         padding=int((dilation_rate*(kernel_size-1))/2), dilation=dilation_rate))
            self.convs.append(nn.Conv1d(out_channels, out_channels, kernel_size=1))

    def forward(self, x):
        x = self.convs[0](x)
        res = x
        for i in range(self.num_rates):
            x = torch.tanh(self.filter_convs[i](x)) * torch.sigmoid(self.gate_convs[i](x))
            x = self.convs[i + 1](x)
            res = res + x
        return res

class Classifier(nn.Module):
    def __init__(self, inch=3, kernel_size=3):
        super().__init__()
        self.LSTM = nn.GRU(input_size=128, hidden_size=128, num_layers=4,
                           batch_first=True, bidirectional=True)
        
        self.wave_block2 = Wave_Block(inch, 32, 8, kernel_size)
        self.wave_block3 = Wave_Block(32, 64, 4, kernel_size)
        self.wave_block4 = Wave_Block(64, 128, 1, kernel_size)
        self.fc1 = nn.Linear(256, 3)

    def forward(self, x):
        x = x.permute(0, 2, 1)
        x = self.wave_block2(x)
        x = self.wave_block3(x)
        x = self.wave_block4(x)
        x = x.permute(0, 2, 1)
        x, h = self.LSTM(x)
        x = self.fc1(x)
        return x

不同模型

WaveNet-GRU-v1

训练笔记本链接:

  • https://www.kaggle.com/code/adityakumarsinha/wavenet-4096-v6/notebook
    该模型在训练和验证时使用所有可用数据,不考虑Valid列的True或False值,仅保存最佳权重。每个fold的最后2个最佳权重用于推理。

WaveNet-GRU-v2

训练笔记本链接:

  • https://www.kaggle.com/code/adityakumarsinha/wavenet-2000-v6-public/notebook
    该模型在训练时使用所有可用数据,验证数据则选择Valid列为True的数据。保存所有平均精度分数>0.25的权重,并选择其中最佳的2个权重。

WaveNet-GRU-v3

该方案基于无标签数据进行预训练。预训练目标是预测时间序列中的下一个值。数据创建时,每个无标签序列被分割成长度为100,000的片段。

数据创建笔记本: https://www.kaggle.com/code/adityakumarsinha/unlabeled-data-creation/notebook
注意: 该笔记本在Kaggle内核中会失败,因为需要比Kaggle默认提供的更多磁盘空间。请在PC/服务器/虚拟机上运行。

预训练笔记本: https://www.kaggle.com/code/adityakumarsinha/pretrain-wavenet-4096-v1/notebook
训练将在单fold上执行,最佳权重将作为WaveNet-GRU-v3的初始权重(不含LSTM层)。
注意: 在RTX 3090上单轮训练约需1-1.5小时,因此Kaggle内核会超时。请在PC/服务器/虚拟机上运行。

WaveNet-GRU-v3训练笔记本: https://www.kaggle.com/code/adityakumarsinha/wavenet-2000-from-pretrain/notebook
最终推理时使用每个fold的最佳权重。
该笔记本的CV分数相比WaveNet-GRU-v1和v2较低,但能改善最终集成效果(比赛期间它提升了CV分数,但由于推理代码中的bug,最终私有排行榜分数下降。我将在推理部分解释)。

推理方法

  • 每个序列独立进行预测
  • 推理时,每个序列被分割成大小为16,000或20,000的片段,最后一个片段包含序列的最后16,000/20,000个数据点。对于tdcsfog数据,可能单步即可完成整个序列的预测
  • tdcsfog数据重采样至100Hz,预测结果再恢复到128Hz
  • 使用librosa 0.10.0进行重采样。比赛结束后我发现librosa 0.9.2能略微提升分数,这是因为我训练时使用librosa 0.9.2导致的疏漏,但对最终分数影响不大
  • 所有模型的预测结果使用简单平均进行集成

基于CPU的推理方法

由于最后一周GPU配额已用完,我需要使用CPU进行推理。简单的PyTorch CPU推理超过了9小时的时间限制。因此需要将PyTorch模型转换为ONNX格式。模型转换笔记本: https://www.kaggle.com/code/adityakumarsinha/openvino-model-converter-all-models-v3/notebook

转换后的模型用于最终推理。其中一个最终推理笔记本:https://www.kaggle.com/adityakumarsinha/gait-openvion-bunch-v2

比赛结束后我发现,在集成中WaveNet-GRU-v3(使用预训练权重的模型)在公共排行榜上过度拟合,在私有排行榜上其加入反而降低了分数。而在本地CV集成中,该模型却能提升CV分数。

因此我进一步调试,发现使用GPU推理时WaveNet-GRU-v3确实能提升分数。事实上,仅WaveNet-GRU-v1和WaveNet-GRU-v3的简单集成在私有排行榜上达到了0.437分,超过了第三名的成绩。

最佳GPU推理笔记本:https://www.kaggle.com/code/adityakumarsinha/wavenet-subm-focal-v2/notebook

此致
阿迪蒂亚

同比赛其他方案