Kaggle 经典比赛 UW-Madison GI Tract Image Segmentation 高分方案解析

238 阅读5分钟

本篇文章为比赛第一名方案解析,该比赛涉及到CV-图像分割-医疗方向。

介绍:在本次竞赛中,参赛者将创建一个模型,以便在 MRI 扫描中自动分割胃和肠,基于这些扫描的数据集来制定算法,以提出创造性的深度学习解决方案,帮助癌症患者获得更好的护理。

网址:www.kaggle.com/competition…

2.5D 方法总体流程

我们的 2.5D 解决方案的整体流程分为两个阶段:分类阶段和分割阶段。前者负责确定图像中是否存在目标,而后者则对图像中的目标进行分割。通过分析分类阶段来控制图像中的目标分割,分类和分割阶段都是模型加权融合,以增强我们 2.5D 的鲁棒性,纯 2.5D 模型在公共排行榜上可以达到 0.889 的分数。

数据

对于数据生成,我们参考了@awsaf49 的数据生成方法,将步长设置为 2,总共生成三次以产生 2.5D 数据。www.kaggle.com/code/awsaf4…

训练与测试时间增强

我们尝试了 640640 和 512512 的图像调整分辨率。在 640640 分辨率的情况下,我们在训练过程中使用了随机裁剪方法,将目标裁剪到 448448 分辨率。我们还使用了随机翻转、弹性变换、网格畸变和光学畸变,具体参数为

dict(type='RandomFlip', direction='horizental', p=0.5)
dict(type='ElasticTransform', alpha=120, sigma=6.0, alpha_affine=3.6, p=1)
dict(type='GridDistortion', p=1)
dict(type='OpticalDistortion', distort_limit=2, shift_limit=0.5, p=1)

这段代码定义了四个图像数据增强(Data Augmentation)操作,常用于深度学习训练中增加数据多样性。以下是逐条解析:


1. ​随机水平翻转 (RandomFlip)
python
dict(type='RandomFlip', direction='horizental', p=0.5)
  • 作用:以 50% 的概率对图像进行水平翻转。

  • 参数

    • direction='horizental':应更正为 horizontal(存在拼写错误)。水平翻转会镜像图像。
    • p=0.5:应用该操作的概率为 50%。
  • 用途:增加模型对物体方向变化的鲁棒性(如镜像对称的物体)。


2. ​弹性变换 (ElasticTransform)
python
dict(type='ElasticTransform', alpha=120, sigma=6.0, alpha_affine=3.6, p=1)
  • 作用:通过局部扭曲模拟弹性形变(如橡胶拉伸效果),增强模型对形变的适应性。

  • 参数

    • alpha=120:控制形变强度的缩放因子,值越大形变越剧烈。
    • sigma=6.0:高斯滤波器的标准差,控制形变的平滑程度(值越大形变越平缓)。
    • alpha_affine=3.6:控制仿射变换(如旋转、缩放)的强度。
    • p=1:100% 应用此变换。
  • 用途:模拟医学图像或自然场景中的非刚性形变。


3. ​网格畸变 (GridDistortion)
python
dict(type='GridDistortion', p=1)
  • 作用:通过在图像上生成网格并随机扭曲网格点,产生规则或非规则畸变。

  • 参数

    • p=1:100% 应用此变换。
    • (未显式设置的参数可能使用库的默认值,如 num_steps=5distort_limit=0.3
  • 用途:模拟镜头畸变或透视变化,增强模型对几何变形的鲁棒性。


4. ​光学畸变 (OpticalDistortion)
python
dict(type='OpticalDistortion', distort_limit=2, shift_limit=0.5, p=1)
  • 作用:模拟相机镜头的光学畸变(如桶形畸变、枕形畸变)和色彩偏移。

  • 参数

    • distort_limit=2:控制畸变强度,正值为桶形畸变,负值为枕形畸变。
    • shift_limit=0.5:控制色彩通道的偏移范围(模拟色差)。
    • p=1:100% 应用此变换。
  • 用途:增强模型对相机成像缺陷的适应性。

测试时,我们使用水平翻转方法来生成新的图像,并使用加权融合来获取输出掩码。TTA 大约可以提高我们的分数 0.001 ~ 0.002。

Backbone

该算法基于 Unet,我们尝试了高效的 EfficientNet b4 ~ b7 作为骨干网络,单个模型在公共排行榜上可以达到约 0.883,提交时的模型融合可以达到约 0.889。至于深度学习框架,我们使用了www.kaggle.com/code/carnoz…

训练和推理技巧 & 损失函数

分类网络在包含空图片以及带掩码图像的全数据集上训练,而分割网络仅负责分割目标图像,分割网络仅在带掩码图像的全数据集上训练。分类网络使用单个 BCELoss 进行训练,分割网络使用 BCE 和 Dice 加权损失函数,损失函数比例为 1:3。
此外,我们使用 fp16 训练方法使我们的训练更快,并且可以节省大约 50%的 GPU 内存,这使得我们能够使用更大的批量大小。

  未来工作

在分析数据时,我发现存在一些包含无有用信息的边缘,我尝试使用 CenterCrop 方法去除这些无用的边缘(可能无用,我不确定),这对分数的影响很小。

def CenterCrop(image, crop_ratio=0.9):
   '''
   input numpy type image
       width
   h ###################
   e #                 #
   i #                 #
   g #                 #
   h #                 # 
   t ###################
   crop_ratio -> remain ratio
   return crop_image, xmin, ymin, xmax, ymax, org_size 
   '''
   height, width, channel = image.shape
   xmin, ymin, xmax, ymax = int(width  * (1 - crop_ratio) / 2), \
                            int(height * (1 - crop_ratio) / 2), \
                            int(width  * (1 + crop_ratio) / 2), \
                            int(height * (1 + crop_ratio) / 2)
   crop_image = image[ymin:ymax, xmin:xmax, ...]
   extra_info = [height, width, xmin, ymin, xmax, ymax]
   return crop_image, extra_info
def PaddingCrop(crop_image, extra_info):
   '''
   input crop_image -> the centerCrop image
   input extra_info -> original image size and Crop size infomation
   '''
   crop_shape = np.array(crop_image.shape[:2])
   height, width, xmin, ymin, xmax, ymax = extra_info
   pady = [ymin - 1, height - ymax + 1]
   padx = [xmin - 1, width - xmax + 1]
   original_image = np.pad(crop_image, [pady, padx, [0, 0]])
   return original_image