Esempio n. 1
0
 private static double NoSoundStateEmissionProbability(PitchHmmEmission emission)
 {
     // 無音 0.3、それ以外 0.7
     // 変化したタイミングで入力が来るので、無音でないパターンもそれなりに可能性があると考える
     return(Math.Log(emission.IsSilent ? 0.3 : 0.7 / 12.0));
 }
        public void InputObservation(PitchHmmEmission observation)
        {
            var states = this._model.States;

            var maxLogProbabilities = new double[states.Count];

            for (var i = 0; i < maxLogProbabilities.Length; i++)
            {
                maxLogProbabilities[i] = double.NegativeInfinity;
            }

            // 初期状態確率 * 遷移確率 * 生成確率 を計算する
            foreach (var(fromStateIndex, stateLogProbability) in this._stateLogProbabilities)
            {
                foreach (var(toStateIndex, transitionLogProbability) in states[fromStateIndex].LogProbabilitiesByOutgoingStateIndexes)
                {
                    var lp = stateLogProbability + transitionLogProbability + states[toStateIndex].EmissionLogProbability(observation);

                    if (!(lp <= 0.0))
                    {
                        throw new Exception("確率が不正な値になりました。");               // NaN チェックも含めるため not <=
                    }
                    if (lp > maxLogProbabilities[toStateIndex])
                    {
                        maxLogProbabilities[toStateIndex] = lp;
                    }
                }
            }

            var stateLogProbabilities = this._stateLogProbabilities;

            stateLogProbabilities.Clear();

            var logSum  = double.NegativeInfinity;
            var maxP    = double.NegativeInfinity; // 最大の確率
            var argmaxP = 0;                       // 最大の確率のときの状態

            for (var stateIndex = 0; stateIndex < maxLogProbabilities.Length; stateIndex++)
            {
                var lp = maxLogProbabilities[stateIndex];
                if (double.IsNegativeInfinity(lp))
                {
                    continue;
                }

                logSum = Special.LogSum(logSum, lp);
                stateLogProbabilities.Add(new KeyValuePair <int, double>(stateIndex, lp));

                if (lp > maxP)
                {
                    maxP    = lp;
                    argmaxP = stateIndex;
                }
            }

            if (stateLogProbabilities.Count == 0)
            {
                throw new Exception("すべての状態の確率が 0 になりました。");
            }

            // 確率が最も高い状態を現在のノートとして認識
            this.CurrentNote = states[argmaxP].Value.ReportingNote;

            // 次の計算のために確率を均しておく
            // 新しい確率 = 確率 / 確率の合計
            for (var i = 0; i < stateLogProbabilities.Count; i++)
            {
                var(stateIndex, lp)      = stateLogProbabilities[i];
                stateLogProbabilities[i] = new KeyValuePair <int, double>(stateIndex, lp - logSum);
            }
        }