当前位置: 代码迷 >> 综合 >> Kaggle-人类蛋白质图谱图像分类(Human Protein Atlas)
  详细解决方案

Kaggle-人类蛋白质图谱图像分类(Human Protein Atlas)

热度:67   发布时间:2023-10-18 07:49:09.0

转载于Gary https://zhuanlan.zhihu.com/p/54743461

比赛介绍

任务介绍
本次比赛的问题是场景识别 定位的是蛋白质所处位置的识别,例如在细胞液,细胞核里之类的 依输出分所属多标签分类(Multi-lable Classification)
难点及数据介绍
首先一张示例图如下:

Kaggle-人类蛋白质图谱图像分类(Human Protein Atlas)

  • 一个样本由四个"通道图"组成(分成四张存储,每个"通道图"单通道),2048*2048大小,官方提供了插值缩小为512大小的数据
  • 外部数据70k(每个"通道图"都是rgb格式)
  • 图片伪重多,然后四个"通道图",id相同但实例不同的情况也很多,如下
    Kaggle-人类蛋白质图谱图像分类(Human Protein Atlas)
    难点:
  • 对比我们发现了外部数据总共有4 * 3个通道,而官方数据只有4 * 1个
  • 最麻烦的是伪重问题,伪重造成验证集leak,不能制作一个好的验证集

外部数据处理后加入训练集,要制作一个好的验证集就得跨过两道坎

  • 外部数据无论咋处理总是和测试集分布有些不一样的
  • 训练集里伪重过多,如何保证验证集不leak

solution

model config1

  1. 数据增广(亮度对比度调整,crop_resize,flip,other)

    1.1、 我们总共用了12倍的TTA
    1.2、亮度对比度主要用于让模型对外部数据和官方数据差异的鲁棒性更好
    1.3、crop_resize对于显微镜下实例大小方差巨大的情况,带来了较好的线下收益 受限于调试成本,为了不避免数据增广带来的分布偏移问题,于是只选择性的尝试了上述几种

def get_augumentor(mode):if mode =='train':return iaa.SomeOf(n=(1,6),children=[iaa.Noop(),iaa.Sequential([iaa.Add((-5,5),per_channel=True),iaa.Multiply((0.8,1.2),per_channel=True)]),iaa.Crop(percent=(0,0.15)),iaa.Affine(shear=(-16, 16)),iaa.OneOf([iaa.Affine(rotate=90),iaa.Affine(rotate=180),iaa.Affine(rotate=270),iaa.Fliplr(1),iaa.Flipud(1),])])elif mode == 'TTA0':return iaa.Noop()elif mode == 'TTA1':return iaa.Flipud(1)elif mode == 'TTA2':return iaa.Fliplr(1)elif mode == 'TTA3':return iaa.Affine(rotate=90)elif mode == 'TTA4':return iaa.Affine(rotate=180)elif mode == 'TTA5':return iaa.Affine(rotate=270)elif mode == 'TTA6':return iaa.Sequential([iaa.Crop(percent=0.15),iaa.Flipud(1)])elif mode == 'TTA7':return iaa.Sequential([iaa.Crop(percent=0.15),iaa.Fliplr(1)])elif mode == 'TTA8':return iaa.Sequential([iaa.Crop(percent=0.15),iaa.Affine(rotate=90)])elif mode == 'TTA9':return iaa.Sequential([iaa.Crop(percent=0.15),iaa.Affine(rotate=180)])elif mode == 'TTA10':return iaa.Sequential([iaa.Crop(percent=0.15),iaa.Affine(rotate=270)])elif mode == 'TTA11':return iaa.Crop(percent=0.15)else:raise ValueError("aug error")
  1. Models
res18 (batchsize=64)
res34 (batchsize=32)
bninception (batchsize=32)
inceptionv3 (batchsize=32)
xception (batchsize=24, P40-24G)
se-resnext50(batchsize=24, P40-24G)

其中模型对batchsize大小十份敏感,正确来说是模型对参与batchnorm计算的样本数十分敏感,需用sync-bn或者P40(24G)显存实现

同时,如果按照榜上的分数来体现,融合有效的模型为res18,xception,se-resnext50,融合无效的模型原来是模型之间的差异性较小。

  1. lr schedule
    3.1、Nadam优化器
    3.2、阶段性学习率衰减(根据小模型的log而手动设置了衰减的位置)
    3.3、差分学习率(其中初层用于转换通道的卷积和最后的model head同学习率,中间的backbone学习率小一倍)

model config2
只简述一下与config1差异的部分

1. 优化器和schedule的不同
1.1、lr schedule
1.2、SGD 优化器(init=5e-2, momontum=0.9, weight_decay=4e-4)
1.3、cosine lr

2. 数据增强

fair_img_tsfm = Compose([Flip(p=0.75),Transpose(),RandomBrightnessContrast(brightness_limit=(-0.25, 0.1), contrast_limit=(-0, 0)),])weighted_img_tsfm = Compose([ShiftScaleRotate(rotate_limit=45, shift_limit=0.1, scale_limit=0.1, p=1,border_mode=cv2.BORDER_CONSTANT)])

3. custom f1 loss

fair_img_tsfm = Compose([Flip(p=0.75),Transpose(),RandomBrightnessContrast(brightness_limit=(-0.25, 0.1), contrast_limit=(-0, 0)),])weighted_img_tsfm = Compose([ShiftScaleRotate(rotate_limit=45, shift_limit=0.1, scale_limit=0.1, p=1,border_mode=cv2.BORDER_CONSTANT)])

4. 杂项
res18/34 (96batchsize + float16 + 过采样)

Threshold
在阈值的选取上,我们试过多种固定阈值,和search不同类不同阈值,但根据public榜的分数都没有很好的效果,最终选取了我手调适应public最高分的threshold=0.205

postprocess
基本是利用了伪重的性质 将测试集中的相似图片的预测进行共享,其中预测选择图片质量较高的那张,约0.002的收益

ensemble
外部数据灰度化和外部数据取高范数的通道两种方案得到了两份数据 两份数据上训练出来的模型进行差异化集成 model config1 和 config2进行集成

其中一个比较具有通用性的trick,可供大家参考 cnn with image patches (lb 0.619) 图片分成多个patch,将baseline模型对这些块输出分数,拿那些响应最高的patch重新训练一次模型, 相当于一个hard attention

  相关解决方案