Пример #1
0
    def _update_inputs(self, x, x_ind, y, f, obs):
        available = ~B.isnan(y[:, 0])

        def estimate(x_):
            # If observations are available, estimate using the posterior mean;
            # otherwise, use the prior mean.
            return ((f | obs) if obs else f).mean(x_)

        # Update inputs of inducing points.
        if self.sparse:
            x_ind = B.concat([x_ind, estimate(x_ind)], axis=1)

        # Impute missing data and replace available data.
        if self.impute and self.replace:
            y = estimate(x)
        else:
            # Just impute missing data.
            if self.impute and B.any(~available):
                y = merge(y, estimate(x[~available]), ~available)

            # Just replace available data.
            if self.replace and B.any(available):
                y = merge(y, estimate(x[available]), available)

        # Finally, actually update inputs.
        x = B.concat([x, y], axis=1)

        return x, x_ind
Пример #2
0
def per_output(y, keep=False):
    """Return observations per output, respecting that the data must be
    closed downwards.

    Args:
        y (tensor): Outputs.
        keep (bool, optional): Also return missing observations that would
            make the data closed downwards.

    Returns:
        generator: Generator that generates tuples containing the
            observations per layer and a mask which observations are not
            missing relative to the previous layer.
    """
    p = B.shape_int(y)[1]  # Number of outputs

    for i in range(p):
        # Check current and future availability.
        available = ~B.isnan(y)
        future = B.any(available[:, i + 1:], axis=1)

        # Initialise the mask to current availability.
        mask = available[:, i]

        # Take into account future observations if necessary.
        if keep and i < p - 1:  # Check whether this is the last output.
            mask = mask | future

        # Give stuff back.
        yield y[mask, i:i + 1], mask

        # Filter observations.
        y = y[mask]
Пример #3
0
    def logpdf(self,
               x,
               y,
               w,
               only_last_layer=False,
               sample_missing=False,
               return_inputs=False,
               x_ind=None,
               outputs=None):
        """Compute the logpdf.

        Args:
            x (tensor): Inputs.
            y (tensor): Outputs.
            w (tensor): Weights.
            only_last_layer (bool, optional): Compute the logpdf for only the
                last layer. Defaults to `False`.
            sample_missing (bool, optional): Sample missing data to compute an
                unbiased estimate of the pdf, *not* logpdf. Defaults to `False`.
            return_inputs (bool, optional): Instead return the inputs and
                inputs for the inducing points with previous outputs
                concatenated. This can be used to perform precomputation.
                Defaults to `False`.
            x_ind (tensor, optional): Inputs for the inducing points. This
                can be used to resume a computation. Defaults to
                :attr:`.model.GPAR.x_ind`.
            outputs (list[int], optional): Only compute the logpdf for a
                subset of outputs. The list specifies the indices of the
                outputs. Defaults to computing the logpdf for all outputs.

        Returns:
            scalar: Logpdf. If `return_inputs` is set to `True`, instead
                return a tuple containing the inputs and the inputs for the
                inducing points with previous outputs concatenated
        """
        logpdf = B.cast(B.dtype(x), 0)
        x_ind = self.x_ind if x_ind is None else x_ind

        y_per_output = per_output(y, w, self.impute or sample_missing)
        for is_last, ((y, w, mask), model) in \
                last(zip(y_per_output, self.layers), select=outputs):
            x = x[mask]  # Filter according to mask.
            f, e = model()  # Construct model.
            obs = self._obs(x, x_ind, y, w, f, e)  # Construct observations.

            # Accumulate logpdf.
            if not only_last_layer or (is_last and only_last_layer):
                logpdf += f.graph.logpdf(obs)

            if not is_last:
                missing = B.isnan(y[:, 0])
                # Sample missing data for an unbiased sample of the pdf.
                if sample_missing and B.any(missing):
                    y = merge(y, ((f + e) | obs)(x[missing]).sample(), missing)

                # Update inputs.
                x, x_ind = self._update_inputs(x, x_ind, y, f, obs)

        # Return inputs if asked for.
        return (x, x_ind) if return_inputs else logpdf
Пример #4
0
def per_output(y, w=None, keep=False):
    """Return observations per output, respecting that the data must be
    closed downwards.

    The function supports caching by feeding it a dictionary where the keys
    the are values for `keep` and the values lists containing items
    that the function should yield.

    Args:
        y (tensor): Outputs.
        w (tensor): Weights.
        keep (bool, optional): Also return missing observations that would
            make the data closed downwards.

    Returns:
        generator: Generator that generates tuples containing the
            observations per layer and a mask which observations are not
            missing relative to the previous layer.
    """
    # Handle cache, if that is given.
    if isinstance(y, dict):
        for yi in y[keep]:
            yield yi
        return

    p = B.shape(y)[1]  # Number of outputs
    available = ~B.isnan(y)  # Availability of outputs.

    for i in range(p):
        # Initialise the mask to current availability.
        mask = available[:, i]

        # Take into account future observations if necessary.
        if keep and i < p - 1:  # Check whether this is the last output.
            mask = mask | B.any(available[:, i + 1:], axis=1)

        # Give stuff back.
        yield y[mask, i:i + 1], w[mask, i], mask

        # Filter observations and availability.
        y = y[mask]
        w = w[mask]
        available = available[mask]