Baseline跑通遇到的问题以及解决方案:
import cupy报错
一开始采用的是pip install cupy-cuda110安装成功后但是报如上图所示的错,后改用conda安装成功,安装命令为conda install -c conda-forge cupy cudatoolkit=11.0。注意安装CUDA对应的版本。
import StratifiedGroupKFold
import StratifiedGroupKFold报错显示ImportError: cannot import name 'StratifiedGroupKFold' from 'sklearn.model_selection'。后更新了scikit-learnd的版本后运行成功。
运行成功显示如下:
Baseline框架以及改进想法:
模型
Baseline模型采用的是Unet原始结构,backbone采用的是efficientnet-b1。
在Baseline中使用了segmentation_models_pytorch包,其可支持的结构如下。一般显示效果不错的是Unet和FPN。也可以尝试一些新的Unet结构比如TransUnet和SwinUnet,但是segmentation_models_pytorch暂不支持。
改进想法:模型是性能的下限,好的模型就有好的开始。Unet是在语义分割尤其是医学语义分割里比较好的模型,我所接触的医学语义分割大都是以Unet为基准进行一些魔改操作,包括:
1.Backbone的选择:目前最常用就是EfficientNet系列、ResNet系列、ResNeXt系列,Baseline中采用的是efficientnet-b1,从b2-b5都可以尝试。ResNeXt可以达到与EfficientNet相近的效果。Inception和Mobilenet也是常用的Backbone。一般会基于不同backbone的模型进行集成预测。
2.在Unet中加入其他模块:ASPP(空洞卷积)、Hypercolumn、以及CBAM和SCSE这种注意力模块。segmentation_models_pytorch支持部分操作但是高度集成不适合修改,可以下载segmentation_models_pytorch的源码进行自主的模块添加。
损失函数
Baseline中采用的是BCELoss和TverskyLoss,语义分割中可以采用的损失如下所示:
改进想法:常见有效的损失包括BCELoss、DICEloss、BCELoss+DICEloss,其中Lovaszloss有的时候有奇效,对于Lovaszloss的改进网上也有现成的方法。Focal Loss可以针对样本不平衡的情况并进行难例挖掘。好的损失可以带来不小的提升。
训练
1.Baseline采用的优化器是Adam,Adam的好处是不用特别关注怎么调整学习率,3e-4号称是Adam最好的初始学习率。但是如果可以好的调整学习率,SGD号称可以在Adam的基础上提升性能。lr_find()提供了一种寻找最优初始学习率的方式。
2.Baseline学习率调整策略StepLR,衰减位置的确定需要一定的经验和感觉,可以根据验证loss的走势调整衰减位置。Warmup + Cosine也是一种常用的学习率调整策略,每个iteration逐渐增大至初始学习率,然后余弦下降至终止学习率。CosineAnnealingLR+Snapshot Ensembles是一个循环衰减学习率获得不同局部最优模型的集成策略。
3.Batchsize和分辨率大小也是可以调整的训练参数。一般Batchsize都不会选择不合理。图像输入的分辨率大小对于模型也很关键,我遇到过不同分辨率模型的集成预测方案。或者,在训练期间进行多尺度训练,然后测试的时候选取其中某几个尺度表现优异的预测结果出来融合,提升模型对多尺度的鲁棒。
数据预处理和后处理
该部分最能体现比赛目标相关,决定性能的上限。好的预处理和后处理带来的提升很大。
1. Baseline采用的数据增强策略:
对数据增强的改进没有固定的策略,依赖于一些经验和直觉。比较重要的是可以对模型预测中的bad case做针对性的调整。 还有一些针对大图像需要切割成patch的各种策略,目前来看应该不适用于本数据集。使用额外数据集进行预训练也是常见的方法,但是额外数据集不容易获得。
2.后处理中有一些通用的技巧:包括TTA(将同一图像进行不同几何变换后预测,将预测结果变换回来后取预测平均值)、集成预测(TTA也属于集成预测,还包括训练不同模型得到不同的预测,预测结果可以投票或者取平均,或者采用stacking的方式,利用机器学习模型对预测进行训练后得到集成预测结果)。
3.利用伪标签进行半监督学习,变相扩增数据集。有时有效有时过拟合,需要谨慎使用。如果验证集或者测试集出现了训练集没有的样本种类,该方法更可能有效。比较安全的方法是:(1)筛选预测置信度高的样本作为伪标签,如分类里,再test里的预测概率是大于0.9的,则视为正确的预测,此时将其作为伪标签来使用。(2)帮第一次的伪标签扔进去训练集一起训练后,得到新的模型,按相同的规则再次挑一次伪标签出来。(3)如此不断循环多次,置信度的阈值可以适当作调整。实际使用中可能没那么复杂只进行了第一步。
4.一些新颖的或者针对本次比赛的idea可以从kaggle的讨论区获得,经常会有一些不错的想法。