This commit is contained in:
Vitor Santos Costa
2019-03-15 12:38:09 +00:00
parent e3c399af48
commit 044329d115
12 changed files with 250 additions and 344 deletions

View File

@@ -0,0 +1,146 @@
%========================================================================
%=
%=
%=
%========================================================================
/**
* @file problog/lbdd.yap
* support routines for BDD evaluation.
*
*/
%========================================================================
%= Updates all values of query_probability/2 and query_gradient/4
%= should be called always before these predicates are accessed
%= if the old values are still valid, nothing happens
%========================================================================
update_values :-
values_correct,
!.
update_values :-
\+ values_correct,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% delete old values
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
retractall(query_probability_intern(_,_)),
retractall(query_gradient_intern(_,_,_,_)),
assertz(values_correct).
update_query_cleanup(QueryID) :-
(
(query_is_similar(QueryID,_) ; query_is_similar(_,QueryID))
->
% either this query is similar to another or vice versa,
% therefore we don't delete anything
true;
retractall(query_gradient_intern(QueryID,_,_,_))
).
update_query(QueryID,Symbol,What_To_Update) :-
(
query_is_similar(QueryID,_)
->
% we don't have to evaluate the BDD
format_learning(4,'#',[]);
(
problog_flag(sigmoid_slope,Slope),
((What_To_Update=all;query_is_similar(_,QueryID)) -> Method='g' ; Method='l'),
gradient(QueryID, Method, Slope),
format_learning(4,'~w',[Symbol])
)
).
maplist_to_hash([], H0, H0).
maplist_to_hash([I-V|MapList], H0, Hash) :-
rb_insert(H0, V, I, H1),
maplist_to_hash(MapList, H1, Hash).
bind_maplist([]).
bind_maplist([Node-Theta|MapList]) :-
get_prob(Node, ProbFact),
inv_sigmoid(ProbFact, Theta),
bind_maplist(MapList).
tree_to_grad([], _, Grad, Grad).
tree_to_grad([Node|Tree], H, Grad0, Grad) :-
node_to_gradient_node(Node, H, GNode),
tree_to_grad(Tree, H, [GNode|Grad0], Grad).
%get_prob(Node, Prob) :-
% query_probability(Node,Prob), !.
get_prob(Node, Prob) :-
get_fact_probability(Node,Prob).
gradient(QueryID, l, Slope) :-
probability( QueryID, Slope, Prob),
assert(query_probability_intern(QueryID,Prob)),
fail.
gradient(_QueryID, l, _).
/* query_probability(21,6.775948e-01). */
gradient(QueryID, g, Slope) :-
recorded(QueryID, BDD, _),
query_gradients(BDD,Slope,I,Grad),
% writeln(grad(QueryID:I:Grad)),
assert(query_gradient_intern(QueryID,I,p,Grad)),
fail.
gradient(QueryID, g, Slope) :-
gradient(QueryID, l, Slope).
query_probability( DBDD, Slope, Prob) :-
DBDD = bdd(Dir, Tree, MapList),
bind_maplist(MapList),
run_sp(Tree, Slope, 1.0, Prob0),
(Dir == 1 -> Prob0 = Prob ; Prob is 1.0-Prob0).
query_gradients(bdd(Dir, Tree, MapList),Slope,I,Grad) :-
bind_maplist(MapList),
member(I-_, MapList),
run_grad(Tree, I, Slope, 0.0, Grad0),
( Dir = 1 -> Grad = Grad0 ; Grad is -Grad0).
node_to_gradient_node(pp(P-G,X,L,R), H, gnodep(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
node_to_gradient_node(pn(P-G,X,L,R), H, gnoden(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
run_sp([], _, P0, P0).
run_sp(gnodep(P,_G, X, _Id, PL, _GL, PR, _GR).Tree, Slope, _, PF) :-
EP = 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL+ (1.0-EP)*PR,
run_sp(Tree, Slope, P, PF).
run_sp(gnoden(P,_G, X, _Id, PL, _GL, PR, _GR).Tree, Slope, _, PF) :-
EP is 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL + (1.0-EP)*(1.0 - PR),
run_sp(Tree, Slope, P, PF).
run_grad([], _I, _, G0, G0).
run_grad([gnodep(P,G, X, Id, PL, GL, PR, GR)|Tree], I, Slope, _, GF) :-
EP is 1.0/(1.0 + exp(-X * Slope)),
P is EP*PL+ (1.0-EP)*PR,
G0 is EP*GL + (1.0-EP)*GR,
% don' t forget the -X
( I == Id -> G is G0+(PL-PR)* EP*(1-EP)*Slope ; G = G0 ),
run_grad(Tree, I, Slope, G, GF).
run_grad([gnoden(P,G, X, Id, PL, GL, PR, GR)|Tree], I, Slope, _, GF) :-
EP is 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL + (1.0-EP)*(1.0 - PR),
G0 is EP*GL - (1.0 - EP) * GR,
( I == Id -> G is G0+(PL+PR-1)*EP*(1-EP)*Slope ; G = G0 ),
run_grad(Tree, I, Slope, G, GF).

View File

@@ -25,8 +25,7 @@ graph2bdd(Query,1,bdd(D,T,Vs)) :-
graph(X,Y, TrieList, Vs),
bdd_new(TrieList, C),
bdd_tree(C, BDD),
BDD = bdd(D,T,_Vs0),
writeln(BDD).
BDD = bdd(D,T,_Vs0).
:- set_problog_flag(init_method,(Q,N,Bdd,user:graph2bdd(Q,N,Bdd))).

View File

@@ -421,6 +421,7 @@ do_learning_intern(Iterations,Epsilon) :-
logger_start_timer(duration),
% mse_testset,
% ground_truth_difference,
%leash(0),trace,
gradient_descent,
once(save_model),
@@ -486,8 +487,8 @@ init_learning :-
succeeds_n_times(user:example(_,_,_,_),TrainingExampleCount),
assertz(example_count(TrainingExampleCount)),
format_learning(3,'~q training examples~n',[TrainingExampleCount]),
current_probs <== array[TrainingExampleCount ] of floats,
current_lls <== array[TrainingExampleCount ] of floats,
%current_probs <== array[TrainingExampleCount ] of floats,
%current_lls <== array[TrainingExampleCount ] of floats,
forall(tunable_fact(FactID,_GroundTruth),
set_fact_probability(FactID,0.5)
),
@@ -507,18 +508,6 @@ init_learning :-
format_learning(1,'~n',[]).
%========================================================================
%= Updates all values of query_probability/2 and query_gradient/4
%= should be called always before these predicates are accessed
%= if the old values are still valid, nothing happensv
%========================================================================
update_values :-
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% delete old values
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
qp <== current_probs.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Check, if continuous facts are used.
% if yes, switch to problog_exact
@@ -586,7 +575,7 @@ init_one_query(QueryID,Query,_Type) :-
problog_flag(init_method,(Query,N,Bdd,user:graph2bdd(Query,N,Bdd))),
!,
b_setval(problog_required_keep_ground_ids,false),
(QueryID mod 100 =:= 0 -> writeln(QueryID) ; true),
(QueryID mod 100 =:= 0 ->writeln(QueryID) ; true),
Bdd = bdd(Dir, Tree,MapList),
user:graph2bdd(Query,N,Bdd),
rb_new(H0),
@@ -792,8 +781,7 @@ inv_sigmoid(T,Slope,InvSig) :-
%= probabilities of the examples have to be recalculated
%========================================================================
save_old_probabilities :-
old_prob <== p.
save_old_probabilities.
% vsc: avoid silly search
@@ -828,59 +816,56 @@ set_tunable(I,Slope,P) :-
sigmoid(X,Slope,Pr),
set_fact_probability(I,Pr).
:- include(problog/lbdd).
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% start calculate gradient
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
user:evaluate(LLH_Training_Queries, X,Grad,N,_,_) :-
%Handle = user_error,
LLs = current_lls,
Probs = current_probs,
%Handle = user_error,
example_count(TrainingExampleCount),
ExProbs <== array[TrainingExampleCount] of floats,
LLs <== array[N] of floats,
Probs <== array[N] of floats,
problog_flag(sigmoid_slope,Slope),
N1 is N-1,
forall(between(0,N1,I),
(Grad[I] <== 0.0, S <== X[I], sigmoid(S,Slope, P), Probs[I] <== P)
),
writeln(e0),
leash(0),trace,
forall(
user:example(QueryID,_Query,QueryProb),
compute_grad(QueryID, QueryProb,Grad, Probs, Slope,LLs)
recorded(QueryID,BDD,_),
compute_probability(BDD,Slope,QueryID,ExProbs)
),
writeln(Grad),
forall(
user:example(QueryID,_Query,QueryProb),
compute_gradient(QueryID, QueryProb,Grad, Probs, Slope,LLs)
),
trace,
LLH_Training_Queries <== sum(LLs).
compute_probability( BDD, Slope, Id, Probs) :-
query_probability( BDD, Slope, Prob),
Probs[Id] <== Prob.
compute_grad(QueryID,QueryProb, Grad, Probs, Slope, LLs) :-
recorded(QueryID,BDD,_),
BDD = bdd(_Dir, _GradTree, MapList),
bind_maplist(MapList, Slope, Probs),
qprobability(BDD,Slope,BDDProb),
compute_gradient(QueryID,QueryProb, Grad, Probs, ExProbs, Slope, LLs) :-
recorded(QueryID,BDD,_),
BDDProb <== ExProbs[QueryID],
forall(
query_gradients(BDD,Slope,I,GradValue),
gradient_pair(BDDProb, QueryProb, Grad, GradValue, I, Probs)
),
LL is (BDDProb-QueryProb)*(BDDProb-QueryProb),
LLs[QueryID] <== LL,
forall(
member(I-_,MapList),
gradientpair(Slope,BDDProb, QueryProb,Grad,Probs,BDD,I)
),
writeln(LL).
writeln(LL),
LLs[QueryID] <== LL.
gradientpair(Slope,BDDProb, QueryProb, Grad, Probs,BDD,I) :-
qgradient(I, BDD, Slope, FactID, GradValue),
G0 <== Grad[FactID],
Prob <== Probs[FactID],
gradient_pair(BDDProb, QueryProb, Grad, GradValue, I, Probs) :-
G0 <== Grad[I],
Prob <== Probs[I],
GN is G0-GradValue*2*Prob*(1-Prob)*(QueryProb-BDDProb),
Grad[FactID] <== GN.
qprobability(bdd(Dir, Tree, _MapList), Slope, Prob) :-
/* query_probability(21,6.775948e-01). */
run_sp(Tree, Slope, 1, Prob0),
(Dir == 1 -> Prob0 = Prob ; Prob is 1.0-Prob0).
qgradient(I, bdd(Dir,Tree,_), Slope, I, Grad) :-
run_grad(Tree, I, Slope, 1.0, 0.0, Grad0),
( Dir = 1 -> Grad = Grad0 ; Grad is -Grad0).
writeln(G0),
Grad[I] <== GN.
wrap( X, Grad, GradCount) :-
tunable_fact(FactID,GroundTruth),
@@ -894,52 +879,6 @@ wrap( X, Grad, GradCount) :-
wrap( _X, _Grad, _GradCount).
% writeln(grad(QueryID:I:Grad)),
% assert(query_gradient_intern(QueryID,I,p,Grad)),
% fail.
%gradient(QueryID, g, Slope) :-
% gradient(QueryID, l, Slope).
maplist_to_hash([], H0, H0).
maplist_to_hash([I-V|MapList], H0, Hash) :-
rb_insert(H0, V, I, H1),
maplist_to_hash(MapList, H1, Hash).
tree_to_grad([], _, Grad, Grad).
tree_to_grad([Node|Tree], H, Grad0, Grad) :-
node_to_gradient_node(Node, H, GNode),
tree_to_grad(Tree, H, [GNode|Grad0], Grad).
node_to_gradient_node(pp(P-G,X,L,R), H, gnodep(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
node_to_gradient_node(pn(P-G,X,L,R), H, gnoden(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
run_sp([], _, P0, P0).
run_sp(gnodep(P,_G, EP, _Id, PL, _GL, PR, _GR).Tree, Slope, PL, PF) :-
P is EP*PL+ (1.0-EP)*PR,
run_sp(Tree, Slope, P, PF).
run_sp(gnoden(P,_G, EP, _Id, PL, _GL, PR, _GR).Tree, Slope, PL, PF) :-
P is EP*PL + (1.0-EP)*(1.0 - PR),
run_sp(Tree, Slope, P, PF).
run_grad([], _I, _, _, G0, G0).
run_grad([gnodep(P,G, EP, Id, PL, GL, PR, GR)|Tree], I, Slope, PL, GL, GF) :-
P is EP*PL+ (1.0-EP)*PR,
G0 is EP*GL + (1.0-EP)*GR,
% don' t forget the -X
( I == Id -> G is PL-PR ; G = G0 ),
run_grad(Tree, I, Slope, P, G, GF).
run_grad([gnoden(P,G, EP, Id, PL, GL, PR, GR)|Tree], I, Slope, PL, GL, GF) :-
P is EP*PL + (1.0-EP)*(1.0 - PR),
G0 is EP*GL - (1.0 - EP) * GR,
( I == Id -> G is PL-(1.0-PR) ; G = G0 ),
run_grad(Tree, I, Slope, P, G, GF).
prob2log(_X,Slope,FactID,V) :-
@@ -1023,4 +962,3 @@ init_logger :-
:- initialization(init_flags).
:- initialization(init_logger).

View File

@@ -664,138 +664,6 @@ init_one_query(_QueryID,_Query,_Type) :-
%========================================================================
%= Updates all values of query_probability/2 and query_gradient/4
%= should be called always before these predicates are accessed
%= if the old values are still valid, nothing happens
%========================================================================
update_values :-
values_correct,
!.
update_values :-
\+ values_correct,
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% delete old values
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
retractall(query_probability_intern(_,_)),
retractall(query_gradient_intern(_,_,_,_)),
assertz(values_correct).
%========================================================================
%=
%=
%=
%========================================================================
update_query_cleanup(QueryID) :-
(
(query_is_similar(QueryID,_) ; query_is_similar(_,QueryID))
->
% either this query is similar to another or vice versa,
% therefore we don't delete anything
true;
retractall(query_gradient_intern(QueryID,_,_,_))
).
update_query(QueryID,Symbol,What_To_Update) :-
(
query_is_similar(QueryID,_)
->
% we don't have to evaluate the BDD
format_learning(4,'#',[]);
(
problog_flag(sigmoid_slope,Slope),
((What_To_Update=all;query_is_similar(_,QueryID)) -> Method='g' ; Method='l'),
gradient(QueryID, Method, Slope),
format_learning(4,'~w',[Symbol])
)
).
bind_maplist([]).
bind_maplist([Node-Theta|MapList]) :-
get_prob(Node, ProbFact),
inv_sigmoid(ProbFact, Theta),
bind_maplist(MapList).
%get_prob(Node, Prob) :-
% query_probability(Node,Prob), !.
get_prob(Node, Prob) :-
get_fact_probability(Node,Prob).
gradient(QueryID, l, Slope) :-
/* query_probability(21,6.775948e-01). */
recorded(QueryID, bdd(Dir, Tree, MapList), _),
bind_maplist(MapList),
run_sp(Tree, Slope, 1.0, Prob0),
(Dir == 1 -> Prob0 = Prob ; Prob is 1.0-Prob0),
assert(query_probability_intern(QueryID,Prob)),
fail.
gradient(_QueryID, l, _).
gradient(QueryID, g, Slope) :-
recorded(QueryID, bdd(Dir, Tree, MapList), _),
bind_maplist(MapList),
member(I-_, MapList),
run_grad(Tree, I, Slope, 0.0, Grad0),
( Dir = 1 -> Grad = Grad0 ; Grad is -Grad0),
% writeln(grad(QueryID:I:Grad)),
assert(query_gradient_intern(QueryID,I,p,Grad)),
fail.
gradient(QueryID, g, Slope) :-
gradient(QueryID, l, Slope).
maplist_to_hash([], H0, H0).
maplist_to_hash([I-V|MapList], H0, Hash) :-
rb_insert(H0, V, I, H1),
maplist_to_hash(MapList, H1, Hash).
tree_to_grad([], _, Grad, Grad).
tree_to_grad([Node|Tree], H, Grad0, Grad) :-
node_to_gradient_node(Node, H, GNode),
tree_to_grad(Tree, H, [GNode|Grad0], Grad).
node_to_gradient_node(pp(P-G,X,L,R), H, gnodep(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
node_to_gradient_node(pn(P-G,X,L,R), H, gnoden(P,G,X,Id,PL,GL,PR,GR)) :-
rb_lookup(X,Id,H),
(L == 1 -> GL=0, PL=1 ; L == 0 -> GL = 0, PL=0 ; L = PL-GL),
(R == 1 -> GR=0, PR=1 ; R == 0 -> GR = 0, PR=0 ; R = PR-GR).
run_sp([], _, P0, P0).
run_sp(gnodep(P,_G, X, _Id, PL, _GL, PR, _GR).Tree, Slope, _, PF) :-
EP = 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL+ (1.0-EP)*PR,
run_sp(Tree, Slope, P, PF).
run_sp(gnoden(P,_G, X, _Id, PL, _GL, PR, _GR).Tree, Slope, _, PF) :-
EP is 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL + (1.0-EP)*(1.0 - PR),
run_sp(Tree, Slope, P, PF).
run_grad([], _I, _, G0, G0).
run_grad([gnodep(P,G, X, Id, PL, GL, PR, GR)|Tree], I, Slope, _, GF) :-
EP is 1.0/(1.0 + exp(-X * Slope)),
P is EP*PL+ (1.0-EP)*PR,
G0 is EP*GL + (1.0-EP)*GR,
% don' t forget the -X
( I == Id -> G is G0+(PL-PR)* EP*(1-EP)*Slope ; G = G0 ),
run_grad(Tree, I, Slope, G, GF).
run_grad([gnoden(P,G, X, Id, PL, GL, PR, GR)|Tree], I, Slope, _, GF) :-
EP is 1.0 / (1.0 + exp(-X * Slope) ),
P is EP*PL + (1.0-EP)*(1.0 - PR),
G0 is EP*GL - (1.0 - EP) * GR,
( I == Id -> G is G0+(PL+PR-1)*EP*(1-EP)*Slope ; G = G0 ),
run_grad(Tree, I, Slope, G, GF).
%========================================================================
%= This predicate reads probability and gradient values from the file