예제 #1
0
def sstats_to_sqrt_features(ss, gmm):
    """ Converts sufficient statistics into an approximated form of sqrt
    Fisher vectors.

    Inputs
    ------
    ss: array [N * (K + 2 * D * K), ]
        Sufficient statistics.

    gmm: instance of the yael object, gmm
        Gaussian mixture model.

    Output
    ------
    fv: array [N, K + 2 * D * K]
        Fisher vectors for each of the N sufficient statistics.

    """
    K = gmm.k
    D = gmm.d
    ss = ss.reshape(-1, K + 2 * K * D)
    N = ss.shape[0]

    # Get parameters and reshape them.
    pi = yael.fvec_to_numpy(gmm.w, K)  # 1xK
    mu = (yael.fvec_to_numpy(gmm.mu,
                             K * D).reshape(D, K,
                                            order='F')[np.newaxis])  # 1xDxK
    sigma = (yael.fvec_to_numpy(gmm.sigma,
                                K * D).reshape(D, K,
                                               order='F')[np.newaxis])  # 1xDxK

    # Get each part of the sufficient statistics.
    Q_sum = ss[:, :K]  # NxK (then Nx1xK)
    Q_xx = ss[:, K:K + D * K]  # NxKD
    Q_xx_2 = ss[:, K + D * K:K + 2 * D * K]  # NxKD

    # Sqrt the soft counts.
    sqrtQ = np.sqrt(Q_sum)

    # Compute the gradients.
    d_pi = sqrtQ
    d_mu = Q_xx - (Q_sum[:, np.newaxis] * mu).reshape(N, D * K, order='F')
    d_mu = d_mu / np.repeat(sqrtQ, D)
    d_sigma = (-Q_xx_2 -
               (Q_sum[:, np.newaxis] * mu**2).reshape(N, D * K, order='F') +
               (Q_sum[:, np.newaxis] * sigma).reshape(N, D * K, order='F') +
               2 * Q_xx * mu.reshape(1, K * D, order='F')) / np.repeat(
                   sqrtQ, D)

    # Glue everything together.
    fv = np.hstack((d_pi, d_mu, d_sigma))
    return fv
예제 #2
0
def descriptors_to_fisher_vector(xx, gmm, **kwargs):
    """Computes the Fisher vector on a set of descriptors.

    Parameters
    ----------
    xx: array_like, shape (N, D) or (D, )
        The set of descriptors

    gmm: instance of yael object gmm
        Gauassian mixture model of the descriptors.

    Returns
    -------
    fv: array_like, shape (K + 2 * D * K, )
        Fisher vector (derivatives with respect to the mixing weights, means
        and variances) of the given descriptors.

    Reference
    ---------
    J. Krapac, J. Verbeek, F. Jurie.  Modeling Spatial Layout with Fisher
    Vectors for Image Categorization.  In ICCV, 2011.
    http://hal.inria.fr/docs/00/61/94/03/PDF/final.r1.pdf

    """
    # yael assumes that the data is in C-contiguous format.
    xx = np.ascontiguousarray(np.atleast_2d(xx))

    N = xx.shape[0]
    K = gmm.k
    D = gmm.d

    # Compute posterior probabilities using yael.
    Q = gmm_predict_proba(xx, gmm)  # NxK

    # Get parameters and reshape them.
    pi = yael.fvec_to_numpy(gmm.w, K)                          # 1xK
    mu = yael.fvec_to_numpy(gmm.mu, K * D).reshape(K, D)       # DxK
    sigma = yael.fvec_to_numpy(gmm.sigma, K * D).reshape(K, D) # DxK

    # Compute the sufficient statistics of descriptors.
    Q_sum = np.sum(Q, 0)[:, np.newaxis] / N  # Kx1
    Q_xx = np.dot(Q.T, xx) / N               # KxD
    Q_xx_2 = np.dot(Q.T, xx ** 2) / N        # KxD

    # Compute derivatives with respect to mixing weights, means and variances.
    d_pi = Q_sum.squeeze() - pi
    d_mu = Q_xx - Q_sum * mu
    d_sigma = - Q_xx_2 - Q_sum * mu ** 2 + Q_sum * sigma + 2 * Q_xx * mu

    # Merge derivatives into a vector.
    return np.hstack((d_pi, d_mu.flatten(), d_sigma.flatten()))
