영역 분할
Semantic Segmentation
1Dataset¶
Crowd Instance-level Human Parsing Dataset
Crowd Instance-level Human Parsing (CIHP) 데이터셋은 38,280개의 다양한 인간 이미지를 포함하고 있습니다. CIHP 데이터셋의 각 이미지는 20가지 카테고리에 대한 픽셀 단위 주석 및 인스턴스 수준의 식별 정보로 레이블이 지정되어 있습니다. 이 데이터셋은 “인간 부분 세분화” 작업에 사용될 수 있습니다.
인간 부분 세분화 작업은 이미지에서 인간 몸의 다른 부분(머리, 상체, 팔, 다리 등)을 식별하고 분할하는 것을 목표로 합니다. 이 작업은 인간 활동 인식, 인간 자세 추정, 가상 의류 시스템 등 다양한 컴퓨터 비전 응용 프로그램에서 중요합니다.
CIHP 데이터셋은 인간 부분 세분화 모델의 학습 및 평가에 널리 사용됩니다. 그 크기가 크고 다양한 이미지 범위를 가지므로 이 도메인에서 견고하고 일반화된 모델을 개발하기에 적합합니다.
import os
from glob import glob
data_dir = '../data/instance-level-human-parsing/instance-level_human_parsing/instance-level_human_parsing/'
# 훈련 데이터셋 파일 경로
train_image_list = glob(os.path.join(data_dir, 'Training', 'Images/*.jpg'))
train_mask_list = glob(os.path.join(data_dir, 'Training', 'Category_ids/*.png'))
# 검증 데이터셋 파일 경로
val_image_list = glob(os.path.join(data_dir, 'Validation', 'Images/*.jpg'))
val_mask_list = glob(os.path.join(data_dir, 'Validation', 'Category_ids/*.png'))
# 테스트 데이터셋 파일 경로
test_image_list = glob(os.path.join(data_dir, 'Testing', 'Images/*.jpg'))
print(len(train_image_list), len(train_mask_list))
print(len(val_image_list), len(val_mask_list))
print(len(test_image_list))28280 28280
5000 5000
5000
2TensorFlow Dataset¶
from collections import namedtuple
import tensorflow as tf
configs = namedtuple('configs', ['image_size', 'batch_size', 'num_classes'])
configs.image_size = (512, 512)
configs.batch_size = 4
configs.num_classes = 20
def read_image(image_path, image_size, 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)
else:
image = tf.image.decode_jpeg(image, channels=3)
image.set_shape([None, None, 3])
image = tf.image.resize(images=image, size=image_size)
image = tf.keras.applications.resnet50.preprocess_input(image)
return image
def load_data(image_list, mask_list):
image = read_image(image_list, image_size=configs.image_size)
mask = read_image(mask_list, image_size=configs.image_size, mask=True)
return image, mask
def 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(configs.batch_size, drop_remainder=True)
return dataset
train_dataset = data_generator(train_image_list[:1000], train_mask_list[:1000])
valid_dataset = data_generator(val_image_list[:50], val_mask_list[:50])for image, mask in train_dataset.take(1):
print(image.shape, mask.shape)(4, 512, 512, 3) (4, 512, 512, 1)
3DeepLabV3+¶
import tensorflow.keras.layers as layers
def conv_block(inputs, filters=256, kernel_size=3, dilation_rate=1, padding='same', use_bias=False):
x = layers.Conv2D(filters=filters, kernel_size=kernel_size, dilation_rate=dilation_rate, padding=padding, use_bias=use_bias)(inputs)
x = layers.BatchNormalization()(x)
x = layers.ReLU()(x)
return x
def DilatedSpatialPyramidPooling(inputs):
dims = inputs.shape
x = layers.AveragePooling2D(pool_size=(dims[-3], dims[-2]))(inputs)
x = conv_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 = conv_block(inputs, kernel_size=1, dilation_rate=1)
out_6 = conv_block(inputs, kernel_size=3, dilation_rate=6)
out_12 = conv_block(inputs, kernel_size=3, dilation_rate=12)
out_18 = conv_block(inputs, kernel_size=3, dilation_rate=18)
x = layers.Concatenate(axis=-1)([out_pool, out_1, out_6, out_12, out_18])
output = conv_block(x, kernel_size=1)
return output
def build_model(input_shape=(512, 512, 3), num_classes=20):
inputs = tf.keras.Input(shape=input_shape)
# Encoder
resnet50 = tf.keras.applications.ResNet50(include_top=False, input_tensor=inputs, weights='imagenet')
x = resnet50.get_layer('conv4_block6_2_relu').output
x = DilatedSpatialPyramidPooling(x)
# Decoder
IMAGE_SIZE = input_shape[0]
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('conv2_block3_2_relu').output
input_b = conv_block(input_b, filters=48, kernel_size=1)
x = layers.Concatenate(axis=-1)([input_a, input_b])
x = conv_block(x)
x = conv_block(x)
x = layers.UpSampling2D(size=(IMAGE_SIZE // x.shape[1], IMAGE_SIZE // x.shape[2]), interpolation='bilinear')(x)
outputs = layers.Conv2D(num_classes, kernel_size=1, padding='same')(x)
return tf.keras.Model(inputs=inputs, outputs=outputs, name='DeepLabV3_Plus')
model = build_model(input_shape=configs.image_size + (3,), num_classes=configs.num_classes)
model.summary()Fetching long content....
model.compile(
optimizer=tf.keras.optimizers.Adam(learning_rate=1e-3),
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True),
metrics=['acc'])
callbacks = [
tf.keras.callbacks.ModelCheckpoint('./checkpoints/DeepLabV3_Plus.h5', save_best_only=True)
]
history = model.fit(
train_dataset,
validation_data=valid_dataset,
epochs=2,
callbacks=callbacks
)
Epoch 1/2
250/250 [==============================] - ETA: 0s - loss: 1.5655 - acc: 0.5699250/250 [==============================] - 326s 1s/step - loss: 1.5655 - acc: 0.5699 - val_loss: 1.4022 - val_acc: 0.6219
Epoch 2/2
250/250 [==============================] - 310s 1s/step - loss: 1.4878 - acc: 0.5804 - val_loss: 1.3587 - val_acc: 0.6388