Answered by:
learning parameters (Migrated from community.research.microsoft.com)

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!
- Marked as answer by Microsoft Research Friday, June 3, 2011 6:38 PM
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 DiscreteFriday, 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!
- Marked as answer by Microsoft Research Friday, June 3, 2011 6:38 PM
Friday, June 3, 2011 6:38 PM