《Keras 3 :使用 DeepLabV3+ 的多类语义分割》
作者:Soumik Rakshit
创建日期:2021/08/31
最后修改时间:2024/01/05
描述:实现 DeepLabV3+ 架构以进行多类语义分割。
在 Colab 中查看
GitHub 源
介绍
语义分割,目标是为图像中的每个像素分配语义标签, 是一项必不可少的计算机视觉任务。在此示例中,我们实现 用于多类语义分割的 DeepLabV3+ 模型,一个全卷积模型 在语义分割基准测试中表现良好的架构。
引用:
- 具有 Atrous 可分离卷积的编码器-解码器,用于语义图像分割
- 重新思考语义图像分割的 Atrous 卷积
- DeepLab:使用深度卷积网络、Atrous 卷积和全连接 CRF 进行语义图像分割
下载数据
我们将使用 Crowd Instance 级 Human Parsing Dataset 来训练我们的模型。Crowd 实例级人类解析 (CIHP) 数据集有 38280 张不同的人类图像。 CIHP 中的每张图像都标有 20 个类别的像素级注释,以及实例级标识。 此数据集可用于 “人体部位分割” 任务。
import keras
from keras import layers
from keras import opsimport os
import numpy as np
from glob import glob
import cv2
from scipy.io import loadmat
import matplotlib.pyplot as plt# For data preprocessing
from tensorflow import image as tf_image
from tensorflow import data as tf_data
from tensorflow import io as tf_io
!gdown "1B9A9UCJYMwTL4oBEo4RZfbMZMaZhKJaz&confirm=t"
!unzip -q instance-level-human-parsing.zip
Downloading... From: https://drive.google.com/uc?id=1B9A9UCJYMwTL4oBEo4RZfbMZMaZhKJaz&confirm=t To: /content/keras-io/scripts/tmp_7009966/instance-level-human-parsing.zip 100% 2.91G/2.91G [00:22<00:00, 129MB/s]
创建 TensorFlow 数据集
在包含 38,280 张图像的整个 CIHP 数据集上进行训练需要大量时间,因此我们将使用 在此示例中,用于训练模型的 200 张图像的较小子集。
IMAGE_SIZE = 512
BATCH_SIZE = 4
NUM_CLASSES = 20
DATA_DIR = "./instance-level_human_parsing/instance-level_human_parsing/Training"
NUM_TRAIN_IMAGES = 1000
NUM_VAL_IMAGES = 50train_images = sorted(glob(os.path.join(DATA_DIR, "Images/*")))[:NUM_TRAIN_IMAGES]
train_masks = sorted(glob(os.path.join(DATA_DIR, "Category_ids/*")))[:NUM_TRAIN_IMAGES]
val_images = sorted(glob(os.path.join(DATA_DIR, "Images/*")))[NUM_TRAIN_IMAGES : NUM_VAL_IMAGES + NUM_TRAIN_IMAGES
]
val_masks = sorted(glob(os.path.join(DATA_DIR, "Category_ids/*")))[NUM_TRAIN_IMAGES : NUM_VAL_IMAGES + NUM_TRAIN_IMAGES
]def read_image(image_path, mask=False):image = tf_io.read_file(image_path)if mask:image = tf_image.decode_png(image, channels=1)image.set_shape([None, None, 1])image = tf_image.resize(images=image, size=[IMAGE_SIZE, IMAGE_SIZE])else:image = tf_image.decode_png(image, channels=3)image.set_shape([None, None, 3])image = tf_image.resize(images=image, size=[IMAGE_SIZE, IMAGE_SIZE])return imagedef load_data(image_list, mask_list):image = read_image(image_list)mask = read_image(mask_list, mask=True)return image, maskdef data_generator(image_list, mask_list):dataset = tf_data.Dataset.from_tensor_slices((image_list, mask_list))dataset = dataset.map(load_data, num_parallel_calls=tf_data.AUTOTUNE)dataset = dataset.batch(BATCH_SIZE, drop_remainder=True)return datasettrain_dataset = data_generator(train_images, train_masks)
val_dataset = data_generator(val_images, val_masks)print("Train Dataset:", train_dataset)
print("Val Dataset:", val_dataset)
Train Dataset: <_BatchDataset element_spec=(TensorSpec(shape=(4, 512, 512, 3), dtype=tf.float32, name=None), TensorSpec(shape=(4, 512, 512, 1), dtype=tf.float32, name=None))> Val Dataset: <_BatchDataset element_spec=(TensorSpec(shape=(4, 512, 512, 3), dtype=tf.float32, name=None), TensorSpec(shape=(4, 512, 512, 1), dtype=tf.float32, name=None))>
构建 DeepLabV3+ 模型
DeepLabv3+ 通过添加编码器-解码器结构来扩展 DeepLabv3。编码器模块 通过在多个 缩放,而 Decoder 模块则沿对象边界优化分割结果。
Dilated convolution:通过扩张卷积,随着我们在网络中深入,我们可以保持 步幅常数,但视野更大,且不增加参数数量 或计算量。此外,它还支持更大的输出特征图,即 用于语义分割。
使用扩张空间金字塔池化的原因是,当 采样率变大,有效滤波器权重(即 应用于有效特征区域,而不是填充的零)会变小。
def convolution_block(block_input,num_filters=256,kernel_size=3,dilation_rate=1,use_bias=False,
):x = layers.Conv2D(num_filters,kernel_size=kernel_size,dilation_rate=dilation_rate,padding="same",use_bias=use_bias,kernel_initializer=keras.initializers.HeNormal(),)(block_input)x = layers.BatchNormalization()(x)return ops.nn.relu(x)def DilatedSpatialPyramidPooling(dspp_input):dims = dspp_input.shapex = layers.AveragePooling2D(pool_size=(dims[-3], dims[-2]))(dspp_input)x = convolution_block(x, kernel_size=1, use_bias=True)out_pool = layers.UpSampling2D(size=(dims[-3] // x.shape[1], dims[-2] // x.shape[2]),interpolation="bilinear",)(x)out_1 = convolution_block(dspp_input, kernel_size=1, dilation_rate=1)out_6 = convolution_block(dspp_input, kernel_size=3, dilation_rate=6)out_12 = convolution_block(dspp_input, kernel_size=3, dilation_rate=12)out_18 = convolution_block(dspp_input, kernel_size=3, dilation_rate=18)x = layers.Concatenate(axis=-1)([out_pool, out_1, out_6, out_12, out_18])output = convolution_block(x, kernel_size=1)return output
编码器功能首先按因子 4 进行双倍上采样,然后 与来自网络主干的相应低级特征连接,该 具有相同的空间分辨率。在此示例中,我们 使用在 ImageNet 上预先训练的 ResNet50 作为主干模型,我们使用 来自 backbone 块的低级特征。conv4_block6_2_relu
def DeeplabV3Plus(image_size, num_classes):model_input = keras.Input(shape=(image_size, image_size, 3))preprocessed = keras.applications.resnet50.preprocess_input(model_input)resnet50 = keras.applications.ResNet50(weights="imagenet", include_top=False, input_tensor=preprocessed)x = resnet50.get_layer("conv4_block6_2_relu").outputx = DilatedSpatialPyramidPooling(x)input_a = layers.UpSampling2D(size=(image_size // 4 // x.shape[1], image_size // 4 // x.shape[2]),interpolation="bilinear",)(x)input_b = resnet50.get_layer(