貝葉斯網絡的構建-學習-推理(C++源代碼)分析

貝葉斯網絡的構建-學習-推理(C++源代碼)分析

編譯環境

VS.NET 2003

應用程序:BayesNetAplication

應用庫:PNL(以上傳至CSDN)

 PNL -- Probabilistic Networks Library. Beta 2.0.    30-March-2004

模型

BayesNet 模型

在工具-》選項-projects->VC++目錄中設置路徑

../PNL/include

.. /PNL/lib

/////////////////////////////////源代碼inf_learn_bnet.cpp////////////////////////////////////////////

//(代碼中含//*<-的行,可視情況更改)

#include "pnl_dll.hpp"

#include <fstream>

 

PNL_USING

//加載庫文件

#pragma comment(lib,"pnl.lib")

#pragma comment(lib,"cxcored.lib")

#pragma comment(lib,"cxcore.lib")

//設置證據節點

CEvidence* CreateEvidenceForBNet( const CBNet* pBnet )

{

    //make one node observed

    int nObsNds = 3;//*<-輸入證據節點數

    //the observed node is

    int obsNds[] = { 0, 1, 2};//*<-輸入證據節點列表

    //node 0 takes its second value (from two possible values {0, 1})

    valueVector obsVals;

    obsVals.resize(nObsNds);

    obsVals[0].SetInt(1);//*<-輸入證據節點的值

       obsVals[1].SetInt(1);//*<-

    obsVals[2].SetInt(1);//*<-

    CEvidence* pEvid = CEvidence::Create( pBnet, nObsNds, obsNds, obsVals );

    return pEvid;

}

 

//whether the learn process is successful;用於判斷學習後的模型與原模型是否相同,如不同則學習成功

int IsTheModelEqual( const CBNet* bnet1, const CBNet * bnet2, float epsilon )

{

    //compare every potential

    int numberOfNodes = bnet1->GetNumberOfNodes();

   

    int ret = 1;

   

    for( int i = 0; i < numberOfNodes; i++ )

    {

        if( !(bnet1->GetFactor(i)->IsFactorsDistribFunEqual(

            bnet2->GetFactor(i), epsilon )))

        {

            ret = 0;

        }

    }

   

    return ret;

}

//構建貝葉斯網絡

CBNet* CreateBNet()

{

       // Creation Water-Sprinkler Bayesian network

 

       const int numOfNds = 4;//*<-聲明網絡節點數

 

       // 1 STEP:

       // need to specify the graph structure of the model;

       // there are two way to do it

 

       CGraph *pGraph;

 

              // Graph creation using neighbors list

        int C=0,S=1,R=2,W=3;

              int numOfNbrs[numOfNds] = { 2, 2, 2, 2 };//*<-與各節點的鄰接點個數(包括父節點與子節點)

              int nbrs0[] = { S, R };//*<-定義網絡結構

              int nbrs1[] = { C, W };//*<-

              int nbrs2[] = { C, W };//*<-

              int nbrs3[] = { S, R};//*<-

 

              // number of neighbors for every node

              int *nbrs[] = { nbrs0, nbrs1, nbrs2, nbrs3 };

 

              // neighbors can be of either one of the three following types:

              // a parent, a child (for directed arcs) or just a neighbor (for undirected graphs).

              // Accordingly, the types are ntParent, ntChild or ntNeighbor.

 

              ENeighborType nbrsTypes0[] = { ntChild, ntChild };//*<-定義鄰接點的類別

              ENeighborType nbrsTypes1[] = { ntParent, ntChild };//*<-

              ENeighborType nbrsTypes2[] = { ntParent, ntChild };//*<-

              ENeighborType nbrsTypes3[] = { ntParent, ntParent };//*<-

 

              ENeighborType *nbrsTypes[] = { nbrsTypes0, nbrsTypes1,nbrsTypes2, nbrsTypes3 };

 

              // this is creation of a directed graph for the BNet model using neighbors list

              pGraph = CGraph::Create( numOfNds, numOfNbrs, nbrs, nbrsTypes );

 

       // 2 STEP:

       // Creation NodeType objects and specify node types for all nodes of the model.

 

       nodeTypeVector  nodeTypes;

 

       // number of node types is 1, because all nodes are of the same type

       // all four are discrete and binary

       CNodeType nt(1,2);//*<-定義各節點變量的類別nt(變量類別數,變量取值數)

       nodeTypes.push_back(nt);

 

       intVector nodeAssociation;

       // reflects association between node numbers and node types

       // nodeAssociation[k] is a number of node type object in the

       // node types array for the k-th node

       nodeAssociation.assign(numOfNds, 0);

 

       // 2 STEP:

       // Creation base for BNet using Graph, types of nodes and nodes association

 

       CBNet* pBNet = CBNet::Create( numOfNds, nodeTypes, nodeAssociation, pGraph );

 

       // 3 STEP:

       // Allocation space for all factors of the model

       pBNet->AllocFactors();

 

       // 4 STEP:

       // Creation factors and attach their to model

 

       //create raw data tables for CPDs

       float table0[] = { 0.5f, 0.5f };//*<-定義初始CPT

       float table1[] = { 0.5f, 0.5f, 0.9f, 0.1f };

       float table2[] = { 0.8f, 0.2f, 0.2f, 0.8f };

       float table3[] = { 1.0f, 0.0f, 0.1f, 0.9f, 0.1f, 0.9f, 0.01f, 0.99f };

 

       float* table[] = { table0, table1, table2, table3 };//*<-

 

       int i;

       for( i = 0; i < numOfNds; ++i )

       {

              pBNet->AllocFactor(i);

 

              CFactor* pFactor = pBNet->GetFactor(i);

 

              pFactor->AllocMatrix( table[i], matTable );

       }

 

       return pBNet;

}

