/** * Train the HMM with the given input sequence * * @param slHiddenMarkovModel $hmm * @param array $sequence * @return void */ public function train(slHiddenMarkovModel $hmm, array $sequence) { $sequence = $hmm->mapLabels($sequence); $sequenceLength = count($sequence); $oldHmm = clone $hmm; $states = count($hmm); $labels = $hmm->countLabels(); // Calculate forward and backwards variables, first $forward = $this->calcForward($oldHmm, $sequence); $backward = $this->calcBackwards($oldHmm, $sequence); // Reevaluate the start probabilities for ($i = 0; $i < $states; ++$i) { $hmm->setStart($i, $this->calcGamma($oldHmm, $i, 0, $sequence, $forward, $backward)); } // Reevaluate the transistion probabilities for ($i = 0; $i < $states; ++$i) { for ($j = 0; $j < $states; ++$j) { $numerator = 0; $denominator = 0; for ($t = 0; $t <= $sequenceLength - 1; ++$t) { $numerator += $this->calcP($oldHmm, $t, $i, $j, $sequence, $forward, $backward); $denominator += $this->calcGamma($oldHmm, $i, $t, $sequence, $forward, $backward); } $hmm->setTransition($i, $j, $this->divide($numerator, $denominator)); } } // Reevaluate the emission probabilities for ($i = 0; $i < $states; ++$i) { for ($k = 0; $k < $labels; ++$k) { for ($t = 0; $t <= $sequenceLength - 1; ++$t) { $gamma = $this->calcGamma($oldHmm, $i, $t, $sequence, $forward, $backward); $numerator += $gamma * ($k == $sequence[$t] ? 1 : 0); $denominator += $gamma; } $hmm->setEmission($i, $k, $this->divide($numerator, $denominator)); } } }
public function testMapLabels() { $hmm = new slHiddenMarkovModel(4, array(1, 2, 3)); $this->assertSame(array(0, 1, 0, 2), $hmm->mapLabels(array(1, 2, 1, 3))); }