2016-02-02 9 views
24

Próbuję zastosować głęboką naukę dla problemu klasyfikacji binarnej z wysokim poziomem niezbilansowania klas pomiędzy klasami docelowymi (500k, 31K). Chcę napisać niestandardową funkcję utraty, która powinna wyglądać następująco: minimize (100 - ((predicted_smallerclass)/(total_smallerclass)) * 100)Funkcja utraty klasy niewyważonego klasyfikatora binarnego w przepływie Tensor

Doceń wszelkie wskazówki, w jaki sposób mogę zbudować tę logikę.

Odpowiedz

24

Możesz dodać wagi klas do funkcji utraty, pomnażając logi. Regularne krzyż strata entropia jest taka:

loss(x, class) = -log(exp(x[class])/(\sum_j exp(x[j]))) 
       = -x[class] + log(\sum_j exp(x[j])) 

ważonej w przypadku:

loss(x, class) = weights[class] * -x[class] + log(\sum_j exp(weights[class] * x[j])) 

więc mnożąc logits, jesteś ponowne skalowanie przewidywania każdej klasy na podstawie jego wagi klasy.

Na przykład:

ratio = 31.0/(500.0 + 31.0) 
class_weight = tf.constant([ratio, 1.0 - ratio]) 
logits = ... # shape [batch_size, 2] 
weighted_logits = tf.mul(logits, class_weight) # shape [batch_size, 2] 
xent = tf.nn.softmax_cross_entropy_with_logits(
    weighted_logits, labels, name="xent_raw") 

Jest to standardowa straty funkcja teraz, że wspiera obciążniki na partię:

tf.losses.sparse_softmax_cross_entropy(labels=label, logits=logits, weights=weights) 

przypadku wagi powinny być przekształcony z klasy odważniki o masie na przykład (w kształcie [batch_size]). Zobacz documentation here.

31

Kod, który zaproponowałeś, wydaje mi się błędny. Strata powinna być pomnożona przez wagę, zgadzam się.

Ale jeśli pomnożyć logit przez odważników klasy, skończyć z:

weights[class] * -x[class] + log(\sum_j exp(x[j] * weights[class])) 

drugi termin nie jest równa:

weights[class] * log(\sum_j exp(x[j])) 

Aby to pokazać, że możemy być przepisz tę ostatnią jako:

log((\sum_j exp(x[j])^weights[class]) 

Oto kod, którym jestem p roposing:

ratio = 31.0/(500.0 + 31.0) 
class_weight = tf.constant([[ratio, 1.0 - ratio]]) 
logits = ... # shape [batch_size, 2] 

weight_per_label = tf.transpose(tf.matmul(labels 
          , tf.transpose(class_weight))) #shape [1, batch_size] 
# this is the weight for each datapoint, depending on its label 

xent = tf.mul(weight_per_label 
     , tf.nn.softmax_cross_entropy_with_logits(logits, labels, name="xent_raw") #shape [1, batch_size] 
loss = tf.reduce_mean(xent) #shape 1 
+1

Mam do czynienia z tym samym problemem, ale próbując zrozumieć powyższy kod, nie rozumiem "\ sum_" - czy możesz to wyjaśnić? Wydaje się, że to kod lateksu; działa to w Pythonie? –

+0

Ale w rzeczywistości najlepszym podejściem jest budowanie zrównoważonych mini-partii !! –

+1

@Ron: równanie mówi tylko, że różni się od: pomnóż logit przez masę klasy vs pomnóż odległość (entropia krzyżowa) przez wagi. Kod u dołu działa w języku Python. Ale ogólnie rzecz biorąc, wystarczy zrównoważyć każdą miksturę, a otrzymasz lepszy model! –

8

Zastosowanie tf.nn.weighted_cross_entropy_with_logits() i ustawić pos_weight 1/(oczekiwany stosunek pozytywnych).

+0

Wciąż jestem początkujący w głębokim nauce, więc przepraszam, jeśli moje pytanie jest naiwne. co masz na myśli przez oczekiwany stosunek pozytywów? i jaka jest różnica między tą funkcją a "sigmoid_cross_entropy"? – Maystro

1

Czy OPS tf.nn.weighted_cross_entropy_with_logits() na dwie klasy:

classes_weights = tf.constant([0.1, 1.0]) 
cross_entropy = tf.nn.weighted_cross_entropy_with_logits(logits=logits, targets=labels, pos_weight=classes_weights) 
2

można sprawdzić prowadnice na tensorflow https://www.tensorflow.org/api_guides/python/contrib.losses

...

Podczas określania skalarnego straty przeskalowuje straty na całej partii, czasami chcemy przeskalować stratę na próbkę wsadu. Na przykład, jeśli mamy pewne przykłady, które są dla nas ważniejsze, aby uzyskać poprawne wyniki, możemy chcieć mieć wyższą stratę niż inne próbki, których błędy są mniejsze. W tym przypadku możemy dostarczyć wektor wagowy o długości batch_size, który powoduje utratę każdej próbki w partii skalowanej przez odpowiedni element wagi.Na przykład, rozważmy przypadek problemu klasyfikacji gdzie chcemy zwiększyć naszą dokładność ale szczególnie zainteresowany w uzyskaniu dużej dokładności dla konkretnej klasy:

inputs, labels = LoadData(batch_size=3) 
logits = MyModelPredictions(inputs) 

# Ensures that the loss for examples whose ground truth class is `3` is 5x 
# higher than the loss for all other examples. 
weight = tf.multiply(4, tf.cast(tf.equal(labels, 3), tf.float32)) + 1 

onehot_labels = tf.one_hot(labels, num_classes=5) 
tf.contrib.losses.softmax_cross_entropy(logits, onehot_labels, weight=weight) 
0

musiałem pracować z podobnym niezrównoważonego zbiorze wielu klas i to jak pracowałem przez to, mam nadzieję, że to pomoże ktoś szuka podobnego rozwiązania:

to idzie wewnątrz modułu szkolenia:

from sklearn.utils.class_weight import compute_sample_weight 
#use class weights for handling unbalanced dataset 
if mode == 'INFER' #test/dev mode, not weighing loss in test mode 
    sample_weights = np.ones(labels.shape) 
else: 
    sample_weights = compute_sample_weight(class_weight='balanced', y=labels) 

to idzie wewnątrz modelu definicji klasy:

#an extra placeholder for sample weights 
#assuming you already have batch_size tensor 
self.sample_weight = tf.placeholder(dtype=tf.float32, shape=[None], 
         name='sample_weights') 
cross_entropy_loss = tf.nn.sparse_softmax_cross_entropy_with_logits(
         labels=self.label, logits=logits, 
         name='cross_entropy_loss') 
cross_entropy_loss = tf.reduce_sum(cross_entropy_loss*self.sample_weight)/batch_size