0

I am trying to build a Dynamic Bayesian Network using the BayesServer library in C# for my Unity3D game. I have the following method which implements the network

// numberOfDistractors and levelId will be used later for added complexity in modeling
void InitializeNetworkForLevel(int numberOfDistractors, int levelId)
{
    beliefNet = new BayesServer.Network();

    // add a knowledge node which is a latent variable (parameter to be learned from observed values
    KTrue = new State("KTrue");
    KFalse = new State("KFalse");
    knowledge = new Variable("Knowledge", KTrue, KFalse);
    knowledgeNode = new Node(knowledge)
    {
        TemporalType = TemporalType.Temporal // this is a time series node, hence re-used for each time slice
    };
    beliefNet.Nodes.Add(knowledgeNode);

    // add a question node, which denotes the oberved variable whether the question is answered correctly or not
    // this node has two states, namely correct or incorrect
    QTrue = new State("QTrue");
    QFalse = new State("QFalse");
    question = new Variable("Question", QTrue, QFalse);
    questionNode = new Node(question)
    {
        TemporalType = TemporalType.Temporal  // this is a time series node, hence re-used for each time slice
    };
    beliefNet.Nodes.Add(questionNode);

    // add a link from knowledge node to question node
    beliefNet.Links.Add(new Link(knowledgeNode, questionNode, 0));
    for (int i = 1; i <= 5; i++) 
        beliefNet.Links.Add(new Link(knowledgeNode, knowledgeNode, i)); // time series link (order/lag i)
    QueryNetwork(true);
}

and then another method for making inference:

void QueryNetwork(bool isAnswerCOrrect)
{

    StateContext kTrueTime0 = new StateContext(KTrue, 0);
    StateContext kFalseTime0 = new StateContext(KFalse, 0);

    Table priorKnowledge = knowledgeNode.NewDistribution(0).Table;
    priorKnowledge[kTrueTime0] = 0.5;
    priorKnowledge[kFalseTime0] = 0.5;
    // NewDistribution does not assign the new distribution, so it still must be assigned
    knowledgeNode.Distribution = priorKnowledge;

    // the second is specified for time >= 1
    Table learnRate = knowledgeNode.NewDistribution(1).Table;
    // when specifying temporal distributions, variables which belong to temporal nodes must have times associated
    // NOTE: Each time is specified relative to the current point in time which is defined as zero, 
    // therefore the time for variables at the previous time step is -1
    StateContext kTrueTime1 = new StateContext(KTrue, -1);
    StateContext kFalseTime1 = new StateContext(KFalse, -1);
    learnRate[kTrueTime1, kTrueTime0] = 0.5;
    learnRate[kFalseTime1, kTrueTime0] = 0.5;
    learnRate[kTrueTime1, kFalseTime0] = 0.5;
    learnRate[kFalseTime1, kFalseTime0] = 0.5;
    knowledgeNode.Distributions[1] = learnRate;

    Table answerStatus = questionNode.NewDistribution().Table;
    StateContext qTrue = new StateContext(QTrue, 0);
    StateContext qFalse = new StateContext(QFalse, 0);
    answerStatus[qTrue, kTrueTime0] = 0.5;
    answerStatus[qFalse, kTrueTime0] = 0.5;
    answerStatus[qTrue, kFalseTime0] = 0.5;
    answerStatus[qFalse, kFalseTime0] = 0.5;
    questionNode.Distribution = answerStatus;

    // optional check to validate network
    beliefNet.Validate(new ValidationOptions());
    // at this point the network has been fully specified

    // we will now perform some queries on the network
    RelevanceTreeInference inference = new RelevanceTreeInference(beliefNet);
    RelevanceTreeQueryOptions queryOptions = new RelevanceTreeQueryOptions();
    RelevanceTreeQueryOutput queryOutput = new RelevanceTreeQueryOutput();

    // set some temporal evidence
    if (isAnswerCOrrect)
        inference.Evidence.Set(question, new double?[] { 1, 0 }, 0, 0, 2);
    else
        inference.Evidence.Set(question, new double?[] { 0, 1 }, 0, 0, 2);

    queryOptions.LogLikelihood = true; // only ask for this if you really need it
    inference.Query(queryOptions, queryOutput); // note that this can raise an exception (see help for details)

    Debug.Log("LogLikelihood: " + queryOutput.LogLikelihood.Value);
}

However, I am getting the following exception when trying to validate the network in QueryNetwork method:

InvalidNetworkException: Node [Knowledge] has a null distribution.

BayesServer.Network.Validate (BayesServer.ValidationOptions options) (at :0)

BayesNet.QueryNetwork (System.Boolean isAnswerCOrrect) (at Assets/Scripts/BayesNet.cs:97)

BayesNet.InitializeNetworkForLevel (System.Int32 numberOfDistractors, System.Int32 levelId) (at Assets/Scripts/BayesNet.cs:59)

BayesNet.Start () (at Assets/Scripts/BayesNet.cs:21)

Why does it say that Knowledge Node has null distribution when I am already specifying it in the QueryNetwork method. Although I am able to fix this using the following piece of code:

ValidationOptions opt = new ValidationOptions();
opt.AllowNullDistributions = true;
// optional check to validate network
beliefNet.Validate(opt);

Further, I have assumed all the probabilities to be 50% for the first level, how would I change these values for the second level on the basis of inference from the first level?

Eventually, I'd like to build something like the network shown in image below where the number of Distractors is different on every level (or may be same if it is too complex): enter image description here

Vipin Verma
  • 5,330
  • 11
  • 50
  • 92

1 Answers1

1

It looks like you are adding lags 1 through 5, when I suspect you only need lag 1 on the latent node. Although not required for inference, to test this I would suggest unrolling the network in the User Interface to check that the DBN is as you expect. Note that only adding lag 1 does not restrict the number of time steps, just that each step is only connected to the previous time step.

  • If I add only lag 1, then how will set the evidence for any node (say Q) at t > 0 ? – Vipin Verma Feb 27 '19 at 05:10
  • @vipin8169 you can set evidence for the same node at different times. See the IEvidence.Set method overloads at https://www.bayesserver.com/api/dotnet/api/BayesServer.Inference.IEvidence.html and also an example of using one of the overloads at https://www.bayesserver.com/code/csharp/construction-inference-dbn-cs . Lag 1 means that the node connects to the previous time step (at any time). If you unroll the network, it will look like your diagram. Note that unrolling is not required for inference, but can be helpful to understand the structure of the Dynamic Bayesian network. – John Sandiford Feb 28 '19 at 07:48