Source code for menpo.model.linear

import numpy as np
from scipy.linalg.blas import dgemm


[docs]class LinearModel(object): r""" A Linear Model contains a matrix of vector components, each component vector being made up of `features`. """ def __init__(self, components): self._components = components # getter/setter variable @property
[docs] def n_components(self): r""" The number of bases of the model type: int """ return self._components.shape[0]
@property
[docs] def n_features(self): r""" The number of elements in each linear component. type: int """ return self.components.shape[-1]
@property def components(self): r""" The component matrix of the linear model. type: (n_available_components, n_features) ndarray """ return self._components @components.setter
[docs] def components(self, value): r""" Updates the components of this linear model, ensuring that the shape of the components is not changed. """ if value.shape != self._components.shape: raise ValueError( "Trying to replace components of shape {} with some of " "shape {}".format(self.components.shape, value.shape)) else: np.copyto(self._components, value, casting='safe')
@property
[docs] def d_dp(self): r""" """ return self.components.T
[docs] def component_vector(self, index): r""" A particular component of the model, in vectorized form. Parameters ---------- index : int The component that is to be returned :type: (n_features,) ndarray """ return self.components[index]
[docs] def instance_vector(self, weights): r""" Creates a new vector instance of the model by weighting together the components. Parameters ---------- weights : (n_weights,) ndarray or list The weightings for the first n_weights components that should be used. `weights[j]` is the linear contribution of the j'th principal component to the instance vector. Returns ------- vector : (n_features,) ndarray The instance vector for the weighting provided. """ # just call the plural version and adapt weights = np.asarray(weights) # if eg a list is provided return self.instance_vectors(weights[None, :]).flatten()
[docs] def instance_vectors(self, weights): """ Creates new vectorized instances of the model using all the components of the linear model. Parameters ---------- weights : (n_vectors, n_weights) ndarray or list of lists The weightings for all components of the linear model. All components will be used to produce the instance. `weights[i, j]` is the linear contribution of the j'th principal component to the i'th instance vector produced. Raises ------ ValueError: If n_weights > n_available_components Returns ------- vectors : (n_vectors, n_features) ndarray The instance vectors for the weighting provided. """ weights = np.asarray(weights) # if eg a list is provided n_instances, n_weights = weights.shape if not n_weights == self.n_components: raise ValueError( "Number of weightings has to match number of available " "components = {}".format(self.n_components)) return self._instance_vectors_for_full_weights(weights) # TODO check this is right
def _instance_vectors_for_full_weights(self, full_weights): return dgemm(alpha=1.0, a=full_weights.T, b=self.components.T, trans_a=True, trans_b=True)
[docs] def project_vector(self, vector): """ Projects the `vector` onto the model, retrieving the optimal linear reconstruction weights Parameters ----------- vector : (n_features,) ndarray A vectorized novel instance. Returns ------- weights : (n_components,) A vector of optimal linear weights """ return self.project_vectors(vector[None, :]).flatten()
[docs] def project_vectors(self, vectors): """ Projects each of the `vectors` onto the model, retrieving the optimal linear reconstruction weights for each instance. Parameters ---------- vectors : (n_samples, n_features) ndarray Returns ------- weights : (n_samples, n_components) ndarray The matrix of optimal linear weights """ return dgemm(alpha=1.0, a=vectors.T, b=self.components.T, trans_a=True)
[docs] def reconstruct_vector(self, vector): """ Project a `vector` onto the linear space and rebuild from the weights found. Parameters ---------- vector : (n_features, ) ndarray A vectorized novel instance to project Returns ------- reconstructed : (n_features,) ndarray The reconstructed vector. """ return self.reconstruct_vectors(vector[None, :]).flatten()
[docs] def reconstruct_vectors(self, vectors): """ Projects the `vectors` onto the linear space and rebuilds vectors from the weights found. Parameters ---------- vectors : (n_vectors, n_features) ndarray A set of vectors to project Returns ------- reconstructed : (n_vectors, n_features) ndarray The reconstructed vectors. """ return self.instance_vectors(self.project_vectors(vectors))
[docs] def project_out_vector(self, vector): """ Returns a version of `vector` where all the basis of the model have been projected out. Parameters ---------- vector : (n_features,) ndarray A novel vector. Returns ------- projected_out : (n_features,) ndarray A copy of `vector` with all basis of the model projected out. """ return self.project_out_vectors(vector[None, :])
[docs] def project_out_vectors(self, vectors): """ Returns a version of `vectors` where all the basis of the model have been projected out. Parameters ---------- vectors : (n_vectors, n_features) ndarray A matrix of novel vectors. Returns ------- projected_out : (n_vectors, n_features) ndarray A copy of `vectors` with all basis of the model projected out. """ weights = dgemm(alpha=1.0, a=vectors.T, b=self.components.T, trans_a=True) return (vectors - dgemm(alpha=1.0, a=weights.T, b=self.components.T, trans_a=True, trans_b=True))
[docs] def orthonormalize_inplace(self): r""" Enforces that this models components are orthonormalized s.t. component_vector(i).dot(component_vector(j) = dirac_delta """ Q = np.linalg.qr(self.components.T)[0].T self.components[...] = Q # TODO: Investigate the meaning and consequences of trying to # orthonormalize two identical vectors
[docs] def orthonormalize_against_inplace(self, linear_model): r""" Enforces that the union of this model's components and another are both mutually orthonormal. Both models keep its number of components unchanged or else a value error is raised. Parameters ----------- linear_model : :class:`LinearModel` A second linear model to orthonormalize this against. """ n_components_sum = self.n_components + linear_model.n_components if not self.n_features >= n_components_sum: raise ValueError( "The number of features must be greater or equal than the " "sum of the number of components in both linear models {} < " "{})".format(self.n_features, n_components_sum)) # take the QR decomposition of the model components Q = (np.linalg.qr(np.hstack((linear_model._components.T, self._components.T)))[0]).T # set the orthonormalized components of the model being passed linear_model.components = Q[:linear_model.n_components, :] # set the orthonormalized components of this model self.components = Q[linear_model.n_components:, :]
[docs]class MeanLinearModel(LinearModel): r""" A Linear Model containing a matrix of vector components, each component vector being made up of `features`. The model additionally has a mean component which is handled accordingly when either: 1. A component of the model is selected 2. A projection operation is performed """ def __init__(self, components, mean_vector): super(MeanLinearModel, self).__init__(components) self.mean_vector = mean_vector
[docs] def component_vector(self, index, with_mean=True, scale=1.0): r""" A particular component of the model, in vectorized form. Parameters ---------- index : int The component that is to be returned with_mean: boolean (optional) If True, the component will be blended with the mean vector before being returned. If not, the component is returned on it's own. Default: True scale : float A scale factor that should be directly applied to the component. Only valid in the case where with_mean is True. :type: (n_features,) ndarray """ if with_mean: return (scale * self.components[index]) + self.mean_vector else: return self.components[index]
[docs] def project_vectors(self, vectors): """ Projects each of the `vectors` onto the model, retrieving the optimal linear reconstruction weights for each instance. Parameters ---------- vectors : (n_samples, n_features) ndarray Returns ------- projected: (n_samples, n_components) ndarray The matrix of optimal linear weights """ X = vectors - self.mean_vector return dgemm(alpha=1.0, a=X.T, b=self.components.T, trans_a=True)
def _instance_vectors_for_full_weights(self, full_weights): x = LinearModel._instance_vectors_for_full_weights(self, full_weights) return x + self.mean_vector