Salta al contenuto
Note per Studenti Esercizio - Filtraggio nell'ombrello con pomegranate (laboratorio 6)

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 22 quando si vede un ombrello nei giorni 11 e 22.

  • Qual è la probabilità filtrata di pioggia al giorno 22 quando non si vede l'ombrello al giorno 11 (e lo si vede al giorno 22)?
  • E se non si ha alcuna informazione sugli ombrelli del giorno 11 (solo quello del giorno 22)?

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 P(Rain0)=⟨0,5; 0,5⟩P(\text{Rain}_0)=\langle0{,}5;\ 0{,}5\rangle; transizione P(rt∣rt−1)=0,7P(r_t\mid r_{t-1})=0{,}7, P(rt∣¬rt−1)=0,3P(r_t\mid\neg r_{t-1})=0{,}3; sensore P(ut∣rt)=0,9P(u_t\mid r_t)=0{,}9, P(ut∣¬rt)=0,2P(u_t\mid\neg r_t)=0{,}2. pomegranate sa risolvere solo reti bayesiane statiche, non reti bayesiane dinamiche: il modello va srotolato fino alla profondità desiderata (Rain0→Rain1→Rain2→Rain3\text{Rain}_0\to\text{Rain}_1\to\text{Rain}_2\to\text{Rain}_3, con Umbrellak\text{Umbrella}_k figlio di Raink\text{Rain}_k).


Soluzione

Le tre domande a mano (filtraggio, ft=α OtT⊤ft−1\mathbf f_t=\alpha\,\mathbf O_t\mathbf T^\top\mathbf f_{t-1}). Con f0=⟨0,5; 0,5⟩\mathbf f_0=\langle0{,}5;\ 0{,}5\rangle la predizione del giorno 11 è ⟨0,5; 0,5⟩\langle0{,}5;\ 0{,}5\rangle.

  1. u1u_1 e u2u_2. Giorno 11: ⟨0,9⋅0,5; 0,2⋅0,5⟩=⟨0,45; 0,10⟩→f1=⟨0,818; 0,182⟩\langle0{,}9\cdot0{,}5;\,0{,}2\cdot0{,}5\rangle=\langle0{,}45;\,0{,}10\rangle\to\mathbf f_1=\langle0{,}818;\ 0{,}182\rangle. Predizione del giorno 22: ⟨0,7⋅0,818+0,3⋅0,182; … ⟩=⟨0,627; 0,373⟩\langle0{,}7\cdot0{,}818+0{,}3\cdot0{,}182;\ \dots\rangle=\langle0{,}627;\ 0{,}373\rangle; con u2u_2: ⟨0,9⋅0,627; 0,2⋅0,373⟩=⟨0,5645; 0,0745⟩\langle0{,}9\cdot0{,}627;\,0{,}2\cdot0{,}373\rangle=\langle0{,}5645;\,0{,}0745\rangle, somma 0,6390{,}639: P(r2∣u1,u2)=0,8834.P(r_2\mid u_1,u_2)=0{,}8834.
  2. ¬u1\neg u_1 e u2u_2. Giorno 11: ⟨0,1⋅0,5; 0,8⋅0,5⟩=⟨0,05; 0,40⟩→f1=⟨0,111; 0,889⟩\langle0{,}1\cdot0{,}5;\,0{,}8\cdot0{,}5\rangle=\langle0{,}05;\,0{,}40\rangle\to\mathbf f_1=\langle0{,}111;\ 0{,}889\rangle (senza ombrello è improbabile che piova). Predizione del giorno 22: ⟨0,7⋅0,111+0,3⋅0,889; … ⟩=⟨0,344; 0,656⟩\langle0{,}7\cdot0{,}111+0{,}3\cdot0{,}889;\ \dots\rangle=\langle0{,}344;\ 0{,}656\rangle; con u2u_2: ⟨0,9⋅0,344; 0,2⋅0,656⟩=⟨0,310; 0,131⟩\langle0{,}9\cdot0{,}344;\,0{,}2\cdot0{,}656\rangle=\langle0{,}310;\,0{,}131\rangle: P(r2∣¬u1,u2)=0,310/0,441=0,7028.P(r_2\mid\neg u_1,u_2)=0{,}310/0{,}441=0{,}7028.
  3. Solo u2u_2. La predizione del giorno 22 con il prior uniforme resta ⟨0,5; 0,5⟩\langle0{,}5;\ 0{,}5\rangle (la matrice T\mathbf T è simmetrica, quindi il prior uniforme è stazionario), poi con u2u_2: ⟨0,45; 0,10⟩→\langle0{,}45;\,0{,}10\rangle\to P(r2∣u2)=0,8182.P(r_2\mid u_2)=0{,}8182.

