-->

BayesServer: InvalidNetworkException: Node [Knowle

2019-08-23 03:52发布

问题:

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):

回答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.