Estoy intentando implementar el aprendizaje por clasificación de procesos gaussianos en tensorflow-probability
pero mi estimador resulta estar muy sesgado hacia cero. A diferencia de sklearn
Intenté optimizar directamente la probabilidad logarítmica posterior para encontrar el estimador máximo a posteriori.
¿Hay algo que esté haciendo mal en el proceso? ¿O de hecho es imposible aprender la clasificación de procesos gaussianos directamente a partir de la verdadera probabilidad logarítmica posterior?
Para probar mi configuración, genero una única función $f$ a partir de una distribución GP en puntos independientes dados $X$ y generar una observación independiente en cada punto según $P(Y_i = 1) = \sigma(f(X_i))$ donde $\sigma$ es la función logística $\frac{1}{1 + \exp(-z)}$ .
El siguiente gráfico muestra lo lejos de la verdad que tiende a estar mi estimador:
Generando los datos de la siguiente manera:
import numpy as np
import tensorflow as tf
import tensorflow_probability as tfp
# GP kernel
kernel = tfp.positive_semidefinite_kernels.ExponentiatedQuadratic()
# Independent variable points
X = np.random.uniform(-1,1, (30,1)).astype("float32")
# Generating a latent function at observable points
gp = tfp.distributions.GaussianProcess(kernel=kernel, index_points=X)
f = gp.sample(1)
with tf.Session() as sess:
f_ = sess.run(f)
# Generating observed classes (+-1)
Y = 2*tfp.distributions.Bernoulli(logits=tf.reshape(f_, (-1,))).sample(1) - 1
with tf.Session() as sess:
Y_ = sess.run(Y)
Aprendizaje del espacio latente mediante scikit-learn
que proporciona un estimador utilizando la aproximación de Laplace
from sklearn.gaussian_process import GaussianProcessClassifier
clf = GaussianProcessClassifier()
clf.fit(X, Y_.reshape(-1))
sigma_f_sklearn = clf.predict_proba(X)[:,1]
Optimización directa de la distribución posterior mediante tensorflow
def generate_posterior_log_likelihood(locations, observations):
"""
Build posterior log likelihood function with GP prior at specific locations
"""
gp_infer = tfp.distributions.GaussianProcess(
kernel=kernel, index_points=locations
)
def posterior_log_likelihood(f):
return (
gp_infer.log_prob(f) +
tf.reduce_sum(
tf.log_sigmoid(
tf.multiply(tf.cast(observations, tf.float32), f)
)
)
)
return posterior_log_likelihood
f = tf.get_variable("latent_f", shape=Y.shape,
initializer=tf.initializers.random_normal())
neg_log_likelihood = -generate_posterior_log_likelihood(X, Y_)(f)
optimize = tf.train.AdagradOptimizer(learning_rate=0.1)\
.minimize(neg_log_likelihood)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
prev_neg_log_likelihood = np.inf
# Optimizing until convergence
_, neg_log_likelihood_ = sess.run([optimize, neg_log_likelihood])
while prev_neg_log_likelihood - neg_log_likelihood_ > 1e-12:
prev_neg_log_likelihood = neg_log_likelihood_
_, neg_log_likelihood_ = sess.run([optimize, neg_log_likelihood])
# Calculating the points
f_map = sess.run(f)