annotate SparseHMM.cpp @ 164:a7d9c6142f8f tip

Added tag v1.2 for changeset 4a97f7638ffd
author Chris Cannam
date Thu, 06 Feb 2020 15:02:47 +0000
parents b83e6fbe22cc
children
rev   line source
Chris@9 1 /* -*- c-basic-offset: 4 indent-tabs-mode: nil -*- vi:set ts=8 sts=4 sw=4: */
Chris@9 2
Chris@9 3 /*
Chris@9 4 pYIN - A fundamental frequency estimator for monophonic audio
Chris@9 5 Centre for Digital Music, Queen Mary, University of London.
Chris@9 6
Chris@9 7 This program is free software; you can redistribute it and/or
Chris@9 8 modify it under the terms of the GNU General Public License as
Chris@9 9 published by the Free Software Foundation; either version 2 of the
Chris@9 10 License, or (at your option) any later version. See the file
Chris@9 11 COPYING included with this distribution for more information.
Chris@9 12 */
Chris@9 13
matthiasm@0 14 #include "SparseHMM.h"
matthiasm@0 15 #include <vector>
matthiasm@0 16 #include <cstdio>
matthiasm@0 17 #include <iostream>
matthiasm@0 18
matthiasm@0 19 using std::vector;
matthiasm@0 20 using std::pair;
matthiasm@0 21
mail@132 22 SparseHMM::SparseHMM(int fixedLag) :
mail@132 23 m_fixedLag(fixedLag),
mail@130 24 m_nState(0),
mail@130 25 m_nTrans(0),
mail@130 26 m_init(0),
mail@130 27 m_from(0),
mail@130 28 m_to(0),
mail@130 29 m_transProb(0),
mail@130 30 m_scale(0),
mail@130 31 m_psi(0),
mail@130 32 m_delta(0),
mail@130 33 m_oldDelta(0)
mail@130 34 {
mail@130 35
mail@130 36 }
mail@130 37
mail@130 38 void
mail@130 39 SparseHMM::build()
mail@130 40 { }
mail@130 41
Chris@145 42 std::vector<int>
mail@130 43 SparseHMM::decodeViterbi(std::vector<vector<double> > obsProb)
matthiasm@0 44 {
Chris@142 45 int nFrame = obsProb.size();
mail@130 46 if (nFrame < 1) {
Chris@38 47 return vector<int>();
Chris@38 48 }
Chris@38 49
mail@130 50 initialise(obsProb[0]);
Chris@38 51
Chris@38 52 // rest of forward step
Chris@142 53 for (int iFrame = 1; iFrame < nFrame; ++iFrame)
Chris@38 54 {
mail@130 55 process(obsProb[iFrame]);
mail@130 56 }
Chris@38 57
mail@132 58 vector<int> path = track();
mail@130 59 return(path);
mail@130 60 }
mail@130 61
mail@131 62 void
mail@131 63 SparseHMM::reset()
mail@131 64 {
mail@131 65 m_scale.clear();
mail@131 66 m_psi.clear();
Chris@142 67 for (int i = 0; i < int(m_delta.size()); ++i) m_delta[i] = 0;
Chris@142 68 for (int i = 0; i < int(m_oldDelta.size()); ++i) m_oldDelta[i] = 0;
mail@131 69 }
mail@130 70
mail@130 71 void
mail@130 72 SparseHMM::initialise(vector<double> firstObs)
mail@130 73 {
mail@131 74 reset();
matthiasm@0 75
matthiasm@0 76 double deltasum = 0;
matthiasm@0 77
matthiasm@0 78 // initialise first frame
Chris@142 79 for (int iState = 0; iState < m_nState; ++iState)
matthiasm@0 80 {
mail@130 81 m_oldDelta[iState] = m_init[iState] * firstObs[iState];
mail@130 82 deltasum += m_oldDelta[iState];
matthiasm@0 83 }
matthiasm@0 84
Chris@142 85 for (int iState = 0; iState < m_nState; ++iState)
matthiasm@0 86 {
mail@130 87 m_oldDelta[iState] /= deltasum; // normalise (scale)
matthiasm@0 88 }
matthiasm@0 89
mail@130 90 m_scale.push_back(1.0/deltasum);
mail@130 91 m_psi.push_back(vector<int>(m_nState,0));
mail@130 92 }
matthiasm@0 93
mail@130 94 int
mail@130 95 SparseHMM::process(vector<double> newObs)
mail@130 96 {
mail@130 97 vector<int> tempPsi = vector<int>(m_nState,0);
mail@130 98
mail@130 99 // calculate best previous state for every current state
Chris@142 100 int fromState;
Chris@142 101 int toState;
mail@130 102 double currentTransProb;
mail@130 103 double currentValue;
mail@130 104
mail@130 105 // this is the "sparse" loop
Chris@142 106 for (int iTrans = 0; iTrans < m_nTrans; ++iTrans)
matthiasm@0 107 {
mail@130 108 fromState = m_from[iTrans];
mail@130 109 toState = m_to[iTrans];
mail@130 110 currentTransProb = m_transProb[iTrans];
matthiasm@0 111
mail@130 112 currentValue = m_oldDelta[fromState] * currentTransProb;
mail@130 113 if (currentValue > m_delta[toState])
matthiasm@0 114 {
mail@130 115 // will be multiplied by the right obs later!
mail@130 116 m_delta[toState] = currentValue;
mail@130 117 tempPsi[toState] = fromState;
matthiasm@0 118 }
matthiasm@0 119 }
mail@130 120 m_psi.push_back(tempPsi);
matthiasm@0 121
mail@130 122 double deltasum = 0;
Chris@142 123 for (int jState = 0; jState < m_nState; ++jState)
mail@130 124 {
mail@130 125 m_delta[jState] *= newObs[jState];
mail@130 126 deltasum += m_delta[jState];
mail@130 127 }
mail@130 128
mail@130 129 if (deltasum > 0)
mail@130 130 {
Chris@142 131 for (int iState = 0; iState < m_nState; ++iState)
mail@130 132 {
mail@130 133 m_oldDelta[iState] = m_delta[iState] / deltasum;// normalise (scale)
mail@130 134 m_delta[iState] = 0;
mail@130 135 }
mail@130 136 m_scale.push_back(1.0/deltasum);
mail@130 137 } else
mail@130 138 {
Chris@149 139 // std::cerr << "WARNING: Viterbi has been fed some zero "
Chris@149 140 // "probabilities, at least they become zero "
Chris@149 141 // "in combination with the model." << std::endl;
Chris@142 142 for (int iState = 0; iState < m_nState; ++iState)
mail@130 143 {
mail@130 144 m_oldDelta[iState] = 1.0/m_nState;
mail@130 145 m_delta[iState] = 0;
mail@130 146 }
mail@130 147 m_scale.push_back(1.0);
mail@130 148 }
mail@132 149
Chris@142 150 if (m_fixedLag > 0 && int(m_psi.size()) > m_fixedLag)
mail@132 151 {
mail@132 152 m_psi.pop_front();
mail@132 153 m_scale.pop_front();
mail@132 154 }
mail@132 155
mail@132 156 // std::cerr << m_fixedLag << " " << m_psi.size() << std::endl;
mail@132 157
mail@130 158 return 0;
mail@130 159 }
mail@130 160
Chris@145 161 vector<int>
mail@132 162 SparseHMM::track()
mail@130 163 {
matthiasm@0 164 // initialise backward step
Chris@142 165 int nFrame = m_psi.size();
mail@130 166
mail@130 167 // The final output path (current assignment arbitrary, makes sense only for
mail@130 168 // Chordino, where nChord-1 is the "no chord" label)
mail@130 169 vector<int> path = vector<int>(nFrame, m_nState-1);
mail@130 170
matthiasm@0 171 double bestValue = 0;
Chris@142 172 for (int iState = 0; iState < m_nState; ++iState)
matthiasm@0 173 {
mail@130 174 double currentValue = m_oldDelta[iState];
matthiasm@0 175 if (currentValue > bestValue)
matthiasm@0 176 {
matthiasm@0 177 bestValue = currentValue;
matthiasm@0 178 path[nFrame-1] = iState;
matthiasm@0 179 }
matthiasm@0 180 }
matthiasm@0 181
mail@130 182 // Rest of backward step
matthiasm@0 183 for (int iFrame = nFrame-2; iFrame != -1; --iFrame)
matthiasm@0 184 {
mail@130 185 path[iFrame] = m_psi[iFrame+1][path[iFrame+1]];
matthiasm@0 186 }
mail@130 187
matthiasm@0 188 return path;
Chris@142 189 }