Регрессионная модель с 3 скрытыми плотными вариационными слоями в Tensorflow-Вероятность возвращает nan как потерю во время обучения

#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:

Проблема, по-видимому, заключается в функции потерь: отрицательная логарифмическая вероятность независимого нормального распределения без какого-либо указанного местоположения и масштаба приводит к неукротимой дисперсии, что приводит к увеличению конечного значения потерь. Поскольку вы экспериментируете с вариационными слоями, вас, должно быть, интересует оценка эпистемологической неопределенности, с этой целью я бы рекомендовал применять постоянную дисперсию.

Я попытался внести пару небольших изменений в ваш код в следующих строках:

  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)
     
  2. во-вторых, функция потерь теперь содержит необходимые вычисления с нужным вам нормальным распределением, но со статической дисперсией, чтобы избежать увеличения потерь во время обучения:
      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))
     
  3. затем модель компилируется и обучается таким же образом, как и раньше:
      model.compile(loss=nll, optimizer= 'Adam')
     history = model.fit(x_train, y_train, epochs=3000)
     
  4. и, наконец, давайте выберем 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 точек в качестве данных; таким образом, эффективное обучение невозможно с таким количеством параметров.