locked
Example of Bayesian network (Migrated from community.research.microsoft.com)

    Question

  • Matthis posted on 12-17-2008 9:35 AM

    Hi everybody,

    could anyone provide an simple example how to build a Bayesian network with Infer.NET, e.g. chest clinic?

    Regards

    P. Matthis 

    Friday, June 3, 2011 5:43 PM
    Owner

Answers

All replies

  • jwinn replied on 12-18-2008 10:50 AM

    Below is the C# code for the classic wet grass/sprinkler/rain Bayesian network, as found in Kevin Murphy's tutorial, amongst other places.  Notice that the conditional probability tables (CPTs) are represented by if blocks or nested if blocks, rather than in tabular form.  In general, this allows any structure in the CPTs to be explicitly represented, which can often be exploited to make inference faster and/or more accurate.

    To perform parameter learning in a discrete Bayesian network of this form, create a double random variable with a Beta prior and use it instead of the constants in any of the Variable.Bernoulli() calls.

    // cloudy

    Variable<bool> cloudy = Variable.Bernoulli(0.5);

    // sprinkler
    Variable <bool> sprinkler = Variable.New<bool>();
    using (Variable.If(cloudy)) sprinkler.SetTo(Variable.Bernoulli(0.1));
    using (Variable.IfNot(cloudy)) sprinkler.SetTo(Variable.Bernoulli(0.5));
    // rain
    Variable <bool> rain = Variable.New<bool>();
    using (Variable.If(cloudy)) rain.SetTo(Variable.Bernoulli(0.8));
    using (Variable.IfNot(cloudy)) rain.SetTo(Variable.Bernoulli(0.2));
    // wet grass
    Variable <bool> wetGrass = Variable.New<bool>();
    using (Variable.If(sprinkler)) {
          using (Variable.If(rain)) wetGrass.SetTo(Variable.Bernoulli(0.99));
          using (Variable.IfNot(rain)) wetGrass.SetTo(Variable.Bernoulli(0.9));
    }
    using (Variable.IfNot(sprinkler)) {
          using (Variable.If(rain)) wetGrass.SetTo(Variable.Bernoulli(0.9));
          using (Variable.IfNot(rain)) wetGrass.SetTo(Variable.Bernoulli(0.0));
    }  
    // Observations and inference
    wetGrass.ObservedValue = true;
    InferenceEngine ie = new InferenceEngine();
    ie.ShowProgress= false;
    Console .WriteLine("P(rain      | grass is wet)="+ie.Infer(rain));
    Console .WriteLine("P(sprinkler | grass is wet)="+ie.Infer(sprinkler));
    cloudy.ObservedValue = false;
    Console .WriteLine("P(rain      | grass is wet, not cloudy)="+ie.Infer(rain));
    Console .WriteLine("P(sprinkler | grass is wet, not cloudy)="+ie.Infer(sprinkler));

    The first part of the code defines the Bayesian network. The second part applies the default algorithm, expectation propagation, to the model, which in this case is equivalent to loopy belief propagation.  We compute the posterior marginals for rain and sprinkler given that the grass is wet and then given that both the grass is wet and it is not cloudy.

    Note that EP is an approximate algorithm in graphs with loops, like this one.  Infer.NET is designed for approximate inference in large graphs - there are already many packages that can apply junction tree methods to get exact inference in small graphs.  In this case, the first two answers are in a loopy graph and the second two are in a non-loopy graph (the observation on cloudy breaks the loop) and so the second two answers are exact whilst the first are approximate.  The code prints out: 

    P(rain      | grass is wet)=Bernoulli(0.7841)
    P(sprinkler | grass is wet)=Bernoulli(0.404)
    P(rain      | grass is wet, not cloudy)=Bernoulli(0.3443)
    P(sprinkler | grass is wet, not cloudy)=Bernoulli(0.8361)

    Best, John

    • Proposed as answer by John Winn Wednesday, May 16, 2012 10:38 AM
    Friday, June 3, 2011 5:44 PM
    Owner
  • Matthis replied on 12-18-2008 12:07 PM

    Thank you, John!

    I am working in a bank project and we try to apply Bayesian networks to portfolio risk analyses and estimations, we have rather large networks with flat structure (only few loops). We would like to read in networks from databases or flat files and look for sound tools for inference and simulation. Are there methods in Infer.Net to read networks, e.g. in HUGIN/ or dne-format? Intend you to implement importance sampling?

    Best Regards

    Peter

     

    Friday, June 3, 2011 5:44 PM
    Owner
  • jwinn replied on 12-19-2008 5:21 AM

    Hi Peter,

    In designing Infer.NET we decided to focus on the inference engine itself rather than on I/O or on making a GUI.  It should be straightforward to write code to read in a database or file in whatever format you are using and construct a model using the Infer.NET modelling API. 

    We are looking to implement some form of sampling in a future release - it is most likely that we will start with Gibbs sampling.  However, you may be able to use Infer.NET as a subroutine in an importance sampler e.g. using the EP posterior as the proposal distribution.  Bear in mind that importance sampling does not work well unless the proposal distribution is close to the true distribution - and this becomes increasingly important as the dimensionality of your problem increases (see section 29.2 of Information Theory, Inference and Learning Algorithms by David MacKay for a discussion of the weaknesses of importance sampling).

    Best,
    John

    Friday, June 3, 2011 5:44 PM
    Owner
  • Sean Stromsten replied on 01-21-2009 11:14 PM

    For those of us who aren't familiar with c# and .net., and do not have visual studio, this familiar example would be a good one to use for an excruciatingly detailed walk-through of building and using a model.  What  *exactly* goes into the source file (including imports, etc.)?  How do I compile?  How do I run?  I can't find quite enough detail in the tutorials to get started from my current (low) level. 

     I've had some success with VIBES, so I have high hopes for infer.net--thanks for making this!

    Friday, June 3, 2011 5:44 PM
    Owner
  • minka replied on 01-22-2009 12:08 PM

    Sure, I can provide some more detail.  When you installed Infer.NET, it created a folder "My Documents\Infer.NET 2.2".  In this folder you can find "bin\Debug" as well as "Example Solutions\SimpleGaussian\Program.cs".  This file has the complete set of imports and definitions you need.  You can delete the entire contents of Main and replace with the code John sent above.  To compile, you need to link Program.cs with two Infer.NET dlls which are located in the "bin\Debug" folder mentioned above.  The dlls are Infer.Compiler.dll and Infer.Runtime.dll.  This is done automatically by Visual Studio when the SimpleGaussian.sln solution file is opened.

    Friday, June 3, 2011 5:44 PM
    Owner
  • jwinn replied on 01-22-2009 1:57 PM

    And note that, if you don't have Visual Studio, you can download the C# Express Edition for free.

    Friday, June 3, 2011 5:44 PM
    Owner
  • Sean Stromsten replied on 01-23-2009 1:28 PM

    I hope other c#/.net beginners might benefit from a summary of my adventures so far...

     

    If you want to compile at the command line:

    1. You need to add the directory where csc.exe (c# compiler) lives to your path.  Mine was in "C:\WINDOWS\Microsoft.NET\Framework\v3.5".

    2. To compile, you have to link to "Infer.Compiler" and "Infer.Runtime", which are both in "infer.NET 2.2\bin\Debug" (thanks, Tom).

    3. The obvious compile fails:

    >csc program.cs /r:..\..\bin\Debug\Infer.Compiler.dll /r:..\..\bin\Debug\Infer.Runtime.dll

    Actually, compiling finishes without protest, but the executable fails with a "System.IO.FileNotFoundException" re. Infer.Compiler.  Is there some environment variable or read permission I have to fix?

    4. As a temporary fix, until a c# expert is handy, I moved the source file to the bin\Debug\ directory, and compiled it there.  The executable then ran just fine.




    To use Visual C# 2008 Express Edition (thanks, John), this sequence seems to work:

    1. Make sure you have a sandwich and a good book before starting VS install.

    2. Once you've got VS open, make/name a new project ("File -> New Project...").

    3. Go to "Project -> Add Existing Item..." to add an existing source file (e.g., program.cs).

    4. Go to "Project -> Add Reference..." to link the files "Infer.Compiler" and "Infer.Runtime" in "bin\Debug".

    5. Go to "Build -> Build Solution" to compile.

    6. Go to "Debug -> Start Without Debugging" to double-check that it runs.

    7. Save the project. The executable is named after the project, not the source file, and lives a couple of directories deep in the project's tree, in \bin\Release.

    Friday, June 3, 2011 5:44 PM
    Owner
  • xyc replied on 03-04-2009 8:33 PM

    Hi all,

    I need to extend my Bayesian Network (which is similar to this Sprinkler example) to include training data, how can I load data using Infer.Net?  A simple example would be most helpful.

    Thanks,
    xyc

    Friday, June 3, 2011 5:44 PM
    Owner
  • jwinn replied on 03-05-2009 4:39 AM

    Infer.NET does not provide built-in routines for loading data. Because it is called from within a .NET language (e.g. C#) you just load the data using .NET routines of your own and attach it to the model by setting the ObservedValue of the corresponding variable.  Note that .NET has a lot of support for reading data from files or from databases.  For example if you have a VariableArray<double> in your model called x, then you load in an ordinary .NET double array using a custom C# routine and attach it to the model using x.ObservedValue = MyDoubleArray.

    Best,

    John W.

    Friday, June 3, 2011 5:44 PM
    Owner
  • xyc replied on 03-11-2009 5:40 AM

    Thanks for the reply John.

    On another note, I'm trying to model the following network - worked example 3 from the link: http://controls.engin.umich.edu/wiki/index.php/Bayesian_network_theory#Worked_out_Example_3.

    Is there a clean way in Infer.NET to answer the question:

    What is the probability that a person will develop a blood clot as a result of both medication and trauma, and then have no medical implications?

    The answer is of course:  P(N, BC, M, T) = P(N | BC) P(BC | M, T) P(M) P(T) = (0.25) (0.95) (0.2) (0.05) = 0.2375%, but I have been unable to generate this chain without explicitly
    specifying the conditionals directly. Is there some clean way of infering P(N,BC,M,T) as listed?

    The code below shows the network setup and a related run to infer bloodClot and Nothing when the medication and trauma are observed.

    Thanks,
    xyc

    public void Run() {

        Variable<bool> medication = Variable.Bernoulli(0.2).Named("medication");

        Variable<bool> trauma = Variable.Bernoulli(0.05).Named("trauma");

        Variable<bool> bloodClot = Variable.New<bool>().Named("bloodClot");

        Variable<bool> heartAttack = Variable.New<bool>().Named("heartAttack");

        Variable<bool> nothing = Variable.New<bool>().Named("nothing");

        Variable<bool> stroke = Variable.New<bool>().Named("stroke");

     

        using (Variable.If(medication)) {

            using (Variable.If(trauma)) {

                bloodClot.SetTo(Variable.Bernoulli(0.95).Named("b|m,t"));

            }

     

            using (Variable.IfNot(trauma)) {

                bloodClot.SetTo(Variable.Bernoulli(0.3).Named("b|m,~t"));

            }

        }

     

        using (Variable.IfNot(medication)) {

            using (Variable.If(trauma)) {

                bloodClot.SetTo(Variable.Bernoulli(0.6).Named("b|~m,t"));

            }

            using (Variable.IfNot(trauma)) {

                bloodClot.SetTo(Variable.Bernoulli(0.9).Named("b|~m,~t"));

            }

        }

     

        using (Variable.If(bloodClot)) {

            heartAttack.SetTo(Variable.Bernoulli(0.4).Named("h|b"));

            nothing.SetTo(Variable.Bernoulli(0.25).Named("n|b"));

            stroke.SetTo(Variable.Bernoulli(0.35).Named("s|b"));

        }

     

        using (Variable.IfNot(bloodClot)) {

            heartAttack.SetTo(Variable.Bernoulli(0.15).Named("h|~b"));

            nothing.SetTo(Variable.Bernoulli(0.75).Named("n|~b"));

            stroke.SetTo(Variable.Bernoulli(0.1).Named("s|~b"));

    }

     

        // Inference

        InferenceEngine ie = new InferenceEngine(new VariationalMessagePassing());

        trauma.ObservedValue = true;

        medication.ObservedValue = true;

        Console.WriteLine("nothing and bloodClot: " + ie.Infer(nothing & bloodClot));

    }

    Friday, June 3, 2011 5:45 PM
    Owner
  • minka replied on 03-25-2009 2:15 PM

    It sounds like you are trying to compute the probability of the joint event (trauma=true, medication=true, nothing=true, bloodClot=true).  In Bayesian network terminology, this is the problem of computing the probability of observed data or "evidence".  To compute this in Infer.NET, you can use the method described at: http://research.microsoft.com/en-us/um/cambridge/projects/infernet/docs/Computing%20model%20evidence%20for%20model%20selection.aspx.  Basically you wrap your model and observations in an If block, and query the variable controlling the If block.

    Friday, June 3, 2011 5:45 PM
    Owner
  • caxqueiroz replied on 01-19-2010 10:49 PM

    Hi there, 

    quick question, what is the best way of defining a variable with three possible states. Lets say, I want to have a variable called rain, and the possible states are: low, medium and high. How could I do that using Infer.NET?

    Cheers, 

    Friday, June 3, 2011 5:45 PM
    Owner
  • John Guiver replied on 01-20-2010 3:58 AM

    You would either use a Variable<int> or a Variable<Enum> where Enum is an enum. These variables will have Discrete distributions and be defined using Variable.Discrete or Variable.EnumDiscrete respectively. Here is an example showing how to use enums; this example is inferring attitudes from observing actions.

    public class Program
    {
        public enum Attitude { Happy, Unhappy, Quiet };
        public enum Action { Smile, Cry, LookSilly };
        static void Main(string[] args)
        {
            // Observed actions
           
    Action[ ] observedActions = new Action[] { Action.Smile, Action.Smile, Action.Cry, Action.Smile, Action.LookSilly };
            var actions = Variable.Observed(observedActions);
            // Conditional probabilities of actions given different attitudes
            
    var actionProbs = Variable.Observed(new Vector[] {
                new Vector(0.6,0.2,0.2), // Happy
               
    new Vector(0.2,0.6,0.2), // Unhappy
               
    new Vector(0.4,0.3,0.3), // Quiet
           
    });
            // Model relating attitude to actions
           
    var attitude = Variable.EnumUniform<Attitude>(actionProbs.Range);
            var attInt = Variable.EnumToInt(attitude);
            var j = actions.Range;
            using (Variable.Switch(attInt))
                actions[ j ] = Variable.EnumDiscrete<Action>(actionProbs[attInt]).ForEach( j );
            // Inference of the posterior distribution over attitudes
           
    InferenceEngine ie = new InferenceEngine();
            Console.WriteLine("Posterior over attitude="+Environment.NewLine+ie.Infer(attitude));
        }
    }

    Friday, June 3, 2011 5:45 PM
    Owner
  • caxqueiroz replied on 01-20-2010 4:54 AM

    Nice stuff. Thanks a lot. 

    Friday, June 3, 2011 5:45 PM
    Owner
  • cs96ai replied on 05-06-2010 2:41 PM

    Hi All,

    Just wondering if there are any examples (or if someone could point me in the right direction) for Infer.Net bayesian learning for financial time series.

    I see in the example above there are discrete states like Happy, Quite, Unhappy and these states map back to an indicator like Attitude.

    Then multiple indicators are used to infer actions from attitudes.

    I'm not quite sure how to map the continuous values that I'm working with to discrete states.(Do I even need to worry about that?)

    I'm hoping that there is some way of creating a decision using 10 different indicators over a given period to come to some sort of statistically significant decision.

    Just taking a stab at:

    Actions = Buy, Sell, Do Nothing,
    Moving Average = Increasing, Decreasing, No Change
    Slope = Increasing, Decreasing, No Change
    Rate of Change = Increasing, Decreasing, No Change

    Where I'm getting a little confused is that the last three variables MA, Slope and ROC are never really in a discrete state (+ - or 0 ) there are many varying degrees to these indicators.

     

    Here's an example from trying out SVM (support vector machine):

    Here are some samples of SVM format data
    The first digit is expected direction of that particular time period
    Then there are 1: 2: 3: 4: 5: 6: 7: other indicators that help predict what direction the price should go.

    0 1:0.223099 2:85.714286 3:0.750000 4:0.070588 5:13.905796 6:0.295775 7:65.234030
    0 1:0.000718 2:57.142857 3:0.000000 4:0.000000 5:13.582930 6:0.280655 7:53.996901
    -1 1:0.115725 2:76.923077 3:2.000000 4:0.188813 5:17.812052 6:0.048713 7:54.878737
    -1 1:-0.178044 2:53.846154 3:1.500000 4:0.141643 5:17.610712 6:0.015601 7:45.583048
    -1 1:-0.403649 2:18.181818 3:-1.500000 4:-0.141743 5:39.636925 6:-0.922754 7:29.175296
    -1 1:-0.239349 2:27.272727 3:-2.000000 4:-0.188857 5:39.566156 6:-0.920078 7:33.674388
    -1 1:-0.377649 2:18.181818 3:-1.750000 4:-0.165367 5:40.392139 6:-0.945123 7:29.463218
    1 1:-0.218077 2:27.272727 3:-1.750000 4:-0.165328 5:40.793012 6:-0.935432 7:34.098946
    1 1:0.094301 2:54.545455 3:-1.000000 4:-0.094473 5:38.593789 6:-0.861039 7:46.062651
    1 1:0.258973 2:100.000000 3:0.750000 4:0.070939 5:34.638923 6:-0.755361 7:52.526430
    1 1:0.666433 2:86.666667 3:2.500000 4:0.236574 5:35.012376 6:-0.570023 7:64.493695
    1 1:0.545263 2:86.666667 3:2.000000 4:0.189170 5:35.344334 6:-0.417889 7:64.493695
    1 1:0.444477 2:92.307692 3:1.250000 4:0.117869 5:19.543378 6:-0.067690 7:62.422255
    1 1:0.363663 2:92.307692 3:1.500000 4:0.141476 5:19.038558 6:0.018587 7:62.422255

    I guess I'm wondering if there is a similar method for Infer.Net and how I might go about trying this out?

    Thanks for any and all input!

             =D

                       CS

    Friday, June 3, 2011 5:45 PM
    Owner
  • minka replied on 05-07-2010 6:19 AM

    It sounds like you want to predict a discrete outcome from a set of continuous predictors.  You can do that using multi-class classification (http://research.microsoft.com/en-us/um/cambridge/projects/infernet/docs/Multi-class%20classification.aspx).  If there are only two options (e.g. Up or Down) then you can use a simple Bayes Point Machine (http://research.microsoft.com/en-us/um/cambridge/projects/infernet/docs/Bayes%20Point%20Machine%20tutorial.aspx).  If instead you want to predict a continuous outcome, you can use linear regression as explained in this thread: http://community.research.microsoft.com/forums/p/3275/5374.aspx#5374

    Friday, June 3, 2011 5:45 PM
    Owner
  • dookie replied on 06-05-2010 4:18 PM

    May anyone show us how we can use discrete double variables in this example?

    For example Wet_Grass can take 3 values for it's humidity like: "low humidityl", "normal humidity", "excessive humidity"

    Likewise Rain can take 3 values like: "spattering", "normal rain", "storm"

    Sprinkler and cloudy will be bool.

    Thanks in advance!

    Friday, June 3, 2011 5:46 PM
    Owner
  • minka replied on 06-11-2010 7:52 AM

    This post explains how to define variables with muliple states:

    http://community.research.microsoft.com/forums/p/2434/5024.aspx#5024

    Friday, June 3, 2011 5:46 PM
    Owner
  • Link is broken.  Could you please correct?  Thanks.
    Thursday, December 13, 2012 6:22 PM
  • The old community forum is no longer available, and I'm not sure what this link should be point to. However, Infer.NET now has a detailed Discrete Bayes Network example which includes code. Although all the variables in the example only take on two values, the code is written in a way that easily extends to multiple states (ie it uses integer random variables rather than Boolean, and uses Discrete/Discrete distributions rather than Bernoulli/Beta).

    John

    Friday, December 14, 2012 4:06 PM
    Owner