probability icon indicating copy to clipboard operation
probability copied to clipboard

RBF Kernel - not converging

Open waudinio27 opened this issue 1 year ago • 0 comments

Hello everybody!

I am adopting the RBF Kernel to work with Gaussian Process Regression and data from yfinance. I am able to fit the data and make predicitons, but the last value of SPY is at around 412 and the predictions for the future return values from 65 going down to 40 for the next 10 steps.

y_future array([62.86690553, 64.20991116, 52.24651292, 54.59749465, 65.31611035, 51.90582303, 42.96902065, 49.11250877, 38.20838633, 42.56555457])

It is the same for the train test part. So there is a problem with the scale. How can I adopt the amplitude to work correct? Or what else can it be - so I can investigate the issue myself....

Below is my code:

import yfinance as yf
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
from tensorflow_probability import distributions as tfd

# Download data from yfinance
data = yf.download('SPY', period='1y')
# Use the 'Close' column as the target variable
y = data['Close'].values
# Create an array of indices to use as the input variable
x = np.arange(len(y))[:, np.newaxis]

# Split the data into training and test sets
train_size = int(len(x) * 0.8)
x_train, x_test = x[:train_size], x[train_size:]
y_train, y_test = y[:train_size], y[train_size:]

# Define RBFKernelFn class
class RBFKernelFn(tf.keras.layers.Layer):
    def __init__(self, **kwargs):
        super(RBFKernelFn, self).__init__(**kwargs)
        dtype = kwargs.get('dtype', None)

        self._amplitude = self.add_variable(
            initializer=tf.constant_initializer(0),
            dtype=dtype,
            name='amplitude')
        
        self._length_scale = self.add_variable(
            initializer=tf.constant_initializer(0),
            dtype=dtype,
            name='length_scale')

    def call(self, x):
        # Never called -- this is just a layer so it can hold variables
        # in a way Keras understands.
        return x

    @property
    def kernel(self):
        return tfp.math.psd_kernels.ExponentiatedQuadratic(
          amplitude=tf.nn.softplus(0.1 * self._amplitude),
          length_scale=tf.nn.softplus(5. * self._length_scale)
        )

# For numeric stability, set the default floating-point dtype to float64
tf.keras.backend.set_floatx('float64')

# Build model.
num_inducing_points = 200
model = tf.keras.Sequential([
    tf.keras.layers.InputLayer(input_shape=[1]),
    tf.keras.layers.Dense(1, kernel_initializer='ones', use_bias=False),
    tfp.layers.VariationalGaussianProcess(
        num_inducing_points=num_inducing_points,
        kernel_provider=RBFKernelFn(),
        event_shape=[1],
        inducing_index_points_initializer=tf.constant_initializer(
            np.linspace(x.min(), x.max(), num=num_inducing_points,
                        dtype=x.dtype)[..., np.newaxis]),
        unconstrained_observation_noise_variance_initializer=(
            tf.constant_initializer(np.array(0.54).astype(x.dtype))),
    ),
])

# Do inference.
batch_size = 32
loss = lambda y, rv_y: rv_y.variational_loss(
    y, kl_weight=np.array(batch_size, x.dtype) / x.shape[0])
model.compile(optimizer=tf.optimizers.Adam(learning_rate=0.01), loss=loss)
model.fit(x_train, y_train, batch_size=batch_size, epochs=1000, verbose=False)

# Make a prediction for 10 steps into the future
future_steps = 10
x_future = np.linspace(x_test[-1], x_test[-1] + future_steps, future_steps)[:, np.newaxis]
y_future = model.predict(x_future).squeeze()

This is the graphic:

grafik

waudinio27 avatar May 08 '23 18:05 waudinio27