在前三周的作业中,我构造了概率图模型并调用第三方的求解器对器进行了求解,最终获得了每个随机变量的分布(有向图),最大后验分布(双向图)。本周作业的主要内容就是自行编写概率图模型的求解器。实际上,从根本上来说求解器并不是必要的。其作用只是求取边缘分布或者MAP,在得到联合CPD后,寻找联合CPD的最大值即可获得MAP,对每个变量进行边缘分布求取即可获得边缘分布。但是,这种简单粗暴的方法效率极其低下,对于MAP求取而言,每次得到新的evidance时都要重新搜索CPD,对于单个变量分布而言,更是对每个变量都要反复进行整体边缘化。以一个长度为6字母的单词为例,联合CPD有着多达26^6个数据,反复操作会浪费大量的计算资源。

  团树算法背后的思路是分而治之。对于一组随机变量ABCDEFG,如果A和其他变量之间是独立的,那么无论是求边缘分布还是MAP都可以将A单独考虑。如果ABC联系比较紧密,CDE联系比较紧密,那么如果两个团关于C的边缘分布是相同的,则我们没有必要将ABCDE全部乘在一起再来分别求各个变量的边缘分布。因为反过来想,乘的时候也只是把对应的C乘起来,如果C的边缘分布相同,在相乘的时候其实两个团之间并没有引入其他信息,此时乘法不会对ABDE的边缘分布产生影响。团树算法的数学过程和Variable Elimination是相同的。

  PGM在计算机中的表达是factorLists,factor的var(i),var表示节点连接关系。val描述了factor中var的关系。cliqueTree其实是一种特殊的factorLists,它的var是clique,表示一堆聚类的var。它的val表示的还是var之间的关系。只不过此时var之间的连接不复存在了。所以clique由两个变量组成:1、cliqueTree 2、edges.

  团树算法的初始化可以分为两个过程:1、将变量抱团;2、获取团的初始势;

  变量抱团是一个玄学过程,因为有很多不同的抱法,而且还都是对的。比较常见的是最小边,最小割等...其实如果是人来判断很容易就能得到结果,但是使用计算机算法则要费一些功夫了。不过这不涉及我们对团树算法的理解,所以Koller教授代劳了。

  团的初始势表示团里变量之间的关系。其算法如下,需要注意的是不能重复使用factor.因为一个factor表达了一种关系,如果两个团里都有同一个factor,那么就是...这个事情。。。你帮他重复一遍。。。等于你也有责任的,晓得吧?

  

 1 %COMPUTEINITIALPOTENTIALS Sets up the cliques in the clique tree that is
 2 %passed in as a parameter.
 3 %
 4 %   P = COMPUTEINITIALPOTENTIALS(C) Takes the clique tree skeleton C which is a
 5 %   struct with three fields:
 6 %   - nodes: cell array representing the cliques in the tree.
 7 %   - edges: represents the adjacency matrix of the tree.
 8 %   - factorList: represents the list of factors that were used to build
 9 %   the tree. 
10 %   
11 %   It returns the standard form of a clique tree P that we will use through 
12 %   the rest of the assigment. P is struct with two fields:
13 %   - cliqueList: represents an array of cliques with appropriate factors 
14 %   from factorList assigned to each clique. Where the .val of each clique
15 %   is initialized to the initial potential of that clique.
16 %   - edges: represents the adjacency matrix of the tree. 
17 %
18 % Copyright (C) Daphne Koller, Stanford University, 2012
19 
20 
21 
22 function P = ComputeInitialPotentials(C)
23 Input = C;
24 % number of cliques
25 N = length(Input.nodes);
26 
27 % initialize cluster potentials 
28 P.cliqueList = repmat(struct('var', [], 'card', [], 'val', []), N, 1);
29 P.edges = zeros(N);
30 
31 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
32 % YOUR CODE HERE
33 %
34 % First, compute an assignment of factors from factorList to cliques. 
35 % Then use that assignment to initialize the cliques in cliqueList to 
36 % their initial potentials. 
37 
38 % C.nodes is a list of cliques.
39 % So in your code, you should start with: P.cliqueList(i).var = C.nodes{i};
40 % Print out C to get a better understanding of its structure.
41 %
42 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
43 % N_factors = length(C.factorList);
44 for i = 1:N
45     k = 1;
46     clear clique_
47      N_factors = length(Input.factorList);
48     for j = 1:N_factors
49         if min(ismember(Input.factorList(j).var,Input.nodes{i}))
50             clique_(k) = Input.factorList(j);
51             k = k+1;
52             Input.factorList(j) =struct('var', [], 'card', [], 'val', []);
53         end
54     end
55     Joint_Dis_cliq = ComputeJointDistribution(clique_);
56     Joint_Dis_cliq_std = StandardizeFactors(Joint_Dis_cliq);
57     P.cliqueList(i) = Joint_Dis_cliq_std;
58 end
59 P.edges = Input.edges;
60 end

View Code