Keras深度学习框架第二十二讲:使用KerasCV进行语义分割

csdn推荐

总的来说,目标检测和语义分割在计算机视觉中都扮演着重要的角色,但它们的任务描述、输出结果和关注点存在明显的区别。目标检测更关注于识别和定位图像中的对象,而语义分割则更关注于对图像内容的详细和深入理解。

1.3 kerasCV的语义分割简介

语义分割是一种计算机视觉任务,它涉及将图像的每个像素分配给一个类别标签,如人、自行车或背景,从而有效地将图像划分为对应于不同对象类别或类别的区域。

KerasCV 提供了由 Google 开发的 DeepLabv3+ 模型用于语义分割。本指南将演示如何使用 KerasCV 来微调和使用 DeepLabv3+ 模型进行图像语义分割。DeepLabv3+ 的架构结合了空洞卷积(atrous convolutions)、上下文信息聚合和强大的骨干网络,以实现准确且详细的语义分割。DeepLabv3+ 模型在各种图像分割基准测试中均取得了最先进的结果。

使用 DeepLabv3+ 进行语义分割通常包括以下步骤:

通过使用 KerasCV 和 DeepLabv3+ 模型,程序员可以快速而准确地实现图像语义分割任务,并在各种应用中发挥其强大的功能。

1.4 调用准备工作

安装

!pip install -q --upgrade keras-cv
!pip install -q --upgrade keras # Upgrade to Keras 3.

调用库

安装 keras-core 和 keras-cv 之后,需要为 keras-core 设置后端。本指南可以与任何后端(如 TensorFlow、JAX、PyTorch)一起运行。

简而言之,这意味着 keras-core(和通常的 Keras)是一个高层次的 API,它允许用户选择底层张量计算库(如 TensorFlow、JAX 或 PyTorch)作为其后端来执行实际的计算。在安装完 keras-core 和 keras-cv 之后,用户需要指定他们想要使用的后端,以便这些库能够正确地执行计算任务。在大多数情况下,TensorFlow 是默认的也是最常用的后端。然而,Keras 的设计允许用户根据需要更改后端。

import os
os.environ["KERAS_BACKEND"] = "jax"
import keras
from keras import ops
import keras_cv
import numpy as np
from keras_cv.datasets.pascal_voc.segmentation import load as load_voc

2、kerasCV进行语义分割的步骤

要使用预训练的 DeepLabv3+ 模型进行语义分割,程序员可以使用 KerasCV 库中的 keras_cv.models API。以下是如何构建一个已经在 PASCAL VOC 数据集上预训练的 DeepLabv3+ 模型的步骤:

2.1 构建模型

model = keras_cv.models.DeepLabV3Plus.from_preset(
    "deeplab_v3_plus_resnet50_pascalvoc",
    num_classes=21,
    input_shape=[512, 512, 3],
)

2.2可视化预训练模型的结果

在语义分割任务中,通常的做法是将模型的预测结果(通常是每个像素的类别分数图)转换为可视化的分割图,以便更直观地理解模型对输入图像的理解。这通常涉及到将每个像素的类别分数转换为对应的类别标签,并使用不同的颜色来区分不同的类别。

filepath = keras.utils.get_file(origin="https://i.imgur.com/gCNcJJI.jpg")
image = keras.utils.load_img(filepath)
resize = keras_cv.layers.Resizing(height=512, width=512)
image = resize(image)
image = keras.ops.expand_dims(np.array(image), axis=0)
preds = ops.expand_dims(ops.argmax(model(image), axis=-1), axis=-1)
keras_cv.visualization.plot_segmentation_mask_gallery(
    image,
    value_range=(0, 255),
    num_classes=1,
    y_true=None,
    y_pred=preds,
    scale=3,
    rows=1,
    cols=1,
)

2.3下载数据

我们使用KerasCV的数据集功能来下载PASCAL VOC数据集,并将其分割为训练数据集train_ds和评估数据集eval_ds。

这里,train_ds代表训练数据集,通常用于训练模型;eval_ds代表评估数据集,用于验证模型的性能。在深度学习项目中,将数据集分割为训练集和验证集(或测试集)是一种常见的做法,以确保模型在未见过的数据上也能表现良好。

train_ds = load_voc(split="sbd_train")
eval_ds = load_voc(split="sbd_eval")

2.4数据预处理

preprocess_tfds_inputs 这个实用函数用于预处理输入数据,将其转化为一个包含图像和分割掩码的字典。图像和分割掩码都被调整到 512x512 的大小。预处理后的数据集随后被分批处理成每批包含 4 对图像和分割掩码的数据组。

这些预处理后的训练数据批次可以使用 keras_cv.visualization.plot_segmentation_mask_gallery 函数进行可视化。这个函数接受一批图像和分割掩码作为输入,并将它们以网格的形式显示出来。

def preprocess_tfds_inputs(inputs):
    def unpackage_tfds_inputs(tfds_inputs):
        return {
            "images": tfds_inputs["image"],
            "segmentation_masks": tfds_inputs["class_segmentation"],
        }
    outputs = inputs.map(unpackage_tfds_inputs)
    outputs = outputs.map(keras_cv.layers.Resizing(height=512, width=512))
    outputs = outputs.batch(4, drop_remainder=True)
    return outputs
