2017-01-31 4 views
5

Używam tensorflow do segmentacji semantycznej. Jak mogę powiedzieć tensorflow, aby zignorował określoną etykietę podczas obliczania straty w pikselach?Tensorflow: Jak zignorować określone etykiety podczas segmentacji semantycznej?

Przeczytałem in this post, że dla klasyfikacji obrazów można ustawić etykietę na -1 i zostanie ona zignorowana. Jeśli to prawda, biorąc pod uwagę tensor etykiet, w jaki sposób mogę zmodyfikować moje etykiety tak, aby niektóre wartości zostały zmienione na -1?

W Matlab byłoby coś jak:

ignore_label = 255 
myLabelTensor(myLabelTensor == ignore_label) = -1 

Ale nie wiem, jak to zrobić w TF?

Niektóre informacje tła:
ten sposób etykiety są ładowane:

label_contents = tf.read_file(input_queue[1]) 
label = tf.image.decode_png(label_contents, channels=1) 

ten sposób strata jest obecnie obliczane:

raw_output = net.layers['fc1_voc12'] 
prediction = tf.reshape(raw_output, [-1, n_classes]) 
label_proc = prepare_label(label_batch, tf.pack(raw_output.get_shape()[1:3]),n_classes) 
gt = tf.reshape(label_proc, [-1, n_classes]) 

# Pixel-wise softmax loss. 
loss = tf.nn.softmax_cross_entropy_with_logits(prediction, gt) 
reduced_loss = tf.reduce_mean(loss) 

z

def prepare_label(input_batch, new_size, n_classes): 
    """Resize masks and perform one-hot encoding. 

    Args: 
     input_batch: input tensor of shape [batch_size H W 1]. 
     new_size: a tensor with new height and width. 

    Returns: 
     Outputs a tensor of shape [batch_size h w 21] 
     with last dimension comprised of 0's and 1's only. 
    """ 
    with tf.name_scope('label_encode'): 
     input_batch = tf.image.resize_nearest_neighbor(input_batch, new_size) # as labels are integer numbers, need to use NN interp. 
     input_batch = tf.squeeze(input_batch, squeeze_dims=[3]) # reducing the channel dimension. 
     input_batch = tf.one_hot(input_batch, depth=n_classes) 
    return input_batch 

I używasz tensorflow-deeplab-resnet model, która przenosi Resnet model wdrożony w Caffe do tensorflow przy użyciu caffe-tensorflow.

+0

Możliwy duplikat [TensorFlow: Jak obsługiwać void oznaczone danych w segmentacji obrazu] (https://stackoverflow.com/questions/46097968/tensorflow-how-to-handle-void-labeled-data- w segmentacji obrazu) – Shai

Odpowiedz

0

Zgodnie z dokumentacją, tf.nn.softmax_cross_entropy_with_logits musi być wywoływana z ważnych rozkładów prawdopodobieństwa na labels, lub w inny sposób obliczenia będą nieprawidłowe, a przy użyciu tf.nn.sparse_softmax_cross_entropy_with_logits (co może być wygodniejsze w przypadku) z negatywnymi etykietami albo będzie powodować błąd lub zwróć wartości NaN. Nie liczę na to, że niektóre etykiety będą ignorowane.

Co chciałbym zrobić, to wymienić logits dla ignorowane klasie z nieskończoności w tych pikseli, gdzie prawidłowa klasa jest ignorowane jeden, więc przyczynią się one nic do utraty:

ignore_label = ... 
# Make zeros everywhere except for the ignored label 
input_batch_ignored = tf.concat(input_batch.ndims - 1, 
    [tf.zeros_like(input_batch[:, :, :, :ignore_label]), 
    tf.expand_dims(input_batch[:, :, :, ignore_label], -1), 
    tf.zeros_like(input_batch[:, :, :, ignore_label + 1:])]) 
# Make corresponding logits "infinity" (a big enough number) 
predictions_fix = tf.select(input_batch_ignored > 0, 
    1e30 * tf.ones_like(predictions), predictions) 
# Compute loss with fixed logits 
loss = tf.nn.softmax_cross_entropy_with_logits(prediction, gt) 

Jedyny problem z tą różnicą, że rozważasz, że piksele ignorowanej klasy są zawsze poprawnie przewidywane, co oznacza, że ​​utrata obrazów zawierających dużo tych pikseli będzie sztucznie mniejsza. W zależności od przypadku może się to zdarzyć lub nie, ale jeśli chcesz być naprawdę dokładny, musisz zważyć utratę każdego obrazu zgodnie z liczbą niezignorowanych pikseli, zamiast po prostu wziąć średnią.

# Count relevant pixels on each image 
input_batch_relevant = 1 - input_batch_ignored 
input_batch_weight = tf.reduce_sum(input_batch_relevant, [1, 2, 3]) 
# Compute relative weights 
input_batch_weight = input_batch_weight/tf.reduce_sum(input_batch_weight) 
# Compute reduced loss according to weights 
reduced_loss = tf.reduce_sum(loss * input_batch_weight) 
+0

Przykro mi, ale nie do końca rozumiem odpowiedź: Jak wygląda wyjście "input_batch_ignored = tf.concat (...)"? Wydaje się mieć ten sam kształt, co "przewidywanie" (N x H x W x C) z "zerami" we wszystkich kanałach (C) z wyjątkiem kanału etykiety ignorowania. Ale to oznaczałoby, że przepowiedziałem klasę ignore_label dla wszystkich pikseli w obrazach? Chyba muszę wybrać tylko te piksele, które mają 'ignore_label' jako' gt_label', prawda? Potrzebowałem więc operacji takich jak '' (myLabelTensor == ignore_label) ', aby uzyskać indeksy tych etykiet ... – mcExchange

+0

@mcExchange Jak powiedziałeś,' input_batch_ignored' to wszystkie zera, z wyjątkiem ignorowanej klasy, dla której 'input_batch' są zachowane.Jest ono mnożone przez nieskończoność i dodawane do logitów, skutecznie zmieniając prognozę, tak aby piksele zignorowanej klasy były zawsze poprawne (teraz myślę, czy nieskończoność może dawać złe wyniki, a zamiast tego należy użyć wystarczająco dużej liczby). Oznacza to, że te piksele przyczynią się do ostatecznego kosztu. – jdehesa

+1

@mcExchange Jeśli chcesz zastąpić zignorowaną etykietę wartością -1, możesz zrobić coś w stylu 'label_wo_ignored = tf.select (label! = Ignore_label, label, -1 * tf.ones_like (label))', ale nie jestem na pewno da ci to stratę, którą chcesz (mam na myśli przynajmniej nie według dokumentów). – jdehesa