Mercurial > hg > camir-aes2014
diff toolboxes/FullBNT-1.0.7/bnt/examples/dynamic/HHMM/Square/learn_square_hhmm_discrete.m @ 0:e9a9cd732c1e tip
first hg version after svn
author | wolffd |
---|---|
date | Tue, 10 Feb 2015 15:05:51 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolboxes/FullBNT-1.0.7/bnt/examples/dynamic/HHMM/Square/learn_square_hhmm_discrete.m Tue Feb 10 15:05:51 2015 +0000 @@ -0,0 +1,171 @@ +% Try to learn a 3 level HHMM similar to mk_square_hhmm +% from synthetic discrete sequences + + +discrete_obs = 1; +supervised = 0; +obs_finalF2 = 0; + +seed = 1; +rand('state', seed); +randn('state', seed); + +bnet_init = mk_square_hhmm(discrete_obs, 0); + +ss = 6; +Q1 = 1; Q2 = 2; Q3 = 3; F3 = 4; F2 = 5; Onode = 6; +Qnodes = [Q1 Q2 Q3]; Fnodes = [F2 F3]; + +if supervised + bnet_init.observed = [Q1 Q2 Onode]; +else + bnet_init.observed = [Onode]; +end + +if obs_finalF2 + engine_init = jtree_dbn_inf_engine(bnet_init); + % can't use ndx version because sometimes F2 is hidden, sometimes observed + error('can''t observe F when learning') + % It is not possible to observe F2 if we learn + % because the update_ess method for hhmmF_CPD and hhmmQ_CPD assume + % the F nodes are always hidden (for speed). + % However, for generating, we might want to set the final F2=true + % to force all subroutines to finish. +else + if supervised + engine_init = jtree_ndx_dbn_inf_engine(bnet_init); + else + engine_init = hmm_inf_engine(bnet_init); + end +end + +% generate some synthetic data (easier to debug) +chars = ['L', 'l', 'U', 'u', 'R', 'r', 'D', 'd']; +L=find(chars=='L'); l=find(chars=='l'); +U=find(chars=='U'); u=find(chars=='u'); +R=find(chars=='R'); r=find(chars=='r'); +D=find(chars=='D'); d=find(chars=='d'); + +cases = {}; + +T = 8; +ev = cell(ss, T); +ev(Onode,:) = num2cell([L l U u R r D d]); +if supervised + ev(Q1,:) = num2cell(1*ones(1,T)); + ev(Q2,:) = num2cell( [1 1 2 2 3 3 4 4]); +end +cases{1} = ev; +cases{3} = ev; + +T = 8; +ev = cell(ss, T); +%we start with R then r, even though we are running the model 'backwards'! +ev(Onode,:) = num2cell([R r U u L l D d]); + +if supervised + ev(Q1,:) = num2cell(2*ones(1,T)); + ev(Q2,:) = num2cell( [3 3 2 2 1 1 4 4]); +end + +cases{2} = ev; +cases{4} = ev; + +if obs_finalF2 + for i=1:length(cases) + T = size(cases{i},2); + cases{i}(F2,T)={2}; % force F2 to be finished at end of seq + end +end + + +% startprob should be shared for t=1:T, +% but in the DBN it is shared for t=2:T, +% so we train using a single long sequence. +long_seq = cat(2, cases{:}); +[bnet_learned, LL, engine_learned] = ... + learn_params_dbn_em(engine_init, {long_seq}, 'max_iter', 200); + +% figure out which subsequence each model is responsible for +mpe = calc_mpe_dbn(engine_learned, long_seq); +pretty_print_hhmm_parse(mpe, Qnodes, Fnodes, Onode, chars); + + +% The "true" segmentation of the training sequence is +% Q1: 1 2 +% O: L l U u R r D d | R r U u L l D d | etc. +% +% When we learn in a supervised fashion, we recover the "truth". + +% When we learn in an unsupervised fashion with seed=1, we get +% Q1: 2 1 +% O: L l U u R r D d R r | U u L l D d | etc. +% +% This means for model 1: +% starts in state 2 +% transitions 2->1, 1->4, 4->e, 3->2 +% +% For model 2, +% starts in state 1 +% transitions 1->2, 2->3, 3->4 or e, 4->3 + +% examine the params +eclass = bnet_learned.equiv_class; +CPDQ1=struct(bnet_learned.CPD{eclass(Q1,2)}); +CPDQ2=struct(bnet_learned.CPD{eclass(Q2,2)}); +CPDQ3=struct(bnet_learned.CPD{eclass(Q3,2)}); +CPDF2=struct(bnet_learned.CPD{eclass(F2,1)}); +CPDF3=struct(bnet_learned.CPD{eclass(F3,1)}); +CPDO=struct(bnet_learned.CPD{eclass(Onode,1)}); + +A_learned =add_hhmm_end_state(CPDQ2.transprob, CPDF2.termprob(:,:,2)); +squeeze(A_learned(:,1,:)) +squeeze(A_learned(:,2,:)) + + +% Does the "true" model have higher likelihood than the learned one? +% i.e., Does the unsupervised method learn the wrong model because +% we have the wrong cost fn, or because of local minima? + +bnet_true = mk_square_hhmm(discrete_obs,1); + +% examine the params +eclass = bnet_learned.equiv_class; +CPDQ1_true=struct(bnet_true.CPD{eclass(Q1,2)}); +CPDQ2_true=struct(bnet_true.CPD{eclass(Q2,2)}); +CPDQ3_true=struct(bnet_true.CPD{eclass(Q3,2)}); +CPDF2_true=struct(bnet_true.CPD{eclass(F2,1)}); +CPDF3_true=struct(bnet_true.CPD{eclass(F3,1)}); + +A_true =add_hhmm_end_state(CPDQ2_true.transprob, CPDF2_true.termprob(:,:,2)); +squeeze(A_true(:,1,:)) + + +if supervised + engine_true = jtree_ndx_dbn_inf_engine(bnet_true); +else + engine_true = hmm_inf_engine(bnet_true); +end + +%[engine_learned, ll_learned] = enter_evidence(engine_learned, long_seq); +%[engine_true, ll_true] = enter_evidence(engine_true, long_seq); +[engine_learned, ll_learned] = enter_evidence(engine_learned, cases{2}); +[engine_true, ll_true] = enter_evidence(engine_true, cases{2}); +ll_learned +ll_true + + +% remove concatentation artefacts +ll_learned = 0; +ll_true = 0; +for m=1:length(cases) + [engine_learned, ll_learned_tmp] = enter_evidence(engine_learned, cases{m}); + [engine_true, ll_true_tmp] = enter_evidence(engine_true, cases{m}); + ll_learned = ll_learned + ll_learned_tmp; + ll_true = ll_true + ll_true_tmp; +end +ll_learned +ll_true + +% In both cases, ll_learned >> ll_true +% which shows we are using the wrong cost function!