You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

改进型U-Net训练结果受随机种子影响过大的问题求助

针对高不平衡医学图像分割中种子敏感问题的解决方案

核心问题分析

你的问题本质是高不平衡数据集(仅3%目标像素)下,模型初始化导致训练陷入局部最优。Dice Loss本身对样本分布不平衡极度敏感:当随机初始化的权重让模型倾向于预测全背景时,Dice Loss会稳定在0.95左右(对应几乎完全忽略目标);而优质初始化能让模型捕捉到目标特征,最终Loss降至0.1(对应Dice系数0.9)。

具体改进方案

1. 数据层面:从根源缓解不平衡

  • 加权采样:在get_dataset的shuffle步骤后,加入加权采样逻辑,给包含目标像素的样本设置更高采样权重。比如统计每个样本的目标像素占比,采样权重设为1/(目标占比+1e-6),确保模型能更多接触正样本。
  • 针对性数据增强:仅对包含目标的样本施加旋转、翻转、弹性形变等增强,避免对背景样本过度增强。可在map函数中加入判断逻辑,只有当样本掩码存在目标时才执行增强操作。

2. 损失函数优化:适配不平衡场景

你试过多种损失函数,可进一步尝试以下鲁棒性更强的变体:

  • 加权Dice Loss:给正样本像素设置权重,对应背景占比调整参数,修改后的损失函数如下:
    def weighted_dice_loss(y_true, y_pred):
        smooth = 1.
        alpha = 0.97  # 匹配背景像素占比97%
        y_true_f = tf.keras.backend.flatten(y_true)
        y_pred_f = tf.keras.backend.flatten(y_pred)
        intersection = tf.keras.backend.sum(y_true_f * y_pred_f)
        return 1. - (2. * intersection + smooth) / (alpha * tf.keras.backend.sum(y_true_f) + tf.keras.backend.sum(y_pred_f) + smooth)
    
  • Focal Tversky Loss:结合Focal聚焦难样本的特性与Tversky对不平衡的鲁棒性,公式为FTL = (1 - (TP)/(TP + alpha*FN + beta*FP))^gamma,其中alpha=0.97、beta=0.03、gamma=2。

3. 模型与训练策略调整

  • 输出层偏向初始化:给sigmoid输出层设置偏向正样本的初始偏置,让模型初始时更倾向于预测目标,对应代码修改:
    # 在unet函数的conv10定义处修改
    init_bias = np.log(0.03 / 0.97)  # 基于目标像素占比计算先验概率
    conv10 = Conv2D(1, (1,1), activation='sigmoid', 
                    bias_initializer=tf.keras.initializers.Constant(init_bias))(conv9)
    
  • 学习率调度:用余弦退火学习率替代固定值,帮助模型跳出局部最优,在训练时加入调度器:
    lr_scheduler = tf.keras.callbacks.LearningRateScheduler(lambda epoch: learning_rate * 0.5**(epoch//5))
    # 然后在model.fit的callbacks中加入lr_scheduler
    
  • 多阶段训练:先用Binary Cross Entropy训练10个epoch,让模型先学习基础特征区分,再切换为Dice Loss继续训练,避免初始阶段陷入全背景局部最优。

4. 训练稳定性提升

  • 增大或模拟大Batch:硬件允许的话将batch_size从16提升至32+,让batch内样本分布更稳定;若硬件受限,用梯度累积模拟大batch(每N步更新一次权重)。
  • 精简Batch Normalization:小Batch下BN的均值方差估计不稳定,会加剧初始化敏感。可尝试仅保留编码部分前两层的BN,或替换为Layer Normalization。

代码调整示例(核心部分)

# 定义加权Dice Loss
def weighted_dice_loss(y_true, y_pred):
    smooth = 1.
    alpha = 0.97
    y_true_f = tf.keras.backend.flatten(y_true)
    y_pred_f = tf.keras.backend.flatten(y_pred)
    intersection = tf.keras.backend.sum(y_true_f * y_pred_f)
    return 1. - (2. * intersection + smooth) / (alpha * tf.keras.backend.sum(y_true_f) + tf.keras.backend.sum(y_pred_f) + smooth)

# 修改U-Net模型输出层初始化
def unet(pretrained_weights = None,input_size = (size,size,1), df=filter_size, kernel_size = kernel_dimension): 
    # ... 其余代码保持不变 ...
    conv9 = Conv2D(2, kernel_size, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(conv9)
    # 设置偏向正样本的偏置
    init_bias = np.log(0.03 / 0.97)
    conv10 = Conv2D(1, (1,1), activation = 'sigmoid', 
                    bias_initializer=tf.keras.initializers.Constant(init_bias))(conv9)
    # ... 其余代码保持不变 ...
    model.compile(optimizer = Adam(lr = learning_rate), loss = weighted_dice_loss, metrics = ['accuracy','binary_accuracy', 'mae',
                            tf.keras.metrics.Precision(name='precision'), dice_coef, jacard_coef,                
                            tf.keras.metrics.FalseNegatives(thresholds=0.5, name='FN', dtype=None),
                            tf.keras.metrics.FalsePositives(thresholds=0.5, name='FP', dtype=None),
                            tf.keras.metrics.TrueNegatives(thresholds=0.5, name='TN', dtype=None),
                            tf.keras.metrics.TruePositives(thresholds=0.5, name='TP', dtype=None)])
    # ... 其余代码保持不变 ...

额外建议

  • 种子融合:若仍存在波动,可训练多个不同种子的模型,对预测结果取均值或投票,抵消单个种子的随机性影响。
  • 早停监控:记录训练过程中的FN指标,当FN持续居高不下时,提前终止训练,节省计算资源。

内容的提问来源于stack exchange,提问作者px3791

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 00:18:24