Tensorflow U-Net 多类标签

Tensorflow U-Net Multiclass Label

我是 Whosebug 的新手,所以请为任何典型的新手错误道歉。

我想在 Python 和 Tensorflow 中建立一个带有 U-Net 架构的 CNN。我尝试重用我得到的一些代码,这些代码适用于二进制 classification,并希望对其进行调整以检测 3 classes。我得到的代码非常适合 2 个输出层,它有一个二进制图像作为标签 groundtruth。

现在我的问题是:multiclass 标签的外观是否有约定?我应该使用只有一层(灰度)的 labelimage 和三个值来表示不同的 classes(比如 0、127、255)吗?或者我应该为每个 class 使用一种颜色的 rgb 图像(例如 class 0 为 255, 0, 0;class 1 为 0, 255, 0 等等... )?

""" 0) Creating placeholders for input images and labels """
# Placeholder for input images
x = tf.placeholder(tf.float32, [None, 3*img_size]) # None = arbitrary (Number of images)
# Arrangeing images in 4D format
x_shaped = tf.reshape(x, [-1, img_height, img_width, 3]) # 3 for 3 channels RGB
# Placeholder for labels of input images (ground truth)
y = tf.placeholder(tf.float32, [None, 2*img_size])
# Arrangeing labels in 4D format
y_shaped = tf.reshape(y, [-1, img_size, 2])


""" 1) Defining FCN-8 VGGNet-16 """
network = conv_layer(x_shaped, 64, filter_size=[3, 3], name='conv1a')
network = conv_layer(network, 64, filter_size=[3, 3], name='conv1b')
network = max_pool_layer(network, name='pool1')

network = conv_layer(network, 128, filter_size=[3, 3], name='conv2a')
network = conv_layer(network, 128, filter_size=[3, 3], name='conv2b')
network = max_pool_layer(network, name='pool2')

network = conv_layer(network, 256, filter_size=[3, 3], name='conv3a')
network = conv_layer(network, 256, filter_size=[3, 3], name='conv3b')
network = conv_layer(network, 256, filter_size=[3, 3], name='conv3c')
network = max_pool_layer(network, name='pool3')
net_pool3 = network

network = conv_layer(network, 512, filter_size=[3, 3], name='conv4a')
network = conv_layer(network, 512, filter_size=[3, 3], name='conv4b')
network = conv_layer(network, 512, filter_size=[3, 3], name='conv4c')
network = max_pool_layer(network, name='pool4')
net_pool4 = network

network = conv_layer(network, 512, filter_size=[3, 3], name='conv5a')
network = conv_layer(network, 512, filter_size=[3, 3], name='conv5b')
network = conv_layer(network, 512, filter_size=[3, 3], name='conv5c')
network = max_pool_layer(network, name='pool5')

network = deconv_layer(network, 256, filter_size=[3, 3], name='deconv1')
network = tf.concat([network, net_pool4], 3)
network = conv_layer(network, 256, filter_size=[5, 5], name='conv6')

network = deconv_layer(network, 128, filter_size=[3, 3], name='deconv2')
network = tf.concat([network, net_pool3], 3)
network = conv_layer(network, 128, filter_size=[5, 5], name='conv7')

# in the next lines I would have to change 2 into 3 to get 3 output classes
network = deconv_layer(network, 2, filter_size=[7, 7], strides=[8, 8], name='deconv3')
network = conv_layer(network, 2, filter_size=[7, 7], activation=' ', name='conv8')
y_ = tf.nn.softmax(network)

计算后生成输出图像(测试阶段,训练完成后)

for i in range(rows):
    for j in range(cols):
        for k in range(layers):
            imdata[i*img_height:(i+1)*img_height, j*img_width:(j+1)*img_width, k] = cnn_output[cols*i+j, :, :, k]
imdata = imdata[0:im.height, 0:im.width]
for row in range(real_height):
            for col in range(real_width):
                if(np.amax(imdata[row,col,:]) == imdata[row,col,0]):
                    imdata[row,col,:] = 255, 0, 0
                elif(np.amax(imdata[row,col,:]) == imdata[row,col,1]):
                    imdata[row,col,:] = 0, 255, 0
                else:
                    imdata[row,col,:] = 0, 0, 255
                #img[row][col] = imdata[row][col]
        # Save the image
        scipy.misc.imsave(out_file, imdata)
        im.close()

imdata 具有我的 3 层图像的形状(1080、1920、3)。

分类标签通常是一个向量,其中每个元素代表一个 class:

class A: [1, 0, 0]
class B: [0, 1, 0]
class C: [0, 0, 1]

原因是您的网络的输出是一个 softmax 函数,它将产生一个值介于 0 和 1 之间的向量。例如它可以输出[0.1, 0.1, 0.8]。这些值将始终加起来为 1,因此使用 softmax 假设图片上的每个像素只能属于一个 class,因为增加一个 class 的网络输出会降低其他 class 的输出=43=]es.

在分段中,每个点都分配了 class,因此您的输入现在是 3*img_size 而不是 2*img_size:

# Placeholder for labels of input images (ground truth)
y = tf.placeholder(tf.float32, [None, 3*img_size])
# Arranging labels in 4D format
y_shaped = tf.reshape(y, [-1, img_size, 3])


对于输出:

我假设 cnn_output 只包含一张图片的输出,而不是整批图片的输出。

您需要找出哪个 class 得分最高。在这方面 np.argmax 可以提供帮助:

class_index = np.argmax(cnn_output, axis=2)

class_index 现在包含得分最高的 class 个数字。 (如果 cnn_output 只是二维的,请将 axis 设置为 1。)接下来,您需要将这些值映射到颜色:

colors = {0 : [255, 0, 0], 1 : [0, 255, 0], 2 : [0, 0, 255]}
colored_image = np.array([colors[x] for x in np.nditer(class_index)], 
                         dtype=np.uint8)
output_image = np.reshape(colored_image, (img_height, img_width, 3))

首先我们创建了 colored_image,它现在包含每个点的颜色,但它是一个一维数组,因此您必须通过 np.reshape 将其转换为 3 维数组。您现在可以绘制 output_image:

plt.imshow(output_image)
plt.show()

如果我对你的问题理解正确,你想知道你的标签图像对于 3-class 问题应该如何。

让我们先看看对于一个双class问题应该如何。标签图像将仅由零和一组成,您将为每个像素使用二元交叉熵损失,然后(可能)对整个图像进行平均。

对于 n-class 问题,您的标签图像的大小为 H x W x n,如果您在整个深度上切片,它将是一个单热编码向量。因此,向量除了一个零和一个零(对应于 class)外,其余都是零。

两张图片均来自here。我鼓励您阅读该博客。

预测标签图像后,您可以通过为标签指定特定颜色来轻松转换它。例如,在 2-class 分割图像中,标签 0 => 颜色 0 和标签 1 => 颜色 255 - 即二值图像。

对于 n-class 分割图像,您可以在 [0, 0, 0] 到 [255, 255, 255] 范围内获得 n 个等距点,然后将这些颜色中的每一种分配给一个标签。通常,您可以手动选择这些颜色(例如 4 classes 的红色、绿色、蓝色、黄色),但如果您想要非常花哨,您可以使用类似 this.[=15= 的颜色]