annotate toolboxes/FullBNT-1.0.7/bnt/examples/dynamic/fhmm_infer.m @ 0:cc4b1211e677 tip

initial commit to HG from Changeset: 646 (e263d8a21543) added further path and more save "camirversion.m"
author Daniel Wolff
date Fri, 19 Aug 2016 13:07:06 +0200
parents
children
rev   line source
Daniel@0 1 function [loglik, gamma] = fhmm_infer(inter, CPTs_slice1, CPTs, obsmat, node_sizes)
Daniel@0 2 % FHMM_INFER Exact inference for a factorial HMM.
Daniel@0 3 % [loglik, gamma] = fhmm_infer(inter, CPTs_slice1, CPTs, obsmat, node_sizes)
Daniel@0 4 %
Daniel@0 5 % Inputs:
Daniel@0 6 % inter - the inter-slice adjacency matrix
Daniel@0 7 % CPTs_slice1{s}(j) = Pr(Q(s,1) = j) where Q(s,t) = hidden node s in slice t
Daniel@0 8 % CPT{s}(i1, i2, ..., j) = Pr(Q(s,t) = j | Pa(s,t-1) = i1, i2, ...),
Daniel@0 9 % obsmat(i,t) = Pr(y(t) | Q(t)=i)
Daniel@0 10 % node_sizes is a vector with the cardinality of the hidden nodes
Daniel@0 11 %
Daniel@0 12 % Outputs:
Daniel@0 13 % gamma(i,t) = Pr(X(t)=i | O(1:T)) as in an HMM,
Daniel@0 14 % except that i is interpreted as an M digit, base-K number (if there are M chains each of cardinality K).
Daniel@0 15 %
Daniel@0 16 %
Daniel@0 17 % For M chains each of cardinality K, the frontiers (i.e., cliques)
Daniel@0 18 % contain M+1 nodes, and it takes M steps to advance the frontier by one time step,
Daniel@0 19 % so the run time is O(T M K^(M+1)).
Daniel@0 20 % An HMM takes O(T S^2) where S is the size of the state space.
Daniel@0 21 % Collapsing the FHMM to an HMM results in S = K^M.
Daniel@0 22 % For details, see
Daniel@0 23 % "The Factored Frontier Algorithm for Approximate Inference in DBNs",
Daniel@0 24 % Kevin Murphy and Yair Weiss, submitted to NIPS 2000.
Daniel@0 25 %
Daniel@0 26 % The frontier algorithm makes the following topological assumptions:
Daniel@0 27 %
Daniel@0 28 % - All nodes are persistent (connect to the next slice)
Daniel@0 29 % - No connections within a timeslice
Daniel@0 30 % - There is a single observation variable, which depends on all the hidden nodes
Daniel@0 31 % - Each node can have several parents in the previous time slice (generalizes a FHMM slightly)
Daniel@0 32 %
Daniel@0 33
Daniel@0 34 % The forwards pass of the frontier algorithm can be explained with the following example.
Daniel@0 35 % Suppose we have 3 hidden nodes per slice, A, B, C.
Daniel@0 36 % The goal is to compute alpha(j, t) = Pr( (A_t,B_t,C_t)=j | Y(1:t))
Daniel@0 37 % We move alpha from t to t+1 one node at a time, as follows.
Daniel@0 38 % We define the following quantities:
Daniel@0 39 % s([a1 b1 c1], 1) = Prob(A(t)=a1, B(t)=b1, C(t)=c1 | Y(1:t)) = alpha(j, t)
Daniel@0 40 % s([a2 b1 c1], 2) = Prob(A(t+1)=a2, B(t)=b1, C(t)=c1 | Y(1:t))
Daniel@0 41 % s([a2 b2 c1], 3) = Prob(A(t+1)=a2, B(t+1)=b2, C(t)=c1 | Y(1:t))
Daniel@0 42 % s([a2 b2 c2], 4) = Prob(A(t+1)=a2, B(t+1)=b2, C(t+1)=c2 | Y(1:t))
Daniel@0 43 % s([a2 b2 c2], 5) = Prob(A(t+1)=a2, B(t+1)=b2, C(t+1)=c2 | Y(1:t+1)) = alpha(j, t+1)
Daniel@0 44 %
Daniel@0 45 % These can be computed recursively as follows:
Daniel@0 46 %
Daniel@0 47 % s([a2 b1 c1], 2) = sum_{a1} P(a2|a1) s([a1 b1 c1], 1)
Daniel@0 48 % s([a2 b2 c1], 3) = sum_{b1} P(b2|b1) s([a2 b1 c1], 2)
Daniel@0 49 % s([a2 b2 c2], 4) = sum_{c1} P(c2|c1) s([a2 b2 c1], 1)
Daniel@0 50 % s([a2 b2 c2], 5) = normalise( s([a2 b2 c2], 4) .* P(Y(t+1)|a2,b2,c2)
Daniel@0 51
Daniel@0 52
Daniel@0 53 [kk,ll,mm] = make_frontier_indices(inter, node_sizes); % can pass in as args
Daniel@0 54
Daniel@0 55 scaled = 1;
Daniel@0 56
Daniel@0 57 M = length(node_sizes);
Daniel@0 58 S = prod(node_sizes);
Daniel@0 59 T = size(obsmat, 2);
Daniel@0 60
Daniel@0 61 alpha = zeros(S, T);
Daniel@0 62 beta = zeros(S, T);
Daniel@0 63 gamma = zeros(S, T);
Daniel@0 64 scale = zeros(1,T);
Daniel@0 65 tiny = exp(-700);
Daniel@0 66
Daniel@0 67
Daniel@0 68 alpha(:,1) = make_prior_from_CPTs(CPTs_slice1, node_sizes);
Daniel@0 69 alpha(:,1) = alpha(:,1) .* obsmat(:, 1);
Daniel@0 70
Daniel@0 71 if scaled
Daniel@0 72 s = sum(alpha(:,1));
Daniel@0 73 if s==0, s = s + tiny; end
Daniel@0 74 scale(1) = 1/s;
Daniel@0 75 else
Daniel@0 76 scale(1) = 1;
Daniel@0 77 end
Daniel@0 78 alpha(:,1) = alpha(:,1) * scale(1);
Daniel@0 79
Daniel@0 80 %a = zeros(S, M+1);
Daniel@0 81 %b = zeros(S, M+1);
Daniel@0 82 anew = zeros(S,1);
Daniel@0 83 aold = zeros(S,1);
Daniel@0 84 bnew = zeros(S,1);
Daniel@0 85 bold = zeros(S,1);
Daniel@0 86
Daniel@0 87 for t=2:T
Daniel@0 88 %a(:,1) = alpha(:,t-1);
Daniel@0 89 aold = alpha(:,t-1);
Daniel@0 90
Daniel@0 91 c = 1;
Daniel@0 92 for i=1:M
Daniel@0 93 ns = node_sizes(i);
Daniel@0 94 cpt = CPTs{i};
Daniel@0 95 for j=1:S
Daniel@0 96 s = 0;
Daniel@0 97 for xx=1:ns
Daniel@0 98 %k = kk(xx,j,i);
Daniel@0 99 %l = ll(xx,j,i);
Daniel@0 100 k = kk(c);
Daniel@0 101 l = ll(c);
Daniel@0 102 c = c + 1;
Daniel@0 103 % s = s + a(k,i) * CPTs{i}(l);
Daniel@0 104 s = s + aold(k) * cpt(l);
Daniel@0 105 end
Daniel@0 106 %a(j,i+1) = s;
Daniel@0 107 anew(j) = s;
Daniel@0 108 end
Daniel@0 109 aold = anew;
Daniel@0 110 end
Daniel@0 111
Daniel@0 112 %alpha(:,t) = a(:,M+1) .* obsmat(:, obs(t));
Daniel@0 113 alpha(:,t) = anew .* obsmat(:, t);
Daniel@0 114
Daniel@0 115 if scaled
Daniel@0 116 s = sum(alpha(:,t));
Daniel@0 117 if s==0, s = s + tiny; end
Daniel@0 118 scale(t) = 1/s;
Daniel@0 119 else
Daniel@0 120 scale(t) = 1;
Daniel@0 121 end
Daniel@0 122 alpha(:,t) = alpha(:,t) * scale(t);
Daniel@0 123
Daniel@0 124 end
Daniel@0 125
Daniel@0 126
Daniel@0 127 beta(:,T) = ones(S,1) * scale(T);
Daniel@0 128 for t=T-1:-1:1
Daniel@0 129 %b(:,1) = beta(:,t+1) .* obsmat(:, obs(t+1));
Daniel@0 130 bold = beta(:,t+1) .* obsmat(:, t+1);
Daniel@0 131
Daniel@0 132 c = 1;
Daniel@0 133 for i=1:M
Daniel@0 134 ns = node_sizes(i);
Daniel@0 135 cpt = CPTs{i};
Daniel@0 136 for j=1:S
Daniel@0 137 s = 0;
Daniel@0 138 for xx=1:ns
Daniel@0 139 %k = kk(xx,j,i);
Daniel@0 140 %m = mm(xx,j,i);
Daniel@0 141 k = kk(c);
Daniel@0 142 m = mm(c);
Daniel@0 143 c = c + 1;
Daniel@0 144 % s = s + b(k,i) * CPTs{i}(m);
Daniel@0 145 s = s + bold(k) * cpt(m);
Daniel@0 146 end
Daniel@0 147 %b(j,i+1) = s;
Daniel@0 148 bnew(j) = s;
Daniel@0 149 end
Daniel@0 150 bold = bnew;
Daniel@0 151 end
Daniel@0 152 % beta(:,t) = b(:,M+1) * scale(t);
Daniel@0 153 beta(:,t) = bnew * scale(t);
Daniel@0 154 end
Daniel@0 155
Daniel@0 156
Daniel@0 157 if scaled
Daniel@0 158 loglik = -sum(log(scale)); % scale(i) is finite
Daniel@0 159 else
Daniel@0 160 lik = alpha(:,1)' * beta(:,1);
Daniel@0 161 loglik = log(lik+tiny);
Daniel@0 162 end
Daniel@0 163
Daniel@0 164 for t=1:T
Daniel@0 165 gamma(:,t) = normalise(alpha(:,t) .* beta(:,t));
Daniel@0 166 end
Daniel@0 167
Daniel@0 168 %%%%%%%%%%%
Daniel@0 169
Daniel@0 170 function [kk,ll,mm] = make_frontier_indices(inter, node_sizes)
Daniel@0 171 %
Daniel@0 172 % Precompute indices for use in the frontier algorithm.
Daniel@0 173 % These only depend on the topology, not the parameters or data.
Daniel@0 174 % Hence we can compute them outside of fhmm_infer.
Daniel@0 175 % This saves a lot of run-time computation.
Daniel@0 176
Daniel@0 177 M = length(node_sizes);
Daniel@0 178 S = prod(node_sizes);
Daniel@0 179
Daniel@0 180 mns = max(node_sizes);
Daniel@0 181 kk = zeros(mns, S, M);
Daniel@0 182 ll = zeros(mns, S, M);
Daniel@0 183 mm = zeros(mns, S, M);
Daniel@0 184
Daniel@0 185 for i=1:M
Daniel@0 186 for j=1:S
Daniel@0 187 u = ind2subv(node_sizes, j);
Daniel@0 188 x = u(i);
Daniel@0 189 for xx=1:node_sizes(i)
Daniel@0 190 uu = u;
Daniel@0 191 uu(i) = xx;
Daniel@0 192 k = subv2ind(node_sizes, uu);
Daniel@0 193 kk(xx,j,i) = k;
Daniel@0 194 ps = find(inter(:,i)==1);
Daniel@0 195 ps = ps(:)';
Daniel@0 196 l = subv2ind(node_sizes([ps i]), [uu(ps) x]); % sum over parent
Daniel@0 197 ll(xx,j,i) = l;
Daniel@0 198 m = subv2ind(node_sizes([ps i]), [u(ps) xx]); % sum over child
Daniel@0 199 mm(xx,j,i) = m;
Daniel@0 200 end
Daniel@0 201 end
Daniel@0 202 end
Daniel@0 203
Daniel@0 204 %%%%%%%%%
Daniel@0 205
Daniel@0 206 function prior=make_prior_from_CPTs(indiv_priors, node_sizes)
Daniel@0 207 %
Daniel@0 208 % composite_prior=make_prior(individual_priors, node_sizes)
Daniel@0 209 % Make the prior for the first node in a Markov chain
Daniel@0 210 % from the priors on each node in the equivalent DBN.
Daniel@0 211 % prior{i}(j) = Pr(X_i=j), where X_i is the i'th node in slice 1.
Daniel@0 212 % composite_prior(i) = Pr(slice1 = i).
Daniel@0 213
Daniel@0 214 n = length(indiv_priors);
Daniel@0 215 S = prod(node_sizes);
Daniel@0 216 prior = zeros(S,1);
Daniel@0 217 for i=1:S
Daniel@0 218 vi = ind2subv(node_sizes, i);
Daniel@0 219 p = 1;
Daniel@0 220 for k=1:n
Daniel@0 221 p = p * indiv_priors{k}(vi(k));
Daniel@0 222 end
Daniel@0 223 prior(i) = p;
Daniel@0 224 end
Daniel@0 225
Daniel@0 226
Daniel@0 227
Daniel@0 228 %%%%%%%%%%%
Daniel@0 229
Daniel@0 230 function [loglik, alpha, beta] = FHMM_slow(inter, CPTs_slice1, CPTs, obsmat, node_sizes, data)
Daniel@0 231 %
Daniel@0 232 % Same as the above, except we don't use the optimization of computing the indices outside the loop.
Daniel@0 233
Daniel@0 234
Daniel@0 235 scaled = 1;
Daniel@0 236
Daniel@0 237 M = length(node_sizes);
Daniel@0 238 S = prod(node_sizes);
Daniel@0 239 [numex T] = size(data);
Daniel@0 240
Daniel@0 241 obs = data;
Daniel@0 242
Daniel@0 243 alpha = zeros(S, T);
Daniel@0 244 beta = zeros(S, T);
Daniel@0 245 a = zeros(S, M+1);
Daniel@0 246 b = zeros(S, M+1);
Daniel@0 247 scale = zeros(1,T);
Daniel@0 248
Daniel@0 249 alpha(:,1) = make_prior_from_CPTs(CPTs_slice1, node_sizes);
Daniel@0 250 alpha(:,1) = alpha(:,1) .* obsmat(:, obs(1));
Daniel@0 251 if scaled
Daniel@0 252 s = sum(alpha(:,1));
Daniel@0 253 if s==0, s = s + tiny; end
Daniel@0 254 scale(1) = 1/s;
Daniel@0 255 else
Daniel@0 256 scale(1) = 1;
Daniel@0 257 end
Daniel@0 258 alpha(:,1) = alpha(:,1) * scale(1);
Daniel@0 259
Daniel@0 260 for t=2:T
Daniel@0 261 fprintf(1, 't %d\n', t);
Daniel@0 262 a(:,1) = alpha(:,t-1);
Daniel@0 263 for i=1:M
Daniel@0 264 for j=1:S
Daniel@0 265 u = ind2subv(node_sizes, j);
Daniel@0 266 xnew = u(i);
Daniel@0 267 s = 0;
Daniel@0 268 for xold=1:node_sizes(i)
Daniel@0 269 uold = u;
Daniel@0 270 uold(i) = xold;
Daniel@0 271 k = subv2ind(node_sizes, uold);
Daniel@0 272 ps = find(inter(:,i)==1);
Daniel@0 273 ps = ps(:)';
Daniel@0 274 l = subv2ind(node_sizes([ps i]), [uold(ps) xnew]);
Daniel@0 275 s = s + a(k,i) * CPTs{i}(l);
Daniel@0 276 end
Daniel@0 277 a(j,i+1) = s;
Daniel@0 278 end
Daniel@0 279 end
Daniel@0 280 alpha(:,t) = a(:,M+1) .* obsmat(:, obs(t));
Daniel@0 281
Daniel@0 282 if scaled
Daniel@0 283 s = sum(alpha(:,t));
Daniel@0 284 if s==0, s = s + tiny; end
Daniel@0 285 scale(t) = 1/s;
Daniel@0 286 else
Daniel@0 287 scale(t) = 1;
Daniel@0 288 end
Daniel@0 289 alpha(:,t) = alpha(:,t) * scale(t);
Daniel@0 290
Daniel@0 291 end
Daniel@0 292
Daniel@0 293
Daniel@0 294 beta(:,T) = ones(S,1) * scale(T);
Daniel@0 295 for t=T-1:-1:1
Daniel@0 296 fprintf(1, 't %d\n', t);
Daniel@0 297 b(:,1) = beta(:,t+1) .* obsmat(:, obs(t+1));
Daniel@0 298 for i=1:M
Daniel@0 299 for j=1:S
Daniel@0 300 u = ind2subv(node_sizes, j);
Daniel@0 301 xold = u(i);
Daniel@0 302 s = 0;
Daniel@0 303 for xnew=1:node_sizes(i)
Daniel@0 304 unew = u;
Daniel@0 305 unew(i) = xnew;
Daniel@0 306 k = subv2ind(node_sizes, unew);
Daniel@0 307 ps = find(inter(:,i)==1);
Daniel@0 308 ps = ps(:)';
Daniel@0 309 l = subv2ind(node_sizes([ps i]), [u(ps) xnew]);
Daniel@0 310 s = s + b(k,i) * CPTs{i}(l);
Daniel@0 311 end
Daniel@0 312 b(j,i+1) = s;
Daniel@0 313 end
Daniel@0 314 end
Daniel@0 315 beta(:,t) = b(:,M+1) * scale(t);
Daniel@0 316 end
Daniel@0 317
Daniel@0 318
Daniel@0 319 if scaled
Daniel@0 320 loglik = -sum(log(scale)); % scale(i) is finite
Daniel@0 321 else
Daniel@0 322 lik = alpha(:,1)' * beta(:,1);
Daniel@0 323 loglik = log(lik+tiny);
Daniel@0 324 end