locked
inferring Beta (Migrated from community.research.microsoft.com) RRS feed

  • Question

  • andym posted on 03-04-2011 2:15 PM

    Normal 0 false false false EN-US X-NONE X-NONE

    Hi,

    Thanks for putting together framework with a great potential!

    I am running into a problem trying to run a simple inference -- say I am trying to infer whether the coin is fair. I have somewhat of informative prior from Beta(10,10). My data consist of a single coin toss which lands on “heads.” My posterior should be Beta(10+1,10), the mean of which is (1+10)/(1+20) == 11/21 == 0.5238.

    Using (most probably incorrectly) infer.net I am getting mean of posterior of 0.5. Please let me know what is wrong

                Variable<double> theta = Variable.Beta(10, 10).Named("theta");

                var toss1 = Variable.Bernoulli(theta);

                toss1 = Variable.Observed(true);

                Console.WriteLine("posterior=" + (float)m_engine.Infer<Beta>(theta).GetMean());

    Thanks!

    Friday, June 3, 2011 6:30 PM

Answers

  • andym replied on 03-08-2011 11:41 AM

    Thank you for the reply!

    Normal 0 false false false EN-US X-NONE X-NONE

    I have spent some time over the weekend learning the framework. Looking at code samples I admired how easy it is to implement a model for otherwise complex network, yet I was running into difficulties when I tried to implement even the simplest models in infer.net. The problem appears to stem from the “nonlinear” translation of graphical model into the infer.net syntax. I think the framework would greatly benefit the initial adoption by having a set of wrappers which would make construction of Bayesian nets reflective of the underlying graph structure. (the best analogy I could think of is STL for C++ where it alleviates the need for construction of most commonly used data structures).

    Let me illustrate – for the purpose of learning infer.net I have decided to implement a simple 3 variable battery/gauge/tank model described in Bishop’s book page 377. My expectation of the pseudo-code for syntax for the model that builds graph and sets CPDs was something like this:

                var battery = new RandomVariable<Bernoulli>(); battery.Probability = 0.9;

                var fuel = new RandomVariable<Bernoulli>(); fuel.Probability = 0.9;

                var gauge = new RandomVariable<Bernoulli>();           

                double[][] cpt =

                {

                    new double[] { 0.8, 0.2 },

                    new double[] { 0.2, 0.1 }

                };

     

                gauge.EdgeFrom(new Vertice[] { battery, fuel }, cpt);

                gauge.ObservedValue = true;

               

               

    The first 3 lines in infer.net were spot on (and I was very happy to see type safety)

                Variable<bool> battery = Variable.Bernoulli(0.9); // b=1 -- charged

                Variable<bool> fuel = Variable.Bernoulli(0.9);    // f=1 -- full tank

                Variable<bool> gauge = Variable.New<bool>();      // g=1 -- gauge says tank is full

                double[][] cpt = {

                                    new double[] { 0.8, 0.2 },

                                    new double[] { 0.2, 0.1 },

                                  };

    Not so for the connecting edges and setting up the CPT. I had to look it up (and “how do I setup CPT” appears to be an often asked question on the forum). The code below sets the CPT but there’s no concept of “edge” connecting variables and no concept of “table” that specifies distribution:

                using (Variable.If(battery))

                {

                    using (Variable.If(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[0][0])); }

                    using (Variable.IfNot(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[0][1])); }

                }

     

                using (Variable.IfNot(battery))

                {

                    using (Variable.If(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[1][0])); }

                    using (Variable.IfNot(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[1][1])); }

                }

    To put it other way, Bishop (and others) in their books could have chosen to specify topologies by cascading IFs instead of graph as well but doing so loses descriptiveness. The other problem here is that adding extra edge this way (think of adding auxiliary battery random variable) causes large churn to IF statements layout as one has to roll more IFs, where program statements are co-mingled with model parameters, while with graph approach most changes are to data localized in one spot (change to the array).

    Next I have attempted to replace Bernoulli distribution with equivalent Discrete distribution. The change to declaration was straightforward:

    Variable<int> battery = Variable.Discrete(new double[] { 0.9, 0.1 });

    Variable<int> fuel = Variable.Discrete(new double[] { 0.9, 0.1 });                    Variable<int> gauge = Variable.New<int>();                            

     

    Next we replace Variable.If with Variable.Switch. The trick is in figuring out what goes inside – all the samples show that only random variable can be indexed inside the switch by switch parameter thus it seems like I should need a random variable array for my CPT (while CPT does not consists of random variables)

              using (Variable.Switch(battery))

              {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(/* how to index my cpt here? */));

                        }

              }

    Puzzled, I turn to search on forum and code-up the solution below. Note that my model has only 3 random variables but in order to accommodate Switch() semantics I have to declare 4 more random variables which go into array and represent the CPT. The next iteration of my solution looks as following:

                    Vector[,] vcpt =

                    {

                        { Vector.FromArray(new double[] { 1-cpt[1][1], cpt[1][1] })

                            , Vector.FromArray(new double[] { 1-cpt[1][0], cpt[1][0] } ) }

                          ,{ Vector.FromArray(new double[] { 1-cpt[0][1], cpt[0][1] })

                            , Vector.FromArray(new double[] { 1-cpt[0][0], cpt[0][0] } ) }

                    };

     

                    Range batteryRange = new Range(vcpt.GetLength(0));

                    Range fuelRange = new Range(vcpt.GetLength(1));

                    var rndcpt = Variable.Array<Vector>(batteryRange, fuelRange);

                    rndcpt.ObservedValue = vcpt;

     

                    using (Variable.Switch(battery))

                    {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(rndcpt[battery, fuel]));                       

                        }

                    }

     

    The model fails to compile with an error indicating that switch parameter needs a range. Looking through docs I find a constructor that takes a range and modify my code as below which finally works:

                    Vector[,] vcpt =

                    {

                        { Vector.FromArray(new double[] { 1-cpt[1][1], cpt[1][1] })

                            , Vector.FromArray(new double[] { 1-cpt[1][0], cpt[1][0] } ) }

                          ,{ Vector.FromArray(new double[] { 1-cpt[0][1], cpt[0][1] })

                            , Vector.FromArray(new double[] { 1-cpt[0][0], cpt[0][0] } ) }

                    };

     

                    Range batteryRange = new Range(vcpt.GetLength(0));

                    Range fuelRange = new Range(vcpt.GetLength(1));  

                    var rndcpt = Variable.Array<Vector>(batteryRange, fuelRange);

                    rndcpt.ObservedValue = vcpt;

     

                    Variable<int> battery = Variable.Discrete(batteryRange, new double[] { 1-0.9, 0.9 }); 

                    Variable<int> fuel = Variable.Discrete(fuelRange, new double[] { 1-0.9, 0.9 });    

                    Variable<int> gauge = Variable.New<int>();

     

                    using (Variable.Switch(battery))

                    {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(rndcpt[battery, fuel]));

                        }

                    }

     

    My observation is that in most cases changing type Boolean to Integer is a simple global search and replace through the code. Change from Bernoulli to equivalent 2-state Discrete by no means is a straightforward replacement -- first, we introduce 4 random variables which seem to have nothing to do with the model but are needed to configure CPT, then we need to use a range for switch, and lastly we need to change the declaration order where we declare CPT first so we can declare variables based on ranges used in CPT. We have to do that while we made absolutely no change to the neither the topology of the model nor the underlying distribution. On the other hand, if I were to use my naïve pseudo-code I’d type the following:

                var battery = new RandomVariable<Discrete>();

                battery.Probability = new double[] { 0.9 };

                var fuel = new RandomVariable<Discrete>();

                fuel.Probability = new double[] { 0.9 };

                var gauge = new RandomVariable<Discrete>();           

                double[][] cpt =

                {

                    new double[] { 0.8, 0.2 },

                    new double[] { 0.2, 0.1 }

                };

     

                gauge.EdgeFrom(new Vertice[] { battery, fuel }, cpt);

                gauge.ObservedValue = true;

     

    I hope my comments are taken in constructive way as I think other will benefit from my learning experience and the APIs framework exposes can be made easier to use.

    Thanks!

    -- Andy

    Friday, June 3, 2011 6:31 PM

