Source code for sv_utils

# -*- coding: utf-8 -*-
#
# This file is part of SIDEKIT.
#
# SIDEKIT is a python package for speaker verification.
# Home page: http://www-lium.univ-lemans.fr/sidekit/
#
# SIDEKIT is a python package for speaker verification.
# Home page: http://www-lium.univ-lemans.fr/sidekit/
#    
# SIDEKIT is free software: you can redistribute it and/or modify
# it under the terms of the GNU LLesser General Public License as 
# published by the Free Software Foundation, either version 3 of the License, 
# or (at your option) any later version.
#
# SIDEKIT is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with SIDEKIT.  If not, see <http://www.gnu.org/licenses/>.

"""
Copyright 2014-2015 Anthony Larcher

:mod:`sv_utils` provides utilities to facilitate the work with SIDEKIT.
"""

__license__ = "LGPL"
__author__ = "Anthony Larcher"
__copyright__ = "Copyright 2014-2015 Anthony Larcher"
__license__ = "LGPL"
__version__ = "1.0"
__maintainer__ = "Anthony Larcher"
__email__ = "anthony.larcher@univ-lemans.fr"
__status__ = "Production"
__docformat__ = 'reStructuredText'

import numpy as np
import scipy as sp
import pickle
import gzip
import os


[docs]def save_svm(svmFileName, w, b): """Save SVM weights and biais in PICKLE format :param svmFileName: name of the file to write :param w: weight coefficients of the SVM to store :param b: biais of the SVM to store """ if not os.path.exists(os.path.dirname(svmFileName)): os.makedirs(os.path.dirname(svmFileName)) with gzip.open(svmFileName, "wb" ) as f: pickle.dump( (w, b), f)
[docs]def read_svm(svmFileName): """Read SVM model in PICKLE format :param svmFileNale: name of the file to read from :return: a tupple of weight and biais """ with gzip.open(svmFileName, "rb" ) as f: (w, b) = pickle.load(f) return np.squeeze(w), b
[docs]def check_file_list(inputFileList, fileDir, fileExtension): """Check the existence of a list of files in a specific directory Return a new list with the existing segments and a list of indices of those files in the original list. Return outputFileList and idx such that inputFileList[idx] = outputFileList :param inputFileList: list of file names :param fileDir: directory where to search for the files :param fileExtension: extension of the files to search for :return: a list of existing files and the indices of the existing files in the input list """ existFiles = np.array([os.path.isfile(os.path.join(fileDir, f + fileExtension)) for f in inputFileList]) outputFileList = inputFileList[existFiles, ] idx = np.argwhere(np.in1d(inputFileList, outputFileList)) return outputFileList, idx.transpose()[0]
[docs]def initialize_iv_extraction_weight(ubm, T): """ Estimate matrices W and T for approximation of the i-vectors For more information, refers to [Glembeck09]_ :param ubm: Mixture object, Universal Background Model :param T: Raw TotalVariability matrix as a ndarray :return: W: fix matrix pre-computed using the weights from the UBM and the total variability matrix Tnorm: total variability matrix pre-normalized using the co-variance of the UBM """ # Normalize the total variability matrix by using UBM co-variance sqrt_invcov = np.sqrt(ubm.get_invcov_super_vector()[:, np.newaxis]) Tnorm = T * sqrt_invcov # Split the Total Variability matrix into sub-matrices per distribution Tnorm_c = np.array_split(Tnorm, ubm.distrib_nb()) # Compute fixed matrix W W = np.zeros((T.shape[1],T.shape[1])) for c in range(ubm.distrib_nb()): W = W + ubm.w[c] * np.dot(Tnorm_c[c].transpose(), Tnorm_c[c]) return W, Tnorm
[docs]def initialize_iv_extraction_eigen_decomposition(ubm, T): """Estimate matrices Q, D_bar_c and Tnorm, for approximation of the i-vectors. For more information, refers to [Glembeck09]_ :param ubm: Mixture object, Universal Background Model :param T: Raw TotalVariability matrix :return: Q: Q matrix as described in [Glembeck11] D_bar_c: matrices as described in [Glembeck11] Tnorm: total variability matrix pre-normalized using the co-variance of the UBM """ # Normalize the total variability matrix by using UBM co-variance sqrt_invcov = np.sqrt(ubm.get_invcov_super_vector()[:, np.newaxis]) Tnorm = T * sqrt_invcov # Split the Total Variability matrix into sub-matrices per distribution Tnorm_c = np.array_split(Tnorm, ubm.distrib_nb()) # Compute fixed matrix Q W = np.zeros((T.shape[1],T.shape[1])) for c in range(ubm.distrib_nb()): W = W + ubm.w[c] * np.dot(Tnorm_c[c].transpose(), Tnorm_c[c]) eigenValues, Q = sp.linalg.eig(W) # Compute D_bar_c matrix which is the diagonal approximation of Tc' * Tc D_bar_c = np.zeros((ubm.distrib_nb(), T.shape[1])) for c in range(ubm.distrib_nb()): D_bar_c[c, :] = np.diag(reduce(np.dot, [Q.transpose(), Tnorm_c[c].transpose(), Tnorm_c[c], Q])) return Q, D_bar_c, Tnorm
[docs]def initialize_iv_extraction_fse(ubm, T): """Estimate matrices for approximation of the i-vectors. For more information, refers to [Cumani13]_ :param ubm: Mixture object, Universal Background Model :param T: Raw TotalVariability matrix :return: Q: Q matrix as described in [Glembeck11] D_bar_c: matrices as described in [Glembeck11] Tnorm: total variability matrix pre-normalized using the co-variance of the UBM """ # TODO: complete documentation and write the code #%% #% Initialize the process #%init = 1; # #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #% Extract i-vectors by using different methods #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #%rank_T = 10; #%featureSize = 50; #%distribNb = 32; #%dictSize = 5; #%dictSizePerDis=rank_T; % a modifier par la suite # #%ubm_file = 'gmm/world32.gmm'; #%t_file = 'mat/TV_32.matx'; # # #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #% Load data #%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% # #% Load UBM for weight parameters that are used in the optimization #% function #%UBM = ALize_LoadModel(ubm_file); # #% Load meand from Minimum Divergence re-estimation #%sv_mindiv = ALize_LoadVect(minDiv_file)'; # #% Load T matrix #%T = ALize_LoadMatrix(t_file)'; # # #function [O,PI,Q] = factorized_subspace_estimation(UBM,T,dictSize,outIterNb,inIterNb) # # rank_T = size(T,2); # distribNb = size(UBM.W,2); # featureSize = size(UBM.mu,1); # # % Normalize matrix T # sv_invcov = reshape(UBM.invcov,[],1); # T_norm = T .* repmat(sqrt(sv_invcov),1,rank_T); # # Tc{1,distribNb} = []; # for ii=0:distribNb-1 # % Split the matrix in sub-matrices # Tc{ii+1} = T_norm((ii*featureSize)+1:(ii+1)*featureSize,:); # end # # % Initialize O and Qc by Singular Value Decomposition # init_FSE.Qc{distribNb} = []; # init_FSE.O{distribNb} = []; # PI{distribNb} = []; # # for cc=1:distribNb # init_FSE.Qc{cc} = zeros(featureSize,featureSize); # init_FSE.O{cc} = zeros(featureSize,featureSize); # PI{cc} = sparse(zeros(featureSize,dictSize*distribNb)); % a remplacer par une matrice sparse # end # # % For each distribution # for cc=1:distribNb # fprintf('Initilize matrice for distribution %d / %d\n',cc,distribNb); # % Initialized O with Singular vectors from SVD # [init_FSE.O{cc},~,V] = svd(UBM.W(1,cc)*Tc{cc}); # init_FSE.Qc{cc} = V'; # end # # # % Concatenate Qc to create the matrix Q: A MODIFIER POUR DISSOCIER # % dictSize DU NOMBRE DE DISTRIBUTIONS # Q = []; # for cc=1:distribNb # Q = [Q;init_FSE.Qc{cc}(1:dictSize,:)]; # end # O = init_FSE.O; # clear 'init_FSE' # # # % OUTER iteration process : update Q iteratively # for it = 1:outIterNb # # fprintf('Start iteration %d / %d for Q re-estimation\n',it,5); # # % INNER iteration process: update PI and O iteratively # for pioIT = 1:inIterNb # fprintf(' Start iteration %d / %d for PI and O re-estimation\n',pioIT,10); # # % Update PI # %Compute diagonal terms of QQ' #% diagQ = diag(Q*Q'); # # for cc=1:distribNb # # % Compute optimal k and optimal v # % for each line f of PI{cc} # A = O{cc}'*Tc{cc}*Q'; # f = 1; # while (f < size(A,1)+1) # # if(f == 1) # A = O{cc}'*Tc{cc}*Q'; % equation (26) # PI{cc} = sparse(zeros(featureSize,dictSize*distribNb)); # end # # % Find the optimal index k # [~,k] = max(A(f,:).^2); # k_opt = k; # # % Find the optimal value v # v_opt = A(f,k_opt); # # % Update the line of PI{cc} with the value v_opt in the # % k_opt-th column # PI{cc}(f,k_opt) = v_opt; # # % if the column already has a non-zero element, # % update O and PI # I = find(PI{cc}(:,k_opt)~=0); # if size(I,1)>1 # % get indices of the two lines of PI{cc} which # % have a non-zero element on the same column # a = I(1); # b = I(2); # # % Replace column O{cc}(:,a) and O{cc}(:,b) # Oa = (PI{cc}(a,k_opt)*O{cc}(:,a)+PI{cc}(b,k_opt)*O{cc}(:,b))/(sqrt(PI{cc}(a,k_opt)^2+PI{cc}(b,k_opt)^2)); # Ob = (PI{cc}(a,k_opt)*O{cc}(:,b)-PI{cc}(b,k_opt)*O{cc}(:,a))/(sqrt(PI{cc}(a,k_opt)^2+PI{cc}(b,k_opt)^2)); # O{cc}(:,a) = Oa; # O{cc}(:,b) = Ob; # # PI{cc}(a,k_opt) = sqrt(PI{cc}(a,k_opt)^2+PI{cc}(b,k_opt)^2); # PI{cc}(b,k_opt) = 0; # # f = 0; # end # f =f +1; # end # end # # obj = computeObjFunc(UBM.W,Tc,O,PI,Q); # fprintf('Objective Function after estimation of PI = %2.10f\n',obj); # # % Update O # for cc=1:distribNb # # % Compute # Z = PI{cc}*Q*Tc{cc}'; # # % Compute Singular value decomposition of Z # [Uz,~,Vz] = svd(Z); # # % Compute the new O{cc} # O{cc} = Vz*Uz'; # end # obj = computeObjFunc(UBM.W,Tc,O,PI,Q); # fprintf('Objective Function after estimation of O = %2.10f\n',obj); # end % END OF INNER ITERATION PROCESS # # # % Update Q # D = sparse(zeros(size(PI{cc},2),size(PI{cc},2))); # E = zeros(size(PI{cc},2),rank_T); # for cc=1:distribNb # % Accumulate D # D = D + UBM.W(1,cc) * PI{cc}'*PI{cc}; # # % Accumulate the second term # E = E + UBM.W(1,cc) * PI{cc}'*O{cc}'*Tc{cc}; # end # Q = D\E; # # % Normalize rows of Q and update PI accordingly # # % Compute norm of each row # c1 = bsxfun(@times,Q,Q); # c2 = sum(c1,2); # c3 = sqrt(c2); # Q = bsxfun(@rdivide,Q,c3); # # % Update PI accordingly # PI = cellfun(@(x)x*sparse(diag(c3)), PI, 'uni',false); # # obj = computeObjFunc(UBM.W,Tc,O,PI,Q); # fprintf('Objective Function after re-estimation of Q = %2.10f\n',obj); # end #end # pass