Learning (Parameter Learning)
Il Parameter Learning è un processo che permette di apprendere le probabilità dei fatti da dati osservati, senza doverle definire manualmente. È il meccanismo che trasforma un programma probabilistico in un modello guidato dai dati.
Il cuore del learning in ProbLog è il predicato t() che rende un fatto "apprendibile"; il motore del learning è un algoritmo Expectation-Maximization (EM), chiamato Learning From Interpretations (LFI).
Definendo i fatti in un programma per il learning si può scegliere tra le seguenti modalità:
- un fatto preceduto da una probabilità fissa che non verrà modificata dall'apprendimento, come già precedentemente visto;
- un fatto apprendibile preceduto da
t(p)::dove p è un valore di partenza che riflette una "ipotesi" iniziale; - un fatto apprendibile preceduto da
t(_)::in modo che la probabilità verrà inizializzata a un valore casuale all'inizio dell'algoritmo EM.
Si provi questo primo esempio nell'editor on line selezionando il modello Learning e inserendo prima il programma
% Fatti apprendibili: probabilità che ogni moneta dia testa
t(_)::heads(c1).
t(_)::heads(c2).
t(_)::heads(c3).
% Regole per definire eventi complessi (opzionali)
two_heads :- heads(c1), heads(c2).
all_heads :- heads(c1), heads(c2), heads(c3).
e quindi negli Examples i seguenti dati osservati.
% Lancio 1: c1 e c3 danno testa, c2 dà croce
evidence(heads(c1), true).
evidence(heads(c3), true).
evidence(heads(c2), false).
---
% Lancio 2: solo c2 dà testa
evidence(heads(c2), true).
evidence(heads(c1), false).
evidence(heads(c3), false).
---
% Lancio 3: tutte e tre danno testa
evidence(all_heads, true).
---
% Lancio 4: nessuna dà testa
evidence(heads(c1), false).
evidence(heads(c2), false).
evidence(heads(c3), false).
---
% Lancio 5: c1 e c2 danno testa, c3 no
evidence(heads(c1), true).
evidence(heads(c2), true).
evidence(heads(c3), false).
---
% Lancio 6: solo c3 dà testa
evidence(heads(c3), true).
evidence(heads(c1), false).
evidence(heads(c2), false).
---
% Lancio 7: c1 e c3 danno testa
evidence(heads(c1), true).
evidence(heads(c3), true).
evidence(heads(c2), false).
---
% Lancio 8: due testa
evidence(two_heads, true).
---
% Lancio 9: tutte danno testa
evidence(all_heads, true).
---
% Lancio 10: solo c1 dà testa
evidence(heads(c1), true).
evidence(heads(c2), false).
evidence(heads(c3), false).
Un primo semplice esempio da far girare in Python è il seguente.
from problog.logic import Term
from problog.program import PrologString
from problog.learning import lfi
model = r"""
% Fatti apprendibili: probabilità che la moneta dia testa
t(_)::heads.
"""
# Definizione dei termini
heads = Term('heads')
examples = [
[(heads, False)],
[(heads, False)],
[(heads, True)],
[(heads, False)],
[(heads, False)],
[(heads, False)],
[(heads, False)],
[(heads, False)],
[(heads, True)],
[(heads, False)]
]
score, weights, atoms, iteration, lfi_problem = lfi.run_lfi(PrologString(model), examples, max_iter=50)
print (lfi_problem.get_model())
0.2::heads.
L'esempio proposto per primo in questa pagina, nell'ambiente gestito da Python sarà descritto nel modo seguente.
model = r"""
%Fatti apprendibili: probabilità che ogni moneta dia testa
t(_)::heads(c1).
t(_)::heads(c2).
t(_)::heads(c3).
% Regole per definire eventi complessi (opzionali)
two_heads :- heads(c1), heads(c2).
all_heads :- heads(c1), heads(c2), heads(c3).
"""
# Definizione di termini relativi alle monete per un utilizzo più semplice
heads_c1 = Term('heads', Term('c1'))
heads_c2 = Term('heads', Term('c2'))
heads_c3 = Term('heads', Term('c3'))
two_heads = Term('two_heads')
all_heads = Term('all_heads')
examples = [
[(heads_c1, True), (heads_c3, True), (heads_c2, False)],
[(heads_c2, True), (heads_c1, False), (heads_c3, False)],
[(all_heads, True)],
[(heads_c1, False), (heads_c2, False), (heads_c3, False)],
[(heads_c1, True), (heads_c2, True), (heads_c3, False)],
[(heads_c3, True), (heads_c1, False), (heads_c2, False)],
[(heads_c1, True), (heads_c3, True), (heads_c2, False)],
[(two_heads, True)],
[(all_heads, True)],
[(heads_c1, True), (heads_c2, False), (heads_c3, False)]
]
score, weights, atoms, iteration, lfi_problem = lfi.run_lfi(PrologString(model), examples, max_iter=5000)
print (lfi_problem.get_model())
prog = lfi_problem.get_model()+"""
query(two_heads).
query(all_heads).
"""
run(PrologString(prog))
0.7::heads(c1).
0.5::heads(c2).
0.555555555555556::heads(c3).
two_heads :- heads(c1), heads(c2).
all_heads :- heads(c1), heads(c2), heads(c3).
{two_heads: 0.3499999999999999, all_heads: 0.1944444444444446}
La classe Term in ProbLog, importata da problog.logic rappresenta un termine della logica del primo ordine.
Il seguente è un altro esempio.
model = r"""
t(0.5)::burglary.
0.2::earthquake.
t(_)::p_alarm1.
t(_)::p_alarm2.
t(_)::p_alarm3.
alarm :- burglary, earthquake, p_alarm1.
alarm :- burglary, \+earthquake, p_alarm2.
alarm :- \+burglary, earthquake, p_alarm3.
"""
alarm = Term('alarm')
burglary = Term('burglary')
earthquake = Term('earthquake')
examples = [
[(burglary, False), (alarm, False)],
[(earthquake, False), (alarm, True), (burglary, True)],
[(burglary, False)]
]
score, weights, atoms, iteration, lfi_problem = lfi.run_lfi(PrologString(model), examples)
print (lfi_problem.get_model())
0.333333333333333::burglary.
0.2::earthquake.
0.220226823615252::p_alarm1.
1.0::p_alarm2.
0.0::p_alarm3.
alarm :- burglary, earthquake, p_alarm1.
alarm :- burglary, \+earthquake, p_alarm2.
alarm :- \+burglary, earthquake, p_alarm3.
e quindi
prog = lfi_problem.get_model()+"""
query(alarm).
"""
run(PrologString(prog))
{alarm: 0.3068552187773007}