Source code for anomalib.models.components.stats.multi_variate_gaussian
"""Multi Variate Gaussian Distribution."""# Copyright (C) 2020 Intel Corporation## Licensed under the Apache License, Version 2.0 (the "License");# you may not use this file except in compliance with the License.# You may obtain a copy of the License at## http://www.apache.org/licenses/LICENSE-2.0## Unless required by applicable law or agreed to in writing,# software distributed under the License is distributed on an "AS IS" BASIS,# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.# See the License for the specific language governing permissions# and limitations under the License.fromtypingimportAny,List,OptionalimporttorchfromtorchimportTensor,nn
[docs]def_cov(observations:Tensor,rowvar:bool=False,bias:bool=False,ddof:Optional[int]=None,aweights:Tensor=None,)->Tensor:"""Estimates covariance matrix like numpy.cov. Args: observations (Tensor): A 1-D or 2-D array containing multiple variables and observations. Each row of `m` represents a variable, and each column a single observation of all those variables. Also see `rowvar` below. rowvar (bool): If `rowvar` is True (default), then each row represents a variable, with observations in the columns. Otherwise, the relationship is transposed: each column represents a variable, while the rows contain observations. Defaults to False. bias (bool): Default normalization (False) is by ``(N - 1)``, where ``N`` is the number of observations given (unbiased estimate). If `bias` is True, then normalization is by ``N``. These values can be overridden by using the keyword ``ddof`` in numpy versions >= 1.5. Defaults to False ddof (Optional, int): If not ``None`` the default value implied by `bias` is overridden. Note that ``ddof=1`` will return the unbiased estimate, even if both `fweights` and `aweights` are specified, and ``ddof=0`` will return the simple average. See the notes for the details. The default value is ``None``. aweights (Tensor): 1-D array of observation vector weights. These relative weights are typically large for observations considered "important" and smaller for observations considered less "important". If ``ddof=0`` the array of weights can be used to assign probabilities to observation vectors. (Default value = None) Returns: The covariance matrix of the variables. """# ensure at least 2Difobservations.dim()==1:observations=observations.view(-1,1)# treat each column as a data point, each row as a variableifrowvarandobservations.shape[0]!=1:observations=observations.t()ifddofisNone:ifbias==0:ddof=1else:ddof=0weights=aweightsweights_sum:AnyifweightsisnotNone:ifnottorch.is_tensor(weights):weights=torch.tensor(weights,dtype=torch.float)# pylint: disable=not-callableweights_sum=torch.sum(weights)avg=torch.sum(observations*(weights/weights_sum)[:,None],0)else:avg=torch.mean(observations,0)# Determine the normalizationifweightsisNone:fact=observations.shape[0]-ddofelifddof==0:fact=weights_sumelifaweightsisNone:fact=weights_sum-ddofelse:fact=weights_sum-ddof*torch.sum(weights*weights)/weights_sumobservations_m=observations.sub(avg.expand_as(observations))ifweightsisNone:x_transposed=observations_m.t()else:x_transposed=torch.mm(torch.diag(weights),observations_m).t()covariance=torch.mm(x_transposed,observations_m)covariance=covariance/factreturncovariance.squeeze()
[docs]defforward(self,embedding:Tensor)->List[Tensor]:"""Calculate multivariate Gaussian distribution. Args: embedding (Tensor): CNN features whose dimensionality is reduced via either random sampling or PCA. Returns: mean and inverse covariance of the multi-variate gaussian distribution that fits the features. """device=embedding.devicebatch,channel,height,width=embedding.size()embedding_vectors=embedding.view(batch,channel,height*width)self.mean=torch.mean(embedding_vectors,dim=0)covariance=torch.zeros(size=(channel,channel,height*width),device=device)identity=torch.eye(channel).to(device)foriinrange(height*width):covariance[:,:,i]=self._cov(embedding_vectors[:,:,i],rowvar=False)+0.01*identity# calculate inverse covariance as we need only the inverseself.inv_covariance=torch.linalg.inv(covariance.permute(2,0,1))return[self.mean,self.inv_covariance]
[docs]deffit(self,embedding:Tensor)->List[Tensor]:"""Fit multi-variate gaussian distribution to the input embedding. Args: embedding (Tensor): Embedding vector extracted from CNN. Returns: Mean and the covariance of the embedding. """returnself.forward(embedding)