Я хочу обучить сегментации семанти c для набора данных A2D2 . Я построил себе фреймворк для разработки и тестирования различных модельных архитектур. Проблема, с которой я сталкиваюсь, как только я пытаюсь реализовать встроенный кодировщик (например, Keras ResNet50V2), заключается в том, что качество сегментации страдает. В конце обучения модель часто предсказывает сгустки классов с почти постоянной формой для каждого входного изображения.
Я уменьшил количество изображений с 40К до 1К для целей тестирования. Я пытался тренироваться с изображениями 10 тыс., Но это не улучшило качество прогноза. В своих испытаниях я также пытался уменьшить количество классов до 38 и 14, что также не улучшило качество.
У кого-нибудь есть идеи, в чем проблема? Подробнее см. Ниже.
Настройки, которые я использовал для создания модели:
- input_shape: (720, 1280, 3)
- kernel_size: (3, 3)
- пул: макс.
- пул_размер: (2, 2)
- заполнение: те же
- шаги: (1, 1)
- активация : relu
- bn_axis: 3
Настройки, которые я использовал для обучения:
- Эпохи: 20
- Размер партии: 3
- Оптимизатор:
Adam(learning_rate=0.01, beta_1=0.9, beta_2=0.999, amsgrad=False)
def lr_schedule(epoch):
learning_rate = 0.01
if epoch > 10:
learning_rate = 0.001
if epoch > 15:
learning_rate = 0.0001
return learning_rate
lr_scheduler = LearningRateScheduler(lr_schedule)
- Предварительная обработка для изображений:
def preprocess_input(self, x):
return x / 255.
- Предварительная обработка для этикеток
label = to_categorical(label, num_classes=num_classes)
Сравнение результатов
Метка истинности заземления против прогноза
Собственная сборка модель ( FCN_3D_2U_BN_Adam_RLS )
Хотя в некоторых случаях присвоение класса является правильным, модель распознает такие признаки, как дорожный знак на правая сторона.
Готовая модель ( ResNe t50_2U_BN_Adam_RLS )
Здесь вы уже можете увидеть потерю распознанных функций. Ниже приведены более экстремальные случаи.
Модель: "FCN_3D_2U_BN_Adam_RLS"
Код
input_node = Input(shape=self.input_shape)
# Conv Block 1
x = mutils.Conv2dBn(filters=32, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(input_node)
x = mutils.Conv2dBn(filters=32, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(x)
x = MaxPooling2D(pool_size=self.pool_size, padding=self.padding)(x)
# Conv Block 2
x = mutils.Conv2dBn(filters=64, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(x)
x = mutils.Conv2dBn(filters=64, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(x)
x = MaxPooling2D(pool_size=self.pool_size, padding=self.padding)(x)
# Conv Block 3
x = mutils.Conv2dBn(filters=256, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(x)
x = mutils.Conv2dBn(filters=256, kernel_size=self.kernel_size, strides=self.strides, padding=self.padding,
activation=self.activation, use_batchnorm=True)(x)
x = MaxPooling2D(pool_size=self.pool_size, padding=self.padding)(x)
# Upsample
x = Conv2DTranspose(filters=128, kernel_size=(4, 4), strides=(2, 2), padding='same', activation=None)(x)
x = BatchNormalization(axis=self.bn_axis)(x)
x = Activation(activation=self.activation)(x)
# Upsampling to image shape
x = Conv2DTranspose(self.num_classes, kernel_size=(8, 8), strides=(4, 4), padding='same', activation=None)(x)
x = BatchNormalization(axis=self.bn_axis)(x)
output_node = Activation('softmax')(x)
# Create model
model = Model(input_node, output_node, name=self.model_name)
Слой Conv2dBn скопирован из qubvel / segmentation_models .
Метри c Результаты
- Точность: 0,53
- Категориальная_кросентропия: 1,87
Результаты COCO
| | Mean IOU | FW IOU | Mean accuracy | Pixel accuracy |
|:----------|-----------:|---------:|----------------:|-----------------:|
| leaves | 0.0451 | 0.4278 | 0.0668 | 0.6181 |
Модель: "ResNet50_2U_BN_Adam_RLS"
Код
input_node = Input(shape=self.input_shape)
encoder_resnet = ResNet50V2(include_top=False, weights=None, input_tensor=input_node, pooling=self.pooling,
classes=self.num_classes)
encoder_output = encoder_resnet.get_layer('conv4_block6_1_relu').output
# Upsample
x = Conv2DTranspose(filters=128, kernel_size=(8, 8), strides=(4, 4), padding='same', activation=None)(
encoder_output)
x = BatchNormalization(axis=self.bn_axis)(x)
x = Activation(activation=self.activation)(x)
# Upsampling to image shape
x = Conv2DTranspose(self.num_classes, kernel_size=(8, 8), strides=(4, 4), padding='same', activation=None)(x)
x = BatchNormalization(axis=self.bn_axis)(x)
output_node = Activation('softmax')(x)
# Create model
model = Model(input_node, output_node, name=self.model_name)
Единственное изменение в части декодера - увеличение шагов от (2 , 2) - (4, 4) для первого слоя Conv2DTranspose, чтобы получить правильную выходную форму.
Метри c Результаты
- Точность: 0,50
- Категориальная_кросентропия: 1,81
Результаты COCO
| | Mean IOU | FW IOU | Mean accuracy | Pixel accuracy |
|:----------|-----------:|---------:|----------------:|-----------------:|
| leaves | 0.0444 | 0.4204 | 0.0669 | 0.6165 |
Приложение
Несколько более экстремальных случаев с BLOB-объектами
Я тренировался со многими различными сетями и настройками декодера. Одним из них был PS PNet из segmentation_models с Adam, ReduceLROnPlateau, функцией взвешенных потерь, предварительно обученными весами и замороженным кодером для 20% эпох.
Для большего набора данных и большего количества эпох ResNet50_2U_BN_Adam_RLS будет в конечном итоге достичь тех же пятен, что и выше. Однако для этой модели у меня нет такого прекрасно сопоставимого примера. Тем не менее, я думаю, что капли сегментации модели Re sNet уже видны.