388. TReNDS Neuroimaging | trends-assessment-prediction
感谢 Kaggle 和主办方举办了这场非常有趣的比赛。能与 @cpmpml、@philippsinger、@ericfreeman 和 @fakeplastictrees 这样才华横溢的队友一起合作真是太棒了——我在很短的时间内从他们身上学到了很多东西,非常感谢他们的组队。同时也要祝贺所有获得金牌的选手,我非常期待阅读你们的解决方案!
我对团队的主要贡献是构建了一个 3D Resnet。我决定使用 Keras,架构的大部分是基于我在 github 上找到的这段代码,我只是对其进行了一些修改以适配 tf2.0。模型本身在排行榜(LB)上的表现并不好,但与优秀的表格数据模型混合后,分数有了显著提升。
我们最初有一个 LB 分数为 0.1589 的表格模型 -> 与 3D Resnet 按 20/80 比例混合后,LB 提升至 0.1587 -> 加入 mixup 数据增强后,LB 进一步提升至 0.1578。
我还将所有的 fMRI 和表格数据转换为 tfrecords 格式,以优化磁盘加载速度。
模型的主要部分如下所示:
input = Input(shape=input_shape, name='fMRI')
# first conv
conv1 = conv_bn_relu3D(filters=64, kernel_size=(7, 7, 7),
strides=(2, 2, 2),
kernel_regularizer=l2(reg_factor)
)(input)
pool1 = MaxPooling3D(pool_size=(3, 3, 3),
strides=(2, 2, 2),
padding="same")(conv1)
# repeat blocks
block = pool1
filters = 64
for i, r in enumerate(repetitions):
block = residual_block3d(block_fn, filters=filters,
kernel_regularizer=l2(reg_factor),
repetitions=r, is_first_layer=(i == 0)
)(block)
filters *= 2
# last activation
block_output = bn_relu(block)
# average poll and classification
pool2 = AveragePooling3D()(block_output)
pool_dense = Dense(256*4*4, activation='sigmoid')(pool2)
flatten1 = Flatten()(pool_dense)
# Dense output
dense_out = Dense(units=num_outputs))(flatten1)
我在这个模型中最大的收益来自于添加了针对 4D 的定制版 mixup。其思路与图像的 mixup 相同——我将两张随机图像混合,然后将这个“新”大脑的目标标签设为原标签的加权平均值。我在 TensorFlow 的数据集管道中按批次执行此操作。虽然这确实显著减慢了训练速度(每个 epoch 从 200 秒变成了 300 秒),但在混合后,它使 CV 和 LB 分数提高了约 0.001。
增强代码参考了 @cdeotte 针对 2D 图像的笔记本,链接在这里:
def mixup4D(image, label, prob=1.0):
"""
4D Mixup of fMRI images size (BATCH,53, 63, 52, 53)
"""
imgs = []; labs = []
for j in range(BATCH):
P = tf.cast( tf.random.uniform([],0,1)<=prob, tf.float32)
k = tf.cast( tf.random.uniform([],0,BATCH),tf.int32