wolffd@0
|
1 function bnet = mk_hhmm3(varargin)
|
wolffd@0
|
2 % MK_HHMM3 Make a 3 level Hierarchical HMM
|
wolffd@0
|
3 % bnet = mk_hhmm3(...)
|
wolffd@0
|
4 %
|
wolffd@0
|
5 % 3-layer hierarchical HMM where level 1 only connects to level 2, not 3 or obs.
|
wolffd@0
|
6 % This enforces sub-models (which differ only in their Q1 index) to be shared.
|
wolffd@0
|
7 % Also, we enforce the fact that each model always starts in its initial state
|
wolffd@0
|
8 % and only finishes in its final state. However, the prob. of finishing (as opposed to
|
wolffd@0
|
9 % self-transitioning to the final state) can be learned.
|
wolffd@0
|
10 % The fact that we always finish from the same state means we do not need to condition
|
wolffd@0
|
11 % F(i) on Q(i-1), since finishing prob is indep of calling context.
|
wolffd@0
|
12 %
|
wolffd@0
|
13 % The DBN is the same as Fig 10 in my tech report.
|
wolffd@0
|
14 %
|
wolffd@0
|
15 % Q1 ----------> Q1
|
wolffd@0
|
16 % | / |
|
wolffd@0
|
17 % | / |
|
wolffd@0
|
18 % | F2 ------- |
|
wolffd@0
|
19 % | ^ \ |
|
wolffd@0
|
20 % | /| \ |
|
wolffd@0
|
21 % v | v v
|
wolffd@0
|
22 % Q2-| --------> Q2
|
wolffd@0
|
23 % /| | ^
|
wolffd@0
|
24 % / | | /|
|
wolffd@0
|
25 % | | F3 ---------/ |
|
wolffd@0
|
26 % | | ^ \ |
|
wolffd@0
|
27 % | v / v
|
wolffd@0
|
28 % | Q3 -----------> Q3
|
wolffd@0
|
29 % | |
|
wolffd@0
|
30 % \ |
|
wolffd@0
|
31 % v v
|
wolffd@0
|
32 % O
|
wolffd@0
|
33 %
|
wolffd@0
|
34 % Q1 (slice 1) is clamped to be uniform.
|
wolffd@0
|
35 % Q2 (slice 1) is clamped to always start in state 1.
|
wolffd@0
|
36 % Q3 (slice 1) is clamped to always start in state 1.
|
wolffd@0
|
37 % F3 by default will only finish if Q3 is in its last state (F3 is a tabular_CPD)
|
wolffd@0
|
38 % F2 by default gets the default hhmmF_CPD params.
|
wolffd@0
|
39 % Q1:Q3 (slice 2) by default gets the default hhmmQ_CPD params.
|
wolffd@0
|
40 % O by default gets the default tabular/Gaussian params.
|
wolffd@0
|
41 %
|
wolffd@0
|
42 % Optional arguments in name/value format [default]
|
wolffd@0
|
43 %
|
wolffd@0
|
44 % Qsizes - sizes at each level [ none ]
|
wolffd@0
|
45 % Osize - size of O node [ none ]
|
wolffd@0
|
46 % discrete_obs - 1 means O is tabular_CPD, 0 means O is gaussian_CPD [0]
|
wolffd@0
|
47 % Oargs - cell array of args to pass to the O CPD [ {} ]
|
wolffd@0
|
48 % Q1args - args to be passed to constructor for Q1 (slice 2) [ {} ]
|
wolffd@0
|
49 % Q2args - args to be passed to constructor for Q2 (slice 2) [ {} ]
|
wolffd@0
|
50 % Q3args - args to be passed to constructor for Q3 (slice 2) [ {} ]
|
wolffd@0
|
51 % F2args - args to be passed to constructor for F2 [ {} ]
|
wolffd@0
|
52 % F3args - args to be passed to constructor for F3 [ {'CPT', finish in last Q3 state} ]
|
wolffd@0
|
53 %
|
wolffd@0
|
54
|
wolffd@0
|
55 ss = 6; D = 3;
|
wolffd@0
|
56 Q1 = 1; Q2 = 2; Q3 = 3; F3 = 4; F2 = 5; obs = 6;
|
wolffd@0
|
57 Qnodes = [Q1 Q2 Q3]; Fnodes = [F2 F3];
|
wolffd@0
|
58 names = {'Q1', 'Q2', 'Q3', 'F3', 'F2', 'obs'};
|
wolffd@0
|
59
|
wolffd@0
|
60 intra = zeros(ss);
|
wolffd@0
|
61 intra(Q1, Q2) = 1;
|
wolffd@0
|
62 intra(Q2, [F2 Q3 obs]) = 1;
|
wolffd@0
|
63 intra(Q3, [F3 obs]) = 1;
|
wolffd@0
|
64 intra(F3, F2) = 1;
|
wolffd@0
|
65
|
wolffd@0
|
66 inter = zeros(ss);
|
wolffd@0
|
67 inter(Q1,Q1) = 1;
|
wolffd@0
|
68 inter(Q2,Q2) = 1;
|
wolffd@0
|
69 inter(Q3,Q3) = 1;
|
wolffd@0
|
70 inter(F2,[Q1 Q2]) = 1;
|
wolffd@0
|
71 inter(F3,[Q2 Q3]) = 1;
|
wolffd@0
|
72
|
wolffd@0
|
73
|
wolffd@0
|
74 % get sizes of nodes
|
wolffd@0
|
75 args = varargin;
|
wolffd@0
|
76 nargs = length(args);
|
wolffd@0
|
77 Qsizes = [];
|
wolffd@0
|
78 Osize = 0;
|
wolffd@0
|
79 for i=1:2:nargs
|
wolffd@0
|
80 switch args{i},
|
wolffd@0
|
81 case 'Qsizes', Qsizes = args{i+1};
|
wolffd@0
|
82 case 'Osize', Osize = args{i+1};
|
wolffd@0
|
83 end
|
wolffd@0
|
84 end
|
wolffd@0
|
85 if isempty(Qsizes), error('must specify Qsizes'); end
|
wolffd@0
|
86 if Osize==0, error('must specify Osize'); end
|
wolffd@0
|
87
|
wolffd@0
|
88 % set default params
|
wolffd@0
|
89 discrete_obs = 0;
|
wolffd@0
|
90 Oargs = {};
|
wolffd@0
|
91 Q1args = {};
|
wolffd@0
|
92 Q2args = {};
|
wolffd@0
|
93 Q3args = {};
|
wolffd@0
|
94 F2args = {};
|
wolffd@0
|
95
|
wolffd@0
|
96 % P(Q3, F3)
|
wolffd@0
|
97 CPT = zeros(Qsizes(3), 2);
|
wolffd@0
|
98 % Each model can only terminate in its final state.
|
wolffd@0
|
99 % 0 params will remain 0 during EM, thus enforcing this constraint.
|
wolffd@0
|
100 CPT(:, 1) = 1.0; % all states turn F off ...
|
wolffd@0
|
101 p = 0.5;
|
wolffd@0
|
102 CPT(Qsizes(3), 2) = p; % except the last one
|
wolffd@0
|
103 CPT(Qsizes(3), 1) = 1-p;
|
wolffd@0
|
104 F3args = {'CPT', CPT};
|
wolffd@0
|
105
|
wolffd@0
|
106 for i=1:2:nargs
|
wolffd@0
|
107 switch args{i},
|
wolffd@0
|
108 case 'discrete_obs', discrete_obs = args{i+1};
|
wolffd@0
|
109 case 'Oargs', Oargs = args{i+1};
|
wolffd@0
|
110 case 'Q1args', Q1args = args{i+1};
|
wolffd@0
|
111 case 'Q2args', Q2args = args{i+1};
|
wolffd@0
|
112 case 'Q3args', Q3args = args{i+1};
|
wolffd@0
|
113 case 'F2args', F2args = args{i+1};
|
wolffd@0
|
114 case 'F3args', F3args = args{i+1};
|
wolffd@0
|
115 end
|
wolffd@0
|
116 end
|
wolffd@0
|
117
|
wolffd@0
|
118 ns = zeros(1,ss);
|
wolffd@0
|
119 ns(Qnodes) = Qsizes;
|
wolffd@0
|
120 ns(obs) = Osize;
|
wolffd@0
|
121 ns(Fnodes) = 2;
|
wolffd@0
|
122
|
wolffd@0
|
123 dnodes = [Qnodes Fnodes];
|
wolffd@0
|
124 if discrete_obs
|
wolffd@0
|
125 dnodes = [dnodes obs];
|
wolffd@0
|
126 end
|
wolffd@0
|
127 onodes = [obs];
|
wolffd@0
|
128
|
wolffd@0
|
129 bnet = mk_dbn(intra, inter, ns, 'observed', onodes, 'discrete', dnodes, 'names', names);
|
wolffd@0
|
130 eclass = bnet.equiv_class;
|
wolffd@0
|
131
|
wolffd@0
|
132 % SLICE 1
|
wolffd@0
|
133
|
wolffd@0
|
134 % We clamp untied nodes in the first slice, since their params can't be estimated
|
wolffd@0
|
135 % from just one sequence
|
wolffd@0
|
136
|
wolffd@0
|
137 % uniform prior on initial model
|
wolffd@0
|
138 CPT = normalise(ones(1,ns(Q1)));
|
wolffd@0
|
139 bnet.CPD{eclass(Q1,1)} = tabular_CPD(bnet, Q1, 'CPT', CPT, 'adjustable', 0);
|
wolffd@0
|
140
|
wolffd@0
|
141 % each model always starts in state 1
|
wolffd@0
|
142 CPT = zeros(ns(Q1), ns(Q2));
|
wolffd@0
|
143 CPT(:, 1) = 1.0;
|
wolffd@0
|
144 bnet.CPD{eclass(Q2,1)} = tabular_CPD(bnet, Q2, 'CPT', CPT, 'adjustable', 0);
|
wolffd@0
|
145
|
wolffd@0
|
146 % each model always starts in state 1
|
wolffd@0
|
147 CPT = zeros(ns(Q2), ns(Q3));
|
wolffd@0
|
148 CPT(:, 1) = 1.0;
|
wolffd@0
|
149 bnet.CPD{eclass(Q3,1)} = tabular_CPD(bnet, Q3, 'CPT', CPT, 'adjustable', 0);
|
wolffd@0
|
150
|
wolffd@0
|
151 bnet.CPD{eclass(F2,1)} = hhmmF_CPD(bnet, F2, Qnodes, 2, D, F2args{:});
|
wolffd@0
|
152
|
wolffd@0
|
153 bnet.CPD{eclass(F3,1)} = tabular_CPD(bnet, F3, F3args{:});
|
wolffd@0
|
154
|
wolffd@0
|
155 if discrete_obs
|
wolffd@0
|
156 bnet.CPD{eclass(obs,1)} = tabular_CPD(bnet, obs, Oargs{:});
|
wolffd@0
|
157 else
|
wolffd@0
|
158 bnet.CPD{eclass(obs,1)} = gaussian_CPD(bnet, obs, Oargs{:});
|
wolffd@0
|
159 end
|
wolffd@0
|
160
|
wolffd@0
|
161 % SLICE 2
|
wolffd@0
|
162
|
wolffd@0
|
163 bnet.CPD{eclass(Q1,2)} = hhmmQ_CPD(bnet, Q1+ss, Qnodes, 1, D, Q1args{:});
|
wolffd@0
|
164 bnet.CPD{eclass(Q2,2)} = hhmmQ_CPD(bnet, Q2+ss, Qnodes, 2, D, Q2args{:});
|
wolffd@0
|
165 bnet.CPD{eclass(Q3,2)} = hhmmQ_CPD(bnet, Q3+ss, Qnodes, 3, D, Q3args{:});
|