To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / _FullBNT / BNT / CPDs / @hhmmQ_CPD / hhmmQ_CPD.m @ 8:b5b38998ef3b
History | View | Annotate | Download (4.38 KB)
| 1 |
function CPD = hhmmQ_CPD(bnet, self, varargin) |
|---|---|
| 2 |
% HHMMQ_CPD Make the CPD for a Q node in a hierarchical HMM |
| 3 |
% CPD = hhmmQ_CPD(bnet, self, ...) |
| 4 |
% |
| 5 |
% Fself(t-1) Qps(t) |
| 6 |
% \ | |
| 7 |
% \ v |
| 8 |
% Qold(t-1) -> Q(t) |
| 9 |
% / |
| 10 |
% / |
| 11 |
% Fbelow(t-1) |
| 12 |
% |
| 13 |
% Let ss = slice size = num. nodes per slice. |
| 14 |
% This node is Q(t), and has mandatory parents Qold(t-1) (assumed to be numbered Q(t)-ss) |
| 15 |
% and optional parents Fbelow, Fself, Qps. |
| 16 |
% We require parents to be ordered (numbered) as follows: |
| 17 |
% Qold, Fbelow, Fself, Qps, Q. |
| 18 |
% |
| 19 |
% If Fself=2, we use the transition matrix, else we use the prior matrix. |
| 20 |
% If Fself node is omitted (eg. top level), we always use the transition matrix. |
| 21 |
% If Fbelow=2, we may change state, otherwise we must stay in the same state. |
| 22 |
% If Fbelow node is omitted (eg., bottom level), we may change state at every step. |
| 23 |
% If Qps (Q parents) are specified, all parameters are conditioned on their joint value. |
| 24 |
% We may choose any subset of nodes to condition on, as long as they as numbered lower than self. |
| 25 |
% |
| 26 |
% optional args [defaults] |
| 27 |
% |
| 28 |
% Fself - node number <= ss |
| 29 |
% Fbelow - node number <= ss |
| 30 |
% Qps - node numbers (all <= 2*ss) - uses 2TBN indexing |
| 31 |
% transprob - transprob(i,k,j) = prob transition from i to j given Qps = k ['leftright'] |
| 32 |
% selfprob - prob of a transition from i to i given Qps=k [0.1] |
| 33 |
% startprob - startprob(k,j) = prob start in j given Qps = k ['leftstart'] |
| 34 |
% startargs - other args to be passed to the sub tabular_CPD for learning startprob |
| 35 |
% transargs - other args will be passed to the sub tabular_CPD for learning transprob |
| 36 |
% fullstartprob - 1 means startprob depends on Q(t-1) [0] |
| 37 |
% hhmmQ_CPD is a subclass of tabular_CPD so we inherit inference methods like CPD_to_pot, etc. |
| 38 |
% |
| 39 |
% We create isolated tabular_CPDs with no F parents to learn transprob/startprob |
| 40 |
% so we can avail of e.g., entropic or Dirichlet priors. |
| 41 |
% In the future, we will be able to represent the transprob using a tree_CPD. |
| 42 |
% |
| 43 |
% For details, see "Linear-time inference in hierarchical HMMs", Murphy and Paskin, NIPS'01. |
| 44 |
|
| 45 |
|
| 46 |
ss = bnet.nnodes_per_slice; |
| 47 |
ns = bnet.node_sizes(:); |
| 48 |
|
| 49 |
% set default arguments |
| 50 |
Fself = []; |
| 51 |
Fbelow = []; |
| 52 |
Qps = []; |
| 53 |
startprob = 'leftstart'; |
| 54 |
transprob = 'leftright'; |
| 55 |
startargs = {};
|
| 56 |
transargs = {};
|
| 57 |
selfprob = 0.1; |
| 58 |
fullstartprob = 0; |
| 59 |
|
| 60 |
for i=1:2:length(varargin) |
| 61 |
switch varargin{i},
|
| 62 |
case 'Fself', Fself = varargin{i+1};
|
| 63 |
case 'Fbelow', Fbelow = varargin{i+1};
|
| 64 |
case 'Qps', Qps = varargin{i+1};
|
| 65 |
case 'transprob', transprob = varargin{i+1};
|
| 66 |
case 'selfprob', selfprob = varargin{i+1};
|
| 67 |
case 'startprob', startprob = varargin{i+1};
|
| 68 |
case 'startargs', startargs = varargin{i+1};
|
| 69 |
case 'transargs', transargs = varargin{i+1};
|
| 70 |
case 'fullstartprob', fullstartprob = varargin{i+1};
|
| 71 |
end |
| 72 |
end |
| 73 |
|
| 74 |
CPD.fullstartprob = fullstartprob; |
| 75 |
|
| 76 |
ps = parents(bnet.dag, self); |
| 77 |
ndsz = ns(:)'; |
| 78 |
CPD.dom_sz = [ndsz(ps) ns(self)]; |
| 79 |
CPD.Fself_ndx = find_equiv_posns(Fself, ps); |
| 80 |
CPD.Fbelow_ndx = find_equiv_posns(Fbelow, ps); |
| 81 |
%CPD.Qps_ndx = find_equiv_posns(Qps+ss, ps); |
| 82 |
CPD.Qps_ndx = find_equiv_posns(Qps, ps); |
| 83 |
old_self = self-ss; |
| 84 |
CPD.old_self_ndx = find_equiv_posns(old_self, ps); |
| 85 |
|
| 86 |
Qps = ps(CPD.Qps_ndx); |
| 87 |
CPD.Qsz = ns(self); |
| 88 |
CPD.Qpsz = prod(ns(Qps)); |
| 89 |
CPD.Qpsizes = ns(Qps); |
| 90 |
Qsz = CPD.Qsz; |
| 91 |
Qpsz = CPD.Qpsz; |
| 92 |
|
| 93 |
if strcmp(transprob, 'leftright') |
| 94 |
LR = mk_leftright_transmat(Qsz, selfprob); |
| 95 |
transprob = repmat(reshape(LR, [1 Qsz Qsz]), [Qpsz 1 1]); % transprob(k,i,j) |
| 96 |
transprob = permute(transprob, [2 1 3]); % now transprob(i,k,j) |
| 97 |
end |
| 98 |
transargs{end+1} = 'CPT';
|
| 99 |
transargs{end+1} = transprob;
|
| 100 |
CPD.sub_CPD_trans = mk_isolated_tabular_CPD(ns([old_self Qps self]), transargs); |
| 101 |
S = struct(CPD.sub_CPD_trans); |
| 102 |
%CPD.transprob = myreshape(S.CPT, [Qsz Qpsz Qsz]); |
| 103 |
CPD.transprob = S.CPT; |
| 104 |
|
| 105 |
|
| 106 |
if strcmp(startprob, 'leftstart') |
| 107 |
startprob = zeros(Qpsz, Qsz); |
| 108 |
startprob(:,1) = 1; |
| 109 |
end |
| 110 |
if isempty(CPD.Fself_ndx) |
| 111 |
CPD.sub_CPD_start = []; |
| 112 |
CPD.startprob = []; |
| 113 |
else |
| 114 |
startargs{end+1} = 'CPT';
|
| 115 |
startargs{end+1} = startprob;
|
| 116 |
if CPD.fullstartprob |
| 117 |
CPD.sub_CPD_start = mk_isolated_tabular_CPD(ns([self Qps self]), startargs); |
| 118 |
S = struct(CPD.sub_CPD_start); |
| 119 |
%CPD.startprob = myreshape(S.CPT, [Qsz Qpsz Qsz]); |
| 120 |
CPD.startprob = S.CPT; |
| 121 |
else |
| 122 |
CPD.sub_CPD_start = mk_isolated_tabular_CPD(ns([Qps self]), startargs); |
| 123 |
S = struct(CPD.sub_CPD_start); |
| 124 |
%CPD.startprob = myreshape(S.CPT, [CPD.Qpsizes Qsz]); |
| 125 |
CPD.startprob = S.CPT; |
| 126 |
end |
| 127 |
end |
| 128 |
|
| 129 |
CPD = class(CPD, 'hhmmQ_CPD', tabular_CPD(bnet, self)); |
| 130 |
|
| 131 |
CPD = update_CPT(CPD); |
| 132 |
|