Mercurial > hg > dml-open-cliopatria
comparison cpack/dml/lib/grammars.pl @ 0:718306e29690 tip
commiting public release
author | Daniel Wolff |
---|---|
date | Tue, 09 Feb 2016 21:05:06 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:718306e29690 |
---|---|
1 /* Part of DML (Digital Music Laboratory) | |
2 Copyright 2014-2015 Samer Abdallah, University of London | |
3 | |
4 This program is free software; you can redistribute it and/or | |
5 modify it under the terms of the GNU General Public License | |
6 as published by the Free Software Foundation; either version 2 | |
7 of the License, or (at your option) any later version. | |
8 | |
9 This program is distributed in the hope that it will be useful, | |
10 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 GNU General Public License for more details. | |
13 | |
14 You should have received a copy of the GNU General Public | |
15 License along with this library; if not, write to the Free Software | |
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | |
17 */ | |
18 | |
19 :- module(grammars, | |
20 [ model_name/2 | |
21 , model_module_prep/3 | |
22 , build_options/2 | |
23 , build_subset_options/2 | |
24 , learn/6 | |
25 , learn_bpe/6 | |
26 , learn_model/7 | |
27 , model_sequence_parses/4 | |
28 , nnums_ivals/2 | |
29 , restart_prism/0 | |
30 , best_first/6 | |
31 , method_model_dataset_results/4 | |
32 , dataset_num_events/2 | |
33 ]). | |
34 | |
35 :- multifile dataset_sequences/2. | |
36 | |
37 :- use_module(library(memo)). | |
38 :- use_module(library(typedef)). | |
39 :- use_module(library(lambda)). | |
40 :- use_module(library(plml)). | |
41 :- use_module(library(prism/prism)). | |
42 :- use_module(library(argutils)). | |
43 :- use_module(library(snobol)). | |
44 | |
45 :- type pmodule == ground. | |
46 :- type natural == nonneg. | |
47 :- type prep == callable. | |
48 :- type options == ordset. | |
49 :- type model ---> model(atom, list, prep, list(pair(ground,list(number)))). | |
50 :- type method ---> vb(ground) ; map(ground). | |
51 :- type matlab_method ---> vb ; map. | |
52 | |
53 % % hmmmn.. maybe module issues here... | |
54 % error:has_type(\Checker,Term) :- call(Checker,Term). | |
55 error:has_type(ordset,Term) :- is_ordset(Term). | |
56 | |
57 :- persistent_memo | |
58 learn( +method, +pmodule, +prep, +dataset:ground, +options, -scores:list), | |
59 learn_model( +method, +pmodule, +prep, +dataset:ground, +options, -scores:list, -model), | |
60 dataset_num_events( +dataset:ground, -num_events:nonneg). | |
61 | |
62 dataset_num_events(Dataset,NumEvents) :- | |
63 dataset_sequences(Dataset,Seqs), | |
64 maplist(length,Seqs,Lens), | |
65 sumlist(Lens,NumEvents). | |
66 % aggregate_all(sum(L),(member(S,Seqs),length(S,L)),NumEvents). | |
67 | |
68 :- initialization memo_attach(memo(learned),[]). | |
69 :- setting(timeout, number, 900, 'Time limit for learning in seconds'). | |
70 | |
71 user:file_search_path(prism,'psm'). | |
72 user:matlab_path(grammars,['stats/hmm']). | |
73 | |
74 partition_options([],[],[],[]). | |
75 partition_options([O|OX],[O|MO],IO,LO) :- option_class(O,model), partition_options(OX,MO,IO,LO). | |
76 partition_options([O|OX],MO,[O|IO],LO) :- option_class(O,init), partition_options(OX,MO,IO,LO). | |
77 partition_options([O|OX],MO,IO,[O|LO]) :- option_class(O,learn), partition_options(OX,MO,IO,LO). | |
78 | |
79 option_class(switch_mode(_),model). | |
80 option_class(prior_weight(_),model). | |
81 option_class(gamut(_),model). | |
82 option_class(leap_range(_),model). | |
83 option_class(log_scale(_),learn). | |
84 option_class(O,init) :- \+option_class(O,model), \+option_class(O,learn). | |
85 | |
86 option_mlopt(gamut(X-Y),gamut:[X,Y]) :- !. | |
87 option_mlopt(init(none),perturb:0) :- !. | |
88 option_mlopt(init(perturb(U)),perturb:U) :- !. | |
89 option_mlopt(F,N:V) :- F=..[N,V]. | |
90 | |
91 learn(vb(InitMeth),matlab(Function),Prepare,DataSet,Opts,[free_energy(FE)]) :- !, | |
92 dataset_sequences(DataSet, D1), | |
93 maplist(Prepare,D1,D), | |
94 maplist(option_mlopt,[init(InitMeth)|Opts],Opts1), | |
95 compileoptions(Opts1,Opts2), | |
96 [float(FE)]===feval(@Function,cell(D),Opts2). | |
97 | |
98 % method dependent options | |
99 | |
100 learn(Method,Module,Prepare,DataSet,Opts,Scores) :- | |
101 member(Method,[vb(_),map(_)]), | |
102 % prepare data | |
103 dataset_sequences(DataSet, D1), | |
104 maplist(Prepare,D1,D), | |
105 % method dependent options | |
106 method_switch_mode(Method,Mode), | |
107 option(log_scale(LS), Opts, on), | |
108 % load up prism and initialise | |
109 restart_prism, load_prism(prism(Module)), | |
110 #init_model([switch_mode(Mode)|Opts]), | |
111 #init_switches(Opts), | |
112 set_prism_flag(log_scale,LS), | |
113 % allow 15 minutes for learning | |
114 setting(timeout, TimeLimit), | |
115 get_time(Time), | |
116 debug(learn,'Calling PRISM with time limit ~w at ~@...', | |
117 [TimeLimit, format_time(current_output,'%T',Time)]), | |
118 call_with_time_limit(TimeLimit, prism_learn(Method, D, [], Scores)). | |
119 | |
120 method_switch_mode(vb(_),a). | |
121 method_switch_mode(map(_),d). | |
122 | |
123 learn_model(Method,Module,Prepare,DataSet,Opts,Scores,model(Module,ModelOpts,Prepare,Counts)) :- | |
124 % must re-compute to get final state | |
125 compute(learn(Method,Module,Prepare,DataSet,Opts,Scores)), | |
126 partition_options(Opts,ModelOpts,_,_), | |
127 get_prism_state(ps(_,_,Counts1,_,_,_)), | |
128 map_filter(unfixed_count,Counts1,Counts). | |
129 | |
130 unfixed_count(sw(SW,a,set(unfixed,Counts)), SW-Counts). | |
131 | |
132 model_initial_state(model(Module,MO,_,_),State) :- | |
133 restart_prism, | |
134 load_prism(prism(Module)), | |
135 #init_model([switch_mode(a)|MO]), | |
136 get_prism_state(State). | |
137 | |
138 with_model_data(model(Module,MO,Prepare,Counts),Data,Goal) :- | |
139 restart_prism, load_prism(prism(Module)), | |
140 #init_model([switch_mode(a)|MO]), | |
141 #maplist(SW-C,set_sw_a(SW,C),Counts), | |
142 call(Prepare,Data,D), | |
143 call(Goal,D). | |
144 | |
145 learn_bpe(Method,Module,Prepare,DataSet,Opts,BPE) :- | |
146 browse(learn(Method,Module,Prepare,DataSet,Opts,Scores)), | |
147 catch( bits_per_event(Method,DataSet,Scores,BPE), _, fail). | |
148 | |
149 bits_per_event(Method,DS,Scores,BPE) :- | |
150 dataset_num_events(DS,NumEvents), | |
151 score(Method,NumEvents,Scores,BPE). | |
152 | |
153 score(map(_),NumEvents,Scores,BitsPerEvent) :- | |
154 member(log_lik(LL), Scores), | |
155 BitsPerEvent is -(LL/NumEvents)/log(2). | |
156 | |
157 score(vb(_),NumEvents,Scores,BitsPerEvent) :- | |
158 member(free_energy(LL), Scores), | |
159 BitsPerEvent is -(LL/NumEvents)/log(2). | |
160 | |
161 score(vb_pm(_),NumEvents,Scores,BitsPerEvent) :- | |
162 member(free_energy(LL), Scores), | |
163 BitsPerEvent is -(LL/NumEvents)/log(2). | |
164 | |
165 %% tree_syntax(+Mod:module,+Tree:prism_tree,-Syntax:tree) is det. | |
166 % | |
167 % Create a parse tree from a PRISM Viterbi tree. | |
168 % Works for models gilbert1, gilbert2, gilbert2a, gilbert3 and gilbert2m. | |
169 tree_syntax(Mod,[s(_),TT],T2) :- tree_parse_tree(Mod,TT,T2). | |
170 | |
171 tree_parse_tree(_,msw(i(I),terminal),node(t(I),[])). | |
172 tree_parse_tree(Mod,[pp(s,_,_)|Children],Term) :- member(Mod,[gilbert2,gilbert2a,gilbert3,gilbert2m]), !, | |
173 member(msw(s,Rule),Children), | |
174 map_filter(tree_parse_tree(Mod),Children,CN), | |
175 ( Rule=grow -> CN=[Child1,T1], T1=node(s,Tail), Term=node(s,[Child1|Tail]) | |
176 ; Rule=last -> CN=[Child], Term=node(s,[Child]) | |
177 ). | |
178 tree_parse_tree(Mod,[pp(s,_,_)|Children],Term) :- Mod=gilbert1, !, | |
179 member(msw(s,Rule),Children), | |
180 map_filter(tree_parse_tree(Mod),Children,CN), | |
181 ( Rule=grow -> CN=[Child1,T1], T1=node(s,Tail), Term=node(s,[Child1|Tail]) | |
182 ; Rule=first -> CN=[], Term=node(s,[]) | |
183 ). | |
184 tree_parse_tree(Mod,[pp(H,_,_)|Children],Term) :- !, | |
185 map_filter(tree_parse_tree(Mod),Children,CN), | |
186 member(msw(H,Rule1),Children), | |
187 ( Rule1=terminal -> Rule=t; Rule=Rule1), | |
188 Term = node(H-Rule,CN). | |
189 | |
190 :- volatile_memo model_sequence_parses(+ground,+list(ground),+natural,-ground). | |
191 | |
192 model_sequence_parses(Model,Seq,N,Parses) :- | |
193 Model=model(Mod,_,_,_), | |
194 with_model_data(Model,Seq,parses(Mod,N,Parses)). | |
195 | |
196 parses(Mod,N,Parses,Goal) :- | |
197 succ(N,M), | |
198 findall(P-T,viterbi_tree(M,Goal,P,[],T),ProbsTrees), | |
199 append(NProbsTrees,[P0-_],ProbsTrees), | |
200 maplist(tree_parse(Mod,P0),NProbsTrees,Parses). | |
201 | |
202 tree_parse(Mod,P0,P-T,RP-S) :- tree_syntax(Mod,T,S), RP is P/P0. | |
203 | |
204 | |
205 % model declarations | |
206 decl_model(markov(nnum,0), p1gram, markovp, with_nnums(s0)). | |
207 decl_model(markov(nnum,1), p2gram, markovp, with_nnums(s1)). | |
208 decl_model(markov(ival,0), i1gram, markovi, with_ivals(s0)). | |
209 decl_model(markov(ival,1), i2gram, markovi, with_ivals(s1)). | |
210 decl_model(gilbert(1), gilbert1, gilbert1, with_pre_ivals(s)). | |
211 decl_model(gilbert(2), gilbert2, gilbert2, with_ivals(s)). | |
212 decl_model(gilbert(3), gilbert3, gilbert3, with_ivals(s)). | |
213 decl_model(gilbert(2-a), gilbert2a, gilbert2a, with_ivals(s)). | |
214 decl_model(gilbert(2-m), gilbert2m, gilbert2m, with_ivals(s)). | |
215 % decl_model(gilbert(4), gilbert1, gilbert1a, with_pre_ivals(s)). | |
216 % decl_model(gilbert(5), gilbert2, gilbert2a, with_ivals(s)). | |
217 % decl_model(gilbert(6), gilbert3, gilbert3a, with_ivals(s)). | |
218 decl_model(hmm(nnum), phmm, phmm, with_nnums(s)). | |
219 decl_model(hmm(nnum,NS), Name, phmm, with_nnums(s)) :- atom_concat(phmm,NS,Name). | |
220 %decl_model(hmm(ival), ihmm, ihmm, with_ivals(s)). | |
221 decl_model(matlab(p1gram), 'ml-p1gram', matlab(p1gram), (=)). | |
222 decl_model(matlab(p2gram), 'ml-p2gram', matlab(p2gram), (=)). | |
223 decl_model(matlab(phmm), 'ml-phmm', matlab(phmm), (=)). | |
224 | |
225 model_name(Model,Name) :- decl_model(Model,Name,_,_). | |
226 model_module_prep(Model,Module,Prepare) :- decl_model(Model,_,Module,Prepare). | |
227 | |
228 with_nnums(Head, Seq, Head1) :- | |
229 addargs(Head,[Seq],Head1). | |
230 | |
231 with_ivals(Head, Seq, Head1) :- | |
232 nnums_ivals(Seq,Seq1), | |
233 addargs(Head,[Seq1],Head1). | |
234 | |
235 with_pre_ivals(Head, Seq, Head1) :- | |
236 nnums_pre_ivals(Seq,Seq1), | |
237 addargs(Head,[Seq1],Head1). | |
238 | |
239 nnums_ivals(NNums,Ivals) :- nnums_post_ivals(NNums,Ivals). | |
240 nnums_post_ivals(NNums,Ivals) :- phrase((ivals(NNums),[end]),Ivals,[]). | |
241 nnums_pre_ivals(NNums,Ivals) :- phrase(([start],ivals(NNums)),Ivals,[]). | |
242 | |
243 ivals([X0,X1|Xs]) --> {I1 is X1-X0}, [I1], ivals([X1|Xs]). | |
244 ivals([_]) --> []. | |
245 | |
246 % NB option defaults here must match those in PRISM source files. | |
247 model_options(markov(nnum,_)) --> | |
248 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
249 optopt(gamut,[40-100]). | |
250 | |
251 model_options(markov(ival,_)) --> | |
252 optopt(prior_shape, [uniform, binomial+uniform, binomial+0.1*uniform]). | |
253 | |
254 model_options(gilbert(_)) --> | |
255 [leap_range((-20)-(20))], | |
256 optopt(leap_shape, [uniform, binomial+uniform, binomial+0.1*uniform]), | |
257 optopt(pass_shape, [binomial, binomial+uniform, binomial+0.1*uniform]). | |
258 | |
259 model_options(hmm(nnum)) --> | |
260 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
261 anyopt(num_states, [1,2,3,5,7,12,18]), | |
262 optopt(trans_self, [1]), | |
263 % optopt(gamut,[40-100]). | |
264 % anyopt(trans_self, [1]), | |
265 anyopt(gamut,[40-100]). | |
266 | |
267 model_options(hmm(nnum,NS)) --> | |
268 [num_states(NS)], | |
269 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
270 optopt(trans_self, [1]), | |
271 % optopt(gamut,[40-100]). | |
272 % anyopt(trans_self, [1]), | |
273 anyopt(gamut,[40-100]). | |
274 | |
275 model_options(hmm(ival)) --> | |
276 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
277 anyopt(num_states, [5,7,12,24]), | |
278 [leap_range((-20)-(20))]. | |
279 | |
280 model_options(matlab(p1gram)) --> | |
281 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
282 optopt(gamut,[40-100]). | |
283 | |
284 model_options(matlab(p2gram)) --> | |
285 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
286 optopt(gamut,[40-100]). | |
287 | |
288 model_options(matlab(phmm)) --> | |
289 optopt(prior_shape, [binomial+0.1*uniform, binomial+uniform, uniform]), | |
290 anyopt(num_states, [1,2,3,5,7,12,18]), | |
291 optopt(gamut,[40-100]). | |
292 | |
293 model_subset_options(markov(nnum,_)) --> [prior_shape(binomial+0.1*uniform)]. | |
294 model_subset_options(markov(ival,_)) --> [prior_shape(binomial+0.1*uniform)]. | |
295 model_subset_options(gilbert(_)) --> []. | |
296 model_subset_options(hmm(nnum)) --> | |
297 [prior_shape(binomial+0.1*uniform)], | |
298 anyopt(num_states,[2,5,7,12,18]). | |
299 model_subset_options(hmm(ival)) --> | |
300 [prior_shape(binomial+0.1*uniform), leap_range((-20)-(20))], | |
301 anyopt(num_states,[2,5,7,12]). | |
302 | |
303 build_options(Model,Opts) :- | |
304 build_options(Model,Opts1,[]), | |
305 sort(Opts1,Opts). | |
306 | |
307 build_options(Model) --> | |
308 optopt(prior_weight,[0.3,3,10]), % NB have removed 0.1 and 30 | |
309 model_options(Model). | |
310 | |
311 build_subset_options(Model,Opts) :- | |
312 build_subset_options(Model,Opts1,[]), | |
313 sort(Opts1,Opts). | |
314 | |
315 build_subset_options(Model) --> | |
316 optopt(prior_weight,[0.1,0.3,3,10,30]), | |
317 model_subset_options(Model). | |
318 | |
319 anyopt(Name,Vals) --> {maplist(\X^Y^(Y=..[Name,X]),Vals,Opts)}, any(Opts). | |
320 optopt(Name,Vals) --> []; anyopt(Name,Vals). | |
321 | |
322 best_first(Meth,Mod,Prepare,DS,Opts,learn(Meth,Mod,Prepare,DS,Opts,F)) :- | |
323 order_by([asc(F)], learn_bpe(Meth,Mod,Prepare,DS,Opts,F)). | |
324 | |
325 /* TODO: | |
326 Sort out HMM init options. They are all wrong: | |
327 init_shape : shape of prior over initial state {uniform} | |
328 trans_shape : shape of prior over transition distribution {uniform} | |
329 trans_persistence : add self transtion counts {0,1,3} | |
330 init_noise : perturbation of initial obs counts {0,0.1} | |
331 restarts: {3} | |
332 | |
333 | |
334 | |
335 compare p2gram with hmm(1) | |
336 */ | |
337 | |
338 | |
339 %% map_filter(+P:pred(A,B),+Xs:list(A),-Ys:list(B)) is det. | |
340 % | |
341 % map_filter(P,Xs,Ys) is similar to maplist(P,Xs,Ys), except that P is allowed to | |
342 % fail and the resulting list Ys contains only those elements Y for which call(P,X,Y). | |
343 % P is used as if it was semi-deterministic: only the first solution is accepted. | |
344 map_filter(_,[],[]). | |
345 map_filter(P,[X|XX],[Y|YY]) :- call(P,X,Y), !, map_filter(P,XX,YY). | |
346 map_filter(P,[_|XX],YY) :- map_filter(P,XX,YY). | |
347 | |
348 user:file_search_path(home,X) :- expand_file_name('~',[X]). | |
349 user:file_search_path(prism,home('src/probprog/prism/psm')). | |
350 restart_prism :- prism_start('prism.log'). | |
351 | |
352 retry_on_error(G,M) :- | |
353 catch((restart_prism,G,Status=ok), Ex, Status=error(Ex)), | |
354 ( Status=ok -> true | |
355 ; format('*** terminated with ~w.\n',[Ex]), | |
356 shell('say ALERT: THERE WAS AN ERROR!'), | |
357 ( succ(N,M) -> retry_on_error(G,N) | |
358 ; writeln('failing after too many retries.'), | |
359 shell('say ALERT: I AM GIVING UP!'), | |
360 shell('say ALERT: I AM GIVING UP!'), | |
361 fail | |
362 ) | |
363 ). | |
364 | |
365 %% summary_array(+Meth:method,+Models:list(model),+Datasets:list(dataset),-Summary) is det. | |
366 summary_array(Meth,Models,Datasets,arr(Summary)) :- | |
367 maplist( \Model^RR^maplist(\DS^{arr(R)}^method_model_dataset_results(Meth,Model,DS,R),Datasets,RR), Models,Summary). | |
368 | |
369 %% method_model_dataset_results(+Method,+Model,+Dataset,Results:list(list(number))) is det. | |
370 method_model_dataset_results(Meth,Model,DS,Results) :- bagof( Row, datum(Meth,Model,DS,Row), Results). | |
371 | |
372 %% datum(+Method:method,+Model:model,+Dataset,-Datum:list(number)) is nondet. | |
373 % | |
374 % Maps trained models to a numerical tuple consisting of | |
375 % the free energy (in bits per event), the prior weight parameter, and one or two | |
376 % shape parameters, depending on the model. The shape parameter is 0 for a uniform | |
377 % prior, 1 for a binomial prior, and between 0 and 1 for linear interpolation between | |
378 % the two. | |
379 % | |
380 % Grammar models have leap_shape and pass_shape parameters, while the others | |
381 % have a single prior_shape parameter. | |
382 datum(Meth,gilbert(I),DS,[FE,W,K1,K2]) :- | |
383 model_module_prep(gilbert(I),Mod,Prep), | |
384 learn_bpe(Meth,Mod,Prep,DS,Opts,FE), | |
385 option(prior_weight(W),Opts,1), | |
386 option(leap_shape(Sh1),Opts,binomial), | |
387 option(pass_shape(Sh2),Opts,uniform), | |
388 shape_param(Sh1,K1), | |
389 shape_param(Sh2,K2). | |
390 | |
391 datum(Meth,markov(Rep,Ord),DS,[FE,W,K]) :- | |
392 model_module_prep(markov(Rep,Ord),Mod,Prep), | |
393 learn_bpe(Meth,Mod,Prep,DS,Opts,FE), | |
394 option(prior_weight(W),Opts,1), | |
395 option(prior_shape(Sh),Opts,binomial), | |
396 shape_param(Sh,K). | |
397 | |
398 datum(Meth,hmm(Rep),DS,[FE,W,K]) :- | |
399 model_module_prep(hmm(Rep),Mod,Prep), | |
400 learn_bpe(Meth,Mod,Prep,DS,Opts,FE), | |
401 option(prior_weight(W),Opts,1), | |
402 option(prior_shape(Sh),Opts,binomial), | |
403 shape_param(Sh,K). | |
404 | |
405 datum(Meth,hmm(Rep,NS),DS,[FE,W,K]) :- | |
406 model_module_prep(hmm(Rep),Mod,Prep), | |
407 learn_bpe(Meth,Mod,Prep,DS,Opts,FE), | |
408 option(num_states(NS),Opts), | |
409 option(prior_weight(W),Opts,1), | |
410 option(prior_shape(Sh),Opts,binomial), | |
411 shape_param(Sh,K). | |
412 | |
413 datum(Meth,matlab(F),DS,[FE,W,K]) :- | |
414 model_module_prep(matlab(F),Mod,Prep), | |
415 learn_bpe(Meth,Mod,Prep,DS,Opts,FE), | |
416 option(prior_weight(W),Opts,1), | |
417 option(prior_shape(Sh),Opts,binomial), | |
418 shape_param(Sh,K). | |
419 | |
420 shape_param(uniform,0). | |
421 shape_param(binomial,1). | |
422 shape_param(binomial+uniform,0.5). | |
423 shape_param(uniform+binomial,0.5). | |
424 shape_param(binomial+K*uniform,Lam) :- Lam = 1/(1+K). | |
425 |