#python-3.x #regression #tensorflow2.0 #tensorflow-probability #densevariational
#python-3.x #регрессия #tensorflow2.0 #tensorflow-вероятность #плотный вариационный
Вопрос:
Я знакомлюсь с Tensorflow-вероятностью, и здесь я сталкиваюсь с проблемой. Во время обучения модель возвращает nan как потерю (возможно, имеется в виду огромная потеря, которая приводит к переполнению). Поскольку функциональная форма синтетических данных не слишком сложна, а соотношение точек данных к параметрам на первый взгляд не пугает, по крайней мере, мне интересно, в чем проблема и как ее можно исправить.
Код следующий — сопровождается некоторыми, возможно, полезными изображениями:
# Create and plot 5000 data points
x_train = np.linspace(-1, 2, 5000)[:, np.newaxis]
y_train = np.power(x_train, 3) 0.1*(2 x_train)*np.random.randn(5000)[:, np.newaxis]
plt.scatter(x_train, y_train, alpha=0.1)
plt.show()
# Define the prior weight distribution -- all N(0, 1) -- and not trainable
def prior(kernel_size, bias_size, dtype = None):
n = kernel_size bias_size
prior_model = Sequential([
tfpl.DistributionLambda(
lambda t: tfd.MultivariateNormalDiag(loc = tf.zeros(n) , scale_diag = tf.ones(n)
))
])
return(prior_model)
# Define variational posterior weight distribution -- multivariate Gaussian
def posterior(kernel_size, bias_size, dtype = None):
n = kernel_size bias_size
posterior_model = Sequential([
tfpl.VariableLayer(tfpl.MultivariateNormalTriL.params_size(n) , dtype = dtype), # The parameters of the model are declared Variables that are trainable
tfpl.MultivariateNormalTriL(n) # The posterior function will return to the Variational layer that will call it a MultivariateNormalTril object that will have as many dimensions
# as the parameters of the Variational Dense Layer. That means that each parameter will be generated by a distinct Normal Gaussian shifted and scaled
# by a mu and sigma learned from the data, independently of all the other weights. The output of this Variablelayer will become the input to the
# MultivariateNormalTriL object.
# The shape of the VariableLayer object will be defined by the number of paramaters needed to create the MultivariateNormalTriL object given
# that it will live in a Space of n dimensions (event_size = n). This number is returned by the tfpl.MultivariateNormalTriL.params_size(n)
])
return(posterior_model)
x_in = Input(shape = (1,))
x = tfpl.DenseVariational(units= 2**4,
make_prior_fn=prior,
make_posterior_fn=posterior,
kl_weight=1/x_train.shape[0],
activation='relu')(x_in)
x = tfpl.DenseVariational(units= 2**4,
make_prior_fn=prior,
make_posterior_fn=posterior,
kl_weight=1/x_train.shape[0],
activation='relu')(x)
x = tfpl.DenseVariational(units=tfpl.IndependentNormal.params_size(1),
make_prior_fn=prior,
make_posterior_fn=posterior,
kl_weight=1/x_train.shape[0])(x)
y_out = tfpl.IndependentNormal(1)(x)
model = Model(inputs = x_in, outputs = y_out)
def nll(y_true, y_pred):
return -y_pred.log_prob(y_true)
model.compile(loss=nll, optimizer= 'Adam')
model.summary()
Обучите модель
history = model.fit(x_train1, y_train1, epochs=500)
Ответ №1:
Проблема, по-видимому, заключается в функции потерь: отрицательная логарифмическая вероятность независимого нормального распределения без какого-либо указанного местоположения и масштаба приводит к неукротимой дисперсии, что приводит к увеличению конечного значения потерь. Поскольку вы экспериментируете с вариационными слоями, вас, должно быть, интересует оценка эпистемологической неопределенности, с этой целью я бы рекомендовал применять постоянную дисперсию.
Я попытался внести пару небольших изменений в ваш код в следующих строках:
- прежде всего, конечный результат y_out поступает непосредственно из конечного вариационного слоя без какого-либо уровня распределения IndpendnetNormal:
y_out = tfpl.DenseVariational(units=1, make_prior_fn=prior, make_posterior_fn=posterior, kl_weight=1/x_train.shape[0])(x)
- во-вторых, функция потерь теперь содержит необходимые вычисления с нужным вам нормальным распределением, но со статической дисперсией, чтобы избежать увеличения потерь во время обучения:
def nll(y_true, y_pred): dist = tfp.distributions.Normal(loc=y_pred, scale=1.0) return tf.reduce_sum(-dist.log_prob(y_true))
- затем модель компилируется и обучается таким же образом, как и раньше:
model.compile(loss=nll, optimizer= 'Adam') history = model.fit(x_train, y_train, epochs=3000)
- и, наконец, давайте выберем 100 различных прогнозов из обученной модели и построим график этих значений, чтобы визуализировать эпистемологическую неопределенность модели:
predicted = [model(x_train) for _ in range(100)] for i, res in enumerate(predicted): plt.plot(x_train, res , alpha=0.1) plt.scatter(x_train, y_train, alpha=0.1) plt.show()
После 3000 эпох результат выглядит следующим образом (с уменьшенным количеством обучающих точек до 3000 вместо 5000 для ускорения обучения):
Ответ №2:
Модель содержит 38 589 обучаемых параметров, но у вас есть только 5000 точек в качестве данных; таким образом, эффективное обучение невозможно с таким количеством параметров.