locked
learning parameters (Migrated from community.research.microsoft.com) RRS feed

  • Question

  • Lato posted on 02-28-2011 3:44 AM

    Hi!

    I'm a student and i'm trying to build a simply BN. i have 3 node in this configuration: H --->  O  <--- S. Only central one is osservable and i want to learn H,S.

    All nodes are discrete variables and they can respectively adopt the following number of values (Range):

     

    H - two values

    O - six values

    S - six values

     

    I tried to modify your example available at this link http://community.research.microsoft.com/forums/t/6357.aspx, but replacing Dirichlet distribution with Discrete distribution, Visual studio compiler report an error.

     

    Thank you in advance!

     

    Alessandro

    Friday, June 3, 2011 6:36 PM

Answers

  • Lato replied on 03-18-2011 10:28 AM

    thank you very much!

    It works!

    Friday, June 3, 2011 6:38 PM

All replies

  • John Guiver replied on 02-28-2011 5:00 AM

    Hi Alessandro

    So presumably you already know the CTPs. If so, you can encode these as an observed variable (cptVar below) and then use the AddChildFromTwoParents code from the other forum thread. I made up some data for O and for the CPTs below:

        static void Main(string[] args)

        {

          int[] oData = new int[] {0, 3, 4, 2, 3, 1, 5, 0, 2, 3};

          int numData = oData.Length;

          Vector[,] cpt = new Vector[,]

          {

            // h = 0

            {Vector.FromArray(.1, .2, .1, .3, .05, .25),

             Vector.FromArray(.2, .1, .3, .1, .25, .05),

             Vector.FromArray(.1, .2, .1, .3, .05, .25),

             Vector.FromArray(.2, .1, .3, .1, .25, .05),

             Vector.FromArray(.1, .2, .05, .25, .1, .3),

             Vector.FromArray(.2, .1, .25, .05, .3, .1)},

            // h = 1

            {Vector.FromArray(.1, .2, .05, .25, .1, .3),

             Vector.FromArray(.2, .1, .25, .05, .3, .1),

             Vector.FromArray(.05, .25, .1, .2, .1, .3),

             Vector.FromArray(.25, .05, .2, .1, .3, .1),

             Vector.FromArray(.05, .25, .1, .2, .1, .3),

             Vector.FromArray(.25, .05, .2, .1, .3, .1)},

          };

     

          Range h = new Range(2);

          Range o = new Range(6);

          Range s = new Range(6);

          Range d = new Range(numData);

     

          var H = Variable.Array<int>(d);

          var S = Variable.Array<int>(d);

          H[d] = Variable.DiscreteUniform(h).ForEach(d);

          S[d] = Variable.DiscreteUniform(s).ForEach(d);

          var cptVar = Variable.Observed<Vector>(cpt, h, s);

     

          var O = AddChildFromTwoParents(H, S, cptVar);

     

          O.ObservedValue = oData;

          var engine = new InferenceEngine();

          var HPosterior = engine.Infer<Discrete[]>(H);

          var SPosterior = engine.Infer<Discrete[]>(S);

        }

     

    Friday, June 3, 2011 6:36 PM
  • Lato replied on 02-28-2011 9:12 AM

    Dear John,

    thank you for your quick answer. I'd like to infer H and S Marginal only from observed variable O.

    I don't know the CPTs.

    Friday, June 3, 2011 6:36 PM
  • John Guiver replied on 02-28-2011 10:17 AM

    Hi Alessandro

    If you don't know the relationship between (H,S) and O (ie. the CPTs) then you will need to learn that relationship, and for that you need examples. i.e. you will need som (H,S,O) triples. You can then use then model from the other thread. Or perhaps I am misunderstanding your problem.

    John

    Friday, June 3, 2011 6:36 PM
  • Lato replied on 03-02-2011 8:48 AM

    Hi John,
    certainly  I haven't made myself clear, i want to implement a
    generative model. Simplifying i suppose there are 2 node (H and O).
    This is the graphical model representing the structure:

    H ---> O

    I can observe only O node, both are discrete variables,

    I understand i must initialize H and O with a Dirichlet distribution
    (as in LDA Example), so i can turn my graph into Bayesian model.

    This is my code:


    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using MicrosoftResearch.Infer.Models;
    using MicrosoftResearch.Infer.Maths;
    using MicrosoftResearch.Infer.Distributions;
    using MicrosoftResearch.Infer;
    using MicrosoftResearch.Infer.Collections;
    namespace Project1
    {
       // Aliases for distributions over 1-D and 2-D probability tables
       using DirichletArray = DistributionRefArray<Dirichlet, Vector>;

       class Model2
       {
           // Model variables
           public Variable<int> NumCases = Variable.New<int>();
           public VariableArray<int> h;
           public VariableArray<int> o;
           // Probability tables and conditional probability tables
           public Variable<Vector> pt_h;
           public VariableArray<Vector> cpt_o;
           // Prior distributions for the probability tables - make these
    variable so we can
           // change at run-time without model recompilation
           public Variable<Dirichlet> pt_h_prior = null;
           public Variable<DirichletArray> cpt_o_prior = null;
           // Inferred posterior distributions over the probability tables
           public Discrete pt_h_posterior = null;
           public Discrete cpt_o_posterior = null;
           public InferenceEngine InfEngine = new InferenceEngine();
           public void CreateModel(int range_o, int range_h)
           {
               NumCases = Variable.New<int>();
               Range n = new Range(NumCases);
               Range r_o = new Range(range_o);
               Range r_h = new Range(range_h);
               pt_h_prior = Variable.New<Dirichlet>();
               cpt_o_prior = Variable.New<DirichletArray>();
               pt_h = Variable<Vector>.Random(pt_h_prior);
               cpt_o = Variable.Array<Vector>(r_h);
               cpt_o.SetTo(Variable<Vector[]>.Random(cpt_o_prior));
               // Set the value ranges for the probability tables
               pt_h.SetValueRange(r_h);
               cpt_o.SetValueRange(r_o);
               // Describe the structure
               h = Variable.Array<int>(n);
               h[n] = Variable.Discrete(pt_h).ForEach(n);
               o = AddChildFromOneParent(h, cpt_o);
           }

           public void InferParameters(int[] o_data){
               NumCases.ObservedValue = o_data.Length;

               o.ObservedValue = o_data;
               // Set the uniform priors for the probability tables
               int num_o = o.GetValueRange().SizeAsInt;
               int num_h = h.GetValueRange().SizeAsInt;
               Dirichlet[] cpt_O_prior = new Dirichlet[num_h];
               for (int i = 0; i < num_h; i++)
                   cpt_O_prior[i] = Dirichlet.Uniform(num_o);
               pt_h_prior.ObservedValue = Dirichlet.Uniform(num_h);
               cpt_o_prior.ObservedValue =
    (DirichletArray)Distribution<Vector>.Array(cpt_O_prior);
               // Run the inference
               InfEngine.InferAll(pt_h,cpt_o);

               pt_h_posterior = InfEngine.Infer<Discrete>(pt_h);

               Console.ReadLine();
           }

           // Model code for adding a child from a single parent
           public static VariableArray<int>
    AddChildFromOneParent(VariableArray<int> parent, VariableArray<Vector>
    cpt)
           {
               var d = parent.Range;
               // data range
               var child = Variable.Array<int>(d);
               using (Variable.ForEach(d))
               using (Variable.Switch(parent[d]))
                   child[d] = Variable.Discrete(cpt[parent[d]]);
               return child;
           }
       }
    }

     



    i'have a problem during casting Dirichlet variable in Discrete

    Friday, June 3, 2011 6:36 PM
  • minka replied on 03-02-2011 9:03 AM

    The problem is this line:

           pt_h_posterior = InfEngine.Infer<Discrete>(pt_h);

    You meant to say this:

         pt_h_posterior = InfEngine.Infer<Dirichlet>(pt_h);

    because pt_h is a probability table.

    Friday, June 3, 2011 6:37 PM
  • Lato replied on 03-03-2011 4:14 AM

    thank you minka,

    now it works!

    last question, which variable should i print to know probability of  O' state

    Friday, June 3, 2011 6:37 PM
  • minka replied on 03-03-2011 10:50 AM

    If you want the posterior distribution for the CPT for O, you'd say Console.WriteLine(InfEngine.Infer(cpt_o));

    Friday, June 3, 2011 6:37 PM
  • Lato replied on 03-07-2011 4:30 AM

    Hi Minka!

    this is my final corrected code

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using MicrosoftResearch.Infer.Models;

    using MicrosoftResearch.Infer.Maths;

    using MicrosoftResearch.Infer.Distributions;

    using MicrosoftResearch.Infer;

    using MicrosoftResearch.Infer.Collections;

    namespace Project1

    {

       // Aliases for distributions over 1-D and 2-D probability tables

       using DirichletArray = DistributionRefArray<Dirichlet, Vector>;

     

       class Model

       {

           // Model variables

           public Variable<int> NumCases = Variable.New<int>();

           public VariableArray<int> h;

           public VariableArray<int> o;

           // Probability tables and conditional probability tables

           public Variable<Vector> pt_h;

           public VariableArray<Vector> cpt_o;

           // Prior distributions for the probability tables - make thes variable so we can

           // change at run-time without model recompilation

           public Variable<Dirichlet> pt_h_prior = null;

           public Variable<DirichletArray> cpt_o_prior = null;

           // Inferred posterior distributions over the probability tables

           public Dirichlet pt_h_posterior = null;

           public Dirichlet cpt_o_posterior = null;

           public InferenceEngine InfEngine = new InferenceEngine();

           public void CreateModel(int range_o, int range_h)

           {

               InfEngine.Algorithm = new GibbsSampling();

               //InfEngine.Algorithm = new ExpectationPropagation();

               //InfEngine.Algorithm = new VariationalMessagePassing();

               NumCases = Variable.New<int>();

               Range n = new Range(NumCases);

               Range r_o = new Range(range_o);

               Range r_h = new Range(range_h);

               pt_h_prior = Variable.New<Dirichlet>();

               cpt_o_prior = Variable.New<DirichletArray>();

               pt_h = Variable<Vector>.Random(pt_h_prior);

               cpt_o = Variable.Array<Vector>(r_h);

               cpt_o.SetTo(Variable<Vector[]>.Random(cpt_o_prior));

               // Set the value ranges for the probability tables

               pt_h.SetValueRange(r_h);

               cpt_o.SetValueRange(r_o);

               // Describe the structure

               h = Variable.Array<int>(n);

               h[n] = Variable.Discrete(pt_h).ForEach(n);

               o = AddChildFromOneParent(h, cpt_o);

           }

     

           public void InferParameters(int[] o_data){

               NumCases.ObservedValue = o_data.Length;

     

               o.ObservedValue = o_data;

               // Set the uniform priors for the probability tables

               int num_o = o.GetValueRange().SizeAsInt;

               int num_h = h.GetValueRange().SizeAsInt;

               Dirichlet[] cpt_O_prior = new Dirichlet[num_h];

               for (int i = 0; i < num_h; i++)

                   cpt_O_prior[i] = Dirichlet.Uniform(num_o);

               pt_h_prior.ObservedValue = Dirichlet.Uniform(num_h);

               cpt_o_prior.ObservedValue = (DirichletArray)Distribution<Vector>.Array(cpt_O_prior);

               // Run the inference

               InfEngine.InferAll(pt_h,cpt_o);

               pt_h_posterior = InfEngine.Infer<Dirichlet>(pt_h);

               Console.WriteLine(pt_h_posterior);

               Console.WriteLine(InfEngine.Infer(cpt_o));

     

               Console.ReadLine();

           }

     

           // Model code for adding a child from a single parent

           public static VariableArray<int> AddChildFromOneParent(VariableArray<int> parent, VariableArray<Vector>

    cpt)

           {

               var d = parent.Range;

               // data range

               var child = Variable.Array<int>(d);

               using (Variable.ForEach(d))

               using (Variable.Switch(parent[d]))

                   child[d] = Variable.Discrete(cpt[parent[d]]);

               return child;

           }

       }

    }

    Using your suggested code the terminal displays the variable values of Dirichlet 

    (Ex:

    [0] Dirichlet (123, 22, .....)

    [1] Dirichlet (323, 34, ...) 

    ....

    )

    and non the probability of  states

    Friday, June 3, 2011 6:37 PM
  • minka replied on 03-14-2011 11:24 AM

    Is this a question?  Are you unhappy with receiving a Dirichlet posterior distribution over the CPT?

    Friday, June 3, 2011 6:37 PM
  • Lato replied on 03-15-2011 3:52 AM

    I'd like to manage dirichlet's parameters. Can i cast a Dirichlet in  a double array?

    Friday, June 3, 2011 6:37 PM
  • John Guiver replied on 03-15-2011 4:12 AM

    You can get the pseudo-counts from the PseudoCount property of a Dirichlet instance.

    You can get the mean by calling the GetMean() method of a Dirichlet instance.

    Both of these are of type Vector.

    If you want a double array from a Vector, you can call ToArray() on the Vector instance.

    Dirichlet class is documented in http://research.microsoft.com/infernet/codedoc/html/T_MicrosoftResearch_Infer_Distributions_Dirichlet.htm.

    Vector class is documented in http://research.microsoft.com/infernet/codedoc/html/T_MicrosoftResearch_Infer_Maths_Vector.htm.

     

    Friday, June 3, 2011 6:37 PM
  • Lato replied on 03-15-2011 7:48 AM

    thanks John, now i can do my computations.

    regarding my initial problem, i wrote this code:

    using System;

    using System.Collections.Generic;

    using System.Linq;

    using System.Text;

    using MicrosoftResearch.Infer.Models;

    using MicrosoftResearch.Infer.Maths;

    using MicrosoftResearch.Infer.Distributions;

    using MicrosoftResearch.Infer;

    using MicrosoftResearch.Infer.Collections;

    namespace Project1

    {

       // Aliases for distributions over 2-D probability tables

        using DirichletArray2D = DistributionRefArray2D<Dirichlet, Vector>;

     

        class Model3bis

        {

            // Model variables

            public Variable<int> NumCases = Variable.New<int>();

            public VariableArray<int> o;

            public VariableArray<int> h;

            public VariableArray<int> s;

            // Probability tables and conditional probability tables

            public Variable<Vector> PT_H;

            public Variable<Vector> PT_S;

            public VariableArray2D<Vector> CPT_O;

            // Prior distributions for the probability tables - make these variable so we can

            // change at run-time without model recompilation

            public Variable<Dirichlet> PT_H_Prior = null;

            public Variable<Dirichlet> PT_S_Prior = null;

            public Variable<DirichletArray2D> CPT_O_Prior = null;

            // Inferred posterior distributions over the probability tables

            public Dirichlet PT_H_Posterior = null;

            public Dirichlet PT_S_Posterior = null;

            public DirichletArray2D CPT_O_Posterior = null;

            // Inference engine

            public InferenceEngine InfEngine = new InferenceEngine();

     

     

            public void CreateModel(int range_o, int range_h, int range_s){

     

                GibbsSampling g = new GibbsSampling();

                g.DefaultNumberOfIterations = 500;

                //InfEngine.Algorithm = g;

                NumCases = Variable.New<int>(); // Set this at run time

                // The ranges and value ranges

                Range n = new Range(NumCases);

                Range r_o = new Range(range_o);

                Range r_s = new Range(range_s);

                Range r_h = new Range(range_h);

                // Define the priors as variables - these will be set (observed) at run time

                PT_H_Prior = Variable.New<Dirichlet>();

                PT_S_Prior = Variable.New<Dirichlet>();

                CPT_O_Prior = Variable.New<DirichletArray2D>();

                // Probability table and conditional probability table variables (parameters)

                PT_H = Variable<Vector>.Random(PT_H_Prior);

                PT_S = Variable<Vector>.Random(PT_S_Prior);

                CPT_O = Variable.Array<Vector>(r_h, r_s);

                CPT_O.SetTo(Variable<Vector[,]>.Random(CPT_O_Prior));

                // Set the value ranges for the probability tables

                PT_H.SetValueRange(r_h);

                PT_S.SetValueRange(r_s);

                CPT_O.SetValueRange(r_o);

                // Describe the structure

                h = Variable.Array<int>(n);

                h[n] = Variable.Discrete(PT_H).ForEach(n);

                s = Variable.Array<int>(n);

                s[n] = Variable.Discrete(PT_S).ForEach(n);

                o = AddChildFromTwoParents(h, s, CPT_O);   

            }

     

            // Infer the probability tables and conditional probability tables

            public void InferParameters(int[] o_data)

            {

                NumCases.ObservedValue = o_data.Length;

                o.ObservedValue = o_data;

     

                // Set the uniform priors for the probability tables

                int numH = h.GetValueRange().SizeAsInt;

                int numO = o.GetValueRange().SizeAsInt;

                int numS = s.GetValueRange().SizeAsInt;

                Dirichlet[,] cpt_O_Prior = new Dirichlet[numH, numS];

                for (int i = 0; i < numH; i++)

                    for (int j = 0; j < numS; j++)

                        cpt_O_Prior[i, j] = Dirichlet.Uniform(numO);

                PT_H_Prior.ObservedValue = Dirichlet.Uniform(numH);

                PT_S_Prior.ObservedValue = Dirichlet.Uniform(numS);

                CPT_O_Prior.ObservedValue = (DirichletArray2D)Distribution<Vector>.Array(cpt_O_Prior);

                // Run the inference

                InfEngine.InferAll(PT_H, PT_S, CPT_O);

                PT_H_Posterior = InfEngine.Infer<Dirichlet>(PT_H);

                PT_S_Posterior = InfEngine.Infer<Dirichlet>(PT_S);

                CPT_O_Posterior = InfEngine.Infer<DirichletArray2D>(CPT_O);

                Console.WriteLine(PT_H_Posterior);

                Console.WriteLine(PT_S_Posterior);

                Console.WriteLine(CPT_O_Posterior);

            }

            // Model code for adding a child from two parents

            public static VariableArray<int> AddChildFromTwoParents(

              VariableArray<int> parent1, VariableArray<int> parent2, VariableArray2D<Vector> cpt)

            {

                var d = parent1.Range;

                // data range

                var child = Variable.Array<int>(d);

                using (Variable.ForEach(d))

                using (Variable.Switch(parent1[d]))

                using (Variable.Switch(parent2[d]))

                    child[d] = Variable.Discrete(cpt[parent1[d], parent2[d]]);

                return child;

            }

        }

    }

    It's similar  to the one previously posted. i don't understand the run time error. I change O from DirichletArray to DirichletArray2d and add another variable like H

    Friday, June 3, 2011 6:38 PM
  • John Guiver replied on 03-15-2011 11:29 AM

    Can you give me a 'Main' so I can run this. What error are you getting?

    Friday, June 3, 2011 6:38 PM
  • Lato replied on 03-16-2011 4:11 AM

    Ok John,

    I think it's faster send you my project

    http://dl.dropbox.com/u/20337898/Infer.net%20project.zip

    It contains classes, data and a error image.

    thanks

    Friday, June 3, 2011 6:38 PM
  • John Guiver replied on 03-16-2011 9:48 AM

    Hi Alessandro

    Thank you - you have unearthed a bug for 2D distribution arrays using Gibbs sampling. This will be fixed at the the next release. In the meantime you can work around this by using arrays of arrays rather than 2D arrays. Here are examples of the changes you will need to make:

    1. Instead of DirichletArray2D, use instead DirichletArrayArray, defined by:

    using DirichletArrayArray = DistributionRefArray<DistributionRefArray<Dirichlet, Vector>, Vector[]>;

    The posterior of a 2-D CPT will be of this type, and the prior will be a variable over this type.

    2. The CPT variables will be of type:

    public VariableArray<VariableArray<Vector>, Vector[][]>

    and the corresponding definition will be, for example:

    cpt_o1 =

    Variable.Array(Variable.Array<Vector>(r_h1), r_s1);
    cpt_o1.SetTo(Variable<Vector[][]>.Random(cpt_o1_prior));

    3. You need to modify the AddChildFromTwoParents code to accept a jagged array variable:

    // Model code for adding a child from two parents
    public static VariableArray<int> AddChildFromTwoParents(
       
    VariableArray<int> parent1, VariableArray<int> parent2,
        
    VariableArray<VariableArray<Vector>, Vector[][]> cpt)
    {
       
    var d = parent1.Range;
       
    // data range
       
    var child = Variable.Array<int>(d);
       
    using (Variable.ForEach(d))
           
    using (Variable.Switch(parent1[d]))
               
    using (Variable.Switch(parent2[d]))
                    child[d] =
    Variable.Discrete(cpt[parent1[d]][parent2[d]]);
       
    return child;
    }

    4. The CPT priors will have to be set using a jagged .NET array:

    Dirichlet[][] cpt_O1_prior = new Dirichlet[num_s1][];
    for (int i = 0; i < num_s1; i++)
    {
        cpt_O1_prior[i] =
    new Dirichlet[num_h1];
       
    for (int j = 0; j < num_h1; j++)
            cpt_O1_prior[i][j] =
    Dirichlet.Uniform(num_o1);
    }
    cpt_o1_prior.ObservedValue = (DirichletArrayArray)Distribution<Vector>.Array(cpt_O1_prior);

    5. The posterior is cast differently:

    cpt_o1_posterior = InfEngine.Infer<DirichletArrayArray>(cpt_o1);

    John

     

     

    Friday, June 3, 2011 6:38 PM
  • Lato replied on 03-18-2011 10:28 AM

    thank you very much!

    It works!

    Friday, June 3, 2011 6:38 PM