# Buggy code
def forward(self, variational_dist_f, target, **kwargs):
    num_batch = variational_dist_f.event_shape.numel()

    log_likelihood = self.likelihood.expected_log_prob(
        target, variational_dist_f, **kwargs
    ).div(num_batch)
    kl_divergence = self.model.variational_strategy.kl_divergence()

    if kl_divergence.dim() > log_likelihood.dim():
        kl_divergence = kl_divergence.sum(-1)

    if log_likelihood.numel() == 1:
        kl_divergence = kl_divergence.sum()

    kl_divergence = kl_divergence.div(self.num_data)

    # Add any additional registered loss terms
    added_loss = torch.zeros_like(kl_divergence)
    had_added_losses = False
    for added_loss_term in self.model.added_loss_terms():
        added_loss.add_(added_loss_term.loss())
        had_added_losses = True

    if self.combine_terms:
        res = log_likelihood - kl_divergence
        for _, prior, closure, _ in self.named_priors():
            res.add_(prior.log_prob(closure()).sum().div(self.num_data))
        return res + added_loss
    else:
        log_prior = torch.zeros_like(log_likelihood)
        for _, prior, closure, _ in self.named_priors():
            log_prior.add_(prior.log_prob(closure()).sum())
        if had_added_losses:
            return (
                log_likelihood,
                kl_divergence,
                log_prior.div(self.num_data),
                added_loss,
            )
        else:
            return log_likelihood, kl_divergence, log_prior.div(self.num_data)


# Traceback (AttributeError)
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-6-c955f39ee560> in <module>
4 with torch.no_grad():
5     for x_batch, y_batch in test_loader:
----> 6         preds = model(x_batch)
7         means = torch.cat([means, preds.mean.cpu()])
8 means = means[1:]

~/miniconda3/envs/mbrl/lib/python3.7/site-packages/gpytorch/models/abstract_variational_gp.py in __call__(self, inputs, **kwargs)
20             inputs = inputs.unsqueeze(-1)
21
---> 22         return self.variational_strategy(inputs)

~/miniconda3/envs/mbrl/lib/python3.7/site-packages/gpytorch/variational/variational_strategy.py in __call__(self, x)
228                 self._memoize_cache = dict()
229
--> 230         return super(VariationalStrategy, self).__call__(x)

~/miniconda3/envs/mbrl/lib/python3.7/site-packages/gpytorch/module.py in __call__(self, *inputs, **kwargs)
20
21     def __call__(self, *inputs, **kwargs):
---> 22         outputs = self.forward(*inputs, **kwargs)
23         if isinstance(outputs, list):
24             return [_validate_module_outputs(output) for output in outputs]

~/miniconda3/envs/mbrl/lib/python3.7/site-packages/gpytorch/variational/variational_strategy.py in forward(self, x)
214                     induc_induc_covar.inv_matmul(induc_data_covar)
215                 )
--> 216                 data_covariance = data_data_covar + neg_induc_data_data_covar
217             predictive_covar = PsdSumLazyTensor(predictive_covar, data_covariance)
218

~/miniconda3/envs/mbrl/lib/python3.7/site-packages/gpytorch/lazy/sum_lazy_tensor.py in __add__(self, other)
75             return SumLazyTensor(*(list(self.lazy_tensors) + [other]))
76         else:
---> 77             raise AttributeError("other must be a LazyTensor")
78
79     def diag(self):

AttributeError: other must be a LazyTensor

# Fixed code
def forward(self, variational_dist_f, target, **kwargs):
    r"""
    Computes the Variational ELBO given :math:`q(\mathbf f)` and :math:`\mathbf y`.
    Calling this function will call the likelihood's :meth:`~gpytorch.likelihoods.Likelihood.expected_log_prob`
    function.

    :param ~gpytorch.distributions.MultivariateNormal variational_dist_f: :math:`q(\mathbf f)`
        the outputs of the latent function (the :obj:`gpytorch.models.ApproximateGP`)
    :param torch.Tensor target: :math:`\mathbf y` The target values
    :param kwargs: Additional arguments passed to the
        likelihood's :meth:`~gpytorch.likelihoods.Likelihood.expected_log_prob` function.
    :rtype: torch.Tensor
    :return: Variational ELBO. Output shape corresponds to batch shape of the model/input data.
    """
    return super().forward(variational_dist_f, target, **kwargs)