annotate toolboxes/FullBNT-1.0.7/HMM/dhmm_em.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 [LL, prior, transmat, obsmat, nrIterations] = ...
Daniel@0 2 dhmm_em(data, prior, transmat, obsmat, varargin)
Daniel@0 3 % LEARN_DHMM Find the ML/MAP parameters of an HMM with discrete outputs using EM.
Daniel@0 4 % [ll_trace, prior, transmat, obsmat, iterNr] = learn_dhmm(data, prior0, transmat0, obsmat0, ...)
Daniel@0 5 %
Daniel@0 6 % Notation: Q(t) = hidden state, Y(t) = observation
Daniel@0 7 %
Daniel@0 8 % INPUTS:
Daniel@0 9 % data{ex} or data(ex,:) if all sequences have the same length
Daniel@0 10 % prior(i)
Daniel@0 11 % transmat(i,j)
Daniel@0 12 % obsmat(i,o)
Daniel@0 13 %
Daniel@0 14 % Optional parameters may be passed as 'param_name', param_value pairs.
Daniel@0 15 % Parameter names are shown below; default values in [] - if none, argument is mandatory.
Daniel@0 16 %
Daniel@0 17 % 'max_iter' - max number of EM iterations [10]
Daniel@0 18 % 'thresh' - convergence threshold [1e-4]
Daniel@0 19 % 'verbose' - if 1, print out loglik at every iteration [1]
Daniel@0 20 % 'obs_prior_weight' - weight to apply to uniform dirichlet prior on observation matrix [0]
Daniel@0 21 %
Daniel@0 22 % To clamp some of the parameters, so learning does not change them:
Daniel@0 23 % 'adj_prior' - if 0, do not change prior [1]
Daniel@0 24 % 'adj_trans' - if 0, do not change transmat [1]
Daniel@0 25 % 'adj_obs' - if 0, do not change obsmat [1]
Daniel@0 26 %
Daniel@0 27 % Modified by Herbert Jaeger so xi are not computed individually
Daniel@0 28 % but only their sum (over time) as xi_summed; this is the only way how they are used
Daniel@0 29 % and it saves a lot of memory.
Daniel@0 30
Daniel@0 31 [max_iter, thresh, verbose, obs_prior_weight, adj_prior, adj_trans, adj_obs] = ...
Daniel@0 32 process_options(varargin, 'max_iter', 10, 'thresh', 1e-4, 'verbose', 1, ...
Daniel@0 33 'obs_prior_weight', 0, 'adj_prior', 1, 'adj_trans', 1, 'adj_obs', 1);
Daniel@0 34
Daniel@0 35 previous_loglik = -inf;
Daniel@0 36 loglik = 0;
Daniel@0 37 converged = 0;
Daniel@0 38 num_iter = 1;
Daniel@0 39 LL = [];
Daniel@0 40
Daniel@0 41 if ~iscell(data)
Daniel@0 42 data = num2cell(data, 2); % each row gets its own cell
Daniel@0 43 end
Daniel@0 44
Daniel@0 45 while (num_iter <= max_iter) & ~converged
Daniel@0 46 % E step
Daniel@0 47 [loglik, exp_num_trans, exp_num_visits1, exp_num_emit] = ...
Daniel@0 48 compute_ess_dhmm(prior, transmat, obsmat, data, obs_prior_weight);
Daniel@0 49
Daniel@0 50 % M step
Daniel@0 51 if adj_prior
Daniel@0 52 prior = normalise(exp_num_visits1);
Daniel@0 53 end
Daniel@0 54 if adj_trans & ~isempty(exp_num_trans)
Daniel@0 55 transmat = mk_stochastic(exp_num_trans);
Daniel@0 56 end
Daniel@0 57 if adj_obs
Daniel@0 58 obsmat = mk_stochastic(exp_num_emit);
Daniel@0 59 end
Daniel@0 60
Daniel@0 61 if verbose, fprintf(1, 'iteration %d, loglik = %f\n', num_iter, loglik); end
Daniel@0 62 num_iter = num_iter + 1;
Daniel@0 63 converged = em_converged(loglik, previous_loglik, thresh);
Daniel@0 64 previous_loglik = loglik;
Daniel@0 65 LL = [LL loglik];
Daniel@0 66 end
Daniel@0 67 nrIterations = num_iter - 1;
Daniel@0 68
Daniel@0 69 %%%%%%%%%%%%%%%%%%%%%%%
Daniel@0 70
Daniel@0 71 function [loglik, exp_num_trans, exp_num_visits1, exp_num_emit, exp_num_visitsT] = ...
Daniel@0 72 compute_ess_dhmm(startprob, transmat, obsmat, data, dirichlet)
Daniel@0 73 % COMPUTE_ESS_DHMM Compute the Expected Sufficient Statistics for an HMM with discrete outputs
Daniel@0 74 % function [loglik, exp_num_trans, exp_num_visits1, exp_num_emit, exp_num_visitsT] = ...
Daniel@0 75 % compute_ess_dhmm(startprob, transmat, obsmat, data, dirichlet)
Daniel@0 76 %
Daniel@0 77 % INPUTS:
Daniel@0 78 % startprob(i)
Daniel@0 79 % transmat(i,j)
Daniel@0 80 % obsmat(i,o)
Daniel@0 81 % data{seq}(t)
Daniel@0 82 % dirichlet - weighting term for uniform dirichlet prior on expected emissions
Daniel@0 83 %
Daniel@0 84 % OUTPUTS:
Daniel@0 85 % exp_num_trans(i,j) = sum_l sum_{t=2}^T Pr(X(t-1) = i, X(t) = j| Obs(l))
Daniel@0 86 % exp_num_visits1(i) = sum_l Pr(X(1)=i | Obs(l))
Daniel@0 87 % exp_num_visitsT(i) = sum_l Pr(X(T)=i | Obs(l))
Daniel@0 88 % exp_num_emit(i,o) = sum_l sum_{t=1}^T Pr(X(t) = i, O(t)=o| Obs(l))
Daniel@0 89 % where Obs(l) = O_1 .. O_T for sequence l.
Daniel@0 90
Daniel@0 91 numex = length(data);
Daniel@0 92 [S O] = size(obsmat);
Daniel@0 93 exp_num_trans = zeros(S,S);
Daniel@0 94 exp_num_visits1 = zeros(S,1);
Daniel@0 95 exp_num_visitsT = zeros(S,1);
Daniel@0 96 exp_num_emit = dirichlet*ones(S,O);
Daniel@0 97 loglik = 0;
Daniel@0 98
Daniel@0 99 for ex=1:numex
Daniel@0 100 obs = data{ex};
Daniel@0 101 T = length(obs);
Daniel@0 102 %obslik = eval_pdf_cond_multinomial(obs, obsmat);
Daniel@0 103 obslik = multinomial_prob(obs, obsmat);
Daniel@0 104 [alpha, beta, gamma, current_ll, xi_summed] = fwdback(startprob, transmat, obslik);
Daniel@0 105
Daniel@0 106 loglik = loglik + current_ll;
Daniel@0 107 exp_num_trans = exp_num_trans + xi_summed;
Daniel@0 108 exp_num_visits1 = exp_num_visits1 + gamma(:,1);
Daniel@0 109 exp_num_visitsT = exp_num_visitsT + gamma(:,T);
Daniel@0 110 % loop over whichever is shorter
Daniel@0 111 if T < O
Daniel@0 112 for t=1:T
Daniel@0 113 o = obs(t);
Daniel@0 114 exp_num_emit(:,o) = exp_num_emit(:,o) + gamma(:,t);
Daniel@0 115 end
Daniel@0 116 else
Daniel@0 117 for o=1:O
Daniel@0 118 ndx = find(obs==o);
Daniel@0 119 if ~isempty(ndx)
Daniel@0 120 exp_num_emit(:,o) = exp_num_emit(:,o) + sum(gamma(:, ndx), 2);
Daniel@0 121 end
Daniel@0 122 end
Daniel@0 123 end
Daniel@0 124 end