#python #tensorflow #conv-neural-network #image-segmentation #loss-function
Вопрос:
Я пытаюсь изменить рабочую реализацию функции потерь Тверского, которая определяется как:
где TP: Истинно положительный, FP: Ложноположительный, FN: ложноотрицательный, 0<дельта
У меня есть метки истинности (64×64), которые разрежены и имеют несколько масок (равных одной) размером (3×3), как показано в этом примере:
Моя цель состоит в том, чтобы автоматически установить нулевое значение прогнозируемых пикселей, близких к области, в которой метка основной истины равна единице. В данном примере это означало бы принудительное значение зеленых пикселей, равных нулю в прогнозируемой метке.
Здесь у меня есть реализация, которая использует массивы numpy, что, как я знаю, невозможно для функции потерь (сделано только для одного класса).:
import tensorflow.keras.backend as K
import tensorflow as tf
import numpy as np
def identify_axis(shape):
# Three dimensional
if len(shape) == 5 : return [1,2,3]
# Two dimensional
elif len(shape) == 4 : return [1,2]
# Exception - Unknown
else : raise ValueError('Metric: Shape of tensor is neither 2D or 3D.')
def modified_tversky_loss(y_true, y_pred):
"""
Paper: Tversky loss function for image segmentation using 3D fully convolutional deep networks
Link: https://arxiv.org/abs/1706.05721
delta: controls weight given to false positive and false negatives.
this equates to the Tversky index when delta = 0.7
smooth: smoothing constant to prevent division by zero errors
"""
delta = 0.9
smooth = 0.00001
axis = identify_axis(y_true.get_shape())
#### Part of the code that needs to be changed ####
y_true_copy = y_true.numpy()
y_pred_copy = y_pred.numpy()
for batch in range(np.shape(y_true_copy)[0]):
#### This part is used to get the bottom left coordinates of ground truth masks ####
is_not_all_zero = np.any(y_true_copy[batch,:,:,0])
pos_list = [] # list containing bottom left coordinates of ground truth masks
while is_not_all_zero:
pos = np.unravel_index(y_true_copy[batch,:,:,0].argmax(), y_true_copy.shape)
y_true_copy[batch, pos[1]:pos[1] 3, pos[2]:pos[2] 3, 0] = 0
pos_list.append(pos)
is_not_all_zero = np.any(y_true_copy[batch,:,:,0])
#### Using the bottom left coordinates of ground truth masks, we set to zero neighbour pixels in the predicted label ####
for k in range(len(pos_list)):
y_pred_copy[batch, pos_list[k][1]-3:pos_list[k][1], pos_list[k][2]-3:pos_list[k][2] 6, 0] = 0
y_pred_copy[batch, pos_list[k][1]:pos_list[k][1] 3, pos_list[k][2]-3:pos_list[k][2], 0] = 0
y_pred_copy[batch, pos_list[k][1]:pos_list[k][1] 3, pos_list[k][2] 3:pos_list[k][2] 6, 0] = 0
y_pred_copy[batch, pos_list[k][1] 3:pos_list[k][1] 6, pos_list[k][2]-3:pos_list[k][2] 6, 0] = 0
y_pred = tf.convert_to_tensor(y_pred_copy, dtype=tf.float32)
#### END ####
# Calculate true positives (tp), false negatives (fn) and false positives (fp)
tp = K.sum(y_true * y_pred, axis=axis)
fn = K.sum(y_true * (1-y_pred), axis=axis)
fp = K.sum((1-y_true) * y_pred, axis=axis)
tversky_class = (tp smooth)/(tp delta*fn (1-delta)*fp smooth)
# Sum up classes to one score
tversky_loss = K.sum(1-tversky_class, axis=[-1])
# adjusts loss to account for number of classes
num_classes = K.cast(K.shape(y_true)[-1],'float32')
tversky_loss = tversky_loss / num_classes
return tversky_loss
Эта реализация была запущена с использованием
model.compile(loss=modified_tversky_loss, optimizer=optimizer, metrics=metrics, run_eagerly=True)
и возвращает следующую ошибку
Ошибка значения: градиенты не предусмотрены ни для одной переменной:
что, я полагаю, происходит из-за некоторой проблемы, связанной с недифференцируемыми операциями.
Я пытался написать эту функцию, используя только функции tensorflow, но среди всех моих проблем самая большая проблема, которую я нахожу, заключается в том, что невозможно присвоить значения тензору tf аналогично массивам numpy.
Есть ли способ написать эту функцию, используя только тензоры ? Спасибо
Комментарии:
1. Вы пробовали переместить функцию identify_axis внутрь функции потерь?
2. У меня нет, но функция работает правильно с identity_axis снаружи, когда я удаляю изменения, внесенные в исходную функцию потери Тверского.