2

我正在尝试拟合一个输出变量始终为正的 keras 模型。我想使用伽马分布来模拟这个问题。问题是损失总是输出 NAN。

我构建了以下 keras 模型:

model_max = tf.keras.Sequential([
            tf.keras.layers.Dense(20,input_dim=10, activation="relu"),    
            tf.keras.layers.Dense(15,activation="relu"),
            tf.keras.layers.Dense(10,activation="relu"),
            tf.keras.layers.Dense(5,activation="relu"),
            tf.keras.layers.Dense(2),
            tfp.layers.DistributionLambda(lambda t:
            tfd.Gamma(concentration = tf.math.softplus(0.005*t[...,:1])+0.001,
             rate = tf.math.softplus(0.005*t[...,1:])+0.001)
            ),
])            

请注意,我使用了 softplus,因为分布的两个参数都必须是正数。我还添加了 0.001 以确保参数始终大于零。

我的损失函数如下:

def gamma_loss(y_true, my_dist):

    dist_mean = my_dist.mean()
    dist_stddev = my_dist.stddev()
    alpha = (dist_mean / dist_stddev)**2
    beta = dist_mean / dist_stddev**2
    gamma_distr = tfd.Gamma(concentration=alpha, rate=beta)
    return -tf.reduce_mean(gamma_distr.log_prob(y_true))

这个功能似乎工作正常。例如,如果我运行以下代码,它运行良好:

import tensorflow as tf
import tensorflow_probability as tfp
tfd = tfp.distributions

def gamma_loss(y_true, my_dist):

    dist_mean = my_dist.mean()
    dist_stddev = my_dist.stddev()
    alpha = (dist_mean / dist_stddev)**2
    beta = dist_mean / dist_stddev**2
    #print(alpha)
    gamma_distr = tfd.Gamma(concentration=alpha, rate=beta)
    return -tf.reduce_mean(gamma_distr.log_prob(y_true)).numpy()

dist = tfd.Gamma(1,1)

gamma_loss(100, dist)

但是,如果我使用以下行编译它:

model_max.compile(optimizer=tf.optimizers.Adam(learning_rate = 0.001),loss=gamma_loss)

损失总是输出 nan

我究竟做错了什么?我尝试了不同的损失函数,但似乎没有任何效果。我认为这与集中论点有关,因为我已经有一个与正态分布类似的模型。在那个模型中,我没有使用 softplus 作为平均值(loc),因为该分布接受任何正值或负值。我使用了标准偏差的确切结构,因为它在正态分布中也必须是正的。它工作得很好。为什么它不适用于 Gamma 分布?

感谢您向任何可以帮助我了解我做错了什么的人提供建议。

4

2 回答 2

1

我想与您分享我为使代码正常工作所做的一切:

1)我确保每一层都有一个kernel_initializer='random_uniform'声明,2)我把我的整个 gamma_loss 函数变成:lambda y, p_y: -p_y.log_prob(y)v

我不确定 gamma_loss 是否是问题所在,但我发现有人在做我正在做的事情的例子,而且更简单的 lambday, p_y: -p_y.log_prob(y)函数工作正常,所以我就这么做了。我认为我的主要问题是权重没有被随机初始化。

另外,我想回应我在寻找答案时在网上找到的一些建议:尝试拟合一个示例并确保在使用真实的训练数据之前效果很好。在我的例子中,我通过采用一个训练示例并复制该行数千次来实现这一点(创建一个所有行都相等的数据集),然后只用它来训练我的模型。当我的模型无法适应时,更容易逐层分析每一层的结果应该是什么。

Brian Patton 给出的答案非常有帮助,因为它确实为我指明了正确的方向,即尝试了解每一层输出的内容并通过一个简单的示例测试您的假设。

为了将来参考,这是我的代码现在的样子:

model_max = tf.keras.Sequential([
            tf.keras.layers.Dense(20,input_dim=10, activation="relu", kernel_initializer='random_uniform' ),   
            tf.keras.layers.Dense(15,activation="relu",kernel_initializer='random_uniform' ),
            tf.keras.layers.Dense(10,activation="relu",kernel_initializer='random_uniform' ),
            tf.keras.layers.Dense(5,activation="relu",kernel_initializer='random_uniform' ),
            tf.keras.layers.Dense(2, kernel_initializer='random_uniform' ),
            tfp.layers.DistributionLambda(lambda t:
            tfd.Gamma(concentration = tf.math.softplus(t[:,0])+0.000000001,
            rate = tf.math.softplus(t[:,1])+0.000000001),
            ),
])     


negloglik = lambda y, p_y: -p_y.log_prob(y)

model_max.compile(optimizer=tf.optimizers.Adamax(learning_rate = 0.0001),loss=negloglik)

于 2019-10-07T15:31:38.493 回答
1

绝对.numpy()从 的末尾删除gamma_loss,因为这会破坏梯度反向传播。

您可能需要稍微大一点的 gamma 参数最小值,因为它们可以使分布非常尖锐。特别是低至 0.5 的浓度参数使分布极其集中在 0。(这是维基百科https://en.wikipedia.org/wiki/Gamma_distribution上称为“shape/alpha/k”的那个)。

这很容易在某个地方导致 +/-inf,然后在其他地方产生一个 nan。

于 2019-09-26T14:21:09.273 回答