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

如何在Keras中正确实现MC Dropout?预测方差为何为零?

MC Dropout预测标准差几乎为零的问题排查

我是机器学习新手,尤其不熟悉Dropout这类复杂技术。我搭建了一个用于回归任务的简单1D CNN模型,希望通过MC Dropout捕捉每个输出像素的预测不确定性,已在每个卷积层后添加Dropout层。

模型架构代码

# Define the model architecture
model = keras.Sequential()

callback = tf.keras.callbacks.EarlyStopping(monitor='val_loss', patience=5, start_from_epoch=20, min_delta=0.00001, 
                                            verbose=True, restore_best_weights=True)

# Convolutional layers
model.add(layers.Conv1D(filters=64, kernel_size=6, activation='relu', input_shape=(input_size,1), name='conv1d_1'))
model.add(layers.MaxPooling1D(pool_size=2, name='max_pooling1d_1'))
model.add(layers.Dropout(0.2))
model.add(layers.Conv1D(filters=48, kernel_size=6, activation='relu', name='conv1d_3'))
model.add(layers.MaxPooling1D(pool_size=2, name='max_pooling1d_3'))
model.add(layers.Dropout(0.2))
model.add(layers.Conv1D(filters=16, kernel_size=6, activation='relu', name='conv1d_4'))
model.add(layers.MaxPooling1D(pool_size=2, name='max_pooling1d_4'))
model.add(layers.Dropout(0.2))

# Flatten the output for dense layers
model.add(layers.Flatten(name='flatten_1'))

# Dense layers
model.add(layers.Dense(64, activation='relu', name='dense_2'))
model.add(layers.Dense(128, activation='relu', name='dense_3'))

# Output layer
model.add(layers.Dense(output_size, activation='linear', name='dense_4'))

# Compile the model
model.compile(optimizer='adam', loss='mse', metrics=['mean_absolute_percentage_error'])

训练及不确定性量化代码

# Train (shape of train and test data are (N_samples, 500))
history = model.fit(train_data[..., np.newaxis], train_truth, batch_size=32, epochs=50, validation_data=(val_data[..., np.newaxis], val_truth), callbacks=[callback])

# Get predictions and uncertainties (only checking for first 10 samples)
y = np.stack([model(test_data[:10, ..., np.newaxis], training=True) for sample in range(100)])
mu = np.mean(y, axis=0)
sigma = np.std(y, axis=0)

我发现sigma(预测标准差)几乎为零,尽管测试集的预测误差超过10%;即使注释掉Dropout层重新训练评估,sigma值仍为零。我认为添加Dropout层应产生显著不确定性,请问我哪里操作有误?


问题原因及解决办法

  • Dropout层覆盖不足,全连接层缺失随机组件
    你仅在卷积层后添加了Dropout,但MC Dropout的不确定性主要来自模型中引入随机性的部分,全连接层通常是贡献不确定性的核心区域。当前的全连接层没有Dropout,整体随机性不足,导致多次预测结果几乎一致。建议在全连接层后补充Dropout:

    model.add(layers.Dense(64, activation='relu', name='dense_2'))
    model.add(layers.Dropout(0.2))  # 新增Dropout层
    model.add(layers.Dense(128, activation='relu', name='dense_3'))
    model.add(layers.Dropout(0.2))  # 新增Dropout层
    
  • 验证training=True是否真正激活Dropout
    虽然调用model(inputs, training=True)理论上会让Dropout进入训练模式,但Sequential模型偶尔会出现层行为异常的情况。可以单独测试Dropout层的随机性:

    # 生成测试输入
    test_input = np.random.rand(1, input_size, 1)
    # 获取第一个Dropout层
    dropout_layer = model.layers[2]
    # 基于卷积+池化后的输出,两次调用Dropout
    conv_pool_output = model.layers[1](model.layers[0](test_input))
    output1 = dropout_layer(conv_pool_output, training=True)
    output2 = dropout_layer(conv_pool_output, training=True)
    # 检查两次输出是否有差异
    print(np.mean(output1.numpy() != output2.numpy()))
    

    如果输出为0,说明Dropout未生效,需要排查模型构建逻辑,比如改用自定义Model类显式控制层的训练状态。

  • 尝试提高Dropout率
    0.2的失活率可能不足以产生明显的预测差异,可以尝试将Dropout率提高到0.3或0.4,增强模型的随机性。

  • 注释Dropout后sigma为零是正常现象
    移除Dropout后,模型没有任何随机组件,多次预测结果完全一致,标准差自然为零。这也侧面说明之前添加Dropout时,可能Dropout未真正启用,导致和无Dropout的表现一致。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.24 02:34:58