EigenChannel.cpp

Go to the documentation of this file.
00001 /*
00002 This file is part of LIA_RAL which is a set of software based on ALIZE
00003 toolkit for speaker recognition. ALIZE toolkit is required to use LIA_RAL.
00004 
00005 LIA_RAL project is a development project was initiated by the computer
00006 science laboratory of Avignon / France (Laboratoire Informatique d'Avignon -
00007 LIA) [http://lia.univ-avignon.fr <http://lia.univ-avignon.fr/>]. Then it
00008 was supported by two national projects of the French Research Ministry:
00009         - TECHNOLANGUE program [http://www.technolangue.net]
00010         - MISTRAL program [http://mistral.univ-avignon.fr]
00011 
00012 LIA_RAL is free software: you can redistribute it and/or modify
00013 it under the terms of the GNU Lesser General Public License as
00014 published by the Free Software Foundation, either version 3 of
00015 the License, or any later version.
00016 
00017 LIA_RAL is distributed in the hope that it will be useful,
00018 but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00020 GNU Lesser General Public License for more details.
00021 
00022 You should have received a copy of the GNU Lesser General Public
00023 License along with LIA_RAL.
00024 If not, see [http://www.gnu.org/licenses/].
00025 
00026 The LIA team as well as the LIA_RAL project team wants to highlight the
00027 limits of voice authentication in a forensic context.
00028 The "Person Authentification by Voice: A Need of Caution" paper
00029 proposes a good overview of this point (cf. "Person
00030 Authentification by Voice: A Need of Caution", Bonastre J.F.,
00031 Bimbot F., Boe L.J., Campbell J.P., Douglas D.A., Magrin-
00032 chagnolleau I., Eurospeech 2003, Genova].
00033 The conclusion of the paper of the paper is proposed bellow:
00034 [Currently, it is not possible to completely determine whether the
00035 similarity between two recordings is due to the speaker or to other
00036 factors, especially when: (a) the speaker does not cooperate, (b) there
00037 is no control over recording equipment, (c) recording conditions are not
00038 known, (d) one does not know whether the voice was disguised and, to a
00039 lesser extent, (e) the linguistic content of the message is not
00040 controlled. Caution and judgment must be exercised when applying speaker
00041 recognition techniques, whether human or automatic, to account for these
00042 uncontrolled factors. Under more constrained or calibrated situations,
00043 or as an aid for investigative purposes, judicious application of these
00044 techniques may be suitable, provided they are not considered as infallible.
00045 At the present time, there is no scientific process that enables one to
00046 uniquely characterize a persones voice or to identify with absolute
00047 certainty an individual from his or her voice.]
00048 
00049 Copyright (C) 2004-2010
00050 Laboratoire d'informatique d'Avignon [http://lia.univ-avignon.fr]
00051 LIA_RAL admin [alize@univ-avignon.fr]
00052 Jean-Francois Bonastre [jean-francois.bonastre@univ-avignon.fr]
00053 */
00054 
00055 #if !defined(ALIZE_EigenChannel_cpp)
00056 #define ALIZE_EigenChannel_cpp
00057 
00058 #include <fstream>
00059 #include <cstdio>               
00060 #include <cassert>
00061 #include <cmath>
00062 #include "liatools.h"
00063 #include "EigenChannel.h"
00064 #include "AccumulateJFAStat.h"
00065 
00066 using namespace alize;
00067 using namespace std;
00068 
00069 void verifyEMLK(FactorAnalysisStat & FA,XList &ndx,FeatureServer &fs,Config &config) {
00070         XLine *pline; String *pFile; ndx.rewind();      
00071         double total=0.0;
00072         unsigned long maxLLKcomputed=1;
00073         maxLLKcomputed=config.getParam("computeLLK").toLong();  
00074         bool FALLK=false;
00075         if (config.existsParam("FALLK")) {FALLK=true;if(verbose) cout<<"(EigenChannel) Computing Factor Analysis Likelihoods"<<endl;}
00076         unsigned long cnt=0;
00077         while((pline=ndx.getLine())!=NULL && cnt < maxLLKcomputed) { 
00078                 while((pFile=pline->getElement())!=NULL && cnt < maxLLKcomputed) {
00080                         MixtureServer ms(config);
00081                         MixtureGD &model=ms.loadMixtureGD(config.getParam("inputWorldFilename"));
00082                         if (FALLK) FA.getFactorAnalysisModel(model,*pFile);
00083                         else FA.getSpeakerModel(model,*pFile);
00084                         
00086                         FeatureServer fs(config,*pFile);
00087                         SegServer segmentsServer;
00088                         LabelServer labelServer;
00089                         initializeClusters(*pFile,segmentsServer,labelServer,config);
00090                         verifyClusterFile(segmentsServer,fs,config);
00091                         unsigned long codeSelectedFrame=labelServer.getLabelIndexByString(config.getParam("labelSelectedFrames"));
00092                         SegCluster& selectedSegments=segmentsServer.getCluster(codeSelectedFrame);  
00093                         double llk=FA.getLLK(selectedSegments,model,fs,config); 
00094                         if (verbose) cout << "(EigenChannel) LLK["<<*pFile<<"]="<<llk<<endl;
00095                         cnt++;
00096                         total+=llk;
00097                 }
00098         }
00099         if (verbose) cout << "(EigenChannel) Total LLK="<<total<<endl;
00100 }
00101 
00102 int EigenChannel(Config & config){
00103         unsigned long nbIt=config.getParam("nbIt").toLong();
00104         bool _computeLLK=false;
00105         if (config.existsParam("computeLLK")) _computeLLK=true; 
00106         bool init=false;
00107         if (config.existsParam("loadAccs")) init=config.getParam("loadAccs").toBool();;
00108 
00109         XList ndx(config.getParam("ndxFilename"));
00110         XLine allFiles=ndx.getAllElements();                    
00111         FeatureServer fs;
00112         
00113         if (verbose) cout << "** Create Factor Analysis Statistics Accumulator" << endl;
00114         FactorAnalysisStat FA((XList&)ndx,fs,config);   
00115         
00116         // Init, compute Stats on UBM and save for further experiements
00117         if (!init) {
00118                 fs.init(config,allFiles);               
00119                 FA.computeAndAccumulateGeneralFAStats(fs,config);
00120                 FA.saveAccs(config);            
00121         }               
00122         else FA.loadAccs(config);
00123                 
00124         
00125         FA.storeAccs(); // save FA state
00126         for(unsigned long i=0;i<nbIt;i++){
00127                 if (_computeLLK) verifyEMLK(FA,ndx,fs,config);
00128                 if (verbose) cout << "(EigenChannel) --------- Iteration "<<i<<"--------- "<<endl;
00129                 FA.estimateAndInverseL(config);
00130                 FA.substractSpeakerStats();
00131                 FA.getXEstimate();
00132                 
00133                 FA.substractChannelStats(); 
00134                 FA.getYEstimate();
00135 
00136                 FA.getUEstimate(config);
00137                 if (1) { //should be debug
00138                         String mat=config.getParam("channelMatrix")+".lastIt";
00139                         FA.getU().save(mat,config); // save last it matrix in debug mode
00140                 }
00141                 FA.restoreAccs(); // restore state
00142         }
00143         FA.getU().save(config.getParam("channelMatrix"),config);
00144 return 0;
00145 }
00146 
00147 //-----------------------------------------------------------------------------------------------------------------------------------------------------------
00148 int EigenChannelJFA(Config & config){
00149         
00150         //Read the NDX file
00151         String ndxFilename = config.getParam("ndxFilename");
00152         
00153         //Create and initialise the accumulator
00154         JFAAcc jfaAcc(ndxFilename, config);
00155 
00156         //Option used to check the Likelihood at each iteration
00157         bool _checkLLK = false;
00158         if (config.existsParam("checkLLK")) _checkLLK= config.getParam("checkLLK").toBool();
00159         
00160         //Statistics
00161         if((config.existsParam("loadAccs")) && config.getParam("loadAccs").toBool()){   //load pre-computed statistics
00162                 jfaAcc.loadN(config);
00163                 jfaAcc.loadN_h(config);
00164                 jfaAcc.loadF_X(config);
00165                 jfaAcc.loadF_X_h(config);
00166         }
00167         else{                                                                                                                   //Compute statistics if they don't exists
00168                 jfaAcc.computeAndAccumulateJFAStat(config);
00169                 jfaAcc.saveAccs(config);
00170         }
00171         
00172         //Initialise the EC Matrix
00173         if(config.existsParam("loadInitChannelMatrix") && config.getParam("loadInitChannelMatrix").toBool()){   //Load the EC matrix when existing
00174                 jfaAcc.loadEC(config.getParam("initEigenChannelMatrix"), config);
00175         }
00176         else{   //Initialise the EC matrix randomly if does not exists
00177                 jfaAcc.initEC(config);
00178         }
00179         
00180         //Save the initial U matrix to be able restart the process with the same initialisation
00181         bool saveInitMatrix = false;
00182         if(config.existsParam("saveInitChannelMatrix")) saveInitMatrix = config.getParam("saveInitChannelMatrix").toBool();
00183         if(saveInitMatrix){
00184                 jfaAcc.saveU(config.getParam("initEigenChannelMatrix"), config);
00185                 cout<<" (EigenChannel) Save the initial EigenChannel Matrix in "<<config.getParam("initEigenChannelMatrix")<<endl;
00186         }
00187 
00188         //Initialise the EV Matrix
00189         if(config.existsParam("eigenVoiceMatrix")){     //Load the EV matrix when existing
00190                 jfaAcc.loadEV(config.getParam("eigenVoiceMatrix"), config);
00191         }
00192         else{   //Initialise the EV matrix to zero
00193                 jfaAcc.getV().setAllValues(0.0);
00194                 cout<<" (EigenChannel) Initialise NULL EigenVoice Matrix"<<endl;
00195         }
00196 
00197         //iteratively retrain the EC matrix
00198         unsigned long nbIt = config.getParam("nbIt").toULong();
00199         
00200         //Estimate Y factors for each speaker
00201         jfaAcc.storeAccs();
00202         jfaAcc.estimateVEVT(config);
00203         jfaAcc.estimateAndInverseL_EV(config);
00204         jfaAcc.substractMplusDZ(config);
00205         jfaAcc.substractUX(config);
00206         jfaAcc.estimateY(config);
00207         
00208         //Reinitialise the accumulators
00209         jfaAcc.restoreAccs();
00210 
00211         jfaAcc.storeAccs();
00212         for(unsigned long it=0; it<nbIt; it++){
00213                 
00214                 cout<<" (EigenChannel) --------- start iteration "<<it<<" --------"<<endl;
00215                 if (_checkLLK) jfaAcc.verifyEMLK(config);
00216 
00217                 //Compute the vEvT matrices
00218                 jfaAcc.estimateUEUT(config);
00219 
00220                 //Estimate and inverse L matrices
00221                 jfaAcc.estimateAndInverseL_EC(config);
00222 
00223                 //Substract the speaker statistics
00224                 jfaAcc.substractMplusVYplusDZ(config);
00225 
00226                 //On update X pour toutes les sessions
00227                 jfaAcc.estimateXandU(config);
00228                         
00229                 //Update _U
00230                 jfaAcc.updateUestimate();
00231 
00232                 //Reinitialise the accumulators
00233                 jfaAcc.resetTmpAcc();
00234                 jfaAcc.restoreAccs();
00235 
00236                 //Reinitialise the accumulators
00237                 jfaAcc.resetTmpAcc();
00238                 jfaAcc.restoreAccs();
00239 
00240                 //Save the U matrix at the end of the iteration
00241                 bool saveAllMatrices = false;
00242                 if(config.existsParam("saveAllECMatrices")) saveAllMatrices=config.getParam("saveAllECMatrices").toBool();
00243                 if(saveAllMatrices)
00244                 {
00245                         String s;
00246                         String output = config.getParam("eigenChannelMatrix") + s.valueOf(it);
00247                         jfaAcc.saveU(output, config);
00248                 }
00249         }
00250         
00251         cout<<" (EigenChannel) --------- save EigenChannel Matrix --------"<<endl;
00252         jfaAcc.saveU(config.getParam("eigenChannelMatrix") ,config);
00253         cout<<" (EigenChannel) --------- end of process --------"<<endl;
00254 
00255 return 0;
00256 }
00257 
00258 
00259 //-----------------------------------------------------------------------------------------------------------------------------------------------------------
00260 int EigenChannelLFA(Config & config){
00261         
00262         //Read the NDX file
00263         String ndxFilename = config.getParam("ndxFilename");
00264         
00265         //Create and initialise the accumulator
00266         JFAAcc jfaAcc(ndxFilename, config);
00267 
00268         //Option used to check the Likelihood at each iteration
00269         bool _checkLLK = false;
00270         if (config.existsParam("checkLLK")) _checkLLK= config.getParam("checkLLK").toBool();
00271         
00272         //Statistics
00273         if((config.existsParam("loadAccs")) && config.getParam("loadAccs").toBool()){   //load pre-computed statistics
00274                 jfaAcc.loadN(config);
00275                 jfaAcc.loadN_h(config);
00276                 jfaAcc.loadF_X(config);
00277                 jfaAcc.loadF_X_h(config);
00278         }
00279         else{                                                                                                                   //Compute statistics if they don't exists
00280                 jfaAcc.computeAndAccumulateJFAStat(config);
00281                 jfaAcc.saveAccs(config);
00282         }
00283         
00284         //Initialise the EC Matrix
00285         if(config.existsParam("loadInitChannelMatrix") && config.getParam("loadInitChannelMatrix").toBool()){   //Load the EC matrix when existing
00286                 jfaAcc.loadEC(config.getParam("initEigenChannelMatrix"), config);
00287         }
00288         else{   //Initialise the EC matrix randomly if does not exists
00289                 jfaAcc.initEC(config);
00290         }
00291         
00292         //Save the initial U matrix to be able restart the process with the same initialisation
00293         if(config.existsParam("saveInitChannelMatrix") && config.getParam("saveInitChannelMatrix").toBool()){
00294                 jfaAcc.saveU(config.getParam("initEigenChannelMatrix"), config);
00295                 cout<<" (EigenChannel) Save the initial EigenChannel Matrix in "<<config.getParam("initEigenChannelMatrix")<<endl;
00296         }
00297 
00298         //Initialise the EV Matrix
00299         if(config.existsParam("eigenVoiceMatrix")){     //Load the EV matrix when existing
00300                 jfaAcc.loadEV(config.getParam("eigenVoiceMatrix"), config);
00301         }
00302         else{   //Initialise the EV matrix to zero
00303                 jfaAcc.getV().setAllValues(0.0);
00304                 cout<<" (EigenChannel) Initialise NULL EigenVoice Matrix"<<endl;
00305         }
00306 
00307 
00308         //Initialise the D Matrix with MAP paradigm
00309         if(config.getParam("channelCompensation")=="LFA"){
00310                 jfaAcc.initD(config);
00311         }
00312 
00313         //iteratively retrain the EC matrix
00314         unsigned long nbIt = config.getParam("nbIt").toULong();
00315         
00316         //Estimate Y factors for each speaker
00317         jfaAcc.storeAccs();
00318         jfaAcc.estimateVEVT(config);
00319         jfaAcc.estimateAndInverseL_EV(config);
00320         jfaAcc.substractMplusDZ(config);
00321         jfaAcc.substractUX(config);
00322         jfaAcc.estimateY(config);
00323         
00324         //Reinitialise the accumulators
00325         jfaAcc.restoreAccs();
00326 
00327         jfaAcc.storeAccs();
00328         for(unsigned long it=0; it<nbIt; it++){
00329                 
00330                 cout<<" (EigenChannel) --------- start iteration "<<it<<" --------"<<endl;
00331                 if (_checkLLK) jfaAcc.verifyEMLK(config);
00332 
00333                 //Compute the vEvT matrices
00334                 jfaAcc.estimateUEUT(config);
00335 
00336                 //Estimate and inverse L matrices
00337                 jfaAcc.estimateAndInverseL_EC(config);
00338 
00339                 //Substract the speaker statistics
00340                 jfaAcc.substractMplusVYplusDZ(config);
00341 
00342                 //Estimate X
00343                 jfaAcc.estimateX(config);
00344 
00345                 //Substract channel statistics
00346                 jfaAcc.substractMplusUX();
00347 
00348                 //Estimate Z (Y for JFA ??? or Y and Z dans le cas ou on utilise la matrice D du MAP)
00349                 jfaAcc.estimateZMAP(config.getParam("regulationFactor").toLong());
00350 
00351                 //estimate U
00352                 jfaAcc.estimateU();
00353 
00354                 //Update _U
00355                 jfaAcc.updateUestimate();
00356 
00357                 //Reinitialise the accumulators
00358                 jfaAcc.resetTmpAcc();
00359                 jfaAcc.restoreAccs();
00360 
00361                 //Save the U matrix at the end of the iteration
00362                 if(config.getParam("saveAllECMatrices").toBool()){
00363                         String s;
00364                         String output = config.getParam("eigenChannelMatrix") + s.valueOf(it);
00365                         jfaAcc.saveU(output, config);
00366                 }
00367         }
00368         
00369         cout<<" (EigenChannel) --------- save EigenChannel Matrix --------"<<endl;
00370         jfaAcc.saveU(config.getParam("eigenChannelMatrix") ,config);
00371         cout<<" (EigenChannel) --------- end of process --------"<<endl;
00372 
00373 return 0;
00374 }
00375 
00376 #endif