예제 #3
0
def sstats_to_sqrt_features(ss, gmm):
    """ Converts sufficient statistics into an approximated form of sqrt
    Fisher vectors.

    Inputs
    ------
    ss: array [N * (K + 2 * D * K), ]
        Sufficient statistics.

    gmm: instance of the yael object, gmm
        Gaussian mixture model.

    Output
    ------
    fv: array [N, K + 2 * D * K]
        Fisher vectors for each of the N sufficient statistics.

    """
    K = gmm.k
    D = gmm.d
    ss = ss.reshape(-1, K + 2 * K * D)
    N = ss.shape[0]

    # Get parameters and reshape them.
    pi = yael.fvec_to_numpy(gmm.w, K)            # 1xK
    mu = (yael.fvec_to_numpy(gmm.mu, K * D)
          .reshape(D, K, order='F')[np.newaxis])    # 1xDxK
    sigma = (yael.fvec_to_numpy(gmm.sigma, K * D).
             reshape(D, K, order='F')[np.newaxis])  # 1xDxK

    # Get each part of the sufficient statistics.
    Q_sum = ss[:, :K]                            # NxK (then Nx1xK)
    Q_xx = ss[:, K:K + D * K]                    # NxKD
    Q_xx_2 = ss[:, K + D * K:K + 2 * D * K]      # NxKD

    # Sqrt the soft counts.
    sqrtQ = np.sqrt(Q_sum)

    # Compute the gradients.
    d_pi = sqrtQ
    d_mu = Q_xx - (Q_sum[:, np.newaxis] * mu).reshape(N, D * K, order='F')
    d_mu = d_mu / np.repeat(sqrtQ, D)
    d_sigma = (
        - Q_xx_2
        - (Q_sum[:, np.newaxis] * mu ** 2).reshape(N, D * K, order='F')
        + (Q_sum[:, np.newaxis] * sigma).reshape(N, D * K, order='F')
        + 2 * Q_xx * mu.reshape(1, K * D, order='F')) / np.repeat(sqrtQ, D)

    # Glue everything together.
    fv = np.hstack((d_pi, d_mu, d_sigma))
    return fv
예제 #4
0
def readXVecsFromOpenedFile(file, dim, count, extension):
    if extension == 'bvecs':
        points = yael.fvec_new(dim * count)
        yael.b2fvecs_fread(file, points, count)
        a = yael.fvec_to_numpy(points, (count, dim))
        yael.free(points)
        return a
    elif extension == 'fvecs':
        points = yael.fvec_new(dim * count)
        yael.fvecs_fread(file, points, count, dim)
        a = yael.fvec_to_numpy(points, (count, dim))
        yael.free(points)
        return a
    else:
        raise Exception('Bad file extension!')
예제 #5
0
def readXVecsFromOpenedFile(file, dim, count, extension):
    if extension == 'bvecs':
        points = yael.fvec_new(dim * count)
        yael.b2fvecs_fread(file, points, count)
        a = yael.fvec_to_numpy(points, (count, dim))
        yael.free(points)
        return a
    elif extension == 'fvecs':
        points = yael.fvec_new(dim * count)
        yael.fvecs_fread(file, points, count, dim)
        a = yael.fvec_to_numpy(points, (count, dim))
        yael.free(points)
        return a
    else:
        raise Exception('Bad file extension!')
예제 #6
0
    def descs_to_sstats(xx, gmm):
        """ Converts the descriptors to sufficient statistics.

        Inputs
        ------
        xx: array [nr_descs, nr_dimensions]
            Data matrix containing the descriptors.

        gmm: yael.gmm instance
            Mixture of Gaussian object.

        Output
        ------
        sstats: array [nr_clusters + 2 * nr_clusters * nr_dimensions, ]
            Concatenation of the averaged posterior probabilities `Q_sum`, the
            first moment `Q_xx` and second-order moment `Q_xx_2`.

        """
        xx = np.atleast_2d(xx)
        N = xx.shape[0]
        K = gmm.k
        D = gmm.d
        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)  # NxK
        yael.free(Q_yael)
        # Compute statistics.
        sstats = np.zeros(K + 2 * K * D, dtype=np.float32)
        sstats[:K] = np.sum(Q, 0) / N  # 1xK
        sstats[K:K + K * D] = dot(Q.T, xx).flatten() / N  # 1xKD
        sstats[K + K * D:K + 2 * K * D] = dot(Q.T, xx**2).flatten() / N  # 1xKD
        return sstats
예제 #7
0
    def descs_to_sstats(xx, gmm):
        """ Converts the descriptors to sufficient statistics.
        
        Inputs
        ------
        xx: array [nr_descs, nr_dimensions]
            Data matrix containing the descriptors.

        gmm: yael.gmm instance
            Mixture of Gaussian object.

        Output
        ------
        Q_sum: array [nr_clusters, ]
            Averaged posterior probabilities.

        """
        K = gmm.k
        N = xx.shape[0]
        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)
        yael.free(Q_yael)
        # Compute statistics.
        Q_sum = sum(Q, 0) / N  # 1xK
        return np.array(Q_sum, dtype=np.float32)