Confronto: 0,8830{,}883 (due ombrelli) >0,818>0{,}818 (un solo ombrello, nessuna informazione sull'altro giorno) >0,703>0{,}703 (ombrello mancante ieri, presente oggi). Il giorno 11 senza ombrello abbassa la credenza su r1r_1 e, per la persistenza (0,70{,}7), anche su r2r_2.

Codice del corso (pomegranate 0.15)

python
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 è P(Umbrella=n∣Rain=y)=0,1P(\text{Umbrella}=\text{n}\mid\text{Rain}=\text{y})=0{,}1 e ['n', 'y', 0.2] è P(Umbrella=y∣Rain=n)=0,2P(\text{Umbrella}=\text{y}\mid\text{Rain}=\text{n})=0{,}2. Il commento del corso ([ 'Umbrella', 'Rain', <probability>]) scrive l'ordine inverso, ma i valori sono giusti: danno P(u∣r)=0,9P(u\mid r)=0{,}9 e P(u∣¬r)=0,2P(u\mid\neg r)=0{,}2, come conferma l'output 0,88340{,}8834 uguale al calcolo a mano. Lo stesso vale per le transizioni: ['y', 'n', 0.3] per Rain1 è P(Rain1=n∣Rain0=y)P(\text{Rain}_1=\text{n}\mid\text{Rain}_0=\text{y}).

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 Rain3\text{Rain}_3 (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].

python
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 = Rain2

Output del corso:

  • Q2.1 (u1,u2u_1,u_2): (('y', 0.8833570412517777), ('n', 0.11664295874822232));
  • Q2.2 (¬u1\neg u_1, scenario [None, None, 'n', None, 'y', None]): (('y', 0.7027707808564231), ('n', 0.2972292191435768));
  • Q2.3 (nessuna informazione su U1U_1, [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 P(r0)∏k=13P(rk∣rk−1)∏kP(uk∣rk)P(r_0)\prod_{k=1}^3P(r_k\mid r_{k-1})\prod_kP(u_k\mid r_k) come prodotto di CPT, si sommano le 242^4 assegnazioni di Rain0,…,Rain3\text{Rain}_0,\dots,\text{Rain}_3 che sono coerenti con l'evidenza e si normalizza:

python
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.3

Output: [0.8834 0.1166], [0.7028 0.2972], [0.8182 0.1818], identici ai tre output di pomegranate.

Versione ripasso

  • Modello: P(r0)=0,5P(r_0)=0{,}5, P(rt∣rt−1)=0,7P(r_t\mid r_{t-1})=0{,}7, P(rt∣¬rt−1)=0,3P(r_t\mid\neg r_{t-1})=0{,}3, P(u∣r)=0,9P(u\mid r)=0{,}9, P(u∣¬r)=0,2P(u\mid\neg r)=0{,}2. pomegranate richiede la rete srotolata (Rain0→Rain1→Rain2→Rain3\text{Rain}_0\to\text{Rain}_1\to\text{Rain}_2\to\text{Rain}_3, Umbrellak\text{Umbrella}_k figli).
  • Filtraggio (filtraggioft=α OtT⊤ft−1\mathbf f_t=\alpha\,\mathbf O_t\mathbf T^\top\mathbf f_{t-1}: predizione e aggiornamentoRagionamento probabilistico nel tempo - catene di Markov, HMM, filtraggio e smoothing →).
  • u1,u2u_1,u_2: f1=⟨0,818; 0,182⟩\mathbf f_1=\langle0{,}818;\,0{,}182\rangle; predizione 0,6270{,}627; ⟨0,5645; 0,0745⟩/0,639⇒0,8834\langle0{,}5645;\,0{,}0745\rangle/0{,}639\Rightarrow0{,}8834.
  • ¬u1,u2\neg u_1,u_2: f1=⟨0,111; 0,889⟩\mathbf f_1=\langle0{,}111;\,0{,}889\rangle; predizione 0,3440{,}344; ⟨0,310; 0,131⟩⇒0,7028\langle0{,}310;\,0{,}131\rangle\Rightarrow0{,}7028.
  • Solo u2u_2: predizione 0,50{,}5 (prior stazionario), ⟨0,45; 0,10⟩⇒0,8182\langle0{,}45;\,0{,}10\rangle\Rightarrow0{,}8182.
  • Query: predict_proba con una lista (None = non osservato) nell'ordine dei nodi; Rain2 è l'indice 33.
  • Errori tipici: usare l'ordine sbagliato dei nodi nello scenario; dimenticare di normalizzare; credere che senza informazione sull'ombrello del giorno 11 il giorno 11 valga ⟨0,818; 0,182⟩\langle0{,}818;\,0{,}182\rangle.
  • Scenari (ordine dei nodi [Rain0, Rain1, Umbrella1, Rain2, Umbrella2, Rain3]): u1,u2u_1,u_2 [None, None, 'y', None, 'y', None]; ¬u1,u2\neg u_1,u_2 [None, None, 'n', None, 'y', None]; solo u2u_2 [None, None, None, None, 'y', None]. Output del corso: 0,88340{,}8834, 0,70280{,}7028, 0,81820{,}8182.
  • Tabelle: nelle righe di una ConditionalProbabilityTable prima i genitori, poi il valore del nodo, poi la probabilità. Verifica indipendente con enumerazione sulla rete srotolata: stessi tre valori.

Esercizi su questo argomento

Teoria collegata