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