Keras TensorFlow 概率模型不学习分布传播

问题描述 投票:0回答:1

我构建并训练了 Keras Tensorflow 概率模型。它基本上是一个完全连接的神经网络模型,输出层有一个 DistributionLambda。最后一层代码示例在这里:

tfp.layers.DistributionLambda(
            lambda t: tfd.Independent(tfd.Normal(loc=t[..., :n], scale=1e-5 + tf.nn.softplus(c + t[..., n:])),
                                      reinterpreted_batch_ndims=1))

在训练期间,我使用均方误差作为损失函数。训练似乎进展顺利并且数值稳定。

训练后,我首先删除模型的最后一层,然后使用测试集数据进行前向预测。这基本上为我提供了模型为测试集中每个数据点学习的分布的“学习”预期

loc
scale
。然而,由于
softplus
中的
DistributionLambda
修正,我还必须对斩波模型对
scale
的预测应用相同的修正。

我试图验证模型是否学习了根据输入值的适当分布。因此,通过对

loc
(平均值)和
scale
(标准差)的预测,我可以创建校准图来查看模型学习潜在分布的情况。平均值的校准图看起来很棒。我还使用如下代码为
scale
/stdev 参数创建校准图:

def create_stdev_calibration_plot(df: pd.DataFrame,
                              y_true: str = 'y_true',
                              y_pred_mean: str = 'y_pred_mean',
                              y_pred_std: str = 'y_pred_std',
                              title: Optional[str] = None,
                              save_path: Optional[str] = None):

    # Compute the residuals
    df['residual'] = df[y_true] - df[y_pred_mean]

    # Bin data based on predicted standard deviation
    bins = np.linspace(df[y_pred_std].min(), df[y_pred_std].max(), 10)
    df['bin'] = np.digitize(df[y_pred_std], bins)

    # For each bin, compute mean predicted std and actual std of residuals
    df['y_pred_variance'] = df[y_pred_std] ** 2
    bin_means_variance = df.groupby('bin')['y_pred_variance'].mean()

    # Convert back to standard deviation
    bin_means = np.sqrt(bin_means_variance)
    bin_residual_stds = df.groupby('bin')['residual'].std()

    # Create the calibration plot
    plt.figure(figsize=(8, 8))
    plt.plot(bin_means, bin_residual_stds, 'o-')

    xrange = plt.xlim()
    yrange = plt.ylim()
    max_val = max(xrange[1], yrange[1])
    min_val = min(xrange[0], yrange[0])
    plt.axline((min_val, min_val), (max_val, max_val), linestyle='--', color='k', linewidth=2)

    plt.xlabel('Mean Predicted Standard Deviation')
    plt.ylabel('Actual Standard Deviation of Residuals')
    plt.title('Spread Calibration Plot')
    plt.grid(True)
    plt.show()

我生成了一些合成数据来证明此标准偏差校准图按预期工作,如下所示:

# Number of samples
n_samples = 1000

# Input feature
x = np.random.uniform(-10, 10, size=n_samples)

# True mean and standard deviation as functions of the input feature
true_mean = 2 * x + 3
true_std = 0.5 * np.abs(x) + 1

# Generate synthetic data
y_true = np.random.normal(loc=true_mean, scale=true_std)

# Simulate model predictions (with some error)
y_pred_mean = true_mean + np.random.normal(loc=0, scale=1, size=n_samples)
y_pred_std = true_std + np.random.normal(loc=0, scale=0.5, size=n_samples)

# Ensure standard deviations are positive
y_pred_std = np.abs(y_pred_std)

df = pd.DataFrame({
    'y_true': y_true,
    'y_pred_mean': y_pred_mean,
    'y_pred_std': y_pred_std
})

create_stdev_calibration_plot(df)

以下是合成数据的校准结果:

当我对模型的输出数据运行相同的函数时,绘图如下所示:

基于校准图。它看起来就像模型没有学习价差,而只是学习平均值并保持价差较小以最小化损失。我可以对我的训练做出哪些改变来激励模型准确地学习传播?

更新:

我的一个想法是创建一个自定义损失函数,该函数基于均值和分布校准的平均“预期校准误差”。然而,损失函数的输入是模型中的 y_true 张量和

y_pred
张量。
y_pred
只是当前学习分布的样本,我无法知道分布参数(
loc
scale
);这使得扩展校准变得不可能。此外,由于所需的分箱,预期的校准误差是不可微分的,因此也无法通过反向传播进行学习。
更新2:

我目前正在考虑将损失函数更改为负对数似然(NLL)。我将拥有“学习的”分布参数,这样我就可以根据每个数据点的 NLL 与“学习的”分布计算损失。我不相信这会起作用,因为 NLL 仅适用于 1 个数据点(每行 1 个数据点和分布组合)

可能

只是做与 MSE 相同的事情,因为当单个数据点等于分布平均值时,NLL 被最大化.

python tensorflow tf.keras calibration tensorflow-probability
1个回答
0
投票
Update 2

中的建议改用负对数似然,则您将最小化损失函数,您学到的概率分布与训练数据的拟合程度越高,损失函数就越低。请参阅

本教程
,并注意他们如何使用负对数似然作为损失函数。

© www.soinside.com 2019 - 2024. All rights reserved.