All replies

  • minka replied on 03-07-2011 3:43 AM

    The second assignment to toss1 destroys the first assignment.  Instead you want to write:  toss1.ObservedValue = true;

    Friday, June 3, 2011 6:30 PM
  • andym replied on 03-07-2011 9:53 AM

    Normal 0 false false false EN-US X-NONE X-NONE

    Great, thanks (I have noticed that toss1.ObservedValue  = true; fixes the problem as well, but couldn’t reply right away as posts need to be approved first)

    There seems to be a difference between the treatment of Variable and VariableArray as far as setting observed value goes. For example using assignment to Variable.Observed first works just fine with variable array:

                 Variable<double> theta = Variable.Beta(10, 10).Named("theta");           

                VariableArray<bool> tosses = Variable.Observed(new bool[] { true });

                Range r = tosses.Range;

                using (Variable.ForEach(r))

                {

                    tosses[r] = Variable.Bernoulli(theta);

                }           

                Console.WriteLine("p(theta|d)=" + (float)m_engine.Infer<Beta>(theta).GetMean());

    Changing model from array to a single variable seems to require a change to layout of the program as the sample below where the operations are carried in the same order as above does not work.

       Variable<double> theta = Variable.Beta(10, 10).Named("theta");

                Variable<bool> toss1 = Variable.Observed(true);           

                toss1 = Variable.Bernoulli(theta);

                Console.WriteLine("p(theta|d)=" + (float)m_engine.Infer<Beta>(theta).GetMean());

    More generally, it seems that for the Variable type one has to connect model edges first and then set the observed data, while for VariableArray the model construction should be done in opposite order – setting data first and then connecting edges, no?

    Friday, June 3, 2011 6:30 PM
  • minka replied on 03-08-2011 6:40 AM

    Actually ObservedValue works for arrays too:

                      Variable<double> theta = Variable.Beta(10, 10).Named("theta");

                      Range r = new Range(1);

                      VariableArray<bool> tosses = Variable.Array<bool>(r).Named("tosses");

                      using (Variable.ForEach(r)) {

                            tosses[r] = Variable.Bernoulli(theta);

                      }

                      tosses.ObservedValue = new bool[] { true };

                      InferenceEngine engine = new InferenceEngine();

                      Console.WriteLine("p(theta|d)=" + engine.Infer<Beta>(theta).GetMean());

     

    Friday, June 3, 2011 6:30 PM
  • andym replied on 03-08-2011 11:41 AM

    Thank you for the reply!

    Normal 0 false false false EN-US X-NONE X-NONE

    I have spent some time over the weekend learning the framework. Looking at code samples I admired how easy it is to implement a model for otherwise complex network, yet I was running into difficulties when I tried to implement even the simplest models in infer.net. The problem appears to stem from the “nonlinear” translation of graphical model into the infer.net syntax. I think the framework would greatly benefit the initial adoption by having a set of wrappers which would make construction of Bayesian nets reflective of the underlying graph structure. (the best analogy I could think of is STL for C++ where it alleviates the need for construction of most commonly used data structures).

    Let me illustrate – for the purpose of learning infer.net I have decided to implement a simple 3 variable battery/gauge/tank model described in Bishop’s book page 377. My expectation of the pseudo-code for syntax for the model that builds graph and sets CPDs was something like this:

                var battery = new RandomVariable<Bernoulli>(); battery.Probability = 0.9;

                var fuel = new RandomVariable<Bernoulli>(); fuel.Probability = 0.9;

                var gauge = new RandomVariable<Bernoulli>();           

                double[][] cpt =

                {

                    new double[] { 0.8, 0.2 },

                    new double[] { 0.2, 0.1 }

                };

     

                gauge.EdgeFrom(new Vertice[] { battery, fuel }, cpt);

                gauge.ObservedValue = true;

               

               

    The first 3 lines in infer.net were spot on (and I was very happy to see type safety)

                Variable<bool> battery = Variable.Bernoulli(0.9); // b=1 -- charged

                Variable<bool> fuel = Variable.Bernoulli(0.9);    // f=1 -- full tank

                Variable<bool> gauge = Variable.New<bool>();      // g=1 -- gauge says tank is full

                double[][] cpt = {

                                    new double[] { 0.8, 0.2 },

                                    new double[] { 0.2, 0.1 },

                                  };

    Not so for the connecting edges and setting up the CPT. I had to look it up (and “how do I setup CPT” appears to be an often asked question on the forum). The code below sets the CPT but there’s no concept of “edge” connecting variables and no concept of “table” that specifies distribution:

                using (Variable.If(battery))

                {

                    using (Variable.If(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[0][0])); }

                    using (Variable.IfNot(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[0][1])); }

                }

     

                using (Variable.IfNot(battery))

                {

                    using (Variable.If(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[1][0])); }

                    using (Variable.IfNot(fuel)) { gauge.SetTo(Variable.Bernoulli(cpt[1][1])); }

                }

    To put it other way, Bishop (and others) in their books could have chosen to specify topologies by cascading IFs instead of graph as well but doing so loses descriptiveness. The other problem here is that adding extra edge this way (think of adding auxiliary battery random variable) causes large churn to IF statements layout as one has to roll more IFs, where program statements are co-mingled with model parameters, while with graph approach most changes are to data localized in one spot (change to the array).

    Next I have attempted to replace Bernoulli distribution with equivalent Discrete distribution. The change to declaration was straightforward:

    Variable<int> battery = Variable.Discrete(new double[] { 0.9, 0.1 });

    Variable<int> fuel = Variable.Discrete(new double[] { 0.9, 0.1 });                    Variable<int> gauge = Variable.New<int>();                            

     

    Next we replace Variable.If with Variable.Switch. The trick is in figuring out what goes inside – all the samples show that only random variable can be indexed inside the switch by switch parameter thus it seems like I should need a random variable array for my CPT (while CPT does not consists of random variables)

              using (Variable.Switch(battery))

              {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(/* how to index my cpt here? */));

                        }

              }

    Puzzled, I turn to search on forum and code-up the solution below. Note that my model has only 3 random variables but in order to accommodate Switch() semantics I have to declare 4 more random variables which go into array and represent the CPT. The next iteration of my solution looks as following:

                    Vector[,] vcpt =

                    {

                        { Vector.FromArray(new double[] { 1-cpt[1][1], cpt[1][1] })

                            , Vector.FromArray(new double[] { 1-cpt[1][0], cpt[1][0] } ) }

                          ,{ Vector.FromArray(new double[] { 1-cpt[0][1], cpt[0][1] })

                            , Vector.FromArray(new double[] { 1-cpt[0][0], cpt[0][0] } ) }

                    };

     

                    Range batteryRange = new Range(vcpt.GetLength(0));

                    Range fuelRange = new Range(vcpt.GetLength(1));

                    var rndcpt = Variable.Array<Vector>(batteryRange, fuelRange);

                    rndcpt.ObservedValue = vcpt;

     

                    using (Variable.Switch(battery))

                    {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(rndcpt[battery, fuel]));                       

                        }

                    }

     

    The model fails to compile with an error indicating that switch parameter needs a range. Looking through docs I find a constructor that takes a range and modify my code as below which finally works:

                    Vector[,] vcpt =

                    {

                        { Vector.FromArray(new double[] { 1-cpt[1][1], cpt[1][1] })

                            , Vector.FromArray(new double[] { 1-cpt[1][0], cpt[1][0] } ) }

                          ,{ Vector.FromArray(new double[] { 1-cpt[0][1], cpt[0][1] })

                            , Vector.FromArray(new double[] { 1-cpt[0][0], cpt[0][0] } ) }

                    };

     

                    Range batteryRange = new Range(vcpt.GetLength(0));

                    Range fuelRange = new Range(vcpt.GetLength(1));  

                    var rndcpt = Variable.Array<Vector>(batteryRange, fuelRange);

                    rndcpt.ObservedValue = vcpt;

     

                    Variable<int> battery = Variable.Discrete(batteryRange, new double[] { 1-0.9, 0.9 }); 

                    Variable<int> fuel = Variable.Discrete(fuelRange, new double[] { 1-0.9, 0.9 });    

                    Variable<int> gauge = Variable.New<int>();

     

                    using (Variable.Switch(battery))

                    {

                        using (Variable.Switch(fuel))

                        {

                            gauge.SetTo(Variable.Discrete(rndcpt[battery, fuel]));

                        }

                    }

     

    My observation is that in most cases changing type Boolean to Integer is a simple global search and replace through the code. Change from Bernoulli to equivalent 2-state Discrete by no means is a straightforward replacement -- first, we introduce 4 random variables which seem to have nothing to do with the model but are needed to configure CPT, then we need to use a range for switch, and lastly we need to change the declaration order where we declare CPT first so we can declare variables based on ranges used in CPT. We have to do that while we made absolutely no change to the neither the topology of the model nor the underlying distribution. On the other hand, if I were to use my naïve pseudo-code I’d type the following:

                var battery = new RandomVariable<Discrete>();

                battery.Probability = new double[] { 0.9 };

                var fuel = new RandomVariable<Discrete>();

                fuel.Probability = new double[] { 0.9 };

                var gauge = new RandomVariable<Discrete>();           

                double[][] cpt =

                {

                    new double[] { 0.8, 0.2 },

                    new double[] { 0.2, 0.1 }

                };

     

                gauge.EdgeFrom(new Vertice[] { battery, fuel }, cpt);

                gauge.ObservedValue = true;

     

    I hope my comments are taken in constructive way as I think other will benefit from my learning experience and the APIs framework exposes can be made easier to use.

    Thanks!

    -- Andy

    Friday, June 3, 2011 6:31 PM