我正在尝试拟合输出变量始终为正的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分布?
感谢所有能帮助我了解我在做什么错的人的建议。
答案 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)