如何将 Keras 模型拟合到 Gamma 分布?
How to fit a Keras model to a Gamma Distribution?
我正在尝试拟合输出变量始终为正的 keras 模型。我想使用伽玛分布来模拟这个问题。问题是loss总是输出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)
loss总是输出nan
我做错了什么?我尝试了不同的损失函数,但似乎没有任何效果。我认为它与 浓度 参数相关,因为我已经有了一个与正态分布类似的模型。在该模型中,我没有对均值 (loc) 使用 softplus,因为该分布接受任何正值或负值。我使用标准偏差的确切结构,因为它在正态分布中也必须是正数。它工作得很好。为什么它不适用于 Gamma 分布?
感谢您向任何可以帮助我理解我做错了什么的人提出建议。
绝对删除 gamma_loss
末尾的 .numpy()
,因为这会破坏梯度反向传播。
您可能希望 gamma 参数的最小值稍微大一些,因为它们可以使分布非常尖锐。特别是低至 0.5 的浓度参数使分布极度集中在 0。(这就是维基百科 https://en.wikipedia.org/wiki/Gamma_distribution 上称为 'shape/alpha/k' 的那个)。
这很容易在某处导致 +/-inf,然后在其他地方产生 nan。
我想与大家分享我为使我的代码正常工作所做的一切:
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)
我正在尝试拟合输出变量始终为正的 keras 模型。我想使用伽玛分布来模拟这个问题。问题是loss总是输出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)
loss总是输出nan
我做错了什么?我尝试了不同的损失函数,但似乎没有任何效果。我认为它与 浓度 参数相关,因为我已经有了一个与正态分布类似的模型。在该模型中,我没有对均值 (loc) 使用 softplus,因为该分布接受任何正值或负值。我使用标准偏差的确切结构,因为它在正态分布中也必须是正数。它工作得很好。为什么它不适用于 Gamma 分布?
感谢您向任何可以帮助我理解我做错了什么的人提出建议。
绝对删除 gamma_loss
末尾的 .numpy()
,因为这会破坏梯度反向传播。
您可能希望 gamma 参数的最小值稍微大一些,因为它们可以使分布非常尖锐。特别是低至 0.5 的浓度参数使分布极度集中在 0。(这就是维基百科 https://en.wikipedia.org/wiki/Gamma_distribution 上称为 'shape/alpha/k' 的那个)。
这很容易在某处导致 +/-inf,然后在其他地方产生 nan。
我想与大家分享我为使我的代码正常工作所做的一切:
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)