Função Tensorflow Adjusting Cost para dados desequilibrados

12

Eu tenho um problema de classificação com dados altamente desequilibrados. Li que a sobredimensionagem e a subamostragem, bem como a alteração do custo de resultados categóricos sub-representados, levarão a um melhor ajuste. Antes disso, o tensorflow categorizava cada entrada como o grupo majoritário (e ganha mais de 90% de precisão, por menos que seja isso).

Percebi que o log da porcentagem inversa de cada grupo foi o melhor multiplicador que tentei. Existe uma manipulação mais padrão para a função de custo? Isso foi implementado corretamente?

from collections import Counter
counts = Counter(category_train)
weightsArray =[]
for i in range(n_classes):
    weightsArray.append(math.log(category_train.shape[0]/max(counts[i],1))+1)

class_weight = tf.constant(weightsArray)
weighted_logits = tf.mul(pred, class_weight)
cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(weighted_logits, y))
optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate).minimize(cost)
Cole
fonte
Vocês têm alguma referência científica sobre como escolher idealmente os pesos para a função de perda? Não que eu não acredite em você, mas achei você muito inspirado por outra pessoa?
precisa saber é o seguinte
E como a davidparks21 já perguntou, os resultados da sua abordagem seriam muito interessantes :).
precisa saber é o seguinte

Respostas:

4

Esta parece ser uma boa solução para a função de perda. Eu tive sucesso com uma abordagem semelhante recentemente, mas acho que você gostaria de reordenar onde você se multiplica no class_weight.

Pensando nisso logicamente, o resultado class_weightserá uma constante, por isso será transportado e aplicado ao gradiente da mesma maneira que está sendo aplicado à função de custo. Há um problema, entretanto.

Do jeito que você tem, class_weightisso afetaria o valor da previsão. Mas você quer que isso afete a escala do gradiente. Se não estou errado, acho que você deseja reverter a ordem das operações:

# Take the cost like normal
error = tf.nn.softmax_cross_entropy_with_logits(pred, y)

# Scale the cost by the class weights
scaled_error = tf.mul(error, class_weight)

# Reduce
cost = tf.reduce_mean(scaled_error)

Eu ficaria muito interessado em saber como isso funciona em comparação com simplesmente exagerar a classe sub-representada, o que é mais típico. Então, se você tiver alguma ideia, poste sobre isso! :)

Curiosamente, usei com sucesso uma técnica muito semelhante em um domínio de problema diferente recentemente (o que me levou a este post):

Aprendizado multitarefa, encontrando uma função de perda que "ignora" certas amostras

davidparks21
fonte
2

Saída tf.nn.weighted_cross_entropy_with_logits():

Calcula uma entropia cruzada ponderada.

Isso é como sigmoid_cross_entropy_with_logits (), exceto que pos_weight, permite trocar o recall e a precisão aumentando ou diminuindo o custo de um erro positivo em relação a um erro negativo.

Isso deve permitir que você faça o que quiser.

marcos pozzi
fonte
0

Eu tenho 2 implementações diferentes:

  1. com softmax 'regular' com logits : tf.nn.softmax_cross_entropy_with_logits

Onde class_weight é um espaço reservado, preencho a iteração em lote de everey.

self.class_weight  = tf.placeholder(tf.float32, shape=self.batch_size,self._num_classes], name='class_weight')    
self._final_output = tf.matmul(self._states,self._weights["linear_layer"]) + self._biases["linear_layer"] 
self.scaled_logits = tf.multiply(self._final_output, self.class_weight)
self.softmax = tf.nn.softmax_cross_entropy_with_logits(logits=self.scaled_logits,labels= self._labels)
  1. com tf.nn.softmax_cross_entropy_with_logits

Onde eu uso a função tensorflow implementada, mas preciso calcular os pesos para o lote. Os documentos são um pouco confusos. Existem 2 maneiras de fazer isso com o tf.gather ou assim:

self.scaled_class_weights=tf.reduce_sum(tf.multiply(self._labels,self.class_weight),1)
self.softmax = tf.losses.softmax_cross_entropy(logits=self._final_output,
                                                   onehot_labels=self._labels,weights=self.scaled_class_weights)

aqui tem uma boa discussão sobre isso

E, finalmente, como não queria me casar com nenhuma das implementações, acrescentei um pouco de mala e passo o tempo de treinamento para a estratégia que quero usar.

self.sensitive_learning_strategy = tf.placeholder(tf.int32 , name='sensitive_learning_strategy')
self.softmax =tf.case([
            (tf.equal(self.sensitive_learning_strategy, 0), lambda: self.softmax_0),
            (tf.equal(self.sensitive_learning_strategy, 1), lambda: self.softmax_1),
            (tf.equal(self.sensitive_learning_strategy, 2), lambda: self.softmax_2)
AI4U.ai
fonte