Limiti della codifica Huffman ! Codifica intera, assegna codici di lunghezza aprossimata all'intero superiore – Porta ad uno spreco ! Come migliorare Huffman? 2 1 – Usare blocchi di caratteri come simboli – Esempio, nel testo usare le parole come simboli invece dei caratteri – Svantaggio, il numero di blocchi aumenta esponenzialmente con la lunghezza del blocco – Tenere le tabelle necessita di molta memoria M. Diligenti Codifica Aritmetica Michelangelo Diligenti Dipartimento di Ingegneria dell’Informazione Università di Siena Email: [email protected] http://www.dii.unisi.it/~diligmic/BDM2011 M. Diligenti Codifica Aritmetica: idea ! Non si prova ad assegnare ad ogni simbolo una sequenza di bits – Codifiche di questo tipo sono dette “non intere” ! Si rappresenta i dati con un numero in virgola mobile nell'intervallo [0, 1) – Messaggi più lunghi corrispondono a numeri più lunghi dopo la virgola 4 ! Mostreremo i numeri in decimale anche se poi sono memorizzati nella loro forma binaria M. Diligenti Limiti della codifica Huffman ! Un altro modo per migliorare Huffman è di cambiare completamente strategia – Non assegnare una sequenza univoca di bit ad ogni simbolo – Assegnare un numero frazionario di bit ad un simbolo 3 ! Codifiche di questo tipo sono note da solo 15 anni M. Diligenti Un secondo esempio high 1 0.75 0.25 low 0 c b a 6 high_range(c)=1 low_range(c)=0.75 high_range(b)=0.75 low_range(b)=0.25 high_range(a)=0.25 low_range(a)=0 ! Esempi: tre simboli {a,b,c} – p(a)=1/4 p(b)=1/2 p(c)=1/4 (P[c]=1/4) (P[b]=1/2) (P[a]=1/4) M. Diligenti Un primo esempio ! Si assegna ad ogni simbolo un intervallo in [0,1] – Intervallo proporzionale alla probabilità del simbolo high 1 0.6667 0.3333 low 0 c b a 5 high_range(c)=1 low_range(c)=0.667 high_range(b)=0.667 low_range(b)=0.333 high_range(a)=0.333 low_range(a)=0 ! Esempi: tre simboli equiprobabili {a,b,c} p(a)=p(b)=p(c)=1/3 (P[c]=1/3) (P[b]=1/3) (P[a]=1/3) M. Diligenti Torniamo al primo esempio c b a high = 0.6667 low = 0.556 8 Entra 'c', si seleziona intervallo corrispondente a 'c' 0.333 0.444 0.556 high 0.667 low M. Diligenti Torniamo al primo esempio c b a high = 0.6667 low = 0.3333 7 ! Un codificatore aritmetico tiene due numeri low, high. Inizialmente low=0, high=1 ! Si vuole codificare la stringa “bccb” Entra 'b', si seleziona intervallo corrispondente a 'b' high 1 0.6667 0.3333 low 0 M. Diligenti simbolo spazio A B E G I L S T probabilità 0.1 0.1 0.1 0.1 0.1 0.1 0.2 0.1 0.1 Un altro esempio M. Diligenti 10 intervallo [0.00, 0.10) [0.10, 0.20) [0.20, 0.30) [0.30, 0.40) [0.40, 0.50) [0.50, 0.60) [0.60, 0.80) [0.80, 0.90) [0.90, 1.00) Algoritmo di codifica low=0, high=1 while (ci sono simbli da codificare) s = get_next_symbol range = high-low low = low + range * low_range(s) high = low + range * high_range(s) Output low 9 In realtà va bene come Output un qualsiasi numero nell'intervallo [low, high) M. Diligenti Codifica e numeri ! Ho codificato la stringa in input in un range ! Cosa mando in output? – Un qualsiasi numero tra low e high va bene – – – – – – 12 Low=0.00100001001 High=0.0010001011 Numero 0.0010001 è in intervallo [low, high) Ha numero minimo di bit Output solo bits dopo la virgola: 0010001 7 bit per codificare la stringa – Scelgo il numero che è rappresentabile con un numero di bit minimo, esempio: M. Diligenti Codificare una stringa Codifichiamo “BILL GATES” Codifica aritmetica ! Numero di bit di s1 s2 … sn è dato da formula !log(high!low)=!log( p (s 1 )! p (s 2 )!...! p (s n ))=!log( p( s1 ))!log( p( s2 ))!...!log( p (s n )) ! Ogni simbolo contribuisce per -log(si) – È il limite teorico dato da Shannon con la I(S) – Pertanto la codifica Aritmetica è ottimale! – In implementazioni pratiche si raggiunge l'ottimo? 14 • No, l'algoritmo assume artimetica a precisione infinita • I calcolatori hanno precisione finita • Comunque si va molto vicino all'ottimo M. Diligenti Codifica aritmetica ! Eventi ad alta probabilità non decrementano l'intervallo high-low ! Più l'intervallo è piccolo più bits sono necessari a rappresentarlo 13 – Numero di bit proporzionale al logaritmo negativo della dimensione dell'intervallo: -log(high-low) – Si noti che high-low misura della probabilità della sequenza di simboli incontrati in accordo al modello utilizzato M. Diligenti Esercizio ! Dato la tabella di probabilità ! Calcolare il fattore di compressione per la stringa – aaaba – aaababecaba ! Fattore compressione = numero_bit_compressi / numero_bit_iniziali M. Diligenti Domande/esercizi g f e d c b a Simbolo 0.01 0.02 0.02 0.05 0.1 0.3 0.5 Prob 16 ! Cosa succede se vi sono 8 simboli tutti equiprobabili? – Quanti bit sono necessari per codificare una stringa di 10 simboli? ! Supponiamo p(a)=0.90 e p(b)=0.1. Si deve codificare la stringa: “aaaaaaaaab” 15 - Quanto è lontano dal limite di Shannon? - Confrontiamo il fattore di compressione con quello dato da Huffman M. Diligenti Algoritmo di Decodifica ! value = numero_in_input ! while stringa non è stata decodicata 18 – Output simbolo s che contiene value nel suo intervallo – value = (value – low_range(s)) (high_range(s) - low_range(s)) M. Diligenti Decodifica ! Esattamente duale rispetto alla codifica ! Finché ci sono simboli 17 – Output del simbolo il cui intervallo contiene il numero – Aggiorna intervallo M. Diligenti Huffman contro Aritmetica ! Decodifica con H. più veloce, si deve solo navigare l'albero o fare lookup in tabella 20 – Decodifica con A. utilizza operazioni floating point che sono relativamente lente – Possibile fare codifica/decodifica con aritmetica intera (maggior velocità della CPU) ma si perde qualcosa in termini di ottimalità M. Diligenti Huffman contro Aritmetica ! Codifica A. arriva più vicina all'ottimo di H. – Differenza su testo piccola, simboli non hanno mai probabilità alte • Spazio ' ' è il simbolo a probabilità più alta p(' ')=18% 19 – Per immagini alcuni valori possono essere molto ripetuti e A. è da preferirsi a H. – Esempio estremo sono immagini in bianco e nero – H. può essere migliorata raggruppando i singoli simboli in blocchi M. Diligenti Soluzione ai problemi 1 e 2 ! Low e High hanno tante cifre in comune – Cioè si dice che hanno un Prefisso in comune 22 ! Tale prefisso non cambierà durante la codifica, solo le cifre successive possono cambiare ! Soluzione: output delle cifre corrispondenti al prefisso M. Diligenti Alcuni trucchi ! Problema 1: la codifica artimetica genera un valore con un numero arbitrario di cifre dopo la virgola – Dipende dalla lunghezza della stringa – Ma i calcolatori hanno precisione finita, come rappresento i numeri? 21 ! Problema 2: l'output non è disponibile finché tutta la stringa non è stata codificata M. Diligenti Soluzione ai problemi 1 e 2 ! Output delle cifre corrispondenti al prefisso ! Dopo si trasla la sequenza di cifre non in output verso sinistra e si continua la codifica normalmente 24 – In Java e c/c++ esistono operatori che lavorano a livello di bit e non di byte come i classici (+,-,/,*) – Tali operatori sono detti bit-wise – Ad esempio gli operatori '<<', '>>' permettono di traslare una sequenza di bit a sinistra o destra – L'operatore '&' permette di fare maschere: selezionare un certo sottoinsieme di bits – Lo vedremo in laboratorio M. Diligenti Soluzione ai problemi 1 e 2 ! Output delle cifre corrispondenti al prefisso ! Dopo si trasla la sequenza di cifre non in output verso sinistra e si continua la codifica normalmente ! Esempio 23 low=0.04623, high=0.046256 Prefisso 0.0462 Output 0462 Traslo di 4 caratteri a sinistra Low=0.3, high=0.56 Continuo la codifica usando i nuovi valori di low e high M. Diligenti Codifica Aritmetica Adattiva 26 ! Come sempre non vogliamo scandire l'input due volte ! E non vogliamo mandare la tabella di probabilità a parte perché prenderebbe spazio a sua volta ! Soluzione – Partire da valori a priori medi – aggiornare le probabilità al volo via via che si osservano i dati – Aggiorno la mia conoscenza a-priori con l'osservare dei dati, ottenendo una conoscenza aposteriori M. Diligenti Codifica Aritmetica Adattiva 25 ! Adattiva perché? – La codifica aritmetica è ottimale – Per quanto A. arrivi vicina all'ottimo, questo serve a poco se il modello non è adeguato ai dati – Se le p(s) non sono accurate, il range si restringe più del dovuto, necessitando più bits ! Come per Huffman, non è dare delle probabilità a priori sempre valide – Meglio adattarsi ai dati M. Diligenti 28 low 0 0.2 0.8 high 1 ! Entra b come nuovo simbolo – b 3 occorrenze, 5 totali b (P[b]=3/5) (P[c]=1/5) a (P[a]=1/5) c Codifica Aritmetica Adattiva low 0 0.25 0.75 high 1 ! Entra b come primo simbolo – b 2 occorrenze, 4 totali (P[c]=1/4) (P[b]=2/4) (P[a]=1/4) M. Diligenti Codifica Aritmetica Adattiva ! Si lavora con numero occorrenze e non probabilità high 1 0.67 0.33 low 0 c b a 27 – Esempio, all'inizio i simboli sono equiprobabili (1 occorrenza per ognuno), 3 occorrenze totali (P[c]=1/3) (P[b]=1/3) (P[a]=1/3) M. Diligenti c b a Codifica Aritmetica Adattiva ! Ma l'informazione non è costante nei documenti – Principio di località dell'informazione • Un paragrafo di un documento avrà con alta probabilità lo stesso tema del successivo, ma sarà meno correlato ad un brano distante nel testo • Una linea di un'immagine sarà correlata alla precedente e successiva ma meno a quelle distanti – Apprendere “troppo bene” la distribuzione su un pezzo di input può non essere ottimale per i successivi – PROBLEMA: dopo aver visto tanta evidenza, i valori nei denominatori delle frazioni sono alti 30 • le distribuzioni possono convergere all'ottimo troppo lentamente rispetto alle variazioni dell'input M. Diligenti Codifica Aritmetica Adattiva ! Possibile giocare sul peso dato al prior o all'evidenza 29 – Possibile dare una distribuzione alle occorrenze sui simboli che modella la probabilità a priori • Non deve essere uniforme all'inizio • Ad esempio potrebbe modellare la probabilità dei singoli simboli per la lingua inglese – I valori assoluti che inserico all'inzio controllano la velocità di convergenza dello schema adattativo • La distribuzione uniforme può essere realizzata assegnando 1 o 100 occorrenze per simbolo • Cosa cambia nel comportamento dell'algoritmo nei due casi? M. Diligenti Codifica Aritmetica Adattiva ! Soluzione 2 alla lentezza nell'adattività – – – – 32 Riscalare i valori delle occorrenze di un fattore di decay !<1 ad ogni passo di aggiornamento I simboli visti n passi precedenti avranno peso pari a !n I simboli recenti hanno maggior peso, si converge velocemente La scelta di ! mi determina la velocità di convergenza • Valori troppo alti le distribuzioni sono troppo statiche, caso limite !=1 torno al caso statico • Valori troppo bassi, le distribuzioni sono troppo ballerine, credo troppo all'evidenza corrente M. Diligenti Codifica Aritmetica Adattiva ! Soluzione 1 alla lentezza nell'adattività – Dividere l'input in blocchi • Ad esempio, paragrafi, od un insieme di linee – Per ogni nuovo paragrafo reinizializzare le distribuzioni di probabilità con una delle seguenti modalità • Ripartire dal prior. Convenga veloce ma peggiora il grado di compressione all'inizio del blocco • Ripartire dalla distribuzione al blocco precedente ma riscalando il numero di occorrenze. Soluzione migliore – Esempio se al blocco precedente si aveva: p(a)=100/300 p(b)=50/300 p(c)=150/300 ! si riscala a p(a)=2/6 p(b)=1/6 p(c)=3/6 31 • Codifica continuerà quasi ottimale e convergerà velocemente M. Diligenti Codifica Aritmetica Adattiva ! Decodificatore fa le stesse operazioni mentre decodifica 34 – Tutto funziona perché il modello è causale • La tabella delle occorrenze si modifica in base a ciò che è stato già osservato e non in base ai caratteri ancora da codificare – Non è necessario trasmettere la tabella delle probabilità via via che si modifica M. Diligenti 33 low 0 P[c]=0.81/(1+3.7*0.9)=0.19 0.19 P[b]=(1+1.9*0.9)/(1+3.7*0.9)=0.72 0.81 P[a]=0.81/(1+3.7*0.9)=0.19 high 1 ! Entra b come nuovo simbolo Codifica Aritmetica Adattiva a b c ! Esempio, !=0.9, entra b come primo simbolo high 1 P[a]=0.9/(1+3*0.9)=0.9/3.7=0.24 0.76 P[b]=(1+0.9)/(1+3*0.9)=1.9/3.7=0.52 0.24 low 0 P[c]=0.9/(1+3*0.9)=0.9/3.7=0.24 M. Diligenti c b a b a Simbolo 0.2 0.3 0.5 Prob c|b b|b a|b c|a b|a a|a Simbolo 0.1 0.3 0.6 0.0 0.4 0.6 0.2 0.3 0.5 Prob 36 a|c b|c c|c Ulteriori migliorie ai modelli ! Usare tabelle che utilizzano probabilità non assolute ma condizionate – Modello differenzia le probabilità in base al carattere precedente c – Possibile sempre farli adattivi – Esempio passo da M. Diligenti f e d c b a Simbolo 0.01 0.02 0.02 0.05 0.1 0.3 0.5 Prob 35 g Esercizio Codifica Aritmetica ! Data la tabella, codificare la stringa “abca” usando la codifica aritmetica ! Decodificare il risultato della codifica e mostrare che si ricostruisce la stringa iniziale – Codifica [0.37, 0.3775), scegliamo 0.375 – Decodifica 0.375 ! a – (n-low_range(a))/(high_range(a)-low_range(a))= (0.375-0)/0.5=0.75 ! b – (0.75-0.5)/0.3=0.833 ! c – (0.833 – 0.8)/0.1=0.33 ! a M. Diligenti Ulteriori migliorie ai modelli ! Possibile anche usare contesti di dimensioni maggiori – N caratteri precedenti come: p(e|q,u) – N parole precedenti come: p(sera|corriere,della) ! Non conviene tuttavia esagerare con l'uso del contesto 38 – Usare troppi simboli porta ad una esplosione combinatoria del numeo di possibili contesti – Se i contesti sono troppi è probabile che non abbia un buon prior per essi – Inoltre serve troppa evidenza (dati) per stimarli in modo adattivo. Avrei un buon modello quando ho già compresso tutto • Se ho 20 contesti, apprendo le statistiche veloci, ma se ne ho 106 quanti dati devo vedere prima di comprimere bene? M. Diligenti Ulteriori migliorie ai modelli ! Tali modelli condizionati sono molto accurati in certe situazioni – Nel testo il carattere precedente è spesso un buon predittore del successivo, esempio • p(u)=0.03 ma p(u|q)=0.9 • La probabilità di u è in generale bassa ma la p(u|q) è altissima, visto che ad una q segue quasi sempre una u – Lo stesso vale se si usano le parole come simboli • p(york) << p(york|new) 37 – Modelli condizionati possono essere appresi dai dati usando schemi adattivi M. Diligenti Ulteriori migliorie ai modelli ! Alla fine contesti troppo grandi possono peggiorare la situazione – Meglio una distribuzione buona su tutti i dati che – Una distribuzione potenzialmente ottima ma usata con statistiche non accurate ! Un modo alternativo ma simile è di usare automi a stati finiti ! NOTA: usare modelli accurati è consigliabile usando la codifica aritmetica 39 – Riesce a sfruttarli fino in fondo, Huffman è lontano dall'ottimo se un simbolo ha probabilità molto più alta delle altre M. Diligenti