Salta al contenuto
Note per Studenti Esercizio - Filtraggio e smoothing nell'ombrello con la nuova versione di pomegranate (materiale supplementare del laboratorio 6)

Esercizio - Filtraggio e smoothing nell'ombrello con la nuova versione di pomegranate (materiale supplementare del laboratorio 6)

Testo (materiale supplementare del laboratorio 6, Additional materials - implementation with new version of pomegranate, corso di Intelligenza Artificiale, Ing. dell'Informazione UniPD). Il materiale ha due parti sullo stesso 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 →): P(Rain0)=⟨0,5; 0,5⟩P(\text{Rain}_0)=\langle0{,}5;\ 0{,}5\rangle, 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(ut∣rt)=0,9P(u_t\mid r_t)=0{,}9, P(ut∣¬rt)=0,2P(u_t\mid\neg r_t)=0{,}2.

  1. Esempio 11: foglio di calcolo per il filtraggio. Un foglio (Umbrella.xlsx) modella i primi due giorni. In alto la probabilità di pioggia del giorno 00 è il prior; in basso le tabelle del modello di transizione e del sensore. La probabilità predetta per il giorno 11 si calcola dal giorno 00 e dal modello di transizione; la probabilità filtrata del giorno 11 combina la predetta, il modello del sensore e l'informazione sull'ombrello. Esistono due versioni della filtrata: i valori grezzi del calcolo e quelli normalizzati (grezzi scalati perché sommino a 11). Nel foglio la probabilità di umbrella\text{umbrella} vale 11 e quella di not umbrella\text{not umbrella} vale 00: cosa succede se non si vede l'ombrello (probabilità di umbrella\text{umbrella} 00, di not umbrella\text{not umbrella} 11)? E se non si ha alcuna informazione (probabilità 0,50{,}5 e 0,50{,}5)? La colonna del giorno 22 ripete i calcoli del giorno 11 partendo dal risultato normalizzato del giorno 11: la predetta del giorno 22 applica il modello di transizione alla filtrata normalizzata del giorno 11. Osservare cosa accade al variare delle probabilità di ombrello nei giorni 11 e 22.
  2. Esempio 22: pomegranate (nuova versione) per predizione e filtraggio. Si risolvono reti bayesiane (non dinamiche), quindi il modello è srotolato fino alla profondità voluta. Si chiede la probabilità di pioggia nei giorni 11 e 22 senza evidenza, poi con ombrello al giorno 11, poi con ombrelli nei giorni 11 e 22 (con un terzo giorno aggiunto).

Parte 1: il foglio di calcolo

Per ogni giorno: predetta pt=T⊤ft−1\mathbf p_t=\mathbf T^\top\mathbf f_{t-1}; grezza vt=lt×pt\mathbf v_t=\mathbf l_t\times\mathbf p_t, con lt\mathbf l_t la verosimiglianza dell'evidenza data la pioggia; normalizzata ft=vt/∑vt\mathbf f_t=\mathbf v_t/\sum\mathbf v_t. Se la probabilità di vedere l'ombrello è qq (un'evidenza "morbida"), lt=⟨0,9q+0,1(1−q); 0,2q+0,8(1−q)⟩\mathbf l_t=\langle0{,}9q+0{,}1(1-q);\ 0{,}2q+0{,}8(1-q)\rangle.

ombrello giorno 11 predetta 11 grezza 11 filtrata 11 predetta 22 grezza 22 (u2u_2) filtrata 22
visto (q=1q=1) ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle ⟨0,45; 0,10⟩\langle0{,}45;\,0{,}10\rangle ⟨0,818; 0,182⟩\langle0{,}818;\,0{,}182\rangle ⟨0,627; 0,373⟩\langle0{,}627;\,0{,}373\rangle ⟨0,5645; 0,0745⟩\langle0{,}5645;\,0{,}0745\rangle ⟨0,883; 0,117⟩\langle0{,}883;\,0{,}117\rangle
non visto (q=0q=0) ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle ⟨0,05; 0,40⟩\langle0{,}05;\,0{,}40\rangle ⟨0,111; 0,889⟩\langle0{,}111;\,0{,}889\rangle ⟨0,344; 0,656⟩\langle0{,}344;\,0{,}656\rangle ⟨0,310; 0,131⟩\langle0{,}310;\,0{,}131\rangle ⟨0,703; 0,297⟩\langle0{,}703;\,0{,}297\rangle
nessuna informazione (q=0,5q=0{,}5) ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle ⟨0,25; 0,25⟩\langle0{,}25;\,0{,}25\rangle ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle ⟨0,45; 0,10⟩\langle0{,}45;\,0{,}10\rangle ⟨0,818; 0,182⟩\langle0{,}818;\,0{,}182\rangle

Spiegazioni:

  • Non visto: gli ombrelli sono più probabili con la pioggia (0,90{,}9 contro 0,20{,}2), quindi la loro assenza (verosimiglianza 0,10{,}1 contro 0,80{,}8) fa scendere la pioggia da 0,50{,}5 a 0,1110{,}111.
  • Nessuna informazione: la verosimiglianza è uguale (0,50{,}5 e 0,50{,}5) per i due stati: la grezza è solo il predetto scalato, la normalizzazione la riporta a ⟨0,5; 0,5⟩\langle0{,}5;\,0{,}5\rangle e la filtrata coincide con la predetta. Non si impara nulla.
  • Giorno 22: si ripete esattamente lo stesso calcolo (il modello è modulare) partendo dalla filtrata normalizzata del giorno 11.

I valori sono stati ricalcolati in Python con la ricorsione del filtraggio (stessi numeri della tabella); i valori di f2\mathbf f_2 per u1,u2u_1,u_2 e per ¬u1,u2\neg u_1,u_2 (0,8830{,}883 e 0,7030{,}703) coincidono con quelli di Esercizio - Filtraggio nell'ombrello con pomegranate (laboratorio 6).

Parte 2: pomegranate (nuova versione)

Nel codice del corso le variabili sono RainN\text{Rain}_N e UmbrellaN\text{Umbrella}_N; i valori sono 00 (no) e 11 (sì), e le tabelle condizionali hanno la forma [[P(n∣n),P(y∣n)],[P(n∣y),P(y∣y)]][[P(\text{n}\mid\text{n}),P(\text{y}\mid\text{n})],[P(\text{n}\mid\text{y}),P(\text{y}\mid\text{y})]], riga = valore del genitore.

python
from pomegranate.bayesian_network import BayesianNetwork
from pomegranate.distributions import Categorical, ConditionalCategorical

Rain0 = Categorical([[0.5, 0.5]])                       # P(Rain0)
Rain1 = ConditionalCategorical([[[0.7, 0.3],            # P(Rain1 | Rain0 = n)
                                 [0.3, 0.7]]])          # P(Rain1 | Rain0 = y)
Rain2 = ConditionalCategorical([[[0.7, 0.3], [0.3, 0.7]]])
Umbrella1 = ConditionalCategorical([[[0.8, 0.2],        # P(Umbrella1 | Rain1 = n)
                                     [0.1, 0.9]]])      # P(Umbrella1 | Rain1 = y)
Umbrella2 = ConditionalCategorical([[[0.8, 0.2], [0.1, 0.9]]])

model = BayesianNetwork()
model.add_distributions([Rain0, Rain1, Umbrella1, Rain2, Umbrella2])
model.add_edge(Rain0, Rain1); model.add_edge(Rain1, Umbrella1)
model.add_edge(Rain1, Rain2); model.add_edge(Rain2, Umbrella2)

Le query con evidenza passano un tensore con nan per i nodi non osservati, nell'ordine [Rain0, Rain1, Umbrella1, Rain2, Umbrella2]; il risultato è, per ogni nodo, la distribuzione a posteriori.

  1. Nessuna evidenza. P(~Rain1) = 0.5, P(Rain1) = 0.5, e lo stesso per Rain2: prima di vedere ombrelli non si può dire nulla sulla pioggia (la distribuzione ⟨0,5; 0,5⟩\langle0{,}5;\ 0{,}5\rangle rappresenta l'ignoranza, stazionaria per la transizione simmetrica).
  2. Ombrello al giorno 11 (scenario = [[nan, nan, 1, nan, nan]]): Rain1\text{Rain}_1: ⟨0,18; 0,82⟩\langle0{,}18;\ 0{,}82\rangle (filtrata, 0,8180{,}818); Rain2\text{Rain}_2: ⟨0,37; 0,63⟩\langle0{,}37;\ 0{,}63\rangle (predizione, 0,6270{,}627). pomegranate propaga l'evidenza in tutta la rete, quindi calcola anche Rain0\text{Rain}_0: ⟨0,37; 0,63⟩\langle0{,}37;\ 0{,}63\rangle, cioè la probabilità smoothed di pioggia al giorno 00, benché non sia stato osservato nulla quel giorno. È il messaggio all'indietro: un ombrello al giorno 11 rende più probabile la pioggia anche il giorno prima (per la persistenza). A mano: f0×b1:1\mathbf f_0\times\mathbf b_{1:1} con b1:1=TOu1=⟨0,7⋅0,9+0,3⋅0,2; 0,3⋅0,9+0,7⋅0,2⟩=⟨0,69; 0,41⟩\mathbf b_{1:1}=\mathbf T\mathbf O^u\mathbf 1=\langle0{,}7\cdot0{,}9+0{,}3\cdot0{,}2;\ 0{,}3\cdot0{,}9+0{,}7\cdot0{,}2\rangle=\langle0{,}69;\ 0{,}41\rangle, normalizzato con il prior: ⟨0,69⋅0,5; 0,41⋅0,5⟩/0,55=⟨0,627; 0,373⟩\langle0{,}69\cdot0{,}5;\ 0{,}41\cdot0{,}5\rangle/0{,}55=\langle0{,}627;\ 0{,}373\rangle.
  3. Un terzo giorno e ombrelli nei giorni 11 e 22. Si aggiunge Rain3\text{Rain}_3 (Rain3 = ConditionalCategorical(...), arco Rain2→Rain3\text{Rain}_2\to\text{Rain}_3), si crea BayesianNetwork(nodi, archi) e scenario = [[nan, nan, 1, nan, 1, nan]]: Rain1\text{Rain}_1: ⟨0,12; 0,88⟩\langle0{,}12;\ 0{,}88\rangle e Rain2\text{Rain}_2: ⟨0,12; 0,88⟩\langle0{,}12;\ 0{,}88\rangle. Il valore di Rain2\text{Rain}_2 è quello filtrato (0,88340{,}8834) perché Rain3\text{Rain}_3 non ha evidenza: i figli senza evidenza non influenzano. Quello di Rain1\text{Rain}_1 è lo smoothing: f1×b2:2\mathbf f_1\times\mathbf b_{2:2} con b2:2=⟨0,69; 0,41⟩\mathbf b_{2:2}=\langle0{,}69;\ 0{,}41\rangle, ⟨0,818⋅0,69; 0,182⋅0,41⟩/0,639=⟨0,883; 0,117⟩\langle0{,}818\cdot0{,}69;\ 0{,}182\cdot0{,}41\rangle/0{,}639=\langle0{,}883;\ 0{,}117\rangle (stesso numero di f2\mathbf f_2 per la simmetria di T\mathbf T e di O\mathbf O nei due giorni).

Nota. pomegranate non esegue il calcolo del corso (forward-backward): calcola direttamente la probabilità a posteriori di ogni variabile nascosta data l'evidenza, quindi restituisce in automatico gli smoothing di tutti i giorni precedenti all'ultima evidenza (e anche le predizioni per i giorni successivi).

Verifica con numpy

Tutti i numeri sono stati ricalcolati in due modi, con codice proprio: per enumerazione sulla rete srotolata e con forward-backward (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 →):

scenario Rain0\text{Rain}_0 Rain1\text{Rain}_1 Rain2\text{Rain}_2 Rain3\text{Rain}_3
nessuna evidenza 0,5000{,}500 0,5000{,}500 0,5000{,}500
u1u_1 0,6270{,}627 0,8180{,}818 0,6270{,}627
u1,u2u_1,u_2 0,6530{,}653 0,8830{,}883 0,8830{,}883 0,6530{,}653

(valori di P(pioggia)P(\text{pioggia}) per ogni nodo, arrotondati; coincidono con 0.18/0.82, 0.37/0.63 e 0.12/0.88 stampati dal corso).

python
import numpy as np

T = np.array([[0.7, 0.3], [0.3, 0.7]])
O = {True: np.diag([0.9, 0.2]), False: np.diag([0.1, 0.8])}
f0 = np.array([0.5, 0.5])

def filtro(f, e):
    v = O[e] @ T.T @ f
    return v / v.sum()

f1 = filtro(f0, True)                         # filtrata giorno 1 (u1)
f2 = filtro(f1, True)                         # filtrata giorno 2 (u1, u2)
b = T @ O[True] @ np.ones(2)                  # messaggio all'indietro b_{2:2} = <0.69, 0.41>
s1 = f1 * b; s1 /= s1.sum()                   # smoothing del giorno 1
print(f1, f2, s1)

Output: [0.818 0.182] [0.883 0.117] [0.883 0.117].

Versione ripasso

  • Foglio di calcolo: predetta pt=T⊤ft−1\mathbf p_t=\mathbf T^\top\mathbf f_{t-1}; grezza vt=lt×pt\mathbf v_t=\mathbf l_t\times\mathbf p_t; filtrata ft=vt/∑vt\mathbf f_t=\mathbf v_t/\sum\mathbf v_t. Il giorno 22 riparte dalla filtrata normalizzata del giorno 11 (calcolo modulare).
  • Ombrello visto: f1=⟨0,818; 0,182⟩\mathbf f_1=\langle0{,}818;\,0{,}182\rangle, f2=⟨0,883; 0,117⟩\mathbf f_2=\langle0{,}883;\,0{,}117\rangle. Non visto al giorno 1: f1=⟨0,111; 0,889⟩\mathbf f_1=\langle0{,}111;\,0{,}889\rangle, f2\mathbf f_2 (con u2u_2) =⟨0,703; 0,297⟩=\langle0{,}703;\,0{,}297\rangle. Nessuna informazione: f1=⟨0,5; 0,5⟩\mathbf f_1=\langle0{,}5;\,0{,}5\rangle (la filtrata coincide con la predetta).
  • pomegranate: reti statiche, modello srotolato; tabelle con riga = valore del genitore, nan = non osservato. Nessuna evidenza: 0,50{,}5 ovunque. u1u_1: Rain1=0,82\text{Rain}_1=0{,}82 (filtrata), Rain2=0,63\text{Rain}_2=0{,}63 (predizione), Rain0=0,63\text{Rain}_0=0{,}63 (smoothing).
  • Smoothing (forward-backwardP(Xk∣e1:t)=α fk×bk+1:t\mathbf P(X_k\mid e_{1:t})=\alpha\,\mathbf f_k\times\mathbf b_{k+1:t}, con bk+1:t=TOk+1bk+2:t\mathbf b_{k+1:t}=\mathbf T\mathbf O_{k+1}\mathbf b_{k+2:t}Ragionamento probabilistico nel tempo - catene di Markov, HMM, filtraggio e smoothing →): u1,u2u_1,u_2 dà Rain1=0,88\text{Rain}_1=0{,}88, Rain2=0,88\text{Rain}_2=0{,}88 (filtrata, nessuna evidenza sul giorno 33).
  • Differenza: pomegranate calcola la posteriori di ogni nodo (non il forward-backward) e dà gli smoothing in automatico.
  • Errori tipici: pensare che Rain0\text{Rain}_0 non cambi senza evidenza su quel giorno; confondere filtrata e predetta; usare le grezze non normalizzate al giorno successivo.
  • Tabella del foglio (pioggia): visto ⟨0,45; 0,10⟩→0,818→\langle0{,}45;\,0{,}10\rangle\to0{,}818\to predetta 0,627→⟨0,5645; 0,0745⟩→0,8830{,}627\to\langle0{,}5645;\,0{,}0745\rangle\to0{,}883; non visto ⟨0,05; 0,40⟩→0,111→0,344→⟨0,310; 0,131⟩→0,703\langle0{,}05;\,0{,}40\rangle\to0{,}111\to0{,}344\to\langle0{,}310;\,0{,}131\rangle\to0{,}703; nessuna informazione ⟨0,25; 0,25⟩→0,5→0,5→⟨0,45; 0,10⟩→0,818\langle0{,}25;\,0{,}25\rangle\to0{,}5\to0{,}5\to\langle0{,}45;\,0{,}10\rangle\to0{,}818. Evidenza morbida con probabilità qq di ombrello: l=⟨0,9q+0,1(1−q); 0,2q+0,8(1−q)⟩\mathbf l=\langle0{,}9q+0{,}1(1-q);\ 0{,}2q+0{,}8(1-q)\rangle.
  • Ombrello non visto: verosimiglianza 0,10{,}1 contro 0,80{,}8, la pioggia scende da 0,50{,}5 a 0,1110{,}111. Nessuna informazione: verosimiglianze uguali, la filtrata coincide con la predetta.
  • Smoothing a mano: b1:1=TOu1=⟨0,69; 0,41⟩\mathbf b_{1:1}=\mathbf T\mathbf O^u\mathbf 1=\langle0{,}69;\,0{,}41\rangle; Rain0\text{Rain}_0 con u1u_1: ⟨0,345; 0,205⟩/0,55=⟨0,627; 0,373⟩\langle0{,}345;\,0{,}205\rangle/0{,}55=\langle0{,}627;\,0{,}373\rangle (stesso valore della predizione di Rain2\text{Rain}_2 per la simmetria di T\mathbf T).
  • Tabella delle posteriori (pioggia): nessuna evidenza 0,50{,}5 ovunque; u1u_1: Rain0=0,627\text{Rain}_0=0{,}627, Rain1=0,818\text{Rain}_1=0{,}818, Rain2=0,627\text{Rain}_2=0{,}627; u1,u2u_1,u_2: 0,6530{,}653, 0,8830{,}883, 0,8830{,}883, Rain3=0,653\text{Rain}_3=0{,}653 (predizione).
  • Codice numpy: f1 = filtro(f0, True), f2 = filtro(f1, True), b = T @ O[True] @ np.ones(2), s1 = f1 * b normalizzato: [0.883 0.117].

Teoria collegata