Próbuję wytresować CNN do kategoryzowania tekstu według tematu. Kiedy używam binarnej entropii krzyżowej, uzyskuję ~ 80% dokładności, przy kategorycznej entropii krzyżowej uzyskuję ~ 50% dokładności.
Nie rozumiem, dlaczego tak jest. Jest to problem wieloklasowy, czy nie oznacza to, że muszę używać kategorycznej entropii krzyżowej i że wyniki z binarną entropią krzyżową są bez znaczenia?
model.add(embedding_layer)
model.add(Dropout(0.25))
# convolution layers
model.add(Conv1D(nb_filter=32,
filter_length=4,
border_mode='valid',
activation='relu'))
model.add(MaxPooling1D(pool_length=2))
# dense layers
model.add(Flatten())
model.add(Dense(256))
model.add(Dropout(0.25))
model.add(Activation('relu'))
# output layer
model.add(Dense(len(class_id_index)))
model.add(Activation('softmax'))
Następnie kompiluję go w ten sposób, używając categorical_crossentropy
jako funkcji utraty:
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
lub
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Intuicyjnie ma sens, dlaczego chciałbym użyć kategorycznej entropii krzyżowej, nie rozumiem, dlaczego uzyskuję dobre wyniki w przypadku binarności i słabe wyniki w kategoriach.
machine-learning
keras
neural-network
deep-learning
conv-neural-network
Daniel Messias
źródło
źródło
categorical_crossentropy
. Etykiety również muszą zostać przekonwertowane na format kategoryczny. Zobacz, jakto_categorical
to zrobić. Zobacz także definicje jakościowych i binarnych krzyżówek tutaj .categorical_crossentropy
. Jeśli masz dwie klasy, będą one reprezentowane jako0, 1
etykiety binarne oraz10, 01
w formacie etykiety kategorialnej.Dense(1, activation='softmax')
klasyfikacja binarna jest po prostu błędna. Pamiętaj, że wynik softmax to rozkład prawdopodobieństwa, który sumuje się do jednego. Jeśli chcesz mieć tylko jeden neuron wyjściowy z klasyfikacją binarną, użyj sigmoidy z binarną entropią krzyżową.Odpowiedzi:
Przyczyną tej pozornej rozbieżności w wydajności między kategoryczną i binarną entropią krzyżową jest to, co użytkownik xtof54 już zgłosił w swojej odpowiedzi poniżej , tj .:
Chciałbym omówić to bardziej szczegółowo, przedstawić faktyczny problem, wyjaśnić go i zaproponować rozwiązanie.
To zachowanie nie jest błędem; Podstawową przyczyną jest raczej subtelny i nieudokumentowany problem, w jaki sposób Keras faktycznie zgaduje, której dokładności użyć, w zależności od wybranej funkcji straty, gdy po prostu
metrics=['accuracy']
włączasz ją do kompilacji modelu. Innymi słowy, podczas gdy twoja pierwsza opcja kompilacjijest ważny, twój drugi:
nie wytworzy tego, czego się spodziewasz, ale powodem nie jest użycie binarnej entropii krzyżowej (która, przynajmniej w zasadzie, jest absolutnie ważną funkcją straty).
Dlaczego? Jeśli sprawdzisz kod źródłowy metryk , Keras nie definiuje jednej metryki dokładności, ale kilka różnych, między innymi
binary_accuracy
icategorical_accuracy
. To, co dzieje się pod maską, polega na tym, że skoro wybrałeś binarną entropię krzyżową jako funkcję straty i nie określiłeś konkretnej miary dokładności, Keras (błędnie ...) wnioskuje, że jesteś zainteresowanybinary_accuracy
, i to właśnie zwraca - podczas gdy w rzeczywistości jesteś zainteresowanycategorical_accuracy
.Sprawdźmy, czy tak jest, korzystając z przykładu MNIST CNN w Keras, z następującą modyfikacją:
Aby temu zaradzić, czyli użycie rzeczywiście binarny przekrój entropię jako swojej funkcji straty (jak powiedziałem, nic złego w tym, przynajmniej w zasadzie), a jednocześnie coraz kategoryczne dokładności wymaganej przez problem pod ręką, należy zwrócić się wprost do
categorical_accuracy
w kompilacja modeli w następujący sposób:W przykładzie MNIST, po wytrenowaniu, ocenie i przewidywaniu zestawu testowego, jak pokazałem powyżej, te dwie metryki są teraz takie same, jak powinny:
Ustawienia systemu:
AKTUALIZACJA : Po moim poście odkryłem, że ten problem został już zidentyfikowany w tej odpowiedzi .
źródło
loss='categorical_crossentropy', metrics=['categorical_accuracy']
klasyfikacji wieloklasowej? To byłaby moja intuicjaWszystko zależy od rodzaju problemu klasyfikacyjnego, z jakim masz do czynienia. Istnieją trzy główne kategorie
W pierwszym przypadku należy zastosować binarną entropię krzyżową, a cele należy zakodować jako jeden gorący wektory.
W drugim przypadku należy zastosować kategoryczną entropię krzyżową, a cele powinny być zakodowane jako wektory o jednym punkcie.
W ostatnim przypadku należy zastosować binarną entropię krzyżową, a cele powinny być zakodowane jako jedno gorące wektory. Każdy neuron wyjściowy (lub jednostka) jest uważany za oddzielną losową zmienną binarną, a strata dla całego wektora wyjść jest iloczynem utraty pojedynczych zmiennych binarnych. Dlatego jest to iloczyn binarnej entropii krzyżowej dla każdej pojedynczej jednostki wyjściowej.
Binarna entropia krzyżowa jest zdefiniowana jako
a kategoryczna entropia krzyżowa jest zdefiniowana jako
gdzie
c
jest indeks biegnący przez liczbę klasźródło
c
indeks jest zbędny w binarnej formule krzyżowej entropii, nie musi tam być (ponieważ są tylko 2 klasy, a prawdopodobieństwo każdej klasy jest osadzone wy(x)
. W przeciwnym razie te formuły powinny być poprawne, ale zwróć uwagę, że to nie są straty, to są prawdopodobieństwa. Jeśli chcesz straty, musisz ją wziąćlog
.Natrafiłem na „odwrócony” problem - uzyskiwałem dobre wyniki z categorical_crossentropy (z 2 klasami) i słabe z binary_crossentropy. Wygląda na to, że problem dotyczył niewłaściwej funkcji aktywacji. Prawidłowe ustawienia to:
binary_crossentropy
: aktywacji esicy, celu skalarnegocategorical_crossentropy
: aktywacji softmax, jeden-gorący zakodowany celźródło
To naprawdę interesujący przypadek. Właściwie w twojej konfiguracji prawdziwe jest następujące stwierdzenie:
Oznacza to, że aż do stałego mnożnika Twoje straty są równoważne. Dziwne zachowanie, które obserwujesz podczas fazy treningu, może być przykładem następującego zjawiska:
adam
- współczynnik uczenia ma znacznie mniejszą wartość niż na początku treningu (wynika to z natury tego optymalizatora). Powoduje to, że szkolenie jest wolniejsze i utrudnia np. Pozostawienie słabego lokalnego minimum w sieci.Dlatego ten stały czynnik może pomóc w przypadku
binary_crossentropy
. Po wielu epokach - wartość wskaźnika uczenia się jest większa niż wcategorical_crossentropy
przypadku. Zwykle wznawiam trening (i fazę uczenia się) kilka razy, gdy zauważam takie zachowanie lub / i dostosowuję wagi klasy według następującego wzoru:To sprawia, że straty z rzadszych zajęć równoważą wpływ przegranej klasy dominującej na początku treningu oraz w dalszej części procesu optymalizacji.
EDYTOWAĆ:
Właściwie - sprawdziłem, chociaż w przypadku matematyki:
powinien trzymać - w przypadku,
keras
gdy to nieprawda, ponieważkeras
automatycznie normalizuje wszystkie wyniki do sumowania1
. To jest prawdziwy powód tego dziwnego zachowania, ponieważ w przypadku wieloklasyfikacji taka normalizacja szkodzi treningowi.źródło
Po skomentowaniu odpowiedzi @Marcin, dokładniej sprawdziłem kod jednego z moich uczniów, w którym znalazłem to samo dziwne zachowanie, nawet po zaledwie 2 epokach! (Więc wytłumaczenie @ Marcina nie było bardzo prawdopodobne w moim przypadku).
I odkryłem, że odpowiedź jest w rzeczywistości bardzo prosta: dokładność obliczona metodą Keras
evaluate
jest po prostu błędna, gdy używa się binary_crossentropy z więcej niż 2 etykietami. Możesz to sprawdzić, przeliczając dokładność samodzielnie (najpierw wywołaj metodę Keras „przewiduj”, a następnie oblicz liczbę poprawnych odpowiedzi zwróconych przez funkcję prognozy): otrzymujesz prawdziwą dokładność, która jest znacznie niższa niż metoda „oceniania” Keras.źródło
prosty przykład w środowisku wieloklasowym do zilustrowania
załóżmy, że masz 4 klasy (zakodowane w jednym ujęciu), a poniżej jest tylko jedna prognoza
true_label = [0,1,0,0] predicted_label = [0,0,1,0]
kiedy używasz categorical_crossentropy, dokładność wynosi tylko 0, przejmuje się tylko tym, czy poprawnie wykonasz odpowiednią klasę.
jednak gdy używasz binary_crossentropy, dokładność jest obliczana dla wszystkich klas, dla tej prognozy będzie to 50%. a ostateczny wynik będzie średnią z poszczególnych dokładności w obu przypadkach.
zaleca się użycie categorical_crossentropy dla problemu z wieloma klasami (klasy wykluczają się wzajemnie), ale binary_crossentropy dla problemu z wieloma etykietami.
źródło
Ponieważ jest to problem wieloklasowy, musisz użyć categorical_crossentropy, binarna entropia krzyżowa da fałszywe wyniki, najprawdopodobniej oceni tylko dwie pierwsze klasy.
50% dla problemu wieloklasowego może być całkiem dobre, w zależności od liczby klas. Jeśli masz n klas, to 100 / n jest minimalną wydajnością, jaką można uzyskać, wyświetlając losową klasę.
źródło
w przypadku
categorical_crossentropy
utraty wartości docelowe powinny być w formacie kategorialnym (np. jeśli masz 10 klas, cel dla każdej próbki powinien być 10-wymiarowym wektorem składającym się z samych zer, z wyjątkiem 1 w indeksie odpowiadającym klasie próba).źródło
Spójrz na równanie, w którym możesz znaleźć, że binarna entropia krzyżowa nie tylko ukarze te etykiety = 1, przewidywane = 0, ale także etykiety = 0, przewidywane = 1.
Jednak kategoryczna entropia krzyżowa karze tylko te etykiety = 1, ale przewidywane = 1, dlatego zakładamy, że jest tylko JEDNA etykieta pozytywna.
źródło
Przekazujesz docelową tablicę kształtu (x-dim, y-dim), używając jako straty
categorical_crossentropy
.categorical_crossentropy
oczekuje, że cele będą binarnymi macierzami (1 i 0) kształtu (próbki, klasy). Jeśli celami są klasy całkowite, możesz przekonwertować je na oczekiwany format za pomocą:Alternatywnie można
sparse_categorical_crossentropy
zamiast tego użyć funkcji utraty , która nie oczekuje wartości docelowych w postaci liczb całkowitych.źródło
Binary_crossentropy (y_target, y_predict) nie musi mieć zastosowania w problemie z klasyfikacją binarną. .
W kodzie źródłowym binary_crossentropy () The
nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)
funkcja TensorFlow był rzeczywiście używany. W dokumentacji jest napisane, że:źródło