Esercizio - Filtraggio nell'ombrello con pomegranate (laboratorio 6)
Testo (laboratorio 6, Approximate inference and Bayesian networks, part B, corso di Intelligenza Artificiale, Ing. dell'Informazione UniPD). Usare pomegranate per calcolare la probabilità filtrata di pioggia al giorno quando si vede un ombrello nei giorni e .
- Qual è la probabilità filtrata di pioggia al giorno quando non si vede l'ombrello al giorno (e lo si vede al giorno )?
- E se non si ha alcuna informazione sugli ombrelli del giorno (solo quello del giorno )?
Il modello (mondo dell'ombrello, Ragionamento probabilistico nel tempo - catene di Markov, HMM, filtraggio e smoothingPer ragionare sul tempo il mondo è una sequenza di istanti: stato nascosto $X_t$ ed evidenza osservata $E_t$. Ipotesi di Markov del primo ordine $P(X_t\mid X_{0:t-1})=P(X_t\mid X_{t-1})$ (modello di transizione) e ipotesi del sensore $P(E_t\mid X_{0:t},E_{1:t-1})=P(E_t\mid X_t)$ (modello del sensore): congiunta $P(X_0)\prod_t P(X_t\mid X_{t-1})P(E_t\mid X_t)$. Un HMM ha uno stato discreto a $S$ valori: transizione = matrice $\mathbf T$ ($T_{ij}=P(X_t=j\mid X_{t-1}=i)$), sensore = matrici diagonali $\mathbf O_t$. Compiti: filtraggio $P(X_t\mid e_{1:t})$, predizione $P(X_{t+k}\mid e_{1:t})$, smoothing $P(X_{t-k}\mid e_{1:t})$, spiegazione più probabile $\arg\max P(x_{1:t}\mid e_{1:t})$. Filtraggio ricorsivo: $\mathbf f_t=\alpha,\mathbf O_t\mathbf T^\top\mathbf f_{t-1}$ (predizione, poi aggiornamento). Mondo dell'ombrello: $\mathbf f_1=\langle0{,}818;\ 0{,}182\rangle$, $\mathbf f_2=\langle0{,}883;\ 0{,}117\rangle$. Senza normalizzare, $\mathbf s_t=\mathbf O_t\mathbf T^\top\mathbf s_{t-1}$ dà la verosimiglianza $P(e_{1:t})$.Ragionamento probabilistico nel tempo - catene di Markov, HMM, filtraggio e smoothing →): prior ; transizione , ; sensore , . pomegranate sa risolvere solo reti bayesiane statiche, non reti bayesiane dinamiche: il modello va srotolato fino alla profondità desiderata (, con figlio di ).
Soluzione
Le tre domande a mano (filtraggio, ). Con la predizione del giorno è .
- e . Giorno : . Predizione del giorno : ; con : , somma :
- e . Giorno : (senza ombrello è improbabile che piova). Predizione del giorno : ; con : :
- Solo . La predizione del giorno con il prior uniforme resta (la matrice è simmetrica, quindi il prior uniforme è stazionario), poi con :
Confronto: (due ombrelli) (un solo ombrello, nessuna informazione sull'altro giorno) (ombrello mancante ieri, presente oggi). Il giorno senza ombrello abbassa la credenza su e, per la persistenza (), anche su .
Codice del corso (pomegranate 0.15)
from pomegranate import *
Rain0 = DiscreteDistribution({'y': 0.5, 'n': 0.5}) # prior su Rain0
Rain1 = ConditionalProbabilityTable( # transizione: [Rain_N, Rain_N+1, prob]
[['y', 'y', 0.7], ['y', 'n', 0.3],
['n', 'y', 0.3], ['n', 'n', 0.7]], [Rain0])
Rain2 = ConditionalProbabilityTable(
[['y', 'y', 0.7], ['y', 'n', 0.3],
['n', 'y', 0.3], ['n', 'n', 0.7]], [Rain1])
Umbrella1 = ConditionalProbabilityTable( # sensore: [Umbrella, Rain, prob]
[['y', 'y', 0.9], ['y', 'n', 0.1],
['n', 'y', 0.2], ['n', 'n', 0.8]], [Rain1])
Umbrella2 = ConditionalProbabilityTable(
[['y', 'y', 0.9], ['y', 'n', 0.1],
['n', 'y', 0.2], ['n', 'n', 0.8]], [Rain2])In ogni riga di una ConditionalProbabilityTable le prime colonne sono i valori dei genitori, nell'ordine della lista finale (qui [Rain1]), poi il valore del nodo, poi la probabilità. Quindi ['y', 'n', 0.1] per Umbrella1 è e ['n', 'y', 0.2] è . Il commento del corso ([ 'Umbrella', 'Rain', <probability>]) scrive l'ordine inverso, ma i valori sono giusti: danno e , come conferma l'output uguale al calcolo a mano. Lo stesso vale per le transizioni: ['y', 'n', 0.3] per Rain1 è .
Costruzione della rete, nodi (Rain0, Rain1, Umbrella1, Rain2, Umbrella2) con gli archi s1->s2, s2->s3, s2->s4, s4->s5; model.bake() ne fissa la topologia. Poi si aggiunge (s6, figlio di s4) e si richiama bake(). Le domande sono query con evidenza: una lista con un elemento per nodo (None = non osservato), nell'ordine [Rain0, Rain1, Umbrella1, Rain2, Umbrella2, Rain3].
scenario = [[None, None, 'y', None, 'y', None]] # Q2.1: ombrello i giorni 1 e 2
results = model.predict_proba(scenario)
print(results[0][3].items()) # indice 3 = Rain2Output del corso:
- Q2.1 ():
(('y', 0.8833570412517777), ('n', 0.11664295874822232)); - Q2.2 (, scenario
[None, None, 'n', None, 'y', None]):(('y', 0.7027707808564231), ('n', 0.2972292191435768)); - Q2.3 (nessuna informazione su ,
[None, None, None, None, 'y', None]):(('y', 0.8181818181818179), ('n', 0.1818181818181821)).
Verifica con numpy
pomegranate non è installato: i tre valori sono stati ricalcolati con codice proprio. Si scrive la congiunta della rete srotolata come prodotto di CPT, si sommano le assegnazioni di che sono coerenti con l'evidenza e si normalizza:
import itertools
import numpy as np
Tm = {(1, 1): .7, (1, 0): .3, (0, 1): .3, (0, 0): .7} # P(R_k | R_k-1), 1 = pioggia
Pu = {1: .9, 0: .2} # P(u | R)
def post(profondita, evid): # evid: {'U1': 1, ...}
out = [np.zeros(2) for _ in range(profondita + 1)]
for rs in itertools.product((1, 0), repeat=profondita + 1):
p = .5 # prior su Rain0
for a, b in zip(rs[:-1], rs[1:]): p *= Tm[(a, b)]
for k in range(1, profondita + 1):
if 'U%d' % k in evid: # evidenza sull'ombrello k
p *= Pu[rs[k]] if evid['U%d' % k] else 1 - Pu[rs[k]]
for k in range(profondita + 1): out[k][0 if rs[k] else 1] += p
return [o / o.sum() for o in out]
print(post(3, {'U1': 1, 'U2': 1})[2]) # Q2.1
print(post(3, {'U1': 0, 'U2': 1})[2]) # Q2.2
print(post(3, {'U2': 1})[2]) # Q2.3Output: [0.8834 0.1166], [0.7028 0.2972], [0.8182 0.1818], identici ai tre output di pomegranate.
Versione ripasso
- Modello: , , , , .
pomegranaterichiede la rete srotolata (, figli). - Filtraggio (filtraggio: predizione e aggiornamentoRagionamento probabilistico nel tempo - catene di Markov, HMM, filtraggio e smoothing →).
- : ; predizione ; .
- : ; predizione ; .
- Solo : predizione (prior stazionario), .
- Query:
predict_probacon una lista (None= non osservato) nell'ordine dei nodi; Rain2 è l'indice . - Errori tipici: usare l'ordine sbagliato dei nodi nello scenario; dimenticare di normalizzare; credere che senza informazione sull'ombrello del giorno il giorno valga .
- Scenari (ordine dei nodi
[Rain0, Rain1, Umbrella1, Rain2, Umbrella2, Rain3]):[None, None, 'y', None, 'y', None];[None, None, 'n', None, 'y', None]; solo[None, None, None, None, 'y', None]. Output del corso: , , . - Tabelle: nelle righe di una
ConditionalProbabilityTableprima i genitori, poi il valore del nodo, poi la probabilità. Verifica indipendente con enumerazione sulla rete srotolata: stessi tre valori.