void TestBNet(const CBNet* pBnet)//用於測試網絡,輸出網絡結構和參數

{

       pBnet->GetGraph()->Dump();

  //get information from learned model

       int nFactors = pBnet->GetNumberOfFactors();

       const CFactor *pCPD;

       const CNumericDenseMatrix<float> *pMatForCPD;

       int numOfEl;

       const float *dataCPD;

       int f;

       for( f = 0; f < nFactors; f++ )

       {

 

              std::cout<<std::endl<<" probability distribution for node "<<f<<std::endl;

              pCPD = pBnet->GetFactor(f);

              //all matrices are dense

              pMatForCPD = static_cast<CNumericDenseMatrix<float> *>

                     (pCPD->GetMatrix(matTable));

              pMatForCPD->GetRawData( &numOfEl, &dataCPD );

              int j;

              for( j = 0; j < numOfEl; j++ )

              {

                     std::cout<<" "<<dataCPD[j];

              }

       }

       std::cout<<std::endl;

       return;

}

 

CBNet* Learn_process(const CBNet* pBnet)//網絡參數學習

{

       //start learning for this model

       //create WS BNet with different matrices

 

       std::cout<<"Learning procedure /n ";

       CGraph *pGraph = CGraph::Copy( pBnet->GetGraph() );

       CModelDomain *pMD = pBnet->GetModelDomain();

 

       CBNet* pLearnBNet = CBNet::CreateWithRandomMatrices( pGraph, pMD );//定義學習算法

 

       //loading data from file

       const char * fname = "Data/casesForWS";//用於學習訓練的數據

 

       pEvidencesVector evVec;

 

       if( ! CEvidence::Load(fname,  &evVec, pMD) )

       {

              printf("can't open file with cases");

              exit(1);

              getchar();

       }

       int numOfSamples = evVec.size();

       std::cout<<"Number of cases for learning = "<<numOfSamples<<std::endl;

 

       //create learning engine

       CEMLearningEngine *pLearn = CEMLearningEngine::Create( pLearnBNet );

 

       //set data for learning

 

       pLearn->SetData( numOfSamples, &evVec.front() );

       pLearn->Learn();

 

       //compare information from learned model with initial model

       //both BNet have the same topology and node types

       //- we need only to compare CPDs

       //need to set tolerance

       float epsilon = 1e-1f;

       int isEqual = IsTheModelEqual( pBnet, pLearnBNet, epsilon );

 

       std::cout << " The model was learned. The learning was " << std::endl;

 

       if( isEqual )

       {

              std::cout << " successful " << std::endl;

       }

       else

       {

              std::cout << " unsuccessful " << std::endl;

       }

 

       int ev;

       for( ev = 0; ev < evVec.size(); ev++ )

       {

              delete evVec[ev];

       }

       delete pLearn;

       delete pBnet;

       return pLearnBNet;

      

}

void Infer_Process(const CBNet* pBnet)//推論

{

       //create simple evidence for node 0 from BNet

       CEvidence* pEvidForWS = CreateEvidenceForBNet(pBnet);

 

       //create Naive inference for BNet

       CNaiveInfEngine* pNaiveInf = CNaiveInfEngine::Create( pBnet );//定義推論引擎

 

       //enter evidence created before

       pNaiveInf->EnterEvidence( pEvidForWS );

 

       //set the query node

       int numQueryNds = 1;//*<-定義查詢變量的個數

       int queryNds[] = { 3 };//*<-定義查詢變量

    //get a marginal for query set of nodes

       pNaiveInf->MarginalNodes( queryNds, numQueryNds );

       const CPotential* pMarg = pNaiveInf->GetQueryJPD();

    //display the evidence node and such velue of BNet

       intVector obsNds;

       pConstValueVector obsVls;

       pEvidForWS->GetObsNodesWithValues(&obsNds, &obsVls);

 

       int i;

       for( i = 0; i < obsNds.size(); i++ )

       {

              std::cout<<" observed value for node "<<obsNds[i];

              std::cout<<" is "<<obsVls[i]->GetInt()<<std::endl;

       }

 

       //display the query node and such velue of BNet

       int nnodes;

       const int* domain;

       pMarg->GetDomain( &nnodes, &domain );

       std::cout<<" inference results: /n";

 

       std::cout<<" probability distribution for nodes [ ";

 

       for( i = 0; i < nnodes; i++ )

       {

              std::cout<<domain[i]<<" ";

       }

 

       std::cout<<"]"<<std::endl;

 

       CMatrix<float>* pMat = pMarg->GetMatrix(matTable);

 

       // graphical model hase been created using dense matrix

       // so, the marginal is also dense

       EMatrixClass type = pMat->GetMatrixClass();

       if( ! ( type == mcDense || type == mcNumericDense || type == mc2DNumericDense ) )

       {

              assert(0);

       }

 

       int nEl;

       const float* data;

       static_cast<CNumericDenseMatrix<float>*>(pMat)->GetRawData(&nEl, &data);

       for( i = 0; i < nEl; i++ )

       {

              std::cout<<" "<<data[i];

       }

       std::cout<<std::endl;

 

 

       delete pEvidForWS;

       delete pNaiveInf;

}

int main()

{

    //create Water - Sprinkler BNet

    CBNet* pBnet = CreateBNet();

 

    //Test content of Graph

    TestBNet(pBnet);

 

       //Inference Process

       Infer_Process(pBnet);

 

    //Learn Process

       CBNet* pLearnedBnet;

       pLearnedBnet=Learn_process(pBnet);

 

       //get information from learned model

       TestBNet(pLearnedBnet);

 

   //Inference Process

       Infer_Process(pLearnedBnet);

   

   

    getchar();

    return 0;

}

運行結果

 111

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章