Algorytm do przodu i do tyłu
Algorytm przód-tył jest algorytmem wnioskowania dla ukrytych modeli Markowa , który oblicza tylne brzegi wszystkich ukrytych zmiennych stanu przy danej sekwencji obserwacji / emisji , tj. oblicza dla wszystkich ukrytych zmiennych stanu , rozkład . To zadanie wnioskowania jest zwykle nazywane wygładzaniem . Algorytm wykorzystuje zasadę programowania dynamicznego do wydajnego obliczania wartości wymaganych do uzyskania tylnych rozkładów brzeżnych w dwóch przebiegach. Pierwsze przejście idzie do przodu w czasie, podczas gdy drugie cofa się w czasie; stąd nazwa algorytm do przodu i do tyłu .
Termin algorytm do przodu i do tyłu jest również używany w odniesieniu do dowolnego algorytmu należącego do ogólnej klasy algorytmów, które działają na modelach sekwencji w sposób do przodu i do tyłu. W tym sensie opisy w dalszej części tego artykułu odnoszą się tylko do jednej konkretnej instancji tej klasy.
Przegląd
tyłu zestaw prawdopodobieństw do przodu, zakończenia w jakimkolwiek określonym stanie, biorąc pod uwagę pierwsze w sekwencji, tj. . drugim przejściu algorytm oblicza zestaw prawdopodobieństw wstecznych, które zapewniają prawdopodobieństwo zaobserwowania pozostałych obserwacji przy dowolnym punkcie początkowym, . . Te dwa zestawy rozkładów prawdopodobieństwa można następnie połączyć, aby uzyskać rozkład stanów w dowolnym określonym momencie, biorąc pod uwagę całą sekwencję obserwacji:
Ostatni krok wynika z zastosowania reguły Bayesa i warunkowej niezależności o i biorąc pod uwagę .
Jak opisano powyżej, algorytm obejmuje trzy kroki:
- obliczanie prawdopodobieństwa naprzód
- obliczanie prawdopodobieństw wstecznych
- obliczanie wygładzonych wartości.
Kroki do przodu i do tyłu można również nazwać „przekazywaniem wiadomości do przodu” i „przekazywaniem wiadomości wstecz” - terminy te wynikają z przekazywania wiadomości stosowanego w ogólnych podejściach do propagowania przekonań . Przy każdej pojedynczej obserwacji w sekwencji obliczane są prawdopodobieństwa, które zostaną użyte do obliczeń przy następnej obserwacji. Krok wygładzania można obliczyć jednocześnie podczas przejścia wstecz. Ten krok pozwala algorytmowi wziąć pod uwagę wszelkie wcześniejsze obserwacje danych wyjściowych w celu obliczenia dokładniejszych wyników.
Algorytm do przodu i do tyłu może być użyty do znalezienia najbardziej prawdopodobnego stanu dla dowolnego punktu w czasie. Nie można go jednak użyć do znalezienia najbardziej prawdopodobnej sekwencji stanów (patrz algorytm Viterbiego ).
Prawdopodobieństwa naprzód
Poniższy opis będzie wykorzystywał macierze wartości prawdopodobieństwa, a nie rozkłady prawdopodobieństwa, chociaż ogólnie algorytm naprzód-wstecz można zastosować zarówno do ciągłych, jak i dyskretnych modeli prawdopodobieństwa.
Przekształcamy rozkłady prawdopodobieństwa związane z danym ukrytym modelem Markowa na notację macierzową w następujący sposób. P. danej zmiennej losowej reprezentujące wszystkie możliwe stany w ukrytym modelu Markowa będą reprezentowane przez macierz, kolumny będzie reprezentował stan docelowy, a indeks wiersza ja reprezentuje stan początkowy. Przejście ze stanu wierszowego do przyrostowego stanu wektora wierszowego = . Poniższy przykład przedstawia układ, w którym prawdopodobieństwo pozostania w tym samym stanie po każdym kroku wynosi 70%, a prawdopodobieństwo przejścia do innego stanu wynosi 30%. Macierz przejść to wtedy:
W typowym modelu Markowa pomnożylibyśmy wektor stanu przez tę macierz, aby otrzymać prawdopodobieństwa dla kolejnego stanu. W ukrytym modelu Markowa stan jest nieznany i zamiast tego obserwujemy zdarzenia związane z możliwymi stanami. Macierz zdarzeń postaci:
zapewnia prawdopodobieństwa zaobserwowania zdarzeń w określonym stanie. W powyższym przykładzie zdarzenie 1 będzie obserwowane przez 90% czasu, jeśli jesteśmy w stanie 1, podczas gdy prawdopodobieństwo wystąpienia zdarzenia 2 w tym stanie wynosi 10%. W przeciwieństwie do tego, zdarzenie 1 będzie obserwowane tylko przez 20% czasu, jeśli jesteśmy w stanie 2, a zdarzenie 2 ma 80% szans na wystąpienie. Biorąc pod uwagę dowolny wektor wierszowy opisujący stan systemu ( ), prawdopodobieństwo zaobserwowania zdarzenia j wynosi wtedy:
Prawdopodobieństwo danego stanu prowadzącego do obserwowanego zdarzenia j można przedstawić w postaci macierzy, mnożąc wektor wierszowy stanu ( macierz obserwacji ( zawierający tylko wpisy ukośne. Kontynuując powyższy przykład, macierz obserwacji dla zdarzenia 1 wyglądałaby następująco:
To pozwala nam obliczyć nowy nieznormalizowany wektor stanu prawdopodobieństw za pomocą reguły Bayesa, ważąc prawdopodobieństwo, że każdy element wygenerował 1 Jak:
Możemy teraz uczynić tę ogólną procedurę specyficzną dla naszej serii obserwacji. wektor stanu początkowego który można zoptymalizować jako parametr poprzez powtórzenia procedury forward-back), zaczynamy od , a następnie aktualizujemy rozkład stanu i wagę o prawdopodobieństwo pierwszej obserwacji:
Proces ten można przeprowadzić z dodatkowymi obserwacjami przy użyciu:
Ta wartość jest nieznormalizowanym wektorem prawdopodobieństwa w przód. I-ta pozycja tego wektora zapewnia:
Zazwyczaj będziemy normalizować wektor prawdopodobieństwa na każdym kroku, tak aby jego wpisy sumowały się do 1. W ten sposób na każdym kroku wprowadzany jest współczynnik skalowania, tak że:
gdzie reprezentuje przeskalowany wektor z poprzedniego kroku i reprezentuje przeskalowany wektor współczynnik skalowania, który powoduje, że wpisy wynikowego wektora sumują się do 1. Iloczyn współczynników skalowania jest całkowitym prawdopodobieństwem zaobserwowania danych zdarzeń niezależnie od stanów końcowych:
To pozwala nam interpretować skalowany wektor prawdopodobieństwa jako:
Stwierdzamy zatem, że iloczyn współczynników skalowania daje nam całkowite prawdopodobieństwo zaobserwowania danej sekwencji do czasu t, a skalowany wektor prawdopodobieństwa daje nam prawdopodobieństwo przebywania w każdym stanie w tym czasie.
Prawdopodobieństwa wsteczne
Podobną procedurę można skonstruować w celu znalezienia wstecznych prawdopodobieństw. Mają one na celu przedstawienie prawdopodobieństw:
chcemy teraz założyć, że zaczynamy w określonym stanie ( interesuje nas prawdopodobieństwo zaobserwowania wszystkich ten stan. Ponieważ stan początkowy przyjmujemy jako dany (tj. prawdopodobieństwo a priori tego stanu = 100%), zaczynamy od:
Zauważ, że teraz używamy wektora kolumnowego, podczas gdy prawdopodobieństwa naprzód używały wektorów wierszowych. Następnie możemy pracować wstecz, używając:
Chociaż moglibyśmy znormalizować również ten wektor, tak aby jego wpisy sumowały się do jednego, zwykle się tego nie robi. Zauważając, że każdy wpis zawiera prawdopodobieństwo wystąpienia sekwencji przyszłych zdarzeń przy danym stanie początkowym, normalizacja tego wektora byłaby równoznaczna z zastosowaniem twierdzenia Bayesa w celu znalezienia prawdopodobieństwa wystąpienia każdego stanu początkowego przy danych przyszłych zdarzeniach (przy założeniu jednolitych wartości a priori dla wektora stanu końcowego ). bardziej powszechne jest skalowanie tego wektora przy użyciu tych samych które są używane w obliczeniach prawdopodobieństwa w przód. nie jest skalowany, ale kolejne operacje wykorzystują:
gdzie reprezentuje poprzedni, przeskalowany wektor. Wynik jest taki, że skalowany wektor prawdopodobieństwa jest powiązany z wstecznymi prawdopodobieństwami przez:
Jest to przydatne, ponieważ pozwala nam znaleźć całkowite prawdopodobieństwo przebywania w każdym stanie w danym czasie t, mnożąc te wartości:
Aby to zrozumieć, zauważamy, że prawdopodobieństwo zaobserwowania danych zdarzeń w sposób przechodzący przez stan t. To prawdopodobieństwo obejmuje prawdopodobieństwa naprzód obejmujące wszystkie zdarzenia do czasu t, jak również prawdopodobieństwa wsteczne, które obejmują wszystkie przyszłe zdarzenia. To jest licznik, którego szukamy w naszym równaniu i dzielimy przez całkowite prawdopodobieństwo sekwencji obserwacji, aby znormalizować tę wartość i wyodrębnić tylko prawdopodobieństwo, że . Wartości te są czasami nazywane „wartościami wygładzonymi”, ponieważ łączą prawdopodobieństwo do przodu i do tyłu w celu obliczenia ostatecznego prawdopodobieństwa.
Wartości stanie w czasie t. Jako takie są przydatne do określenia najbardziej prawdopodobnego stanu w dowolnym momencie. Termin „stan najbardziej prawdopodobny” jest nieco niejednoznaczny. Podczas gdy najbardziej prawdopodobny stan jest najbardziej prawdopodobny w danym punkcie, sekwencja indywidualnie prawdopodobnych stanów prawdopodobnie nie będzie najbardziej prawdopodobną sekwencją. Dzieje się tak, ponieważ prawdopodobieństwa dla każdego punktu są obliczane niezależnie od siebie. Nie uwzględniają one prawdopodobieństw przejścia między stanami, a zatem możliwe jest uzyskanie stanów w dwóch momentach (t i t+1), które są najbardziej prawdopodobne w tych punktach czasowych, ale które mają bardzo małe prawdopodobieństwo wystąpienia razem, tj. . Najbardziej prawdopodobną sekwencję stanów, która wygenerowała sekwencję obserwacji, można znaleźć za pomocą algorytmu Viterbiego .
Przykład
Ten przykład opiera się na świecie parasoli w Russell & Norvig 2010, rozdział 15, s. 567, w którym chcielibyśmy wywnioskować pogodę na podstawie obserwacji innej osoby niosącej lub nie noszącej parasola. Przyjmujemy dwa możliwe stany pogody: stan 1 = deszcz, stan 2 = brak deszczu. Zakładamy, że pogoda ma 70% szans na pozostanie taką samą każdego dnia i 30% szans na zmianę. Prawdopodobieństwa przejścia wynoszą wtedy:
Zakładamy również, że każdy stan generuje jedno z dwóch możliwych zdarzeń: zdarzenie 1 = parasol, zdarzenie 2 = brak parasola. Prawdopodobieństwa warunkowe dla tych występujących w każdym stanie są określone przez macierz prawdopodobieństwa:
Następnie obserwujemy następującą sekwencję zdarzeń: {parasol, parasol, brak parasola, parasol, parasol}, którą w naszych obliczeniach będziemy reprezentować jako:
że różni się od innych obserwacją „bez parasola”
Przy obliczaniu prawdopodobieństwa naprzód zaczynamy od:
który jest naszym wektorem stanu poprzedniego wskazującym, że nie wiemy, w jakim stanie jest pogoda przed naszymi obserwacjami. Podczas gdy wektor stanu powinien być podany jako wektor wierszowy, użyjemy transpozycji macierzy, aby poniższe obliczenia były łatwiejsze do odczytania. Nasze obliczenia są następnie zapisywane w postaci:
zamiast:
Zauważ, że macierz transformacji jest również transponowana, ale w naszym przykładzie transpozycja jest równa oryginalnej macierzy. Wykonanie tych obliczeń i znormalizowanie wyników zapewnia:
Dla prawdopodobieństw wstecznych zaczynamy od:
Jesteśmy wtedy w stanie obliczyć (wykorzystując obserwacje w odwrotnej kolejności i normalizując z różnymi stałymi):
Na koniec obliczymy wygładzone wartości prawdopodobieństwa. Wyniki te muszą być również przeskalowane, aby suma wpisów wynosiła 1, ponieważ nie skalowaliśmy wstecznych prawdopodobieństw znalezionymi Powyższe wektory wstecznego prawdopodobieństwa reprezentują zatem prawdopodobieństwo każdego stanu w czasie t, biorąc pod uwagę przyszłe obserwacje. Ponieważ te wektory są proporcjonalne do rzeczywistych prawdopodobieństw wstecznych, wynik musi zostać przeskalowany o dodatkowy czas.
Zauważ , że wartość jest równa jest równe . Wynika to naturalnie, ponieważ zarówno , b rozpocznij od jednakowych priorytetów względem wektorów stanu początkowego i końcowego (odpowiednio) i weź pod uwagę wszystkie obserwacje. Jednak będzie równy wektor stanu reprezentuje jednolity przeor (tzn. wszystkie wpisy są sobie równe). Gdy jest, połączyć z wektorem stanu początkowego, aby znaleźć najbardziej prawdopodobny stan Stwierdzamy zatem, że same prawdopodobieństwa naprzód są wystarczające do obliczenia najbardziej prawdopodobnego stanu końcowego. Podobnie, wsteczne prawdopodobieństwa można połączyć z wektorem stanu początkowego, aby uzyskać najbardziej prawdopodobny stan początkowy, biorąc pod uwagę obserwacje. Prawdopodobieństwa do przodu i do tyłu należy tylko połączyć, aby wywnioskować najbardziej prawdopodobne stany między punktami początkowymi i końcowymi.
Z powyższych obliczeń wynika, że najbardziej prawdopodobnym stanem pogody każdego dnia poza trzecim był „deszcz”. Mówią nam jednak więcej, ponieważ teraz zapewniają sposób ilościowego określenia prawdopodobieństw każdego stanu w różnych momentach. Być może najważniejsze, nasza wartość w wiedzę o wektorze stanu na końcu sekwencji obserwacji Możemy następnie wykorzystać to do przewidywania prawdopodobieństwa wystąpienia różnych stanów pogodowych jutro, a także prawdopodobieństwa zaobserwowania parasola.
Wydajność
Algorytm do przodu i do tyłu działa ze złożonością czasową przestrzeni, gdzie sekwencji czasowej, a liczba symboli w alfabecie państwowym. Algorytm może również działać w stałej przestrzeni ze . Dla porównania, procedura brutalnej wygenerowałaby wszystkie możliwe sekwencje każdej sekwencji stanów z obserwowaną serią zdarzeń, które miałyby złożoność czasową . Brutalna siła jest trudna do rozwiązania w przypadku realistycznych problemów, ponieważ liczba możliwych sekwencji ukrytych węzłów jest zazwyczaj bardzo wysoka.
Ulepszenie ogólnego algorytmu do przodu i do tyłu, zwane algorytmem wyspy , zamienia mniejsze zużycie pamięci na dłuższy czas działania, biorąc czas i pamięć modelu procesu w celu uzyskania S 2 odwrócony proces może nie istnieć lub być źle uwarunkowany .
Ponadto opracowano algorytmy do wydajnego obliczania ze stałym opóźnieniem (FLS
Pseudo kod
wejście algorytmu forward_backward : zgadnijState int sekwencjaIndexwyjście : wynik jeśli sekwencjaIndeks jest poza końcem sekwencji następnie zwróć 1 jeśli ( zgadnijState , sekwencjaIndex ) był widziany wcześniej to zwróć zapisany wynik wynik := 0 dla każdego sąsiedniego stanu n: wynik := wynik + (prawdopodobieństwo przejścia z GuessState do n danego elementu obserwacji w sekwencjiIndex ) × Backward(n, sekwencjaIndex + 1) zapisz wynik dla ( GuessState , sekwencjaIndex ) zwróć wynik
Przykład Pythona
Biorąc pod uwagę HMM (podobnie jak w algorytmie Viterbiego ) reprezentowany w języku programowania Python :
stany = ( 'Zdrowy' , 'Gorączka' ) stan_końcowy = 'E' obserwacje = ( 'normalny' , 'zimny' , 'zawroty głowy' ) prawdopodobieństwo_początkowe = { 'Zdrowy' : 0,6 , 'Gorączka' : 0,4 } prawdopodobieństwo_przejścia = { ' Zdrowy” : { „Zdrowy” : 0,69 , „Gorączka” : 0,3 , „E” : 0,01 }, „Gorączka” : { „Zdrowy” : 0,4 , „ Gorączka” : 0,59 , „ E” : 0,01 }, } { „Zdrowy” : { „normalny” : 0,5 , „zimny” : 0,4 , „zawroty głowy” : 0,1 }, „Gorączka” : { „normalny” : 0,1 , „zimny” : 0,3 , „zawroty głowy” : 0,6 }, }
Implementację algorytmu forward-backward możemy napisać w następujący sposób:
0
0
0
0
def fwd_bkw ( obserwacje , stany , próba_początkowa , trans_prob , próba_emm , końcówka ): """Algorytm przód-tył.""" # Część naprzód algorytmu fwd = [] dla i , obserwacja_i in enumerate ( obserwacje ): f_bieżąca = { } dla st w stanach : if i == : # przypadek bazowy dla części forward prev_f_sum = start_prob [ st ] else : prev_f_sum = sum ( f_prev [ k ] * trans_prob [ k ][ st ] dla k w stanach ) f_curr [ st ] = emm_prob [ st ][ obserwacja_i ] * prev_f_sum fwd . append ( f_curr ) f_prev = f_curr p_fwd = sum ( f_curr [ k ] * trans_prob [ k ][ end_st ] dla k w stanach ) # Część wsteczna algorytmu bkw = [ ] dla i , obserwacja_i_plus w wyliczeniu ( odwrócona ( obserwacje [ 1 :] + ( Brak ,))): b_curr = {} dla st w stanach : if i == : # przypadek bazowy dla części wstecz b_curr [ st ] = trans_prob [ st ][ end_st ] else : b_curr [ st ] = suma ( trans_prob [ st ][ l ] * emm_prob [ l ][ obserwacja_i_plus ] * b_prev [ l ] dla l w stanach ) bkw . insert ( , b_curr ) b_prev = b_curr p_bkw = sum ( start_prob [ l ] * emm_prob [ l ][ obserwacje [ ]] * b_curr [ l ] dla l w stanach ) # Scalanie dwóch części posterior = [] dla i w zakresie ( len ( obserwacje )): tylne . dołącz ({ st : fwd [ i ][ st ] * bkw [ i ][ st ] / p_fwd dla st w stanach }) assert p_fwd == p_bkw return fwd , bkw , posterior
Funkcja fwd_bkw
przyjmuje następujące argumenty: x
jest sekwencją obserwacji, np. ['normal', 'cold', 'dizzy']
; stany
to zbiór stanów ukrytych; a_0
jest prawdopodobieństwem startu; a
to prawdopodobieństwa przejścia; a e
to prawdopodobieństwa emisji.
Dla uproszczenia kodu zakładamy, że sekwencja obserwacji x
nie jest pusta oraz że a[i][j]
oraz e[i][j]
są zdefiniowane dla wszystkich stanów i,j.
W poniższym przykładzie algorytm do przodu i do tyłu jest używany w następujący sposób:
def przykład (): return fwd_bkw ( obserwacje , stany , prawdopodobieństwo_początku , prawdopodobieństwo_przejściowe , prawdopodobieństwo_emisji , stan_końcowy )
>>> dla linii w przykładzie (): ... print ( * line ) ... {'Zdrowy': 0,3, 'Gorączka': 0,04000000000000001} {'Zdrowy': 0,0892, 'Gorączka': 0,03408} {'Zdrowy ': 0,007518, 'Gorączka': 0,0281203199999999997} {'Zdrowy': 0,0010418399999999998, 'Gorączka': 0,00109578} {'Zdrowy': 0,00249, 'Gorączka': 0,00394} {'Wyzdrowienie twój': 0,01, 'Gorączka': 0,01} { 'Zdrowy': 0,8770110375573259, 'Gorączka': 0,1229889624426741} {'Zdrowy': 0,623228030950954, 'Gorączka': 0,3767719690490461} {'Zdrowy': 0,2109527 048413057, „Gorączka”: 0,7890472951586943}
Zobacz też
- Lawrence R. Rabiner , Samouczek dotyczący ukrytych modeli Markowa i wybranych zastosowań w rozpoznawaniu mowy. Proceedings of the IEEE , 77 (2), s. 257–286, luty 1989. 10.1109/5.18626
- Lawrence R. Rabiner, BH Juang (styczeń 1986). „Wprowadzenie do ukrytych modeli Markowa”. Magazyn IEEE ASSP : 4–15.
- Eugeniusza Charniaka (1993). Statystyczna nauka języków . Cambridge, Massachusetts: MIT Press. ISBN 978-0-262-53141-2 .
- Stuarta Russella i Petera Norviga (2010). Sztuczna inteligencja Nowoczesne podejście 3. wydanie . Upper Saddle River, New Jersey: Pearson Education/Prentice-Hall. ISBN 978-0-13-604259-4 .
Linki zewnętrzne
- Interaktywny arkusz kalkulacyjny do nauki algorytmu przód-tył (arkusz kalkulacyjny i artykuł z instrukcją krok po kroku)
- Samouczek ukrytych modeli Markowa, w tym algorytmu przód-tył
- Zbiór algorytmów AI zaimplementowanych w Javie (w tym HMM i algorytm forward-backward)