train_ds = preprocess_tfds_inputs(train_ds)
batch = train_ds.take(1).get_single_element()
keras_cv.visualization.plot_segmentation_mask_gallery(
    batch["images"],
    value_range=(0, 255),
    num_classes=21,  # The number of classes for the oxford iiit pet dataset. The VOC dataset also includes 1 class for the background.
    y_true=batch["segmentation_masks"],
    scale=3,
    rows=2,
    cols=2,
)

预处理也应用于评估数据集 eval_ds。

eval_ds = preprocess_tfds_inputs(eval_ds)

2.5数据增强

KerasCV 提供了多种图像增强选项。在这个例子中,我们将使用 RandomFlip 增强来对训练数据集进行增强。RandomFlip 增强会随机地将训练数据集中的图像进行水平或垂直翻转。这有助于提高模型对图像中物体方向变化的鲁棒性。

train_ds = train_ds.map(keras_cv.layers.RandomFlip())
batch = train_ds.take(1).get_single_element()
keras_cv.visualization.plot_segmentation_mask_gallery(
    batch["images"],
    value_range=(0, 255),
    num_classes=21,
    y_true=batch["segmentation_masks"],
    scale=3,
    rows=2,
    cols=2,
)

2.6模型配置

请随意修改模型训练的配置,并注意观察训练结果如何变化。这是一个很好的练习,有助于你更好地理解训练流程。

学习率调度(Schedule)由优化器用来计算每个epoch的学习率。优化器随后使用这个学习率来更新模型的权重。在本例中,学习率调度使用余弦衰减(Cosine Decay)函数。余弦衰减函数开始时较高,然后随时间逐渐降低,最终降至零。VOC 数据集的样本数是 2124,批次大小是 4。数据集的样本数对于学习率衰减很重要,因为它决定了模型将训练多少步。初始学习率与 0.007 成比例,衰减步数是 2124。这意味着学习率将从 INITIAL_LR 开始,然后在 2124 步内逐渐降至零。

BATCH_SIZE = 4
INITIAL_LR = 0.007 * BATCH_SIZE / 16
EPOCHS = 1
NUM_CLASSES = 21
learning_rate = keras.optimizers.schedules.CosineDecay(
    INITIAL_LR,
    decay_steps=EPOCHS * 2124,
)

我们实例化了一个基于 ResNet50 主干网络的 DeepLabV3+ 模型,该主干网络在 ImageNet 分类任务上进行了预训练:resnet50_v2_imagenet 预训练权重将被用作 DeepLabV3Plus 模型的骨干特征提取器。num_classes 参数指定了模型将要训练的分割类别的数量。

model = keras_cv.models.DeepLabV3Plus.from_preset(
    "resnet50_v2_imagenet", num_classes=NUM_CLASSES
)

Downloading data from https://storage.googleapis.com/keras-cv/models/resnet50v2/imagenet/classification-v2-notop.h5
 94687928/94687928 ━━━━━━━━━━━━━━━━━━━━ 1s 0us/step

2.7编译模型

pile() 函数为模型设置了训练过程。它定义了以下组件:

语义分割评估指标:

平均交并比(MeanIoU):MeanIoU 测量了语义分割模型在图像中识别和界定不同对象或区域的准确性。它计算预测和实际对象边界之间的重叠程度,提供一个 0 到 1 之间的分数,其中 1 表示完美匹配。

类别准确率(Categorical Accuracy):类别准确率测量了图像中正确分类的像素的比例。它给出一个简单的百分比,表示模型在整个图像中预测像素类别的准确性。

本质上,MeanIoU 强调了在识别特定对象边界时的准确性,而类别准确率则给出了像素级别整体正确性的宽泛概述。

model.compile(
    optimizer=keras.optimizers.SGD(
        learning_rate=learning_rate, weight_decay=0.0001, momentum=0.9, clipnorm=10.0
    ),
    loss=keras.losses.CategoricalCrossentropy(from_logits=False),
    metrics=[
        keras.metrics.MeanIoU(
            num_classes=NUM_CLASSES, sparse_y_true=False, sparse_y_pred=False
        ),
        keras.metrics.CategoricalAccuracy(),
    ],
)
model.summary()

