locked
Why doesn't my simple HMM implementation work?

    Question

  • Hi,

    I tried to implement a simple HMM model, but it kept generating crazy errors like "y1 has no definition". I think I defined y1 in the using block. What have I done wrong?

    Thank you.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MicrosoftResearch.Infer.Models;
    using MicrosoftResearch.Infer;
    using MicrosoftResearch.Infer.Distributions;
    using MicrosoftResearch.Infer.Maths;

    namespace HMM { class Program { static void Main(string[] args) { int nHidden = 4; int nObserved = 4; Range rHidden = new Range(nHidden).Named("rHidden"); Range rObserved = new Range(nObserved).Named("rObserved"); Vector alpha = Vector.Constant(nHidden, 1.0); Vector theta = Vector.Constant(nObserved, 1.0); Variable<Vector> pi = Variable.Dirichlet(alpha).Named("pi"); VariableArray<Vector> transition = Variable.Array<Vector>(rHidden).Named("transition"); transition[rHidden] = Variable<Vector>.Dirichlet(alpha).ForEach(rHidden).Named("transition_"+rHidden); VariableArray<Vector> emition = Variable.Array<Vector>(rHidden); emition[rHidden] = Variable<Vector>.Dirichlet(theta).ForEach(rHidden).Named("emition_" + rHidden); Dirichlet[] zinit = new Dirichlet[nHidden]; for (int i = 0; i < zinit.Length; i++) { double[] point = new double[nObserved]; for (int j = 0; j < nObserved; j++) { point[j] = Rand.Double(); } zinit[i] = Dirichlet.PointMass(point); } emition.InitialiseTo(Distribution<Vector>.Array(zinit)); int[] data = new int[] { 1, 2, 3, 4, 1, 2, 3, 4, 1, 2, 3, 4 }; int N = data.Length; Range rN = new Range(N); VariableArray<int> y = Variable.Array<int>(rN).Named("y"); VariableArray<int> x = Variable.Array<int>(rN).Named("x"); y[0] = Variable.Discrete(pi).Named("y_0"); for (int i = 1; i < N; ++i) { y[i] = Variable.New<int>().Named("y" + i); for (int j = 0; j < nHidden; j++) { using (Variable.Case(y[i - 1], j)) { y[i].SetTo(Variable.Discrete(transition[j])); } } } for (int i = 0; i < N; ++i) { x[i] = Variable.New<int>().Named("x" + i); for (int j = 0; j < nHidden; j++) { using (Variable.Case(y[i], j)) { x[i].SetTo(Variable.Discrete(emition[j])); } } } x.ObservedValue = data; for (int i = 0; i < N; i++) Console.WriteLine(y[i].ToString()); InferenceEngine ie = new InferenceEngine(); ie.Infer(y); for (int i = 0; i < N; i++) { Console.WriteLine(ie.Infer(y[i])); } } } }



    • Edited by piiswrong Tuesday, August 28, 2012 2:30 AM
    Tuesday, August 28, 2012 2:29 AM

Answers

All replies

  • There are a number of issues, but the initial one is x and y need to be arrays of random variables (of type Variable<int>[]) rather than random variable arrays (of type VariableArray<int>). Here is an implementation of your example.

    John

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MicrosoftResearch.Infer.Models;
    using MicrosoftResearch.Infer;
    using MicrosoftResearch.Infer.Distributions;
    using MicrosoftResearch.Infer.Maths;
    
    namespace HMM
    {
      class Program
      {
        static void Main(string[] args)
        {
          int nHidden = 4;
          int nObserved = 4;
          Range rHidden = new Range(nHidden).Named("rHidden");
          Range rObserved = new Range(nObserved).Named("rObserved");
          double alpha = 0.1;
          double theta = 0.1;
    
          Variable<Vector> pi = Variable.DirichletSymmetric(rHidden, alpha).Named("pi");
    
          VariableArray<Vector> transition = Variable.Array<Vector>(rHidden).Named("transition");
          transition[rHidden] = Variable<Vector>.DirichletSymmetric(rHidden, alpha).ForEach(rHidden);
    
          VariableArray<Vector> emition = Variable.Array<Vector>(rHidden).Named("emition"); ;
          emition[rHidden] = Variable<Vector>.DirichletSymmetric(rObserved, theta).ForEach(rHidden);
    
          int[] data = new int[] { 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 };
          int N = data.Length;
    
          Variable<int>[] y = new Variable<int>[N];
          Variable<int>[] x = new Variable<int>[N];
    
          for (int i = 0; i < N; ++i)
          {
            y[i] = Variable.New<int>().Named("y_" + i);
            y[i].SetValueRange(rHidden);
            x[i] = Variable.New<int>().Named("x_" + i);
            x[i].SetValueRange(rObserved);
          }      
          
          y[0].SetTo(Variable.Discrete(pi));
    
          for (int i = 1; i < N; ++i)
          {
            using (Variable.Switch(y[i-1]))
            {
              y[i].SetTo(Variable.Discrete(transition[y[i-1]]));
            }
          }
    
          for (int i = 0; i < N; ++i)
          {
            using (Variable.Switch(y[i]))
            {
              x[i].SetTo(Variable.Discrete(emition[y[i]]));
            }
          }
    
          // Break symmetry
          int[] randInt = Rand.Perm(nHidden);
          for (int i = 0; i < nHidden && i < N; ++i)
          {
            y[i].InitialiseTo(Discrete.PointMass(randInt[i], nHidden));
          }
    
          for (int i = 0; i < N; ++i)
          {
            x[i].ObservedValue = data[i];
          }
    
          InferenceEngine ie = new InferenceEngine(new VariationalMessagePassing());
    
          var tpost = ie.Infer<Dirichlet[]>(transition);
    
          for (int i = 0; i < N; i++)
          {
            Console.WriteLine("y[{0}] ~ {1}", i, ie.Infer<Discrete>(y[i]).ToString("0.00"));
          }
    
          Console.WriteLine("\nMean of transion matrix =");
          var transitionPost = ie.Infer<Dirichlet[]>(transition);
          for (int i = 0; i < nHidden; i++)
            Console.WriteLine(transitionPost[i].GetMean().ToString("0.00"));
    
          Console.WriteLine("\nMean of emission matrix =");
          var emissionPost = ie.Infer<Dirichlet[]>(emition);
          for (int i = 0; i < nHidden; i++)
            Console.WriteLine(emissionPost[i].GetMean().ToString("0.00"));
        }
      }
    }
    

    Thursday, August 30, 2012 2:10 PM
    Owner
  • Hi

    Can you please explain why x and y need to be arrays of random variables? What is the difference if they are random variable arrays?

    Thanks.

    Monday, August 11, 2014 1:21 PM
  • They can be VariableArrays, but the original code was using statements like:

    y[i] = Variable.New<int>().Named("y" + i);
    

    which are not compatible with VariableArrays.

    • Proposed as answer by RazinR Tuesday, August 12, 2014 7:32 AM
    Monday, August 11, 2014 2:57 PM
    Owner
  • We can't reference a VariableArray's elements with int indexes you mean?

    For example in y array above, can I write something like this?

    for(i=0; i<y.length; i++) {

            y[i] = y[i-1] * w;

    }

    Tuesday, August 12, 2014 9:21 AM
  • Please take a look at this page of the User Guide.
    Tuesday, August 12, 2014 10:24 AM
  • it is a dead link.. :/
    Friday, November 2, 2018 4:18 AM