Python Tensorflow U网分段掩码输入

Python Tensorflow U网分段掩码输入,python,tensorflow,semantic-segmentation,Python,Tensorflow,Semantic Segmentation,我不熟悉tensorflow和语义切分 我正在为语义分段设计一个U-Net。每个图像都有一个我想要分类的对象。但我总共有10个不同物体的图像。我很困惑,如何准备掩码输入?它被认为是多标签分割还是只针对一个类 我应该将输入转换为热编码吗?我应该使用“分类”吗?我找到了多类分割的例子,但我不知道这里是否是这样。因为在一张图像中,我只有一个要检测/分类的对象 我试着用它作为输入代码。但我不确定,我所做的是否正确 #Generation of batches of image and mask clas

我不熟悉tensorflow和语义切分

我正在为语义分段设计一个U-Net。每个图像都有一个我想要分类的对象。但我总共有10个不同物体的图像。我很困惑,如何准备掩码输入?它被认为是多标签分割还是只针对一个类

我应该将输入转换为热编码吗?我应该使用“分类”吗?我找到了多类分割的例子,但我不知道这里是否是这样。因为在一张图像中,我只有一个要检测/分类的对象

我试着用它作为输入代码。但我不确定,我所做的是否正确

#Generation of batches of image and mask
class DataGen(keras.utils.Sequence):
    def __init__(self, image_names, path, batch_size, image_size=128):
        self.image_names = image_names
        self.path = path
        self.batch_size = batch_size
        self.image_size = image_size

    def __load__(self, image_name):
        # Path
        image_path = os.path.join(self.path, "images/aug_test", image_name) + ".png"
        mask_path = os.path.join(self.path, "masks/aug_test",image_name) +  ".png"

        # Reading Image
        image = cv2.imread(image_path, 1)
        image = cv2.resize(image, (self.image_size, self.image_size))


        # Reading Mask
        mask = cv2.imread(mask_path, -1)
        mask = cv2.resize(mask, (self.image_size, self.image_size))

        ## Normalizaing 
        image = image/255.0
        mask = mask/255.0

        return image, mask

    def __getitem__(self, index):
        if(index+1)*self.batch_size > len(self.image_names):
            self.batch_size = len(self.image_names) - index*self.batch_size

        image_batch = self.image_names[index*self.batch_size : (index+1)*self.batch_size]

        image = []
        mask  = []

        for image_name in image_batch:
            _img, _mask = self.__load__(image_name)
            image.append(_img)
            mask.append(_mask)

        #This is where I am defining my input
        image = np.array(image)
        mask  = np.array(mask)
        mask = tf.keras.utils.to_categorical(mask, num_classes=10, dtype='float32') #Is this true?


        return image, mask

    def __len__(self):
        return int(np.ceil(len(self.image_names)/float(self.batch_size)))

这是真的吗?如果是,那么,要将标签/类作为输出,我应该在输入中更改什么?我应该根据我的类别更改遮罩像素的值吗

这是我的U-Net架构

# Convolution and deconvolution Blocks

def down_scaling_block(x, filters, kernel_size=(3, 3), padding="same", strides=1):
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(x)
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(conv)
    pool = keras.layers.MaxPool2D((2, 2), (2, 2))(conv)
    return conv, pool

def up_scaling_block(x, skip, filters, kernel_size=(3, 3), padding="same", strides=1):
    conv_t = keras.layers.UpSampling2D((2, 2))(x)
    concat = keras.layers.Concatenate()([conv_t, skip])
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(concat)
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(conv)
    return conv

def bottleneck(x, filters, kernel_size=(3, 3), padding="same", strides=1):
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(x)
    conv = keras.layers.Conv2D(filters, kernel_size, padding=padding, strides=strides, activation="relu")(conv)
    return conv

我希望我能正确地解释我的问题。欢迎任何帮助

更新:我根据对象类更改了遮罩中每个像素的值。(如果图像包含我想分类为2号对象的对象,则我将掩码像素的值更改为2。整个掩码数组将包含0(bg)和2(对象)。因此,对于每个对象,掩码将包含0和3、0和10等。)

在这里,我首先将掩码更改为二进制,然后如果像素的值大于1,我将其更改为1、2或3。(根据对象/类别编号)

然后,我将它们转换为一个hot和一个tocategory,如代码所示。培训在运行,但网络没有学到任何东西。精度和损耗在两个值之间摇摆不定。我犯了什么错?我是否在生成掩码(更改像素值?)或将函数设置为“分类”时出错

发现的问题: 我在创建掩码时出错。。我用cv2读取图像,它将图像读取为heightxwidth。。在考虑到我的图像尺寸为宽度x高之后,我根据类创建了具有像素值的遮罩。。这就造成了问题,使得网络什么也学不到。。它正在工作

每个图像都有一个我想要分类的对象。但我总共有10个不同物体的图像。我很困惑,如何准备掩码输入?它被认为是多标签分割还是只针对一个类

如果您的数据集有N个不同的标签(即:0-背景、1-狗、2-猫…),则存在多类问题,即使您的图像只包含一种对象

我应该将输入转换为热编码吗?我应该使用“分类”吗

是的,你应该对你的标签进行热编码。使用to_Category可归结为标签的源格式。假设您有N个类,标签是(高度,宽度,1),其中每个像素的值在[0,N]范围内。在这种情况下,keras.utils.to_category(标签,N)将提供一个浮点(高度,宽度,N)标签,其中每个像素为0或1。您不必除以255

如果源格式不同,则可能必须使用自定义函数才能获得相同的输出格式

查看此repo(不是我的作品):“笔记本”文件夹包含两个在小型数据集上训练u-net的示例。它们不是多类的,但很容易一步一步地使用自己的数据集。通过将标签加载为:

im = Image.open(mask).resize((512,512))
im = to_categorical(im,NCLASSES)
按如下方式重新塑造和规格化:

x = np.asarray(imgs_np, dtype=np.float32)/255
y = np.asarray(masks_np, dtype=np.float32)
y = y.reshape(y.shape[0], y.shape[1], y.shape[2], NCLASSES)
x = x.reshape(x.shape[0], x.shape[1], x.shape[2], 3)
使您的模型适应NClass

model = custom_unet(
input_shape,
use_batch_norm=False,
num_classes=NCLASSES,
filters=64,
dropout=0.2,
output_activation='softmax')
选择正确的损失:

from keras.losses import categorical_crossentropy
model.compile(    
   optimizer=SGD(lr=0.01, momentum=0.99),
   loss='categorical_crossentropy',    
   metrics=[iou, iou_thresholded])

希望能有所帮助。

它起作用了。.实际上我在其他地方犯了错误。.我在用cv2读取图像后创建了掩码。.cv2将图像读取为高度和宽度。.我的图像尺寸为176x144,所以cv2将其更改为144x176。.我在创建范围内像素值为(0,类别编号)的掩码时,将其视为176x144。]…这导致网络不学习任何东西。。
from keras.losses import categorical_crossentropy
model.compile(    
   optimizer=SGD(lr=0.01, momentum=0.99),
   loss='categorical_crossentropy',    
   metrics=[iou, iou_thresholded])