Точность двоичного кода Keras отличается от точности вычисления вручную - PullRequest
0 голосов
/ 24 января 2020

Я следовал учебному пособию по тензорному потоку по сегментации изображений .

Я работаю над задачей сегментации двоичных изображений с полутоновыми изображениями. Я просто скопировал изображение 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 ().

Что мне здесь не хватает? Спасибо!

...