28
28
29
29
class WishartProcessLikelihoodBase (MonteCarloLikelihood ):
30
30
"""
31
- Class for Wishart process likelihoods.
31
+ Abstract class for all Wishart process likelihoods.
32
32
"""
33
33
34
34
def __init__ (
@@ -40,6 +40,7 @@ def __init__(
40
40
):
41
41
"""
42
42
Initialize the base Wishart process likelihood.
43
+ This implementation assumes the input is uni-dimensional.
43
44
44
45
Parameters
45
46
----------
@@ -49,6 +50,7 @@ def __init__(
49
50
Degrees of freedom.
50
51
:param num_mc_samples:
51
52
Number of Monte Carlo samples used to approximate gradients (S).
53
+ Sometimes also denoted as R.
52
54
"""
53
55
if num_factors is not None :
54
56
latent_dim = num_factors * nu
@@ -76,7 +78,7 @@ def __init__(
76
78
D : int ,
77
79
nu : int = None ,
78
80
num_mc_samples : int = 2 ,
79
- A_scale_matrix_option : str = 'train_full_matrix' ,
81
+ scale_matrix_cholesky_option : str = 'train_full_matrix' ,
80
82
train_additive_noise : bool = False ,
81
83
additive_noise_matrix_init : float = 0.01 ,
82
84
verbose : bool = True ,
@@ -92,7 +94,7 @@ def __init__(
92
94
Degrees of freedom.
93
95
:param num_mc_samples:
94
96
Number of Monte Carlo samples used to approximate gradients (S).
95
- :param A_scale_matrix_option :
97
+ :param scale_matrix_cholesky_option :
96
98
:param train_additive_noise:
97
99
Whether to train the additive noise matrix (Lambda).
98
100
:param additive_noise_matrix_init:
@@ -109,7 +111,9 @@ def __init__(
109
111
nu = nu ,
110
112
num_mc_samples = num_mc_samples ,
111
113
)
112
- self .A_scale_matrix = self ._set_A_scale_matrix (option = A_scale_matrix_option ) # (D, D)
114
+ self .A_scale_matrix = self ._set_A_scale_matrix (
115
+ option = scale_matrix_cholesky_option
116
+ ) # (D, D)
113
117
114
118
# The additive noise matrix must have positive diagonal values, which this softplus construction guarantees.
115
119
additive_noise_matrix_init = np .log (
@@ -122,7 +126,7 @@ def __init__(
122
126
) # (D, )
123
127
124
128
if verbose :
125
- logging .info (f"A scale matrix option is '{ A_scale_matrix_option :s} '." )
129
+ logging .info (f"Scale matrix Cholesky ( matrix A) option is '{ scale_matrix_cholesky_option :s} '." )
126
130
print ('A_scale_matrix: ' , self .A_scale_matrix )
127
131
print ('initial additive part: ' , self .additive_part )
128
132
@@ -207,13 +211,14 @@ def _log_prob(
207
211
# compute the constant term of the log likelihood
208
212
constant_term = - self .D / 2 * tf .math .log (2 * tf .constant (np .pi , dtype = tf .float64 ))
209
213
210
- # compute the `log(det( AFFA))` component of the log likelihood
214
+ # compute the AFFA component of the log likelihood - our construction of \Sigma
211
215
# TODO: this does not work for nu != D
212
216
# af = tf.matmul(self.A_scale_matrix, f_sample) # (S, N, D, nu)
213
217
af = tf .multiply (self .A_scale_matrix , f_sample )
214
-
215
- affa = tf .matmul (af , af , transpose_b = True ) # (S, N, D, D) - our construction of \Sigma
218
+ affa = tf .matmul (af , af , transpose_b = True ) # (S, N, D, D)
216
219
affa = self ._add_diagonal_additive_noise (affa ) # (S, N, D, D)
220
+
221
+ # compute the `log(det(AFFA))` component of the log likelihood
217
222
# Before, the trainable additive noise sometimes broke the Cholesky decomposition.
218
223
# This did not happen again after forcing it to be positive.
219
224
# TODO: Can adding positive values to the diagonal ever make a PSD matrix become non-PSD?
@@ -224,7 +229,9 @@ def _log_prob(
224
229
print (self .additive_part )
225
230
print (e )
226
231
log_det_affa = 2 * tf .math .reduce_sum (
227
- tf .math .log (tf .linalg .diag_part (L )),
232
+ tf .math .log (
233
+ tf .linalg .diag_part (L )
234
+ ),
228
235
axis = 2
229
236
) # (S, N)
230
237
@@ -317,7 +324,7 @@ def __init__(
317
324
nu : int = None ,
318
325
num_mc_samples : int = 2 ,
319
326
num_factors : int = None ,
320
- A_scale_matrix_option : str = 'train_full_matrix' ,
327
+ scale_matrix_cholesky_option : str = 'train_full_matrix' ,
321
328
train_additive_noise : bool = False ,
322
329
additive_noise_matrix_init : float = 0.01 ,
323
330
verbose : bool = True ,
@@ -330,3 +337,30 @@ def __init__(
330
337
)
331
338
332
339
raise NotImplementedError ("Factorized Wishart process not implemented yet." )
340
+
341
+ def _log_prob (
342
+ self ,
343
+ x_data : np .array ,
344
+ f_sample : tf .Tensor ,
345
+ y_data : np .array ,
346
+ ) -> tf .Tensor :
347
+ """
348
+ Compute the (Monte Carlo estimate of) the log likelihood given samples of the GPs.
349
+
350
+ This overrides the method in MonteCarloLikelihood.
351
+
352
+ Parameters
353
+ ----------
354
+ :param x_data:
355
+ Input tensor.
356
+ NumPy array of shape (num_time_steps, 1) or (N, 1).
357
+ :param f_sample:
358
+ Function evaluation tensor.
359
+ (num_mc_samples, num_time_steps, num_factors, degrees_of_freedom) or (S, N, K, nu) -
360
+ :param y_data:
361
+ Observation tensor.
362
+ (num_time_steps, num_time_series) or (N, D) -
363
+ :return:
364
+ (num_time_steps, ) or (N, )
365
+ """
366
+ assert isinstance (f_sample , tf .Tensor )
0 commit comments