如何将Keras模型拟合到Gamma分布?

时间:2019-09-25 00:15:29

标签: tensorflow keras deep-learning gamma-distribution tensorflow-probability

我正在尝试拟合输出变量始终为正的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

我在做什么错?我尝试了与损失函数不同的方法,但似乎无济于事。我认为这是对 concentration 的论据,因为我已经有一个与此模型相似的正态分布模型。在该模型中,我没有将softplus用作均值(loc),因为该分布接受任何正值或负值。我使用了标准偏差的精确结构,因为它在正态分布中也必须是正值。它工作正常。为什么它不适用于Gamma分布?

感谢所有能帮助我了解我在做什么错的人的建议。

2 个答案:

答案 0 :(得分:0)

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

您可能想要更大一些的gamma参数最小值,因为它们可以使分布非常清晰。尤其是浓度参数低至0.5会使分布极度集中在0。(这在维基百科https://en.wikipedia.org/wiki/Gamma_distribution上称为“ shape / alpha / k”)。

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

答案 1 :(得分:0)

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

1)我确保每一层都有一个kernel_initializer='random_uniform'语句,并且 2)我将整个gamma_loss函数转换为:lambda y, p_y: -p_y.log_prob(y) v

我不确定gamma_loss是否是问题所在,但是我发现一些人在做我正在做的事情的示例,而更简单的lambda y, 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)