本篇文章为比赛第一名方案解析,该比赛涉及到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=5,distort_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