我构建并训练了 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:
只是做与 MSE 相同的事情,因为当单个数据点等于分布平均值时,NLL 被最大化.