Estou tentando treinar uma CNN para categorizar o texto por tópico. Quando uso entropia cruzada binária, obtenho ~ 80% de precisão, com entropia cruzada categórica recebo ~ 50% de precisão.
Eu não entendo por que isso é. É um problema multiclasse, isso não significa que eu tenho que usar entropia cruzada categórica e que os resultados com entropia cruzada binária não têm sentido?
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'))
Então eu compilei assim usando esta categorical_crossentropy
função de perda:
model.compile(loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy'])
ou
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Intuitivamente, faz sentido o motivo pelo qual eu gostaria de usar a entropia cruzada categórica, não entendo por que obtenho bons resultados com binários e maus resultados com categóricos.
machine-learning
keras
neural-network
deep-learning
conv-neural-network
Daniel Messias
fonte
fonte
categorical_crossentropy
. Os rótulos também precisam ser convertidos para o formato categórico. Vejato_categorical
para fazer isso. Veja também definições de entropia cruzada categórica e binária aqui .categorical_crossentropy
. Se você tiver duas classes, elas serão representadas como0, 1
em rótulos binários e10, 01
em formato de rótulo categórico.Dense(1, activation='softmax')
pois a classificação binária está simplesmente errada. Lembre-se de que a saída do softmax é uma distribuição de probabilidade que resume a um. Se você deseja ter apenas um neurônio de saída com classificação binária, use sigmoide com entropia cruzada binária.Respostas:
O motivo dessa aparente discrepância de desempenho entre entropia cruzada categórica e binária é o que o usuário xtof54 já relatou em sua resposta abaixo , ou seja:
Eu gostaria de elaborar mais sobre isso, demonstrar o problema subjacente real, explicá-lo e oferecer um remédio.
Esse comportamento não é um bug; o motivo subjacente é uma questão bastante sutil e não documentada sobre como o Keras realmente adivinha qual precisão usar, dependendo da função de perda que você selecionou, quando você inclui simplesmente
metrics=['accuracy']
na compilação do modelo. Em outras palavras, enquanto sua primeira opção de compilaçãoé válido, seu segundo:
não produzirá o que você espera, mas o motivo não é o uso de entropia cruzada binária (que, pelo menos em princípio, é uma função de perda absolutamente válida).
Por que é que? Se você verificar o código fonte das métricas , o Keras não definirá uma única métrica de precisão, mas várias diferentes, entre elas
binary_accuracy
ecategorical_accuracy
. O que acontece sob o capô é que, como você selecionou a entropia cruzada binária como sua função de perda e não especificou uma métrica de precisão específica, Keras (erroneamente ...) deduz que você está interessadobinary_accuracy
e é isso que ele retorna - enquanto na verdade você está interessado nocategorical_accuracy
.Vamos verificar se é esse o caso, usando o exemplo MNIST CNN em Keras, com a seguinte modificação:
Para remediar isso, ou seja, para usar de fato a entropia cruzada binária como sua função de perda (como eu disse, nada de errado com isso, pelo menos em princípio) enquanto você ainda obtém a precisão categórica exigida pelo problema em questão, solicite explicitamente
categorical_accuracy
no compilação do modelo da seguinte maneira:No exemplo do MNIST, após o treinamento, a pontuação e a previsão do conjunto de testes, como mostro acima, as duas métricas agora são as mesmas, como deveriam ser:
Configuração do sistema:
ATUALIZAÇÃO : Após minha postagem, descobri que esse problema já havia sido identificado nesta resposta .
fonte
loss='categorical_crossentropy', metrics=['categorical_accuracy']
da classificação multiclasse? Esta seria a minha intuiçãoTudo depende do tipo de problema de classificação com o qual você está lidando. Existem três categorias principais
No primeiro caso, a entropia cruzada binária deve ser usada e os alvos devem ser codificados como vetores quentes.
No segundo caso, a entropia cruzada categórica deve ser usada e os alvos devem ser codificados como vetores quentes.
No último caso, a entropia cruzada binária deve ser usada e os alvos devem ser codificados como vetores quentes. Cada neurônio de saída (ou unidade) é considerado uma variável binária aleatória separada, e a perda para todo o vetor de saídas é o produto da perda de variáveis binárias únicas. Portanto, é o produto da entropia cruzada binária para cada unidade de saída única.
A entropia cruzada binária é definida como
entropia cruzada categórica é definida como
onde
c
o índice está sendo executado sobre o número de classesfonte
c
índice é redundante na fórmula de entropia cruzada binária, não precisa estar lá (já que existem apenas 2 classes e a probabilidade de cada classe está incorporaday(x)
. Caso contrário, essas fórmulas devem estar corretas, mas observe que essas não são perdas, essas são probabilidades.Se você quiser a perda, terá que sofrer umalog
delas.Me deparei com um problema "invertido" - eu estava obtendo bons resultados com categorical_crossentropy (com 2 classes) e ruim com binary_crossentropy. Parece que o problema estava com a função de ativação incorreta. As configurações corretas foram:
binary_crossentropy
: ativação sigmóide, alvo escalarcategorical_crossentropy
: ativação softmax, alvo codificado a quentefonte
É um caso realmente interessante. Na verdade, na sua configuração, a seguinte declaração é verdadeira:
Isso significa que, até um fator de multiplicação constante, suas perdas são equivalentes. O comportamento estranho que você está observando durante uma fase de treinamento pode ser um exemplo do seguinte fenômeno:
adam
- a taxa de aprendizado tem um valor muito menor do que tinha no início do treinamento (é por causa da natureza desse otimizador). Isso torna o treinamento mais lento e impede que sua rede, por exemplo, deixe um mínimo local ruim menos possível.É por isso que esse fator constante pode ajudar no caso de
binary_crossentropy
. Após muitas épocas - o valor da taxa de aprendizado é maior do que nocategorical_crossentropy
caso. Normalmente, reinicio o treinamento (e a fase de aprendizado) algumas vezes quando percebo esse comportamento ou / e ajusto o peso de uma classe usando o seguinte padrão:Isso causa perda de classes menos frequentes, equilibrando a influência de uma perda de classe dominante no início de um treinamento e em uma parte adicional de um processo de otimização.
EDITAR:
Na verdade - eu verifiquei que, embora em caso de matemática:
deve se manter - caso
keras
isso não seja verdade, porquekeras
normaliza automaticamente todas as saídas para somar1
. Essa é a verdadeira razão por trás desse comportamento estranho, pois, no caso de multiclassificação, essa normalização prejudica um treinamento.fonte
Depois de comentar a resposta do @Marcin, verifiquei com mais cuidado um código de meus alunos, onde encontrei o mesmo comportamento estranho, mesmo depois de apenas duas épocas! (Portanto, a explicação de @ Marcin não era muito provável no meu caso).
E descobri que a resposta é realmente muito simples: a precisão calculada com o método Keras
evaluate
está totalmente errada ao usar binary_crossentropy com mais de 2 etiquetas. Você pode verificar isso recalculando a precisão você mesmo (primeiro chame o método Keras de "prever" e depois calcule o número de respostas corretas retornadas por previsão): você obtém a precisão verdadeira, que é muito menor do que a Keras "avalia".fonte
um exemplo simples em uma configuração de várias classes para ilustrar
suponha que você tenha 4 classes (codificadas em onehot) e abaixo é apenas uma previsão
true_label = [0,1,0,0] label predito = [0,0,1,0]
ao usar categorical_crossentropy, a precisão é apenas 0, só importa se você acertar a classe em questão.
no entanto, ao usar binary_crossentropy, a precisão é calculada para todas as classes, seria de 50% para esta previsão. e o resultado final será a média das precisões individuais para ambos os casos.
é recomendável usar categorical_crossentropy para problemas com várias classes (as classes são mutuamente exclusivas), mas binary_crossentropy para problemas com vários rótulos.
fonte
Como se trata de um problema de várias classes, é necessário usar o categorical_crossentropy, a entropia cruzada binária produzirá resultados falsos, provavelmente apenas avaliará as duas primeiras classes apenas.
50% para um problema de várias classes pode ser bastante bom, dependendo do número de classes. Se você tiver n classes, 100 / n é o desempenho mínimo que você pode obter produzindo uma classe aleatória.
fonte
ao usar a
categorical_crossentropy
perda, seus alvos devem estar em formato categórico (por exemplo, se você tiver 10 classes, o alvo para cada amostra deve ser um vetor de 10 dimensões que seja todo-zeros, exceto um 1 no índice correspondente à classe da classe amostra).fonte
Dê uma olhada na equação em que você pode descobrir que a entropia cruzada binária não apenas pune os rótulos = 1, preditos = 0, mas também rótulo = 0, preditos = 1.
No entanto, a entropia cruzada categórica apenas pune aqueles marcadores = 1, mas preditos = 1. É por isso que assumimos que existe apenas UM marcador positivo.
fonte
Você está passando uma matriz de forma alvo (x-dim, y-dim) enquanto estiver usando como perda
categorical_crossentropy
.categorical_crossentropy
espera que os alvos sejam matrizes binárias (1s e 0s) de forma (amostras, classes). Se seus destinos forem classes inteiras, você poderá convertê-los para o formato esperado via:Como alternativa, você pode usar a função de perda
sparse_categorical_crossentropy
, que espera destinos inteiros.fonte
O binary_crossentropy (y_target, y_predict) não precisa ser aplicado no problema de classificação binária. .
No código fonte de binary_crossentropy () , a
nn.sigmoid_cross_entropy_with_logits(labels=target, logits=output)
função TensorFlow foi realmente usada. E, na documentação , diz o seguinte:fonte