我遵循了tensorflow tutorial on image segmentation。
我正在处理带有灰度图像的二进制图像分割任务。 我只是将图像复制了3次,以拥有3个通道。
损失函数为binary_crossentropy
,指标为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))
我认为二进制图像分割任务的设置应该可以:
手动计算二进制精度与使用tf.keras.metrics.binary_accuracy()(最后2个打印语句)相同。但是,它与model.fit()报告的结果不同。
我在这里想念什么? 谢谢!