Source code for kerch.level.single_view.PPCA

# coding=utf-8
from typing import Optional
import torch
from torch import Tensor as T

from .._PPCA import _PPCA
from .Level import Level
from ... import utils

[docs] class PPCA(_PPCA, Level): def __init__(self, *args, **kwargs): super(PPCA, self).__init__(*args, **kwargs)
[docs] @torch.no_grad() def h_map(self, phi: Optional[T] = None, k: Optional[T] = None) -> T: r""" Draws a `h` given the maximum a posteriori of the distribution. By choosing the input, you either choose a primal or dual representation. :param phi: Primal representation. :param k: Dual representation. :type phi: Tensor[N, dim_input], optional :type k: Tensor[N, num_idx], optional :return: MAP of h given phi or k. :rtype: Tensor[N, dim_output] """ if phi is not None and k is None: return (phi - self.mu) @ self.weight @ torch.diag(1 / self.vals) * self.num_idx if phi is None and k is not None: return k @ self.hidden @ torch.diag(1 / self.vals) * self.num_idx else: raise AttributeError("One and only one attribute phi or k has to be specified.")
@torch.no_grad() def _solve_primal(self) -> None: C = self.C if self.dim_output is None: self._dim_output = self.dim_feature elif self.dim_output > self.dim_feature: self._logger.warning(f"In primal, the output dimension {self.dim_output} (the number of " f"eigenvectors) must not exceed the feature dimension {self.dim_feature} (the dimension " f"of the correlation matrix to be diagonalized). As this is the case here, the output " f"dimension is reduced to {self.dim_feature}.") self.dim_output = self.dim_feature v, w = utils.eigs(C, k=self.dim_output, psd=True) if self.dim_output == self.num_idx: self.sigma = 0. else: self.sigma = (torch.trace(C) - torch.sum(v)) / (self.num_idx * (self.num_idx - self.dim_output)) self.vals = v self.weight = w @ torch.diag(torch.sqrt(v / self.num_idx - self.sigma ** 2)) @torch.no_grad() def _solve_dual(self) -> None: K = self.K if self.dim_output is None: self._dim_output = self.num_idx elif self.dim_output > self.num_idx: self._logger.warning(f"In dual, the output dimension {self.dim_output} (the number of " f"eigenvectors) must not exceed the number of samples {self.num_idx} (the dimension " f"of the kernel matrix to be diagonalized). As this is the case here, the output " f"dimension is reduced to {self.num_idx}.") self.dim_output = self.num_idx v, h = utils.eigs(K, k=self.dim_output, psd=True) if self.dim_output == self.num_idx: self.sigma = 0. else: self.sigma = (torch.trace(K) - torch.sum(v)) / (self.num_idx * (self.num_idx - self.dim_output)) self.vals = v self.hidden = h @ torch.diag(torch.sqrt(1 / self.num_idx - self.sigma ** 2 / v))