locked
ConstrainEqualRandom and VariableArray (Migrated from community.research.microsoft.com) RRS feed

  • Question

  • amchiclet posted on 03-09-2010 3:30 PM

    I'm building a markov chain of 100 nodes.

    I need to add a bunch of ConstrainEqualRandom calls to each pair of nodes (n, n+1) where n = [0,99).

    The first 4 lines are like this.

                int nodeCount = 100;
                Range rNodeCount = new Range(nodeCount);
                VariableArray<int> nodes = Variable.Array<int>(rNodeCount);
                nodes[rNodeCount] = Variable.DiscreteUniform(3).ForEach(rNodeCount);

    Is there an efficient built-in way for adding constraints to the nodes?

    Friday, June 3, 2011 5:37 PM

Answers

  • John Guiver replied on 03-15-2010 4:14 AM

    A general (though brief) answer to your question is given in the "How can I change the inference schedule?" section in the FAQ. For long chain models, probably the best way to change the schedule is to manually join up the chain using shared variables, or bypass the model compiler altogether and call directly into the message operators with your own schedule. However, I would not revert to these unless you find you are hitting memory or speed limitations with either the rolled-up or unrolled models discussed previously. We've also done a lot of work on generating more efficient schedules which will be available in the next release.

    John

    Friday, June 3, 2011 5:38 PM

All replies

  • John Guiver replied on 03-10-2010 9:29 AM

    There are two ways you can do this - using ranges (as your code starts to do), or using .NET arrays. The model compiler generates unrolled code for the latter and is not very scalable with the number of nodes in terms of length of generated code and compilation speed. I just show the former here as the unrolled version is straightforward. Note that this just implements a homogeneous Markov chain with fixed state transition matrices and no emissions; this model can be extended as necessary to learn transition matrices etc.

    class MarkovChain
    {
      public
    Variable<int> NumNodes = Variable.New<int>();
      public
    Variable<int> NumNodesMinus1 = Variable.New<int>();
      public
    VariableArray<int> PrevIndices;
      public
    VariableArray<int> NextIndices;
      public
    VariableArray<int> Nodes;
      public
    InferenceEngine engine = new InferenceEngine();

      public
    MarkovChain()
      {
        Range n = new
    Range(NumNodes);
        Range n1 = new
    Range(NumNodesMinus1);
        Nodes = Variable.Array<int>(n);
        Nodes[n] = Variable.DiscreteUniform(3).ForEach(n);
        PrevIndices = Variable.Array<int>(n1);
        NextIndices = Variable.Array<int>(n1);
        var
    prev = Variable.Subarray(Nodes, PrevIndices);
        var next = Variable.Subarray(Nodes, NextIndices);
        using (Variable.ForEach(n1))
        {
          using (Variable.Case(prev[n1], 0))
            Variable.ConstrainEqualRandom(next[n1], new
    Discrete(0.1,0.2,0.7));
          using (Variable.Case(prev[n1], 1))
            Variable.ConstrainEqualRandom(next[n1], new
    Discrete(0.5, 0.2, 0.3));
          using (Variable.Case(prev[n1], 2))
            Variable.ConstrainEqualRandom(next[n1], new
    Discrete(0.7, 0.1, 0.2));
        }
      }
      public
    Discrete[] Infer(int numNodes)
      {
        NumNodes.ObservedValue = numNodes;
        int numNodes1 = numNodes-1;
        NumNodesMinus1.ObservedValue = numNodes1;
        int[] prevIndices = new
    int[numNodes1];
        int[] nextIndices = new
    int[numNodes1];
        for (int
    i = 0; i < numNodes1; i++)
        {
          prevIndices[i] = i;
          nextIndices[i] = i+1;
        }
        PrevIndices.ObservedValue = prevIndices;
        NextIndices.ObservedValue = nextIndices;
        return
    engine.Infer<Discrete[]>(Nodes);
      }
    }

    Friday, June 3, 2011 5:37 PM
  • amchiclet replied on 03-10-2010 7:53 PM

    Thank you so much.

    Friday, June 3, 2011 5:37 PM
  • John Guiver replied on 03-11-2010 8:20 AM

    I should add a caveat here. Although the compiler is much more efficient and scalable for the rolled-up version, the runtime performance will almost certainly be less efficient. This is because the node index arrays are set as observed values in the rolled-up version, and the scheduler therefore has no way of knowing in which order to schedule messages. A Markov chain will just need one forward and backward pass, but if the messages are scheduled in arbitrary order, then more iterations will be needed for convergence. So you will need to decide which version is better suited for your application depending on your runtime requirements.

    John

    Friday, June 3, 2011 5:38 PM
  • amchiclet replied on 03-11-2010 1:58 PM

    That's very good to know, John.

    Does Infer.NET currently support overriding the scheduler? That way, programmers can get better compile time without losing optimization opportunities.

    Friday, June 3, 2011 5:38 PM
  • John Guiver replied on 03-15-2010 4:14 AM

    A general (though brief) answer to your question is given in the "How can I change the inference schedule?" section in the FAQ. For long chain models, probably the best way to change the schedule is to manually join up the chain using shared variables, or bypass the model compiler altogether and call directly into the message operators with your own schedule. However, I would not revert to these unless you find you are hitting memory or speed limitations with either the rolled-up or unrolled models discussed previously. We've also done a lot of work on generating more efficient schedules which will be available in the next release.

    John

    Friday, June 3, 2011 5:38 PM