ViterbiAccum.cpp

Go to the documentation of this file.
00001 /*
00002         This file is part of ALIZE which is an open-source tool for 
00003         speaker recognition.
00004 
00005     ALIZE is free software: you can redistribute it and/or modify
00006     it under the terms of the GNU Lesser General Public License as 
00007     published by the Free Software Foundation, either version 3 of 
00008     the License, or any later version.
00009 
00010     ALIZE is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013     GNU Lesser General Public License for more details.
00014 
00015     You should have received a copy of the GNU Lesser General Public 
00016     License along with ALIZE.
00017     If not, see <http://www.gnu.org/licenses/>.
00018         
00019         ALIZE is a development project initiated by the ELISA consortium
00020         [alize.univ-avignon.fr/] and funded by the French Research 
00021         Ministry in the framework of the TECHNOLANGUE program 
00022         [www.technolangue.net]
00023 
00024         The ALIZE project team wants to highlight the limits of voice
00025         authentication in a forensic context.
00026         The "Person  Authentification by Voice: A Need of Caution" paper 
00027         proposes a good overview of this point (cf. "Person  
00028         Authentification by Voice: A Need of Caution", Bonastre J.F., 
00029         Bimbot F., Boe L.J., Campbell J.P., Douglas D.A., Magrin-
00030         chagnolleau I., Eurospeech 2003, Genova].
00031         The conclusion of the paper of the paper is proposed bellow:
00032         [Currently, it is not possible to completely determine whether the 
00033         similarity between two recordings is due to the speaker or to other 
00034         factors, especially when: (a) the speaker does not cooperate, (b) there 
00035         is no control over recording equipment, (c) recording conditions are not 
00036         known, (d) one does not know whether the voice was disguised and, to a 
00037         lesser extent, (e) the linguistic content of the message is not 
00038         controlled. Caution and judgment must be exercised when applying speaker 
00039         recognition techniques, whether human or automatic, to account for these 
00040         uncontrolled factors. Under more constrained or calibrated situations, 
00041         or as an aid for investigative purposes, judicious application of these 
00042         techniques may be suitable, provided they are not considered as infallible.
00043         At the present time, there is no scientific process that enables one to 
00044         uniquely characterize a person=92s voice or to identify with absolute 
00045         certainty an individual from his or her voice.]
00046         Contact Jean-Francois Bonastre for more information about the licence or
00047         the use of ALIZE
00048 
00049         Copyright (C) 2003-2010
00050         Laboratoire d'informatique d'Avignon [lia.univ-avignon.fr]
00051         ALIZE admin [alize@univ-avignon.fr]
00052         Jean-Francois Bonastre [jean-francois.bonastre@univ-avignon.fr]
00053 */
00054 
00055 #if !defined(ALIZE_ViterbiAccum_cpp)
00056 #define ALIZE_ViterbiAccum_cpp
00057 
00058 #include <iostream>
00059 #include <new>
00060 #include "Object.h"
00061 #include "ViterbiAccum.h"
00062 #include "Exception.h"
00063 #include "Mixture.h"
00064 #include "Feature.h"
00065 #include "Config.h"
00066 #include "MixtureStat.h"
00067 #include "StatServer.h"
00068 
00069 using namespace alize;
00070 
00071 //-------------------------------------------------------------------------
00072 ViterbiAccum::ViterbiAccum(StatServer& ss, const Config& c)
00073 :Object(), _pConfig(&c), _pStatServer(&ss) { reset(); } 
00074 //-------------------------------------------------------------------------
00075 ViterbiAccum& ViterbiAccum::create(StatServer& ss, const Config& c,
00076                                    const K&)
00077 {
00078     ViterbiAccum* p = new (std::nothrow) ViterbiAccum(ss, c);
00079     assertMemoryIsAllocated(p, __FILE__, __LINE__);
00080     return *p;
00081 } 
00082 //-------------------------------------------------------------------------
00083 void ViterbiAccum::addState(Mixture& m)
00084 {
00085     _stateVect.addObject(const_cast<Mixture&>(m));
00086     unsigned long size = _stateVect.size();
00087     _transMatrix.setSize(size*size);
00088 }
00089 //-------------------------------------------------------------------------
00090 real_t& ViterbiAccum::logTransition(unsigned long i, unsigned long j)
00091 {
00092     unsigned long size = _stateVect.size();
00093     if (i >= size)
00094         throw IndexOutOfBoundsException("", __FILE__, __LINE__, i, size);
00095     if (j >= size)
00096         throw IndexOutOfBoundsException("", __FILE__, __LINE__, i, size);
00097     return _transMatrix[j*size + i];
00098 }
00099 //-------------------------------------------------------------------------
00100 real_t ViterbiAccum::logTransition(unsigned long i, unsigned long j) const
00101 { return const_cast<ViterbiAccum*>(this)->logTransition(i, j); }
00102 //-------------------------------------------------------------------------
00103 Mixture& ViterbiAccum::getState(unsigned long i) const
00104 { return _stateVect.getObject(i); }
00105 //-------------------------------------------------------------------------
00106 unsigned long ViterbiAccum::getStateCount() const
00107 { return _stateVect.size(); }
00108 //-------------------------------------------------------------------------
00109 
00110 
00111 
00112 
00113 //-------------------------------------------------------------------------
00114 void ViterbiAccum::reset()
00115 {
00116     _tmpTab.clear();
00117     _llpVect.clear();
00118     _llpDefined = false;
00119     _pathDefined = false;
00120     _featureCount = 0;
00121 }
00122 //-------------------------------------------------------------------------
00123 void ViterbiAccum::computeAndAccumulate(const Feature& f, double llkW)
00124 {
00125     unsigned long i, j, nbStates = _stateVect.size();
00126     _llpDefined = _pathDefined = false;
00127 
00128     // compute llk between the feature and each state
00129     _tmpLLKVect.clear();
00130     for (i=0; i<nbStates; i++)
00131         //_tmpLLKVect.addValue(_mixtureStatVect.getObject(i).computeLLK(f)-llkW);
00132         _tmpLLKVect.addValue(computeStateLLK(i, f)-llkW);
00133     //
00134     if (_featureCount == 0) // if first feature
00135         _llpVect = _tmpLLKVect;
00136     else
00137     {
00138         _tmpllpVect.clear();
00139         unsigned long maxInd = 0;
00140         real_t maxllp = 0;
00141         for (i=0; i<nbStates; i++)
00142         {
00143 
00144             for (j=0; j<nbStates; j++)
00145             {
00146                 real_t llp = _llpVect[j] + _tmpLLKVect[i]
00147                                          + logTransition(j, i);
00148                 if (j == 0 || llp > maxllp)
00149                 {
00150                     maxllp = llp;
00151                     maxInd = j;
00152                 }
00153             }
00154             _tmpllpVect.addValue(maxllp);
00155             _tmpTab.addValue(maxInd);
00156         }
00157         _llpVect = _tmpllpVect;
00158     }
00159     _featureCount++;
00160 }
00161 
00162 //-------------------------------------------------------------------------
00163 void ViterbiAccum::computeAndAccumulate(FeatureServer& fs,
00164                DoubleVector& llkW, unsigned long start, unsigned long count)
00165 {
00166   unsigned long i, j, nbStates = _stateVect.size();
00167   _llpDefined = _pathDefined = false;
00168   double l;
00169   Feature f;
00170     
00171   // compute llk between the feature and each state
00172   _tmpLLKVect.clear();
00173   for (i=0; i<nbStates; i++)
00174   {
00175      l = 0.0;
00176     fs.seekFeature(start);
00177     for (unsigned long ifeature=start; ifeature < (start+count); ifeature++)
00178     {
00179        fs.readFeature(f);
00180        l += computeStateLLK(i, f) -llkW[ifeature]+logTransition(i,i);
00181     }     
00182     _tmpLLKVect.addValue(l/count);
00183     //cout << "start: " << start << " & count: " << count << " Etat " << i << " => " << l/count << endl;
00184   }
00185   if (_featureCount == 0)  // if first feature in the viterbi path
00186   {
00187     _llpVect = _tmpLLKVect;
00188     for(unsigned long c=0; c<count; c++)
00189       for (i=0; i<nbStates; i++)    
00190         _tmpTab.addValue(i);
00191   }       
00192   else
00193   {
00194     _tmpllpVect.clear();
00195     unsigned long maxInd = 0;
00196     real_t maxllp = 0;
00197     real_t llp;
00198   
00199     // For the first frame of the n block (n>0)- find the path
00200     for (i=0; i<nbStates; i++)
00201     {
00202       for (j=0; j<nbStates; j++)
00203       {
00204         llp = _llpVect[j] + _tmpLLKVect[i] + logTransition(j, i);
00205         if (j == 0 || llp > maxllp)
00206         {
00207           maxllp = llp;
00208           maxInd = j;
00209         }
00210       }
00211       _tmpllpVect.addValue(maxllp);
00212       _tmpTab.addValue(maxInd);
00213     }
00214     for(unsigned long c=1; c<count; c++)
00215       for (i=0; i<nbStates; i++)
00216         _tmpTab.addValue(i);
00217     _llpVect = _tmpllpVect;
00218   }
00219   _featureCount+=count;
00220   //cout << " FeatureCount: " << _featureCount << endl;
00221 }
00222 //-------------------------------------------------------------------------
00223 void ViterbiAccum::computeAndAccumulate(FeatureServer& fs,
00224                     unsigned long start, unsigned long count, double fudge)
00225 {
00226   unsigned long i, j, nbStates = _stateVect.size();
00227   _llpDefined = _pathDefined = false;
00228   double l;
00229   Feature f;
00230     
00231   // compute llk between the feature and each state
00232   _tmpLLKVect.clear();
00233   for (i=0; i<nbStates; i++)
00234   {
00235     l = 0.0;
00236     fs.seekFeature(start);
00237     for (unsigned long ifeature=start; ifeature < (start+count); ifeature++)
00238     {
00239       fs.readFeature(f);
00240       l += computeStateLLK(i, f);
00241     }     
00242     _tmpLLKVect.addValue(l/count);
00243     //  cout << "start: " << start << " & count: " << count << " Etat " << i << " => " << l/count << endl;
00244   }
00245   if (_featureCount == 0) // if first feature in the viterbi path
00246   {
00247     _llpVect = _tmpLLKVect;
00248     for(unsigned long c=0; c<count; c++)
00249       for (i=0; i<nbStates; i++)    
00250         _tmpTab.addValue(i);
00251   }       
00252   else
00253   {
00254     _tmpllpVect.clear();
00255     unsigned long maxInd = 0;
00256     real_t maxllp = 0;
00257     real_t llp;
00258   
00259     // For the first frame of the n block (n>0)- find the path
00260     for (i=0; i<nbStates; i++)
00261     {
00262       for (j=0; j<nbStates; j++)
00263       {
00264         llp = _llpVect[j] + _tmpLLKVect[i] + logTransition(j, i)*fudge;
00265         if (j == 0 || llp > maxllp)
00266         {
00267           maxllp = llp;
00268           maxInd = j;
00269         }
00270       }
00271       _tmpllpVect.addValue(maxllp);
00272       _tmpTab.addValue(maxInd);
00273     }
00274     for(unsigned long c=1; c<count; c++)
00275       for (i=0; i<nbStates; i++)
00276         _tmpTab.addValue(i);
00277     _llpVect = _tmpllpVect;
00278   }
00279   _featureCount+=count;
00280   //cout << " FeatureCount: " << _featureCount << endl;
00281 }
00282 
00283 /*//-------------------------------------------------------------------------
00284 void ViterbiAccum::computeAndAccumulate(FeatureServer *fs, DoubleVector& llkW, int start, int count)
00285 //-------------------------------------------------------------------------
00286  {
00287     unsigned long i, j, nbStates = _stateVect.size();
00288     _llpDefined = _pathDefined = false;
00289   double l;
00290     
00291     // compute llk between the feature and each state
00292     _tmpLLKVect.clear();
00293     for (i=0; i<nbStates; i++){
00294        l = 0.0;
00295   for(int ifeature=start; ifeature < (start+count); ifeature++){
00296      Feature& f=fs->getFeature(ifeature);
00297     l += computeStateLLK(i, f)-llkW[ifeature];
00298    }     
00299        _tmpLLKVect.addValue(l/count);
00300   //cout << "start: " << start << " & count: " << count << " Etat " << i << " => " << l/count << endl;
00301        
00302     }
00303     if (_featureCount == 0){ // if first feature
00304         _llpVect = _tmpLLKVect;
00305       for(int c=0; c<count; c++){
00306     for (i=0; i<nbStates; i++){    
00307             _tmpTab.addValue(i);
00308     }  
00309    }
00310   
00311     }       
00312     else
00313     {
00314         _tmpllpVect.clear();
00315         unsigned long maxInd = 0;
00316         real_t maxllp = 0;
00317   real_t llp;
00318         for(int c=0; c<count; c++){
00319      if(c==0){
00320       for (i=0; i<nbStates; i++){
00321         for (j=0; j<nbStates; j++){
00322                 llp = _llpVect[j] + _tmpLLKVect[i] + logTransition(j, i);
00323           if (j == 0 || llp > maxllp){
00324                       maxllp = llp;
00325                         maxInd = j;
00326                 }
00327                      }
00328            _tmpllpVect.addValue(maxllp);
00329                  _tmpTab.addValue(maxInd);
00330       }
00331     }
00332          else{
00333       for (i=0; i<nbStates; i++){
00334         _tmpTab.addValue(i);
00335       }
00336     }
00337         }
00338         _llpVect = _tmpllpVect;
00339     }
00340     _featureCount+=count;
00341     //cout << " FeatureCount: " << _featureCount << endl;
00342 }
00343 */
00344  
00345  
00346  //-------------------------------------------------------------------------
00347 /*void ViterbiAccum::computeAndAccumulate(FeatureServer *fs, DoubleVector& llkW, int start, int count)
00348 //-------------------------------------------------------------------------
00349  {
00350     unsigned long i, j, nbStates = _stateVect.size();
00351     _llpDefined = _pathDefined = false;
00352   double l;
00353     
00354     // compute llk between the feature and each state
00355     _tmpLLKVect.clear();
00356     cout << count << " " << start << endl;
00357     for(int c=0, ifeature=start; c<count; c++, ifeature++){
00358        
00359   Feature& f=fs->getFeature(ifeature);
00360       for (i=0; i<nbStates; i++){
00361     l = computeStateLLK(i, f)-llkW[ifeature];
00362     
00363     cout << c << " => " << l << endl;
00364     _tmpLLKVect.addValue(l);   
00365   }
00366        
00367       if (_featureCount == 0){ // if first feature
00368            _llpVect = _tmpLLKVect;
00369     for (i=0; i<nbStates; i++){    
00370              _tmpTab.addValue(i);
00371     }      
00372       }       
00373      else{
00374           _tmpllpVect.clear();
00375           unsigned long maxInd = 0;
00376           real_t maxllp = 0;
00377     real_t llp;
00378           
00379     if(c==0){
00380       for (i=0; i<nbStates; i++){
00381          for (j=0; j<nbStates; j++){
00382               llp = _llpVect[j] + _tmpLLKVect[i] + logTransition(j, i);
00383         if (j == 0 || llp > maxllp){
00384                       maxllp = llp;
00385                   maxInd = j;
00386               }
00387                 }
00388          _tmpllpVect.addValue(maxllp);
00389                _tmpTab.addValue(maxInd);
00390       }
00391     }
00392          else{
00393       for (i=0; i<nbStates; i++){
00394               llp = _llpVect[i] + _tmpLLKVect[i] + logTransition(i, i);
00395           _tmpllpVect.addValue(llp);
00396                 _tmpTab.addValue(i);
00397             }
00398     
00399          }
00400          _llpVect = _tmpllpVect;
00401         }
00402     }//fin for(int c=0... 
00403     _featureCount+=count;
00404     //cout << " FeatureCount: " << _featureCount << endl;
00405 }
00406 */
00407 
00408 //-------------------------------------------------------------------------
00409 void ViterbiAccum::computeAndAccumulate(const Feature& f, double fudge, double penality)
00410 //-------------------------------------------------------------------------
00411  {
00412     unsigned long i, j, nbStates = _stateVect.size();
00413     _llpDefined = _pathDefined = false;
00414 
00415     // compute llk between the feature and each state
00416     _tmpLLKVect.clear();
00417     for (i=0; i<nbStates; i++)
00418       _tmpLLKVect.addValue(computeStateLLK(i, f));
00419     //
00420     if (_featureCount == 0) // if first feature
00421         _llpVect = _tmpLLKVect;
00422     else
00423     {
00424         _tmpllpVect.clear();
00425         unsigned long maxInd = 0;
00426         real_t maxllp = 0;
00427         for (i=0; i<nbStates; i++)
00428         {
00429 
00430             for (j=0; j<nbStates; j++)
00431             {
00432                 real_t llp = _llpVect[j] + _tmpLLKVect[i] + fudge * logTransition(j, i);
00433                 if(i != j) 
00434       llp += penality;
00435                 if (j == 0 || llp > maxllp)
00436                 {
00437                     maxllp = llp;
00438                     maxInd = j;
00439                 }
00440             }
00441             _tmpllpVect.addValue(maxllp);
00442             _tmpTab.addValue(maxInd);
00443         }
00444         _llpVect = _tmpllpVect;
00445     }
00446     _featureCount++;
00447 }
00448 
00449 //-------------------------------------------------------------------------
00450 unsigned long ViterbiAccum::getFeatureCount() const {return _featureCount;}
00451 //-------------------------------------------------------------------------
00452 const ULongVector& ViterbiAccum::getPath()
00453 {
00454     
00455   if (!_pathDefined)
00456     {
00457         unsigned long i, max = 0, nbStates = _stateVect.size();
00458 
00459         // looks for the largest llp
00460         for (i=0; i<nbStates; i++){
00461    if (_llpVect[i] > _llpVect[max])
00462                 max = i;
00463    }
00464         _llp = _llpVect[max];
00465         _llpDefined = true;
00466 
00467         _path.setSize(_featureCount);
00468         if (_featureCount != 0)
00469         {
00470             for (i=_featureCount-1; i>0; i--)
00471             {
00472                 _path[i] = max;
00473                 max = _tmpTab[(i-1)*nbStates+max];
00474             }
00475             _path[0] = max;
00476         }
00477         _pathDefined = true;
00478     }
00479     return _path;
00480 }
00481 //-------------------------------------------------------------------------
00482 real_t ViterbiAccum::getLlp() const
00483 {
00484     if (!_llpDefined)
00485         throw Exception("llp undefined", __FILE__, __LINE__);
00486     return _llp;
00487 }
00488 //-------------------------------------------------------------------------
00489 lk_t ViterbiAccum::computeStateLLK(unsigned long i, const Feature& f) const
00490 {
00491   return _pStatServer->computeLLK(_stateVect.getObject(i), f);
00492 }
00493 //-------------------------------------------------------------------------
00494 
00495 
00496 
00497 
00498 //-------------------------------------------------------------------------
00499 String ViterbiAccum::getClassName() const { return "ViterbiAccum"; }
00500 //-------------------------------------------------------------------------
00501 String ViterbiAccum::toString() const
00502 {
00503     unsigned long i, nbStates = getStateCount();
00504     String s = Object::toString()
00505                + " Nb States = " + String::valueOf(nbStates)
00506                + " Nb features = " + String::valueOf(_featureCount);
00507     for (i=0; i<nbStates; i++)
00508     {
00509         for (unsigned long j=0; j<nbStates; j++)
00510         s += "\n  Log transition " + String::valueOf(i) + "->"
00511            + String::valueOf(j) + " = "
00512            + String::valueOf(logTransition(i, j));
00513     }
00514     if (_llpDefined)
00515         s += "\n  llp = " + String::valueOf(_llp);
00516     else
00517         s += "\n  llp = undefined";
00518 
00519     if (_pathDefined)
00520         for (i=0; i<_featureCount; i++)
00521             s += "\n  path[" + String::valueOf(i) + "]"
00522             + " = " + String::valueOf(_path[i]);
00523     else
00524         s += "\n  path = undefined";
00525     return s;
00526 }
00527 //-------------------------------------------------------------------------
00528 ViterbiAccum::~ViterbiAccum() {}
00529 //-------------------------------------------------------------------------
00530 
00531 #endif // !defined(ALIZE_ViterbiAccum_cpp)