예제 #8
0
    def descs_to_sstats(xx, gmm):
        """ Converts the descriptors to sufficient statistics.

        Inputs
        ------
        xx: array [nr_descs, nr_dimensions]
            Data matrix containing the descriptors.

        gmm: yael.gmm instance
            Mixture of Gaussian object.

        Output
        ------
        sstats: array [nr_clusters + 2 * nr_clusters * nr_dimensions, ]
            Concatenation of the averaged posterior probabilities `Q_sum`, the
            first moment `Q_xx` and second-order moment `Q_xx_2`.

        """
        xx = np.atleast_2d(xx)
        N = xx.shape[0]
        K = gmm.k
        D = gmm.d
        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)  # NxK
        yael.free(Q_yael)
        # Compute statistics.
        sstats = np.zeros(K + 2 * K * D, dtype=np.float32)
        sstats[: K] = np.sum(Q, 0) / N                            # 1xK
        sstats[K: K + K * D] = dot(Q.T, xx).flatten() / N         # 1xKD
        sstats[K + K * D: K + 2 * K * D] = dot(
            Q.T, xx ** 2).flatten() / N                           # 1xKD
        return sstats
예제 #9
0
    def descs_to_sstats(xx, gmm):
        """ Converts the descriptors to sufficient statistics.
        
        Inputs
        ------
        xx: array [nr_descs, nr_dimensions]
            Data matrix containing the descriptors.

        gmm: yael.gmm instance
            Mixture of Gaussian object.

        Output
        ------
        Q_sum: array [nr_clusters, ]
            Averaged posterior probabilities.

        """
        K = gmm.k
        N = xx.shape[0]
        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)
        yael.free(Q_yael)
        # Compute statistics.
        Q_sum = sum(Q, 0) / N                     # 1xK
        return np.array(Q_sum, dtype=np.float32)
예제 #10
0
    def fit(self, X):
        n_samples, self.n_features = X.shape

        yael_X = yael.numpy_to_fvec_ref(X)

        yael_gmm = yael.gmm_learn(
            self.n_features, n_samples, self.n_components, self.n_iter, yael_X,
            self.n_threads, 0, self.n_init,
            yael.GMM_FLAGS_W | yael.GMM_FLAGS_SIGMA | yael.GMM_FLAGS_MU)

        self.means_ = yael.fvec_to_numpy(
            yael_gmm.mu, self.n_components * self.n_features).reshape(
                (self.n_components, self.n_features))
        self.covars_ = yael.fvec_to_numpy(
            yael_gmm.sigma, self.n_components * self.n_features).reshape(
                (self.n_components, self.n_features))
        self.weights_ = yael.fvec_to_numpy(yael_gmm.w, self.n_components)

        yael.gmm_delete(yael_gmm)
예제 #11
0
def gmm_predict_proba(xx, gmm):
    """Computes posterior probabilities using yael."""
    N = xx.shape[0]
    K = gmm.k

    Q_yael = yael.fvec_new(N * K)
    yael.gmm_compute_p(
        N, yael.numpy_to_fvec_ref(xx), gmm, Q_yael, yael.GMM_FLAGS_W)
    Q = yael.fvec_to_numpy(Q_yael, N * K).reshape(N, K)
    yael.free(Q_yael)

    return Q
예제 #12
0
def readXvecs(filename, dim, count, tonumpy=True):
    extension = filename.strip().split('.')[-1]
    if extension == 'bvecs':
        points = yael.fvec_new(dim * count)
        yael.b2fvecs_read(filename, dim, count, points)
        if tonumpy:
            a = yael.fvec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
           return points
    elif extension == 'fvecs':
        points = yael.fvec_new(dim * count)
        yael.fvecs_read(filename, dim, count, points)
        if tonumpy:
            a = yael.fvec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
            return points
    elif extension == 'i8vecs':
        file = open(filename, 'r')
        points = np.zeros((count, dim), dtype='float32')
        for i in xrange(count):
            file.read(4)
            points[i,:] = np.fromfile(file, np.int8, dim).astype('float32')
        return points
    elif extension == 'ivecs':
        points = yael.ivec_new(dim * count)
        yael.ivecs_fread(open(filename, 'r'), points, count, dim)
        if tonumpy:
            a = yael.ivec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
            return points
    else:
        raise Exception('Bad file extension!')
