r""" This method computes the variational lower bound on the likelihood, which is: E_{q(F)} [ \log p(Y|F) ] - KL[ q(F) || p(F)] with q(\mathbf f) = N(\mathbf f \,|\, \boldsymbol \mu, \boldsymbol \Sigma)
(self)
| 109 | "return: []", |
| 110 | ) |
| 111 | def elbo(self) -> tf.Tensor: |
| 112 | r""" |
| 113 | This method computes the variational lower bound on the likelihood, |
| 114 | which is: |
| 115 | |
| 116 | E_{q(F)} [ \log p(Y|F) ] - KL[ q(F) || p(F)] |
| 117 | |
| 118 | with |
| 119 | |
| 120 | q(\mathbf f) = N(\mathbf f \,|\, \boldsymbol \mu, \boldsymbol \Sigma) |
| 121 | |
| 122 | """ |
| 123 | X_data, Y_data = self.data |
| 124 | num_data = tf.convert_to_tensor(self.num_data) |
| 125 | |
| 126 | # Get prior KL. |
| 127 | KL = gauss_kl(self.q_mu, self.q_sqrt) |
| 128 | |
| 129 | # Get conditionals |
| 130 | K = self.kernel(X_data) + tf.eye(num_data, dtype=default_float()) * default_jitter() |
| 131 | L = tf.linalg.cholesky(K) |
| 132 | fmean = tf.linalg.matmul(L, self.q_mu) + self.mean_function(X_data) # [NN, ND] -> ND |
| 133 | q_sqrt_dnn = tf.linalg.band_part(self.q_sqrt, -1, 0) # [D, N, N] |
| 134 | L_tiled = tf.tile(tf.expand_dims(L, 0), tf.stack([self.num_latent_gps, 1, 1])) |
| 135 | LTA = tf.linalg.matmul(L_tiled, q_sqrt_dnn) # [D, N, N] |
| 136 | fvar = tf.reduce_sum(tf.square(LTA), 2) |
| 137 | |
| 138 | fvar = tf.transpose(fvar) |
| 139 | |
| 140 | # Get variational expectations. |
| 141 | var_exp = self.likelihood.variational_expectations(X_data, fmean, fvar, Y_data) |
| 142 | |
| 143 | return tf.reduce_sum(var_exp) - KL |
| 144 | |
| 145 | @inherit_check_shapes |
| 146 | def predict_f( |