Model: "deep_lab_v3_plus_1"
┏━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━┓
┃ Layer (type)        ┃ Output Shape      ┃ Param # ┃ Connected to         ┃
┡━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━┩
│ input_layer_9       │ (None, None,0-                    │
│ (InputLayer)None, 3)          │         │                      │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ functional_11       │ [(None, None,23,556… │ input_layer_9[0][0]  │
│ (Functional)None, 256),       │         │                      │
│                     │ (None, None,      │         │                      │
│                     │ None, 2048)]      │         │                      │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ spatial_pyramid_po… │ (None, None,15,538… │ functional_11[0][1]  │
│ (SpatialPyramidPoo… │ None, 256)        │         │                      │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ encoder_output_ups… │ (None, None,0 │ spatial_pyramid_poo… │
│ (UpSampling2D)None, 256)        │         │                      │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ sequential_14       │ (None, None,12,480 │ functional_11[0][0]  │
│ (Sequential)None, 48)         │         │                      │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ concatenate_1       │ (None, None,0 │ encoder_output_upsa… │
│ (Concatenate)None, 304)        │         │ sequential_14[0][0]  │
├─────────────────────┼───────────────────┼─────────┼──────────────────────┤
│ sequential_15       │ (None, None,84,224 │ concatenate_1[0][0]  │
│ (Sequential)None, 21)         │         │                      │
└─────────────────────┴───────────────────┴─────────┴──────────────────────┘
 Total params: 39,191,488 (149.50 MB)
 Trainable params: 39,146,464 (149.33 MB)
 Non-trainable params: 45,024 (175.88 KB)

实用函数 dict_to_tuple 有效地将训练和验证数据集的字典转换为图像和独热编码的分割掩码组成的元组。这种格式在 DeepLabv3+ 模型的训练和评估过程中被使用。

具体来说,这个函数的作用是将包含图像和分割掩码的数据集字典(通常是从 TensorFlow 数据集(tf.data.Dataset)或其他数据源中获取的)转换为更易于模型训练和评估的格式。在语义分割任务中,通常需要将分割掩码转换为独热编码(one-hot encoding)的形式,以便模型能够处理多类别的输出。

dict_to_tuple 函数会遍历数据集中的每个样本,提取图像和分割掩码,并将它们打包成一个元组。图像可能直接用于模型输入,而分割掩码则会被转换为独热编码形式,以便与模型的输出进行比较。这种元组格式方便了在训练循环中直接获取和使用图像和掩码数据。

在 DeepLabv3+ 模型的训练和评估过程中,使用这种元组格式可以简化数据处理流程,并确保模型能够正确地接收和解释输入数据。

def dict_to_tuple(x):
    import tensorflow as tf
    return x["images"], tf.one_hot(
        tf.cast(tf.squeeze(x["segmentation_masks"], axis=-1), "int32"), 21
    )
train_ds = train_ds.map(dict_to_tuple)
eval_ds = eval_ds.map(dict_to_tuple)
model.fit(train_ds, validation_data=eval_ds, epochs=EPOCHS)

2.8使用训练好的模型进行预测

现在 DeepLabv3+ 的模型训练已经完成,让我们通过在几个样本图像上进行预测来测试它。

test_ds = load_voc(split="sbd_eval")
test_ds = preprocess_tfds_inputs(test_ds)
images, masks = next(iter(train_ds.take(1)))
images = ops.convert_to_tensor(images)
masks = ops.convert_to_tensor(masks)
preds = ops.expand_dims(ops.argmax(model(images), axis=-1), axis=-1)
masks = ops.expand_dims(ops.argmax(masks, axis=-1), axis=-1)
keras_cv.visualization.plot_segmentation_mask_gallery(
    images,
    value_range=(0, 255),
    num_classes=21,
    y_true=masks,
    y_pred=preds,
    scale=3,
    rows=1,
    cols=4,
)

2.9 注意事项

以下是使用 KerasCV 的 DeepLabv3+ 模型的一些额外提示:

在使用这些模型时,请确保您了解数据集、预处理步骤、训练参数和超参数如何影响模型的性能,并根据您的特定任务进行相应的调整。

3、总结

在kerasCV中,语义分割是一个重要的图像理解任务,其目标是为图像中的每个像素分配语义标签,如道路、建筑、天空等。这种技术能够精确地标注出每个像素所属的类别,因此与图像分类相比,其输出结果更为详细。

实现语义分割的常用算法通常基于卷积神经网络(CNN),其中FCN(Fully Convolutional Networks)是一个典型的例子。FCN将传统的CNN分类器替换为卷积层,并通过反卷积层将高维特征向量转换为像素级的类别预测。

在kerasCV中,语义分割模型的构建和训练过程可以通过使用提供的工具进行简化。Keras是一个流行的深度学习框架,它支持多种后端,如TensorFlow、MXNet、CNTK和Theano,这使得Keras成为实现语义分割模型的一个很好的选择。在训练过程中,交叉熵损失函数通常被用来衡量模型输出与真实标签之间的差异,这有助于提高模型的准确性和鲁棒性。

在kerasCV的语义分割应用中,可以使用各种数据集进行训练,包括COCO、PASCAL VOC和Cityscapes等。此外,用户还可以使用自定义数据集对模型进行微调,以改善在特定任务上的性能。

除了基本的语义分割任务外,kerasCV还提供了其他与图像相关的功能,如图像生成和图像增强。例如,利用生成对抗网络(GAN)等技术可以生成逼真的图像,而通过对图像进行各种变换和增强操作,可以提高模型的泛化能力和鲁棒性。

总的来说,kerasCV为语义分割任务提供了强大的工具和支持,使用户能够轻松构建和训练高效的语义分割模型。

文章来源:https://blog.csdn.net/MUKAMO/article/details/139135064



微信扫描下方的二维码阅读本文

© 版权声明
THE END
喜欢就支持一下吧
点赞7 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容