Я следовал учебному пособию по тензорному потоку по сегментации изображений .
Я работаю над задачей сегментации двоичных изображений с полутоновыми изображениями. Я просто скопировал изображение 3 раза, чтобы было 3 канала.
Функция потерь - binary_crossentropy
, а metri c - binary_accuracy
, используя функцию активации sigmoid
на последнем слое. Таким образом, у меня есть только одно выходное значение для каждого пикселя: 0 или 1. Я нормализовал входное значение до [0,1], и метки также равны 0 или 1.
Моя проблема в том, что двоичная точность, рассчитывается по модели, отличается от моего ручного расчета. Вот полный пример небольшого блокнота:
import numpy as np
import tensorflow as tf
# !pip install -q git+https://github.com/tensorflow/examples.git
from tensorflow_examples.models.pix2pix import pix2pix
IMG_SIZE = 32
OUTPUT_CHANNELS = 1
image = np.random.randint(256, size=(IMG_SIZE, IMG_SIZE))
image = image / 255
image = np.repeat(image[..., np.newaxis], 3, -1) # copy the grayscale value 3 times
label = np.random.randint(2, size=(IMG_SIZE, IMG_SIZE))
label = tf.cast(label, tf.float32)
label = tf.expand_dims(label, 2)
train_data = (tf.expand_dims(image, 0),tf.expand_dims(label, 0))
train_data = tf.data.Dataset.from_tensor_slices(train_data).batch(1)
base_model = tf.keras.applications.MobileNetV2(input_shape=[IMG_SIZE, IMG_SIZE, 3], include_top=False)
# Use the activations of these layers
layer_names = [
'block_1_expand_relu', # 64x64
'block_3_expand_relu', # 32x32
'block_6_expand_relu', # 16x16
'block_13_expand_relu', # 8x8
'block_16_project', # 4x4
]
layers = [base_model.get_layer(name).output for name in layer_names]
down_stack = tf.keras.Model(inputs=base_model.input, outputs=layers)
down_stack.trainable = False # Do not train the encoder
up_stack = [
pix2pix.upsample(512, 3), # 4x4 -> 8x8
pix2pix.upsample(256, 3), # 8x8 -> 16x16
pix2pix.upsample(128, 3), # 16x16 -> 32x32
pix2pix.upsample(64, 3), # 32x32 -> 64x64
]
def unet_model(output_channels):
last = tf.keras.layers.Conv2DTranspose(
output_channels, 3, strides=2,
padding='same', activation='sigmoid') #64x64 -> 128x128
inputs = tf.keras.layers.Input(shape=[IMG_SIZE, IMG_SIZE, 3])
x = inputs
# Downsampling through the model
skips = down_stack(x)
x = skips[-1]
skips = reversed(skips[:-1])
for up, skip in zip(up_stack, skips):
x = up(x)
concat = tf.keras.layers.Concatenate()
x = concat([x, skip])
x = last(x)
return tf.keras.Model(inputs=inputs, outputs=x)
def create_mask(pred_mask):
pred_mask = tf.cast(pred_mask.reshape(32,32,1) > 0.5, tf.int32)
return pred_mask
model = unet_model(OUTPUT_CHANNELS)
model.compile(optimizer='adam', loss='binary_crossentropy', metrics=['binary_accuracy'])
model_history = model.fit(train_data, epochs=10)
pred_mask = create_mask(model.predict(tf.expand_dims(image, 0)))
TP = len(tf.where((pred_mask==1)&(label==1)))
TN = len(tf.where((pred_mask==0)&(label==0)))
FP = len(tf.where((pred_mask==1)&(label==0)))
FN = len(tf.where((pred_mask==0)&(label==1)))
print("Binary accuracy manual:", (TP+TN)/(TP+FP+FN+TN))
print("Binary accuracy Keras:", tf.keras.metrics.binary_accuracy(pred_mask, tf.cast(label, tf.int32)).numpy().sum()/(32*32))
Я думаю, что для задачи сегментации двоичного изображения все должно быть в порядке:
- binary_crossentropy
- binary_accuracy
- функция активации сигмовидной кишки
- нормализация до [0,1]
Ручное вычисление двоичной точности такое же, как при использовании tf.keras.metrics.binary_accuracy () (последние 2 печатных заявления). Тем не менее, это не то же самое, что сообщается model.fit ().
Что мне здесь не хватает? Спасибо!