예제 #13
0
def readXvecs(filename, dim, count, tonumpy=True):
    extension = filename.strip().split('.')[-1]
    if extension == 'bvecs':
        points = yael.fvec_new(dim * count)
        yael.b2fvecs_read(filename, dim, count, points)
        if tonumpy:
            a = yael.fvec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
            return points
    elif extension == 'fvecs':
        points = yael.fvec_new(dim * count)
        yael.fvecs_read(filename, dim, count, points)
        if tonumpy:
            a = yael.fvec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
            return points
    elif extension == 'i8vecs':
        file = open(filename, 'r')
        points = np.zeros((count, dim), dtype='float32')
        for i in xrange(count):
            file.read(4)
            points[i, :] = np.fromfile(file, np.int8, dim).astype('float32')
        return points
    elif extension == 'ivecs':
        points = yael.ivec_new(dim * count)
        yael.ivecs_fread(open(filename, 'r'), points, count, dim)
        if tonumpy:
            a = yael.ivec_to_numpy(points, (count, dim))
            yael.free(points)
            return a
        else:
            return points
    else:
        raise Exception('Bad file extension!')
예제 #14
0
    def descs_to_spatial_sstats(xx, ll, gmm):
        """ Computes spatial statistics from descriptors and their position.

        Inputs
        ------
        xx: array [N, D], required
            N D-dimensional descriptors from an video (usually, after they are
            processed with PCA).

        ll: array [N, 3], required
            Descriptor locations in an image; on each row, we have the triplet
            (x, y, t).

        gmm: instance of yael object gmm
            Gauassian mixture object.

        Output
        ------
        ss: array [1, K + 2 * 3 * k]
            Sufficient statistics in the form of a vector that concatenates 
            (i) the sum of posteriors, (ii) an expected value of the locations 
            ll under the posterior distribution Q and (iii) the second-order
            moment of the locations ll under the posterior distribution Q.

        """
        N = ll.shape[0] 
        K = gmm.k

        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)
        yael.free(Q_yael)
        # Compute statistics.
        Q_sum = sum(Q, 0) / N                     # 1xK
        Q_ll = dot(Q.T, ll).flatten() / N         # 1x3K
        Q_ll_2 = dot(Q.T, ll ** 2).flatten() / N  # 1x3K 
        return np.array(hstack((Q_sum, Q_ll, Q_ll_2)), dtype=np.float32)
예제 #15
0
    def descs_to_spatial_sstats(xx, ll, gmm):
        """ Computes spatial statistics from descriptors and their position.

        Inputs
        ------
        xx: array [N, D], required
            N D-dimensional descriptors from an video (usually, after they are
            processed with PCA).

        ll: array [N, 3], required
            Descriptor locations in an image; on each row, we have the triplet
            (x, y, t).

        gmm: instance of yael object gmm
            Gauassian mixture object.

        Output
        ------
        ss: array [1, K + 2 * 3 * k]
            Sufficient statistics in the form of a vector that concatenates 
            (i) the sum of posteriors, (ii) an expected value of the locations 
            ll under the posterior distribution Q and (iii) the second-order
            moment of the locations ll under the posterior distribution Q.

        """
        N = ll.shape[0]
        K = gmm.k

        # Compute posterior probabilities using yael.
        Q_yael = fvec_new(N * K)
        gmm_compute_p(N, numpy_to_fvec_ref(xx), gmm, Q_yael, GMM_FLAGS_W)
        Q = fvec_to_numpy(Q_yael, N * K).reshape(N, K)
        yael.free(Q_yael)
        # Compute statistics.
        Q_sum = sum(Q, 0) / N  # 1xK
        Q_ll = dot(Q.T, ll).flatten() / N  # 1x3K
        Q_ll_2 = dot(Q.T, ll**2).flatten() / N  # 1x3K
        return np.array(hstack((Q_sum, Q_ll, Q_ll_2)), dtype=np.float32)
예제 #16
0
if 'fvec_to_numpy' not in dir(yael):
    #globals():
    print('Numpy interface not compiled in')
    sys.exit(1)

print('float array')
numpy_a = np.array(list(range(5)), dtype='float32')
print(numpy_a)

print('-> Yael A')
yael_a = yael.FloatArray.acquirepointer(yael.numpy_to_fvec(numpy_a))
n = numpy_a.size
yael.fvec_print(yael_a, n)

print('-> Numpy A')
print(yael.fvec_to_numpy(yael_a, n))
print('int array')
numpy_a = np.array(list(range(5)), dtype='int32')
print(numpy_a)

print('-> Yael A2')
yael_a = yael.IntArray.acquirepointer(yael.numpy_to_ivec(numpy_a))
n = numpy_a.size
yael.ivec_print(yael_a, n)

print('-> Numpy A2')
print(yael.ivec_to_numpy(yael_a, n))
print('float array, pass by reference')
numpy_a = np.array(list(range(5)), dtype='float32')
print(numpy_a)