OneClassGMM2.py 3.88 KB
Newer Older
Anjith GEORGE's avatar
GMM2  
Anjith GEORGE committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
# -*- coding: utf-8 -*-
# @author: Amir Mohammadi

from bob.pad.base.algorithm import Algorithm
from bob.pad.base.utils import convert_and_prepare_features
from bob.bio.gmm.algorithm import GMM
import logging
import numpy as np
from collections.abc import Iterable
from multiprocessing import cpu_count

logger = logging.getLogger(__name__)


def bic(trainer, machine, X):
    """Bayesian information criterion for the current model on the input X.

    Parameters
    ----------
    X : array of shape (n_samples, n_dimensions)

    Returns
    -------
    bic : float
        The lower the better.
    """
    log_likelihood = trainer.compute_likelihood(machine)
    n_parameters = (
        machine.means.size + machine.variances.size + len(machine.weights) - 1
    )
    return -2 * log_likelihood * X.shape[0] + n_parameters * np.log(X.shape[0])


class OneClassGMM2(Algorithm):
    """A one class GMM implementation based on Bob's GMM implementation which is more
    stable than scikit-learn's one."""

    def __init__(
        self,
        # parameters for the GMM
        number_of_gaussians,
        # parameters of UBM training
        kmeans_training_iterations=25,  # Maximum number of iterations for K-Means
        gmm_training_iterations=25,  # Maximum number of iterations for ML GMM Training
        training_threshold=5e-4,  # Threshold to end the ML training
        variance_threshold=5e-4,  # Minimum value that a variance can reach
        update_weights=True,
        update_means=True,
        update_variances=True,
50
        n_threads=cpu_count(),
Anjith GEORGE's avatar
GMM2  
Anjith GEORGE committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64
        **kwargs
    ):
        kwargs.setdefault("performs_projection", True)
        kwargs.setdefault("requires_projector_training", True)
        super().__init__(**kwargs)
        self.gmm_alg = GMM(
            number_of_gaussians=number_of_gaussians,
            kmeans_training_iterations=kmeans_training_iterations,
            gmm_training_iterations=gmm_training_iterations,
            training_threshold=training_threshold,
            variance_threshold=variance_threshold,
            update_weights=update_weights,
            update_means=update_means,
            update_variances=update_variances,
65
            n_threads=n_threads,
Anjith GEORGE's avatar
GMM2  
Anjith GEORGE committed
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        )
        self.number_of_gaussians = number_of_gaussians

    def train_projector(self, training_features, projector_file):
        del training_features[1]
        real = convert_and_prepare_features(training_features[0], dtype="float64")
        del training_features[0]

        if isinstance(self.number_of_gaussians, Iterable):
            logger.info(
                "Performing grid search for GMM on number_of_gaussians: %s",
                self.number_of_gaussians,
            )
            lowest_bic = np.infty
            best_n_gaussians = None
            for nc in self.number_of_gaussians:
                logger.info("Testing for number_of_gaussians: %s", nc)
                self.gmm_alg.gaussians = nc
                self.gmm_alg.train_ubm(real)
                bic_ = bic(self.gmm_alg.ubm_trainer, self.gmm_alg.ubm, real)
                logger.info("BIC for number_of_gaussians: %s is %s", nc, bic_)
                if bic_ < lowest_bic:
                    gmm = self.gmm_alg.ubm
                    lowest_bic = bic_
                    best_n_gaussians = nc
                    logger.info("Best parameters so far: number_of_gaussians %s", nc)

            assert best_n_gaussians is not None
            self.gmm_alg.gaussians = best_n_gaussians
        else:
            self.gmm_alg.train_ubm(real)
            gmm = self.gmm_alg.ubm

        self.gmm_alg.ubm = gmm
        self.gmm_alg.save_ubm(projector_file)

    def load_projector(self, projector_file):
        self.gmm_alg.load_ubm(projector_file)

    def project(self, feature):
106
        feature = convert_and_prepare_features([feature], dtype="float64")[0]
Anjith GEORGE's avatar
GMM2  
Anjith GEORGE committed
107

108
        return self.gmm_alg.ubm(feature)
Anjith GEORGE's avatar
GMM2  
Anjith GEORGE committed
109 110

    def score(self, toscore):
111
        return [toscore]