貝葉斯網絡的構建-學習-推理(C++源代碼)分析
編譯環境
VS.NET 2003
應用程序:BayesNetAplication
應用庫:PNL(以上傳至CSDN)
PNL -- Probabilistic Networks Library. Beta 2.0. 30-March-2004
模型
在工具-》選項-》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;
}
運行結果